Full Code of Lepozepo/S3 for AI

master 0dc2d6ba0c33 cached
35 files
41.8 KB
15.7k tokens
1 requests
Download .txt
Repository: Lepozepo/S3
Branch: master
Commit: 0dc2d6ba0c33
Files: 35
Total size: 41.8 KB

Directory structure:
gitextract_nbdvszgl/

├── .gitignore
├── .npm/
│   └── package/
│       ├── .gitignore
│       ├── README
│       └── npm-shrinkwrap.json
├── .versions
├── LICENSE.md
├── README.md
├── client/
│   └── functions.coffee
├── coffeelint.json
├── example/
│   ├── basic/
│   │   ├── .meteor/
│   │   │   ├── .finished-upgraders
│   │   │   ├── .gitignore
│   │   │   ├── .id
│   │   │   ├── packages
│   │   │   ├── platforms
│   │   │   ├── release
│   │   │   └── versions
│   │   ├── basic.coffee
│   │   ├── basic.html
│   │   └── packages/
│   │       └── .gitignore
│   └── mdg_camera/
│       ├── .meteor/
│       │   ├── .finished-upgraders
│       │   ├── .gitignore
│       │   ├── .id
│       │   ├── cordova-plugins
│       │   ├── packages
│       │   ├── platforms
│       │   ├── release
│       │   └── versions
│       ├── mdg_camera.coffee
│       ├── mdg_camera.html
│       └── packages/
│           └── .gitignore
├── package.js
├── server/
│   ├── delete_object.coffee
│   ├── sign_request.coffee
│   └── startup.coffee
└── versions.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.build*
.DS_store
.aws_keys.txt


================================================
FILE: .npm/package/.gitignore
================================================
node_modules


================================================
FILE: .npm/package/README
================================================
This directory and the files immediately inside it are automatically generated
when you change this package's NPM dependencies. Commit the files in this
directory (npm-shrinkwrap.json, .gitignore, and this README) to source control
so that others run the same versions of sub-dependencies.

You should NOT check in the node_modules directory that Meteor automatically
creates; if you are using git, the .gitignore file tells git to ignore it.


================================================
FILE: .npm/package/npm-shrinkwrap.json
================================================
{
  "lockfileVersion": 1,
  "dependencies": {
    "aws-sdk": {
      "version": "2.1.14",
      "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1.14.tgz",
      "integrity": "sha1-cPct9Y1GaiItTDK/IbYarX5QRpg=",
      "dependencies": {
        "xml2js": {
          "version": "0.2.6",
          "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.6.tgz",
          "integrity": "sha1-0gnE5N2h/JxFIUHvQcB39a399sQ=",
          "dependencies": {
            "sax": {
              "version": "0.4.2",
              "resolved": "https://registry.npmjs.org/sax/-/sax-0.4.2.tgz",
              "integrity": "sha1-OfO2AXM9a+yXEFskKipA/Wl4rDw="
            }
          }
        },
        "xmlbuilder": {
          "version": "0.4.2",
          "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-0.4.2.tgz",
          "integrity": "sha1-F3bWXz/brUcKCNhgTN6xxOVA/4M="
        }
      }
    },
    "crypto-js": {
      "version": "3.1.6",
      "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.6.tgz",
      "integrity": "sha1-YUJlGyMtu469+pcWpwooiDWdpsk="
    },
    "knox": {
      "version": "0.9.2",
      "resolved": "https://registry.npmjs.org/knox/-/knox-0.9.2.tgz",
      "integrity": "sha1-NzZZNmniTwJP2vcjtqHcSv2DmnE=",
      "dependencies": {
        "debug": {
          "version": "1.0.4",
          "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz",
          "integrity": "sha1-W5wla9VLbsAigxdvqKDt5tFUy/g=",
          "dependencies": {
            "ms": {
              "version": "0.6.2",
              "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz",
              "integrity": "sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw="
            }
          }
        },
        "mime": {
          "version": "1.3.4",
          "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
          "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM="
        },
        "once": {
          "version": "1.3.1",
          "resolved": "https://registry.npmjs.org/once/-/once-1.3.1.tgz",
          "integrity": "sha1-8/Pk2lt9J7XHMpae4+Z+cpRXsx8=",
          "dependencies": {
            "wrappy": {
              "version": "1.0.1",
              "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz",
              "integrity": "sha1-HmWWmWXMvC20VIxrhKbyxa7dRzk="
            }
          }
        },
        "stream-counter": {
          "version": "1.0.0",
          "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-1.0.0.tgz",
          "integrity": "sha1-kc8lac5NxQYf6816yyY5SloRR1E="
        },
        "xml2js": {
          "version": "0.4.5",
          "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.5.tgz",
          "integrity": "sha1-/EJnUbfPiQqqkJp1bu3jHH84qPw=",
          "dependencies": {
            "sax": {
              "version": "0.6.1",
              "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz",
              "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk="
            },
            "xmlbuilder": {
              "version": "2.6.1",
              "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-2.6.1.tgz",
              "integrity": "sha1-umkhZQEz5YCCiPNdyrDbaWqbqaA=",
              "dependencies": {
                "lodash": {
                  "version": "3.3.1",
                  "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.3.1.tgz",
                  "integrity": "sha1-O5FNShuyfvzuB24N+lgVIBjiBC4="
                }
              }
            }
          }
        }
      }
    },
    "moment": {
      "version": "2.13.0",
      "resolved": "https://registry.npmjs.org/moment/-/moment-2.13.0.tgz",
      "integrity": "sha1-JBYtmVIebUD5muaTnoBtITnqrFI="
    },
    "stream-buffers": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.1.0.tgz",
      "integrity": "sha1-gsG8imgVvwAQje2I6lU/D4vLOzo="
    }
  }
}


