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"
}
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.