================================================
FILE: .versions
================================================
accounts-base@1.4.2
allow-deny@1.1.0
autoupdate@1.4.0
babel-compiler@7.0.4
babel-runtime@1.2.0
base64@1.0.10
binary-heap@1.0.10
boilerplate-generator@1.4.0
caching-compiler@1.1.9
callback-hook@1.1.0
check@1.3.0
coffeescript@1.0.17
ddp@1.4.0
ddp-client@2.3.1
ddp-common@1.4.0
ddp-rate-limiter@1.0.7
ddp-server@2.1.2
diff-sequence@1.1.0
dynamic-import@0.3.0
ecmascript@0.10.0
ecmascript-runtime@0.5.0
ecmascript-runtime-client@0.6.0
ecmascript-runtime-server@0.5.0
ejson@1.1.0
es5-shim@4.7.3
geojson-utils@1.0.10
hot-code-push@1.0.4
http@1.4.0
id-map@1.1.0
lepozepo:s3@5.2.8
livedata@1.0.18
localstorage@1.2.0
logging@1.1.19
meteor@1.8.2
meteor-base@1.3.0
minimongo@1.4.3
modules@0.11.3
modules-runtime@0.9.1
mongo@1.4.2
mongo-dev-server@1.1.0
mongo-id@1.0.6
npm-mongo@2.2.33
ordered-dict@1.1.0
promise@0.10.1
random@1.1.0
rate-limit@1.0.8
reactive-var@1.0.11
reload@1.2.0
retry@1.1.0
routepolicy@1.0.12
server-render@0.3.0
service-configuration@1.0.11
shim-common@0.1.0
socket-stream-client@0.1.0
tracker@1.1.3
underscore@1.0.10
url@1.2.0
webapp@1.5.0
webapp-hashing@1.0.9


================================================
FILE: LICENSE.md
================================================
The MIT License (MIT)

Copyright (c) 2015 Marcelo Reyna

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


================================================
FILE: README.md
================================================
# Amazon S3 Uploader
S3 provides a simple way for uploading files to the Amazon S3 service with a progress bar. This is useful for uploading images and files that you want accesible to the public. S3 is built on [Knox](https://github.com/LearnBoost/knox) and [AWS-SDK](https://github.com/aws/aws-sdk-js). Both modules are made available on the server after installing this package.

If you want to keep using the older version of this package (pre 0.9.0) check it out using `meteor add lepozepo:s3@=3.0.1`

If you want to keep using the version of this package that uses server resources to upload files check it out using `meteor add lepozepo:s3@=4.1.3`

**S3 now uploads directly from the client to Amazon. Client files will not touch your server.**

# Show your support!
Star my code in github or atmosphere if you like my code or shoot me a dollar or two!

[DONATE HERE](https://cash.me/$lepozepo)

## Moving Forward
In line with Meteor's move towards NPM, I'm moving this package to NPM. Along with this move, I'll resolve issues with importing the uploader and making it easy to use in React and React Native. I've already started migrating but I'm only half way there, have a look at the repo [here](https://github.com/Lepozepo/S3-uploader)

## NEW IN 5.2.1
* AWS Signature V4!! This means more regions can use this package

## Installation

``` sh
$ meteor add lepozepo:s3
```

## How to use

### Step 1
Define your Amazon S3 credentials. SERVER SIDE.

``` javascript
S3.config = {
	key: 'amazonKey',
	secret: 'amazonSecret',
	bucket: 'bucketName',
	region: 'eu-west-1' // Only needed if not "us-east-1" or "us-standard"
};
```

### Step 2
Create a file input and progress indicator. CLIENT SIDE.

``` handlebars
<template name="s3_tester">
	<input type="file" class="file_bag">
	<button class="upload">Upload</button>

	{{#each files}}
		<p>{{percent_uploaded}}</p>
	{{/each}}
</template>
```

### Step 3
Create a function to upload the files and a helper to see the uploads progress. CLIENT SIDE.

``` javascript
Template.s3_tester.events({
	"click button.upload": function(){
		var files = $("input.file_bag")[0].files

		S3.upload({
				files:files,
				path:"subfolder"
			},function(e,r){
				console.log(r);
		});
	}
})

Template.s3_tester.helpers({
	"files": function(){
		return S3.collection.find();
	}
})
```

## Create your Amazon S3

For all of this to work you need to create an aws account.

### 1. Create an S3 bucket in your preferred region.

### 2. Access Key Id and Secret Key

1. Navigate to your bucket
2. On the top right side you'll see your account name. Click it and go to Security Credentials.
3. Create a new access key under the Access Keys (Access Key ID and Secret Access Key) tab.
4. Enter this information into your app as defined in "How to Use" "Step 1".
5. Your region can be found under "Properties" button and "Static Website Hosting" tab.
	* bucketName.s3-website-**eu-west-1**.amazonaws.com.
	* If your region is "us-east-1" or "us-standard" then you don't need to specify this in the config.

### 3. Hosting

1. Upload a blank `index.html` file (anywhere is ok, I put it in root).
2. Select the bucket's properties by clicking on the bucket (from All Buckets) then the "Properties" button at the top right.
3. Click **"Static Website Hosting"** tab.
4. Click **Enable Website Hosting**.
5. Fill the `Index Document` input with the path to your `index.html` without a trailing slash. E.g. `afolder/index.html`, `index.html`
6. **Click "Save"**

### 4. CORS

You need to set permissions so that everyone can see what's in there.

1. Select the bucket's properties and go to the "Permissions" tab.
2. Click "Edit CORS Configuration" and paste this:

	``` xml
	<?xml version="1.0" encoding="UTF-8"?>
	<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
		<CORSRule>
			<AllowedOrigin>*</AllowedOrigin>
			<AllowedMethod>PUT</AllowedMethod>
			<AllowedMethod>POST</AllowedMethod>
			<AllowedMethod>GET</AllowedMethod>
			<AllowedMethod>HEAD</AllowedMethod>
			<MaxAgeSeconds>3000</MaxAgeSeconds>
			<AllowedHeader>*</AllowedHeader>
		</CORSRule>
	</CORSConfiguration>
	```

5. Click "Edit bucket policy" and paste this (**Replace the bucket name with your own**):

	``` javascript
	{
		"Version": "2008-10-17",
		"Statement": [
			{
				"Sid": "AllowPublicRead",
				"Effect": "Allow",
				"Principal": {
					"AWS": "*"
				},
				"Action": "s3:GetObject",
				"Resource": "arn:aws:s3:::YOURBUCKETNAMEHERE/*"
			}
		]
	}
	```

7. **Click Save**

### Note

It might take a couple of hours before you can actually start uploading to S3. Amazon takes some time to make things work.

Enjoy, this took me a long time to figure out and I'm sharing it so that nobody has to go through all that.

## API

### S3 (CLIENT SIDE)

#### S3.collection
This is a null Meteor.Collection that exists only on the users client. After the user leaves the page or refreshes, the collection disappears forever.

#### S3.upload(ops,callback)
This is the upload function that manages all the dramatic things you need to do for something so essentially simple.

__Parameters:__
*	__ops.file [OPTIONAL]:__ Must be a File object. You can create this via ```new File()```.  Either this otpion or 'files' just be provided.
*	__ops.files [OPTIONAL]:__ Must be a FileList object. You can get this via jQuery via $("input[type='file']")[0].files.
*	__ops.path [DEFAULT: ""]:__ Must be in this format ("folder/other_folder"). So basically never start with "/" and never end with "/". Defaults to ROOT folder.
*	__ops.unique_name [DEFAULT: true]:__ If set to true, the uploaded file name will be set to a uuid without changing the files' extension. If set to false, the uploaded file name will be set to the original name of the file.
*	__ops.encoding [OPTIONAL: "base64"]:__ If set to "base64", the uploaded file will be uploaded as a base64 string. The uploader will enforce a unique_name if this option is set.
*	__ops.expiration [DEFAULT: 1800000 (30 mins)]:__ Defines how much time the file has before Amazon denies the upload. Must be in milliseconds. Defaults to 1800000 (30 minutes).
*	__ops.uploader [DEFAULT: "default"]:__ Defines the name of the uploader. Useful for forms that use multiple uploaders.
*	__ops.acl [DEFAULT: "public-read"]:__ Access Control List. Describes who has access to the file. Can only be one of the following options:
	* "private"
	* "public-read"
	* "public-read-write"
	* "authenticated-read"
	* "bucket-owner-read"
	* "bucket-owner-full-control"
	* "log-delivery-write"
	* __Support for signed GET is still pending so uploads that require authentication won't be easily reachable__
*	__ops.bucket [DEFAULT: SERVER SETTINGS]:__ Overrides the bucket that will be used for the upload.
*	__ops.region [DEFAULT: SERVER SETTINGS]:__ Overrides the region that will be used for the upload. Only accepts the following regions:
	* "us-west-2"
	* "us-west-1"
	* "eu-west-1"
	* "eu-central-1"
	* "ap-southeast-1"
	* "ap-southeast-2"
	* "ap-northeast-1"
	* "sa-east-1"
	* __file.upload_name [OPTIONAL]:__ A function that returns the name with which you want to upload the file. It takes the file object as the only parameter. eg.
		``` javascript
		// The following function simply replicates the default behavior.
		function(f) {
			var extension = f.type.split("/")[1];
			return Meteor.uuid() + "." + extension;
		}
		```
*	__callback:__ A function that is run after the upload is complete returning an Error as the first parameter (if there is one), and a Result as the second.
*	__Result:__ The returned value of the callback function if there is no error. It returns an object with these keys:
	*	__loaded:__ Integer (bytes)
	*	__total:__ Integer (bytes)
	*	__percent_uploaded:__ Integer (out of 100)
	*	__uploader:__ String (describes which uploader was used to upload the file)
	*	__url:__ String (S3 hosted URL)
	*	__secure_url:__ String (S3 hosted URL for https)
	*	__relative_url:__ String (S3 URL for delete operations, this is what you should save in your DB to control delete)

#### S3.delete(path,callback)
This function permanently destroys a file located in your S3 bucket.

__Parameters:__
*	__path:__ Must be in this format ("/folder/other_folder/file.extension"). So basically always start with "/" and never end with "/". This is required.
*	__callback:__ A function that is run after the delete operation is complete returning an Error as the first parameter (if there is one), and a Result as the second.

### S3 (SERVER SIDE)

#### S3.config(ops)
This is where you define your key, secret, bucket, and other account wide settings.

__Parameters:__
*	__ops.key [REQUIRED]:__ Your Amazon AWS Key.
*	__ops.secret [REQUIRED]:__ Your Amazon AWS Secret.
*	__ops.bucket [REQUIRED]:__ Your Amazon AWS S3 bucket.
*	__ops.denyDelete [DEFAULT: undefined]:__ If set to true, will block delete calls. This is to enable secure deployment of this package before a more granular permissions system is developed.
*	__ops.region [DEFAULT: "us-east-1"]:__ Your Amazon AWS S3 Region. Defaults to US Standard. Can be any of the following:
	* "us-west-2"
	* "us-west-1"
	* "eu-west-1"
	* "eu-central-1"
	* "ap-southeast-1"
	* "ap-southeast-2"
	* "ap-northeast-1"
	* "sa-east-1"

``` javascript
S3.config = {
	key: 'amazonKey',
	secret: 'amazonSecret',
	bucket: 'bucketName'
};
```

#### S3.rules
##### S3.rules.delete
This is a function that runs every time someone uses the delete function on the client side. The context of `this` for the function has access to the `path` and `this` from a Meteor.method.

#### S3.knox
The current knox client.

#### S3.aws
The current aws-sdk client.

#### Developer Notes
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/frames.html
https://github.com/Differential/meteor-uploader/blob/master/lib/UploaderFile.coffee#L169-L178

http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html
http://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
https://github.com/CulturalMe/meteor-slingshot/blob/master/services/aws-s3.js


================================================
FILE: client/functions.coffee
================================================
@S3 =
	collection: new Meteor.Collection(null)
		# file.name
		# file.type
		# file.size
		# loaded
		# total
		# percent_uploaded
		# uploader
		# status: ["signing","uploading","complete"]
		# url
		# secure_url
		# relative_url

	upload: (ops = {},callback) ->
		# ops.files [OPTIONAL]
			# each needs to run file.type, store in a variable, then send. Either files or ops.file must be provided.
		# ops.file [OPTIONAL]
			# single file upload of javascript type File
		# ops.path [DEFAULT: ""]
			# the folder to upload to: blank string for root folder ""
		# ops.unique_name [DEFAULT: true]
			# modifies the file name to a unique string, if false takes the name of the file. Uploads will overwrite existing files instead.
		# ops.encoding [OPTIONAL: only supports "base64"]
			# overrides file encoding, only supports base64 right now
		# ops.content_disposition [DEFAULT: "inline"]
			# overrides file disposition (inline or attachment)
		# ops.server_side_encryption
			# if true, use server side encryption
		# ops.expiration [DEFAULT: 1800000 (30 mins)]
			# How long before uploads to the file are disabled in ms
		# ops.acl [DEFAULT: "public-read"]
			# Access Control List. Describes who has access to the file. Any of these options:
				# "private",
				# "public-read",
				# "public-read-write",
				# "authenticated-read",
				# "bucket-owner-read",
				# "bucket-owner-full-control",
				# "log-delivery-write"
		# ops.bucket [OVERRIDE REQUIRED SERVER-SIDE]
		# ops.region [OVERRIDE DEFAULT: "us-east-1"]
			# Accepts the following regions:
				# "us-west-2"
				# "us-west-1"
				# "eu-west-1"
				# "eu-central-1"
				# "ap-southeast-1"
				# "ap-southeast-2"
				# "ap-northeast-1"
				# "sa-east-1"
		# ops.uploader [DEFAULT: "default"]
			# key to differentiate multiple uploaders on the same form

		_.defaults ops,
			expiration:1800000
			path:""
			acl:"public-read"
			uploader:"default"
			unique_name:true
			connection:Meteor
			server_side_encryption:false
			content_disposition:"inline"

		if ops.file
			uploadFile(ops.file, ops, callback)
		else
			_.each ops.files, (file) ->
				uploadFile(file, ops, callback)

	delete: (path, callback, connection) ->
		conn = if connection then connection else Meteor
		conn.call "_s3_delete", path, callback

	b64toBlob: (b64Data, contentType, sliceSize) ->
		data = b64Data.split("base64,")
		if not contentType
			contentType = data[0].replace("data:","").replace(";","")

		contentType = contentType
		sliceSize = sliceSize or 512

		byteCharacters = atob data[1]
		byteArrays = []

		for offset in [0...byteCharacters.length] by sliceSize
			slice = byteCharacters.slice offset, offset + sliceSize
			byteNumbers = new Array slice.length

			for i in [0...slice.length]
				byteNumbers[i] = slice.charCodeAt(i)

			byteArray = new Uint8Array byteNumbers

			byteArrays.push byteArray

		blob = new Blob(byteArrays, {type: contentType})
		return blob

uploadFile = (file, ops, callback) ->
	if ops.encoding is "base64"
		if _.isString file
			file = S3.b64toBlob file

	if ops.unique_name or ops.encoding is "base64"
		extension = _.last file.name?.split(".")
		if not extension
			extension = file.type.split("/")[1] # a library of extensions based on MIME types would be better

		file_name = "#{Random.id()}.#{extension}"
	else
		if _.isFunction(file.upload_name)
			file_name = file.upload_name(file)
		else if !_.isEmpty(file.upload_name)
			file_name = file.upload_name
		else
			file_name = file.name

	initial_file_data =
		file:
			name:file_name
			type:file.type
			size:file.size
			original_name:file.name
		loaded:0
		total:file.size
		percent_uploaded:0
		uploader:ops.uploader
		status:"signing"

	id = S3.collection.insert initial_file_data

	ops.connection.call "_s3_sign",
		path:ops.path
		file_name: initial_file_data.file.name
		file_type:file.type
		file_size:file.size
		acl:ops.acl
		bucket:ops.bucket
		region:ops.region
		expiration:ops.expiration
		server_side_encryption:ops.server_side_encryption
		content_disposition:ops.content_disposition
		(error,result) ->
			if result
				# Mark as signed
				S3.collection.update id,
					$set:
						status:"uploading"

				# Prepare data
				form_data = new FormData()
				form_data.append "key", result.key
				form_data.append "acl", result.acl
				form_data.append "Content-Type", result.file_type
				if ops.content_disposition
					form_data.append "Content-Disposition", ops.content_disposition
				form_data.append "X-Amz-Date", result.meta_date
				if ops.server_side_encryption
					form_data.append "x-amz-server-side-encryption", "AES256"
				form_data.append "x-amz-meta-uuid", result.meta_uuid
				form_data.append "X-Amz-Algorithm", "AWS4-HMAC-SHA256"
				form_data.append "X-Amz-Credential", result.meta_credential
				form_data.append "X-Amz-Signature",result.signature

				form_data.append "Policy",result.policy

				form_data.append "file",file

				# Send data
				xhr = new XMLHttpRequest()

				xhr.upload.addEventListener "progress", (event) ->
						S3.collection.update id,
							$set:
								status:"uploading"
								loaded:event.loaded
								total:event.total
								percent_uploaded: Math.floor ((event.loaded / event.total) * 100)
					,false

				xhr.addEventListener "load", ->
					if xhr.status < 400
						S3.collection.update id,
							$set:
								status:"complete"
								percent_uploaded: 100
								url:result.url
								secure_url:result.secure_url
								relative_url:result.relative_url

						callback and callback null,S3.collection.findOne id
					else
						callback and callback true,null

				xhr.addEventListener "error", ->
					callback and callback true,null

				xhr.addEventListener "abort", ->
					console.log "aborted by user"

				xhr.open "POST",result.post_url,true

				xhr.send form_data
			else
				callback and callback error,null


================================================
FILE: coffeelint.json
================================================
{
  "arrow_spacing": {
    "level": "error"
  },
  "braces_spacing": {
    "level": "error",
    "spaces": 0,
    "empty_object_spaces": 0
  },
  "camel_case_classes": {
    "level": "error"
  },
  "coffeescript_error": {
    "level": "error"
  },
  "colon_assignment_spacing": {
    "level": "ignore",
    "spacing": {
      "left": 0,
      "right": 0
    }
  },
  "cyclomatic_complexity": {
    "level": "ignore",
    "value": 10
  },
  "duplicate_key": {
    "level": "error"
  },
  "empty_constructor_needs_parens": {
    "level": "ignore"
  },
  "ensure_comprehensions": {
    "level": "warn"
  },
  "eol_last": {
    "level": "ignore"
  },
  "indentation": {
    "value": 1,
    "level": "error"
  },
  "line_endings": {
    "level": "ignore",
    "value": "unix"
  },
  "max_line_length": {
    "value": 80,
    "level": "ignore",
    "limitComments": true
  },
  "missing_fat_arrows": {
    "level": "ignore",
    "is_strict": false
  },
  "newlines_after_classes": {
    "value": 3,
    "level": "ignore"
  },
  "no_backticks": {
    "level": "error"
  },
  "no_debugger": {
    "level": "warn",
    "console": false
  },
  "no_empty_functions": {
    "level": "ignore"
  },
  "no_empty_param_list": {
    "level": "ignore"
  },
  "no_implicit_braces": {
    "level": "ignore",
    "strict": true
  },
  "no_implicit_parens": {
    "level": "ignore",
    "strict": true
  },
  "no_interpolation_in_single_quotes": {
    "level": "ignore"
  },
  "no_nested_string_interpolation": {
    "level": "warn"
  },
  "no_plusplus": {
    "level": "ignore"
  },
  "no_private_function_fat_arrows": {
    "level": "warn"
  },
  "no_stand_alone_at": {
    "level": "ignore"
  },
  "no_tabs": {
    "level": "ignore"
  },
  "no_this": {
    "level": "ignore"
  },
  "no_throwing_strings": {
    "level": "error"
  },
  "no_trailing_semicolons": {
    "level": "error"
  },
  "no_trailing_whitespace": {
    "level": "error",
    "allowed_in_comments": false,
    "allowed_in_empty_lines": true
  },
  "no_unnecessary_double_quotes": {
    "level": "ignore"
  },
  "no_unnecessary_fat_arrows": {
    "level": "warn"
  },
  "non_empty_constructor_needs_parens": {
    "level": "ignore"
  },
  "prefer_english_operator": {
    "level": "ignore",
    "doubleNotLevel": "ignore"
  },
  "space_operators": {
    "level": "ignore"
  },
  "spacing_after_comma": {
    "level": "ignore"
  },
  "transform_messes_up_line_numbers": {
    "level": "warn"
  }
}


================================================
FILE: example/basic/.meteor/.finished-upgraders
================================================
# This file contains information which helps Meteor properly upgrade your
# app when you run 'meteor update'. You should check it into version control
# with your project.

notices-for-0.9.0
notices-for-0.9.1
0.9.4-platform-file
notices-for-facebook-graph-api-2
1.2.0-standard-minifiers-package
1.2.0-meteor-platform-split
1.2.0-cordova-changes
1.2.0-breaking-changes
1.3.0-split-minifiers-package
1.4.0-remove-old-dev-bundle-link
1.4.1-add-shell-server-package


================================================
FILE: example/basic/.meteor/.gitignore
================================================
local


================================================
FILE: example/basic/.meteor/.id
================================================
# This file contains a token that is unique to your project.
# Check it into your repository along with the rest of this directory.
# It can be used for purposes such as:
#   - ensuring you don't accidentally deploy one app on top of another
#   - providing package authors with aggregated statistics

n8dvpiz2lro616zjewc


================================================
FILE: example/basic/.meteor/packages
================================================
# Meteor packages used by this project, one per line.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.

standard-app-packages@1.0.9
autopublish@1.0.7
insecure@1.0.7
coffeescript@1.11.1_4
lepozepo:s3

standard-minifier-css
standard-minifier-js
shell-server


================================================
FILE: example/basic/.meteor/platforms
================================================
server
browser


================================================
FILE: example/basic/.meteor/release
================================================
METEOR@1.4.2.3


================================================
FILE: example/basic/.meteor/versions
================================================
accounts-base@1.2.14
allow-deny@1.0.5
autopublish@1.0.7
autoupdate@1.3.12
babel-compiler@6.13.0
babel-runtime@1.0.1
base64@1.0.10
binary-heap@1.0.10
blaze@2.2.0
blaze-tools@1.0.10
boilerplate-generator@1.0.11
caching-compiler@1.1.9
caching-html-compiler@1.0.7
callback-hook@1.0.10
check@1.2.4
coffeescript@1.11.1_4
ddp@1.2.5
ddp-client@1.3.2
ddp-common@1.2.8
ddp-rate-limiter@1.0.6
ddp-server@1.3.12
deps@1.0.12
diff-sequence@1.0.7
ecmascript@0.6.1
ecmascript-runtime@0.3.15
ejson@1.0.13
fastclick@1.0.13
geojson-utils@1.0.10
hot-code-push@1.0.4
html-tools@1.0.11
htmljs@1.0.11
http@1.2.10
id-map@1.0.9
insecure@1.0.7
jquery@1.11.10
launch-screen@1.1.0
lepozepo:s3@5.2.4
livedata@1.0.18
localstorage@1.0.12
logging@1.1.16
meteor@1.6.0
meteor-base@1.0.4
meteor-platform@1.2.6
minifier-css@1.2.15
minifier-js@1.2.15
minimongo@1.0.19
mobile-status-bar@1.0.13
modules@0.7.7
modules-runtime@0.7.7
mongo@1.1.14
mongo-id@1.0.6
npm-mongo@2.2.11_2
observe-sequence@1.0.14
ordered-dict@1.0.9
promise@0.8.8
random@1.0.10
rate-limit@1.0.6
reactive-dict@1.1.8
reactive-var@1.0.11
reload@1.1.11
retry@1.0.9
routepolicy@1.0.12
service-configuration@1.0.11
session@1.1.7
shell-server@0.2.1
spacebars@1.0.13
spacebars-compiler@1.0.13
standard-app-packages@1.0.9
standard-minifier-css@1.3.2
standard-minifier-js@1.2.1
templating@1.2.15
templating-compiler@1.2.15
templating-runtime@1.2.15
templating-tools@1.0.5
tracker@1.1.1
ui@1.0.12
underscore@1.0.10
url@1.0.11
webapp@1.3.12
webapp-hashing@1.0.9


================================================
FILE: example/basic/basic.coffee
================================================
if Meteor.isClient
	Template.basic.helpers
		"files": -> S3.collection.find()

	Template.basic.events
		"click button.upload": (event) ->
			S3.upload
				files:$("input.file_bag")[0].files
				(error,result) ->
					if error
						console.log "Unable to upload"
					else
						console.log result

		"click button.delete": (event) ->
			S3.delete @relative_url, (error,res) =>
				if not error
					console.log res
					S3.collection.remove @_id
				else
					console.log error

if Meteor.isServer
	S3.config =
		key:"yourkey"
		secret:"yoursecret"
		bucket:"yourbucket"
		# region:"us-standard" #default






================================================
FILE: example/basic/basic.html
================================================
<head>
  <title>basic</title>
</head>

<body>
  {{> basic}}
</body>

<template name="basic">

	<input type="file" class="file_bag" multiple>
	<button class="upload">upload it</button>

	{{#each files}}
		<p>{{percent_uploaded}}</p>
		<img src="{{secure_url}}" height="250px">
		<button class="delete">Delete</button>
	{{/each}}

</template>


================================================
FILE: example/basic/packages/.gitignore
================================================
/s3


================================================
FILE: example/mdg_camera/.meteor/.finished-upgraders
================================================
# This file contains information which helps Meteor properly upgrade your
# app when you run 'meteor update'. You should check it into version control
# with your project.

notices-for-0.9.0
notices-for-0.9.1
0.9.4-platform-file


================================================
FILE: example/mdg_camera/.meteor/.gitignore
================================================
local


================================================
FILE: example/mdg_camera/.meteor/.id
================================================
# This file contains a token that is unique to your project.
# Check it into your repository along with the rest of this directory.
# It can be used for purposes such as:
#   - ensuring you don't accidentally deploy one app on top of another
#   - providing package authors with aggregated statistics

n8dvpiz2lro616zjewc


================================================
FILE: example/mdg_camera/.meteor/cordova-plugins
================================================



================================================
FILE: example/mdg_camera/.meteor/packages
================================================
# Meteor packages used by this project, one per line.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.

standard-app-packages
autopublish
insecure
coffeescript
lepozepo:s3
mdg:camera



================================================
FILE: example/mdg_camera/.meteor/platforms
================================================
server
browser
ios


================================================
FILE: example/mdg_camera/.meteor/release
================================================
METEOR@1.0.4.1


================================================
FILE: example/mdg_camera/.meteor/versions
================================================
accounts-base@1.2.0
autopublish@1.0.3
autoupdate@1.2.0
base64@1.0.3
binary-heap@1.0.3
blaze@2.1.0
blaze-tools@1.0.3
boilerplate-generator@1.0.3
callback-hook@1.0.3
check@1.0.5
coffeescript@1.0.6
ddp@1.1.0
deps@1.0.7
ejson@1.0.6
fastclick@1.0.3
geojson-utils@1.0.3
html-tools@1.0.4
htmljs@1.0.4
http@1.1.0
id-map@1.0.3
insecure@1.0.3
jquery@1.11.3_2
json@1.0.3
launch-screen@1.0.2
lepozepo:s3@5.1.0
less@1.0.13
livedata@1.0.13
localstorage@1.0.3
logging@1.0.7
mdg:camera@1.1.4
meteor@1.1.5
meteor-platform@1.2.2
minifiers@1.1.4
minimongo@1.0.7
mobile-status-bar@1.0.3
mongo@1.1.0
observe-sequence@1.0.5
ordered-dict@1.0.3
random@1.0.3
reactive-dict@1.1.0
reactive-var@1.0.5
reload@1.1.3
retry@1.0.3
routepolicy@1.0.5
service-configuration@1.0.4
session@1.1.0
spacebars@1.0.6
spacebars-compiler@1.0.5
standard-app-packages@1.0.5
templating@1.1.0
tracker@1.0.6
ui@1.0.6
underscore@1.0.3
url@1.0.4
webapp@1.2.0
webapp-hashing@1.0.3


================================================
FILE: example/mdg_camera/mdg_camera.coffee
================================================
if Meteor.isClient
	Template.basic.helpers
		"files": -> S3.collection.find()

	Template.basic.events
		"click button.upload": (event) ->
			S3.upload
				files:[$("textarea").val()]
				path:"tester"
				encoding:"base64"
				(error,result) ->
					if error
						console.log error
					else
						console.log result

		"click button.delete": (event) ->
			S3.delete @relative_url, (error,res) ->
				if not error
					console.log res
				else
					console.log error

if Meteor.isServer
	S3.config =
		key:"yourkey"
		secret:"yousecret"
		bucket:"yourbucket"




================================================
FILE: example/mdg_camera/mdg_camera.html
================================================
<head>
  <title>mdg:camera</title>
</head>

<body>
  {{> basic}}
</body>

<template name="basic">

	<img src="data:image/gif;base64,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">

	<textarea rows="4">
data:image/gif;base64,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
	</textarea>

	<br>
	<button class="upload">upload the base64 image</button>

	{{#each files}}
		<p>{{percent_uploaded}}</p>
		<img src="{{secure_url}}" height="250px">
		<button class="delete">Delete</button>
	{{/each}}

</template>


================================================
FILE: example/mdg_camera/packages/.gitignore
================================================
/s3


================================================
FILE: package.js
================================================
Package.describe({
	name:"lepozepo:s3",
	summary: "Upload files to S3. Allows use of Knox Server-Side.",
	version:"5.2.8",
	git:"https://github.com/Lepozepo/S3"
});

Npm.depends({
	knox: "0.9.2",
	"stream-buffers":"2.1.0",
	"aws-sdk":"2.1.14",
	"crypto-js":"3.1.6",
	"moment":"2.13.0"
});

Package.on_use(function (api) {
	api.versionsFrom('METEOR@1.0');

	api.use(["meteor-base@1.0.1","coffeescript","service-configuration"], ["client", "server"]);
	api.use(["check","random"], ["client","server"]);

	// Client
	api.add_files("client/functions.coffee", "client");

	// Server
	api.add_files("server/startup.coffee", "server");
	api.add_files("server/sign_request.coffee", "server");
	api.add_files("server/delete_object.coffee", "server");

	//Allows user access to Knox
	api.export && api.export("Knox","server");

	//Allows user access to AWS-SDK
	api.export && api.export("AWS","server");
});


================================================
FILE: server/delete_object.coffee
================================================
Future = Npm.require 'fibers/future'

Meteor.methods
	_s3_delete: (path) ->
		@unblock()
		check path,String

		future = new Future()

		if S3.rules?.delete
			delete_context = _.extend this,
				s3_delete_path:path

			auth_function = _.bind S3.rules.delete,delete_context
			if not auth_function()
				throw new Meteor.Error "Unauthorized", "Delete not allowed"

		S3.knox.deleteFile path, (e,r) ->
			if e
				future.return e
			else
				future.return true

		future.wait()


================================================
FILE: server/sign_request.coffee
================================================
Meteor.methods
	_s3_sign: (ops={}) ->
		@unblock()
		# ops.expiration: the signature expires after x milliseconds | defaults to 30 minutes
		# ops.path
		# ops.file_type
		# ops.file_name
		# ops.file_size
		# ops.acl
		# ops.bucket
		# ops.server_side_encryption
		# ops.content_disposition

		_.defaults ops,
			expiration:1800000
			path:""
			bucket:S3.config.bucket
			acl:"public-read"
			region:S3.config.region
			server_side_encryption:false
			content_disposition:"inline"

		check ops,
			expiration:Number
			path:String
			bucket:String
			acl:String
			region:String
			server_side_encryption:Boolean
			file_type:String
			file_name:String
			file_size:Number
			content_disposition:String

		expiration = new Date Date.now() + ops.expiration
		expiration = expiration.toISOString()

		if _.isEmpty ops.path
			key = "#{ops.file_name}"
		else
			key = "#{ops.path}/#{ops.file_name}"

		meta_uuid = Random.id()
		meta_date = "#{moment().format('YYYYMMDD')}T000000Z"
		meta_credential = "#{S3.config.key}/#{moment().format('YYYYMMDD')}/#{ops.region}/s3/aws4_request"
		policy =
			"expiration":expiration
			"conditions":[
				["content-length-range",0,ops.file_size]
				{"key":key}
				{"bucket":ops.bucket}
				{"Content-Type":ops.file_type}
				{"acl":ops.acl}
				{"x-amz-algorithm": "AWS4-HMAC-SHA256"}
				{"x-amz-credential": meta_credential}
				{"x-amz-date": meta_date }
				{"x-amz-meta-uuid": meta_uuid}
			]
		if ops.content_disposition
			policy["conditions"].push({"Content-Disposition": ops.content_disposition})
		if ops.server_side_encryption
			policy["conditions"].push({"x-amz-server-side-encryption": "AES256"})

		# Encode the policy
		policy = new Buffer(JSON.stringify(policy), "utf-8").toString("base64")

		# Sign the policy
		signature = calculate_signature policy, ops.region

		# Identify post_url
		if ops.region is "us-east-1" or ops.region is "us-standard"
			post_url = "https://s3.amazonaws.com/#{ops.bucket}"
		else
			post_url = "https://s3-#{ops.region}.amazonaws.com/#{ops.bucket}"

		# Return results
		policy:policy
		signature:signature
		access_key:S3.config.key
		post_url:post_url
		url:"#{post_url}/#{key}".replace("https://","http://")
		secure_url:"#{post_url}/#{key}"
		relative_url:"/#{key}"
		bucket:ops.bucket
		acl:ops.acl
		key:key
		file_type:ops.file_type
		file_name:ops.file_name
		meta_uuid:meta_uuid
		meta_date:meta_date
		meta_credential:meta_credential


# crypto = Npm.require("crypto")
Crypto = Npm.require "crypto-js"
moment = Npm.require "moment"
{HmacSHA256} = Crypto

calculate_signature = (policy, region) ->
	kDate = HmacSHA256(moment().format("YYYYMMDD"), "AWS4" + S3.config.secret);
	kRegion = HmacSHA256(region, kDate);
	kService = HmacSHA256("s3", kRegion);
	signature_key = HmacSHA256("aws4_request", kService);

	HmacSHA256 policy, signature_key
		.toString Crypto.enc.Hex




================================================
FILE: server/startup.coffee
================================================
#Get Knox and AWS libraries
Knox = Npm.require "knox"

processBrowser = process.browser
process.browser = false
AWS = Npm.require "aws-sdk"
process.browser = processBrowser

#Server side configuration variables
@S3 =
	config:{}
	knox:{}
	aws:{}
	rules:{}

Meteor.startup ->
	if not _.has S3.config,"key"
		console.log "S3: AWS key is undefined"

	if not _.has S3.config,"secret"
		console.log "S3: AWS secret is undefined"

	if not _.has S3.config,"bucket"
		console.log "S3: AWS bucket is undefined"

	if not _.has(S3.config,"bucket") or not _.has(S3.config,"secret") or not _.has(S3.config,"key")
		return

	_.defaults S3.config,
		region:"us-east-1" # us-standard

	S3.knox = Knox.createClient S3.config
	S3.aws = new AWS.S3
		accessKeyId:S3.config.key
		secretAccessKey:S3.config.secret
		region:S3.config.region



================================================
FILE: versions.json
================================================
{
  "dependencies": [
    [
      "accounts-base",
      "1.1.2"
    ],
    [
      "application-configuration",
      "1.0.3"
    ],
    [
      "base64",
      "1.0.1"
    ],
    [
      "binary-heap",
      "1.0.1"
    ],
    [
      "callback-hook",
      "1.0.1"
    ],
    [
      "check",
      "1.0.2"
    ],
    [
      "coffeescript",
      "1.0.4"
    ],
    [
      "ddp",
      "1.0.11"
    ],
    [
      "ejson",
      "1.0.4"
    ],
    [
      "follower-livedata",
      "1.0.2"
    ],
    [
      "geojson-utils",
      "1.0.1"
    ],
    [
      "id-map",
      "1.0.1"
    ],
    [
      "json",
      "1.0.1"
    ],
    [
      "localstorage",
      "1.0.1"
    ],
    [
      "logging",
      "1.0.5"
    ],
    [
      "meteor",
      "1.1.3"
    ],
    [
      "minimongo",
      "1.0.5"
    ],
    [
      "mongo",
      "1.0.8"
    ],
    [
      "ordered-dict",
      "1.0.1"
    ],
    [
      "random",
      "1.0.1"
    ],
    [
      "retry",
      "1.0.1"
    ],
    [
      "service-configuration",
      "1.0.2"
    ],
    [
      "tracker",
      "1.0.3"
    ],
    [
      "underscore",
      "1.0.1"
    ]
  ],
  "pluginDependencies": [],
  "toolVersion": "meteor-tool@1.0.35",
  "format": "1.0"
}
Download .txt
gitextract_nbdvszgl/

├── .gitignore
├── .npm/
│   └── package/
│       ├── .gitignore
│       ├── README
│       └── npm-shrinkwrap.json
├── .versions
├── LICENSE.md
├── README.md
├── client/
│   └── functions.coffee
├── coffeelint.json
├── example/
│   ├── basic/
│   │   ├── .meteor/
│   │   │   ├── .finished-upgraders
│   │   │   ├── .gitignore
│   │   │   ├── .id
│   │   │   ├── packages
│   │   │   ├── platforms
│   │   │   ├── release
│   │   │   └── versions
│   │   ├── basic.coffee
│   │   ├── basic.html
│   │   └── packages/
│   │       └── .gitignore
│   └── mdg_camera/
│       ├── .meteor/
│       │   ├── .finished-upgraders
│       │   ├── .gitignore
│       │   ├── .id
│       │   ├── cordova-plugins
│       │   ├── packages
│       │   ├── platforms
│       │   ├── release
│       │   └── versions
│       ├── mdg_camera.coffee
│       ├── mdg_camera.html
│       └── packages/
│           └── .gitignore
├── package.js
├── server/
│   ├── delete_object.coffee
│   ├── sign_request.coffee
│   └── startup.coffee
└── versions.json
Condensed preview — 35 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (49K chars).
[
  {
    "path": ".gitignore",
    "chars": 32,
    "preview": ".build*\n.DS_store\n.aws_keys.txt\n"
  },
  {
    "path": ".npm/package/.gitignore",
    "chars": 13,
    "preview": "node_modules\n"
  },
  {
    "path": ".npm/package/README",
    "chars": 443,
    "preview": "This directory and the files immediately inside it are automatically generated\nwhen you change this package's NPM depend"
  },
  {
    "path": ".npm/package/npm-shrinkwrap.json",
    "chars": 3964,
    "preview": "{\n  \"lockfileVersion\": 1,\n  \"dependencies\": {\n    \"aws-sdk\": {\n      \"version\": \"2.1.14\",\n      \"resolved\": \"https://reg"
  },
  {
    "path": ".versions",
    "chars": 1072,
    "preview": "accounts-base@1.4.2\nallow-deny@1.1.0\nautoupdate@1.4.0\nbabel-compiler@7.0.4\nbabel-runtime@1.2.0\nbase64@1.0.10\nbinary-heap"
  },
  {
    "path": "LICENSE.md",
    "chars": 1080,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Marcelo Reyna\n\nPermission is hereby granted, free of charge, to any person obt"
  },
  {
    "path": "README.md",
    "chars": 10071,
    "preview": "# Amazon S3 Uploader\nS3 provides a simple way for uploading files to the Amazon S3 service with a progress bar. This is "
  },
  {
    "path": "client/functions.coffee",
    "chars": 5860,
    "preview": "@S3 =\n\tcollection: new Meteor.Collection(null)\n\t\t# file.name\n\t\t# file.type\n\t\t# file.size\n\t\t# loaded\n\t\t# total\n\t\t# percen"
  },
  {
    "path": "coffeelint.json",
    "chars": 2446,
    "preview": "{\n  \"arrow_spacing\": {\n    \"level\": \"error\"\n  },\n  \"braces_spacing\": {\n    \"level\": \"error\",\n    \"spaces\": 0,\n    \"empty"
  },
  {
    "path": "example/basic/.meteor/.finished-upgraders",
    "chars": 462,
    "preview": "# This file contains information which helps Meteor properly upgrade your\n# app when you run 'meteor update'. You should"
  },
  {
    "path": "example/basic/.meteor/.gitignore",
    "chars": 6,
    "preview": "local\n"
  },
  {
    "path": "example/basic/.meteor/.id",
    "chars": 322,
    "preview": "# This file contains a token that is unique to your project.\n# Check it into your repository along with the rest of this"
  },
  {
    "path": "example/basic/.meteor/packages",
    "chars": 309,
    "preview": "# Meteor packages used by this project, one per line.\n#\n# 'meteor add' and 'meteor remove' will edit this file for you,\n"
  },
  {
    "path": "example/basic/.meteor/platforms",
    "chars": 15,
    "preview": "server\nbrowser\n"
  },
  {
    "path": "example/basic/.meteor/release",
    "chars": 15,
    "preview": "METEOR@1.4.2.3\n"
  },
  {
    "path": "example/basic/.meteor/versions",
    "chars": 1482,
    "preview": "accounts-base@1.2.14\nallow-deny@1.0.5\nautopublish@1.0.7\nautoupdate@1.3.12\nbabel-compiler@6.13.0\nbabel-runtime@1.0.1\nbase"
  },
  {
    "path": "example/basic/basic.coffee",
    "chars": 610,
    "preview": "if Meteor.isClient\n\tTemplate.basic.helpers\n\t\t\"files\": -> S3.collection.find()\n\n\tTemplate.basic.events\n\t\t\"click button.up"
  },
  {
    "path": "example/basic/basic.html",
    "chars": 341,
    "preview": "<head>\n  <title>basic</title>\n</head>\n\n<body>\n  {{> basic}}\n</body>\n\n<template name=\"basic\">\n\n\t<input type=\"file\" class="
  },
  {
    "path": "example/basic/packages/.gitignore",
    "chars": 4,
    "preview": "/s3\n"
  },
  {
    "path": "example/mdg_camera/.meteor/.finished-upgraders",
    "chars": 229,
    "preview": "# This file contains information which helps Meteor properly upgrade your\n# app when you run 'meteor update'. You should"
  },
  {
    "path": "example/mdg_camera/.meteor/.gitignore",
    "chars": 6,
    "preview": "local\n"
  },
  {
    "path": "example/mdg_camera/.meteor/.id",
    "chars": 322,
    "preview": "# This file contains a token that is unique to your project.\n# Check it into your repository along with the rest of this"
  },
  {
    "path": "example/mdg_camera/.meteor/cordova-plugins",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "example/mdg_camera/.meteor/packages",
    "chars": 237,
    "preview": "# Meteor packages used by this project, one per line.\n#\n# 'meteor add' and 'meteor remove' will edit this file for you,\n"
  },
  {
    "path": "example/mdg_camera/.meteor/platforms",
    "chars": 19,
    "preview": "server\nbrowser\nios\n"
  },
  {
    "path": "example/mdg_camera/.meteor/release",
    "chars": 15,
    "preview": "METEOR@1.0.4.1\n"
  },
  {
    "path": "example/mdg_camera/.meteor/versions",
    "chars": 928,
    "preview": "accounts-base@1.2.0\nautopublish@1.0.3\nautoupdate@1.2.0\nbase64@1.0.3\nbinary-heap@1.0.3\nblaze@2.1.0\nblaze-tools@1.0.3\nboil"
  },
  {
    "path": "example/mdg_camera/mdg_camera.coffee",
    "chars": 562,
    "preview": "if Meteor.isClient\n\tTemplate.basic.helpers\n\t\t\"files\": -> S3.collection.find()\n\n\tTemplate.basic.events\n\t\t\"click button.up"
  },
  {
    "path": "example/mdg_camera/mdg_camera.html",
    "chars": 5622,
    "preview": "<head>\n  <title>mdg:camera</title>\n</head>\n\n<body>\n  {{> basic}}\n</body>\n\n<template name=\"basic\">\n\n\t<img src=\"data:image"
  },
  {
    "path": "example/mdg_camera/packages/.gitignore",
    "chars": 4,
    "preview": "/s3\n"
  },
  {
    "path": "package.js",
    "chars": 898,
    "preview": "Package.describe({\n\tname:\"lepozepo:s3\",\n\tsummary: \"Upload files to S3. Allows use of Knox Server-Side.\",\n\tversion:\"5.2.8"
  },
  {
    "path": "server/delete_object.coffee",
    "chars": 477,
    "preview": "Future = Npm.require 'fibers/future'\n\nMeteor.methods\n\t_s3_delete: (path) ->\n\t\t@unblock()\n\t\tcheck path,String\n\n\t\tfuture ="
  },
  {
    "path": "server/sign_request.coffee",
    "chars": 2866,
    "preview": "Meteor.methods\n\t_s3_sign: (ops={}) ->\n\t\t@unblock()\n\t\t# ops.expiration: the signature expires after x milliseconds | defa"
  },
  {
    "path": "server/startup.coffee",
    "chars": 818,
    "preview": "#Get Knox and AWS libraries\nKnox = Npm.require \"knox\"\n\nprocessBrowser = process.browser\nprocess.browser = false\nAWS = Np"
  },
  {
    "path": "versions.json",
    "chars": 1234,
    "preview": "{\n  \"dependencies\": [\n    [\n      \"accounts-base\",\n      \"1.1.2\"\n    ],\n    [\n      \"application-configuration\",\n      \""
  }
]

About this extraction

This page contains the full source code of the Lepozepo/S3 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 35 files (41.8 KB), approximately 15.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!