{"_id":"formaline","_rev":"23-f3b5a4387c7125949adebeaeeb1560fd","name":"formaline","description":"formaline is a module for handling form requests ( HTTP POSTs / PUTs ) and for fast parsing of file uploads.","dist-tags":{"latest":"2.0.2"},"versions":{"0.6.4":{"name":"formaline","version":"0.6.4","description":"formaline is a full-featured low-level module for handling form requests ( HTTP POST / PUT ) and for fast parsing of file uploads, it is also ready to use with middlewares like connect","homepage":"https://github.com/rootslab/formaline","repository":{"type":"git","url":"git://github.com/rootslab/formaline.git"},"keywords":["form","upload","multipart","urlencoded","formaline","parser","connect","post"],"tags":["form","upload","multipart","urlencoded","post","json"],"author":{"name":"Guglielmo Ferri","email":"44gatti@gmail.com"},"dependencies":{},"main":"index","engines":{"node":">=0.4.8"},"_id":"formaline@0.6.4","_engineSupported":true,"_npmVersion":"0.3.18","_nodeVersion":"v0.4.12","directories":{"lib":"./lib"},"files":[""],"_defaultsLoaded":true,"dist":{"shasum":"86857a3ab2fbc87f4d12f4ef801da9f36e8b0393","tarball":"https://registry.npmjs.org/formaline/-/formaline-0.6.4.tgz","integrity":"sha512-zUOZI9BAFUAGbgTRWZNEXWdjrNun1v/wMNN4cVMTY6jvar/hNGOYaBzLKPvzDg3i65ZhOYOxDZmgYfVmv03KGQ==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDt5E6E0kW1SyIbHcxV7QKiRDJdrQhIt8pndmFPBKh7LQIhAJAvLm3s6ZOgju6K4ayU7BwAYQcjbV01VFJb/7852PzO"}]},"maintainers":[{"name":"rootslab","email":"44gatti@gmail.com"}]},"0.6.7":{"name":"formaline","version":"0.6.7","description":"formaline, a module for handling form requests ( HTTP POST / PUT ) and for fast parsing of file uploads, it is also ready to use with middlewares like connect","homepage":"https://github.com/rootslab/formaline","repository":{"type":"git","url":"git://github.com/rootslab/formaline.git"},"keywords":["form","upload","multipart","urlencoded","formaline","parser","connect","post"],"tags":["form","upload","multipart","urlencoded","post","json"],"author":{"name":"Guglielmo Ferri","email":"44gatti@gmail.com"},"dependencies":{},"main":"index","engines":{"node":">=0.4.8"},"_id":"formaline@0.6.7","dist":{"shasum":"e02cf099ceba58c3d63622997d81a463d0b8a820","tarball":"https://registry.npmjs.org/formaline/-/formaline-0.6.7.tgz","integrity":"sha512-22negEc5MbrmPtUOqO82E3+PifsybwQIruFXzo+Vf3Dim03+ox3PuM5qrNoT1iuLR+khTkLb9cGzjAJrnQuUzg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCl0zg5ho0ptE8VEAjLoarOzQ0fLQ4TtynCXedN73rhtgIgGNo/AxHH/+FKon1jOCdtJa+vf4mgw/k8O3DQbF7uyWY="}]},"_npmVersion":"1.1.64","_npmUser":{"name":"rootslab","email":"44gatti@gmail.com"},"maintainers":[{"name":"rootslab","email":"44gatti@gmail.com"},{"name":"coolaj86","email":"coolaj86@gmail.com"}]},"2.0.0":{"name":"formaline","version":"2.0.0","description":"Built upon the ultrafast poor-form, truly a formidable competitor.","main":"lib/formaline.js","directories":{"lib":"./lib"},"dependencies":{"poor-form":">=1.1.0 <1.2.0"},"devDependencies":{},"scripts":{"test":"node test.js & sleep 1; bash test.sh"},"repository":{"type":"git","url":"git://github.com/rootslab/formaline.git"},"keywords":["formaline","formidable","good-form","poor-form","multipart","upload","form","connect","express","post","parser"],"author":{"name":"AJ ONeal","email":"coolaj86@gmail.com","url":"http://coolaj86.info"},"license":"MIT","_id":"formaline@2.0.0","dist":{"shasum":"58a86b4be104f7031bfcdba9a94da95594e49d4c","tarball":"https://registry.npmjs.org/formaline/-/formaline-2.0.0.tgz","integrity":"sha512-WZpK6IDmQozqeXabN1RInCPAzvFWH3Ky04xa43kVnezIDvOLYV6TMxr1H3UDwubMyj7t001nL+SflRGrYLo1kg==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCYelzD8JcrC9RBBpHflhwEwFPKqxkjK4scAJyvfCHt6QIgM/9OZanfBzMoUk8VzBm3K2kuUUyScW/RZ6Pm4r2xHlE="}]},"_npmVersion":"1.1.63","_npmUser":{"name":"coolaj86","email":"coolaj86@gmail.com"},"maintainers":[{"name":"rootslab","email":"44gatti@gmail.com"},{"name":"coolaj86","email":"coolaj86@gmail.com"}]},"2.0.1":{"name":"formaline","version":"2.0.1","description":"formaline is a module for handling form requests ( HTTP POSTs / PUTs ) and for fast parsing of file uploads.","main":"lib/formaline.js","directories":{"lib":"./lib"},"dependencies":{"poor-form":">=1.1.3 <1.2.0"},"devDependencies":{},"scripts":{"test":"node test.js & sleep 1; bash test.sh"},"repository":{"type":"git","url":"git://github.com/rootslab/formaline.git"},"keywords":["formaline","formidable","good-form","poor-form","multipart","upload","form","connect","express","post","parser"],"license":"MIT","contributors":[{"name":"AJ ONeal","email":"coolaj86@gmail.com","url":"http://coolaj86.info"},{"name":"Guglielmo Ferri","email":"44gatti@gmail.com","url":"http://rootslab.it"}],"_id":"formaline@2.0.1","dist":{"shasum":"1daecdaef6ea270613b2ec4f9d7020f05218439a","tarball":"https://registry.npmjs.org/formaline/-/formaline-2.0.1.tgz","integrity":"sha512-D1+Ipidso+4Qrvbs+QuYVYw+h28jcxXpXi62TMNPwcdqN/TdH2N37Dln0GMgWpWEG3wG2iT+f+deVlx3RLXTdw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCYB8KbhesTTjEu9W1Q0Xf41gvdTnwguiUNEZJZ7ZEFvQIhAP/+u57X8I7YWabRAp7hLZ+6EYpW95JRiWX6YZXIJPlX"}]},"_npmVersion":"1.1.64","_npmUser":{"name":"rootslab","email":"44gatti@gmail.com"},"maintainers":[{"name":"rootslab","email":"44gatti@gmail.com"},{"name":"coolaj86","email":"coolaj86@gmail.com"}]},"2.0.2":{"name":"formaline","version":"2.0.2","description":"formaline is a module for handling form requests ( HTTP POSTs / PUTs ) and for fast parsing of file uploads.","main":"lib/formaline.js","directories":{"lib":"./lib"},"dependencies":{"poor-form":">=1.1.4 <1.2.0"},"devDependencies":{},"scripts":{"test":"node test.js & sleep 1; bash test.sh"},"repository":{"type":"git","url":"git://github.com/rootslab/formaline.git"},"keywords":["formaline","formidable","good-form","poor-form","multipart","upload","form","connect","express","post","parser"],"license":"MIT","contributors":[{"name":"AJ ONeal","email":"coolaj86@gmail.com","url":"http://coolaj86.com"},{"name":"Guglielmo Ferri","email":"44gatti@gmail.com","url":"http://rootslab.it"}],"gitHead":"de4d0b16cd040cffcd98adfbb0885f519744c978","bugs":{"url":"https://github.com/rootslab/formaline/issues"},"homepage":"https://github.com/rootslab/formaline","_id":"formaline@2.0.2","_shasum":"8850154c2419a0e030293e5203551490ec4131f1","_from":".","_npmVersion":"2.5.1","_nodeVersion":"1.2.0","_npmUser":{"name":"coolaj86","email":"coolaj86@gmail.com"},"maintainers":[{"name":"rootslab","email":"44gatti@gmail.com"},{"name":"coolaj86","email":"coolaj86@gmail.com"}],"dist":{"shasum":"8850154c2419a0e030293e5203551490ec4131f1","tarball":"https://registry.npmjs.org/formaline/-/formaline-2.0.2.tgz","integrity":"sha512-o+09sHQFsrTDHD0/FPCe8IKCjOO7TMu9jzK2n3c+fNDv9+AFvetQ1j/XrxUsuwyA5WxQk/WfZ0g1mxgd0iWGKw==","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHzQqWC4AIMPf5Z6dzSRKxK0YoKBnZH5YtZSk7t2ZKxZAiEAlDQBtMpfOtmM3C4fYNUPG8+jUWMrHHsDRWxTNV0e16Y="}]}}},"maintainers":[{"name":"rootslab","email":"44gatti@gmail.com"},{"name":"coolaj86","email":"coolaj86@gmail.com"}],"time":{"modified":"2022-06-18T03:03:13.846Z","created":"2011-09-27T01:04:04.385Z","0.6.4":"2011-09-27T01:04:04.937Z","0.6.5":"2012-10-27T11:49:27.018Z","0.6.6":"2012-11-05T22:30:48.060Z","0.6.7":"2012-11-06T22:58:11.524Z","2.0.0":"2012-11-24T15:40:49.249Z","2.0.1":"2012-12-03T22:01:47.584Z","2.0.2":"2015-02-19T19:08:32.075Z"},"repository":{"type":"git","url":"git://github.com/rootslab/formaline.git"},"users":{"pid":true},"readme":"## Formaline v2.x\n\nFormaline extends [PoorForm](http://github.com/coolaj86/poor-form) to create a very developer-friendly form parser, and still easy to get at the guts.\n\nIf you don't think Formaline is light-weight enough for you, you're crazy.\nAlso, you'd probably really like [PoorForm](http://github.com/coolaj86/poor-form).\n\nThe **[Formaline v0.x](https://github.com/rootslab/formaline/tree/v0.x)** [documentation](https://github.com/rootslab/formaline/blob/v0.x/Readme.md) is available on the v0.x branch.\n\n## API\n\n  * [`Formaline.create(request, options)`](#formalinecreaterequest-options)\n  * [`Formaline#on('progress', fn)`](#formalineonprogress-function--)\n  * [`Formaline#on('field', fn)`](#formalineonfield-function-name-decodedvalue-)\n  * [`Formaline#on('file', fn)`](#formalineonfile-function-name-formfilestream-headers-)\n    * [`FormFile#name`](#formfile)\n    * [`FormFile#size`](#formfile)\n    * [`FormFile#type`](#formfile)\n    * [`FormFile#lastModifiedDate`](#formfile)\n    * [`FormFile#path`](#formfile)\n    * [`FormFile#headers`](#formfile)\n    * [`FormFile#<hashtype>`](#formfile) (md5, sha1, sha512, etc)\n  * [`Formaline#on('end', fn)`](#formalineonend-function-fields-files-)\n\n### Formaline.create(request, options)\n\nReturns an instance of `PoorForm` with a few extra events tacked on as described above.\n\nLike PoorForm, it returns null if either it's not a multi-part form or the form has already been parsed.\n\n#### Options\n\n    {\n        tmpDir: null || pathString || os.tmpDir()\n      , hashes: [\"md5\", \"sha1\", ...] || []\n      , arrayFields: [fieldNameString] || null\n    }\n\n##### tmpDir\n\nSet `tmpDir` to `null` if you plan to manage the file streams from the `file` event on your own\n(i.e. you want to store them in S3 or whatever and never let them hit the fs).\nAlso, in almost all cases `tmpDir` should be on the same partition as the final destination,\nso change it if the system's default tmp is a different partition than your destination.\n\n##### hashes\n\nAn array of hashes that should be performed on each file (fields are excluded).\nThe hash will be attached to the file before the `end` event.\n\n##### arrayFields\n\nWhen `end` fires it hands back a map for both `fields` and `files`,\nall of which are assumed to be arrays by default (as per the HTTP spec).\n\nHowever, if `arrayFields` is an array of field names (or an empty array),\ntwo special things happen:\n\n  1. All of the fields listed will always return an array, even if it's empty\n\n    I.E. The user created an album, but uploaded 0 photos.\n\n  2. All fields and files not listed in `arrayFields` will be treated as single values\n     (if the field is encountered multiple times, only the first value is kept)\n\n    I.E. If `username` is given twice, only the first value is kept.\n\n#### Example\n\n```javascript\n(function () {\n  \"use strict\";\n\n  var Formaline = require('formaline').Formaline\n    ;\n\n  // Using Connect, for example\n  app.use(function (req, res, next) {\n    var form = Formaline.create(req, {\n            tmpDir: '/mnt/my-app-data/tmp'\n          , hashes: ['md5']\n          , arrayFields: ['photos']\n        })\n      , fieldsMap\n      , filesMap\n      ;\n\n    if (!form) {\n      console.log(\"Either this was already parsed or it isn't a multi-part form\");\n      next();\n      return;\n    }\n\n    // form.on('field', ...)\n    // ...\n  });\n}());\n```\n\n### Formaline#on('progress', function () {})\n\nFires after `Formaline#loaded` is updated so you can compare that against `Formaline#total`.\n\n```javascript\nform.on('progress', function () {\n  var ratio = poorForm.loaded / poorForm.total\n    , percent = Math.round(ratio * 100)\n    ;\n\n  console.log(percent + '% complete (' + poorForm.loaded + ' bytes)');\n  // might be 0 because poorForm.total is Infinity when Content-Length is undefined\n  // I.E. Transfer-Encoding: chunked\n})\n```\n\n### Formaline#on('field', function (name, decodedValue) {})\n\nProvides the form name and decoded string\nabstracted from PoorForm's `fieldstart`, `fielddata`, and `fieldend` events\n(remember than a field's data is occasionally chunked across two `fielddata` events).\n\n```javascript\nform.on('field', function (key, value) {\n  // both key and value have been run through `str = decodeURIComponent(str)`\n  fieldsMap[key] = value;\n  console.log(key, value);\n})\n```\n\n### Formaline#on('file', function (name, formFileStream, headers) {})\n\nProvides the form name (not filename) as well as a FormFile stream (described below, has the filename),\nand all associated headers (generally not needed).\n\nRemember: If you specify `options.tmpDir = null`,\nyou are entirely responsible for writing the file to disk, GridStore, S3, the toilet, or wherever.\n\n```javascript\nform.on('file', function (key, formFile) {\n  // for example, we want to save to amazon s3 using knox\n  var s3 = require('knox').createClient({ key: '<api-key>', secret: '<secret>', bucket: '<foo>'})\n    , s3req\n    , metadata\n    ;\n\n  // and let's say we have a field called `metadata` containing a hash with metadata\n  // such as `lastModifiedDate` and `size` for every file to be uploaded\n  if (!fieldMaps.metadata) {\n    console.error('sad day, no metadata');\n  } else {\n    metadata = JSON.parse(fieldMaps.metadata[formFile.name]);\n  }\n\n  s3req = s3.put('/test/file.bin', {\n      'Content-Length': metadata.size\n    , 'Content-Type': 'application/octet-stream'\n  });\n  formFile.pipe(s3);\n\n  formFile.on('end', function () {\n    // formFile is an instance of EventEmitter, but it `JSON.stringify()`s as you would expect.\n    // Also note that some of the properties are added just before the `end` event fires.\n    formFile.lastModifiedDate = metadata.lastModifiedDate;\n    if (!formFile.sha1 === metadata.sha1) {\n      console.error(\"Oh No! The sha1 sums don't match!\");\n    }\n    console.log(key, JSON.stringify(formFile));\n  });\n\n  s3.on('response', function(res){\n    if (200 == res.statusCode) {\n      console.log('saved to %s', req.url);\n    } else {\n      console.error(\"fell on hard times, didn't save %s\", req.url);\n    }\n  });\n})\n```\n\n#### FormFile\n\nA simple EventEmitter FileStream (pausable, resumable, etc)\nabstracted from PoorForm's `fieldstart`, `fielddata`, and `fieldend` events.\n\n  * `name` is taken from the `filename` in the `Content-Disposition` \n  * `fieldname` is the actual name of the field\n  * `size` is the current byte size of the file, which changes until the `end` event is called\n  * `type` is the `contentType`\n  * `lastModifiedDate` is updated each time a chunk is written to the file\n  * `path` is the current file path (either in `/tmp` or a path you specified)\n  * `headers` is the array of MIME headers associated with the form\n  * `md5`, `sha1`, `sha256`, `sha512`, etc are attached as per the `options.hashes` array\n\n### Formaline#on('end', function (fields, files) {})\n\nCongratulations. You've reached the end of the form.\n\n  * `fields` is a map of arrays of Strings `{ \"anyFieldName\": [\"decodedStringValue\"] }`\n  * `files` is a map of arrays of FormFiles `{ \"anyFileName\": [aFormFile, anOtherFormFile] }`\n  * `options.arrayFields` changes the behavior such that only the listed fields are arrays and all others are singular\n\n```javascript\nform.on('end', function (fields, files) {\n  // Normally the values for each key of fields and files would be arrays\n  // However, I specified `arrayFields`, which means that those names not listed are not arrays\n  console.log(fields.username);\n  console.log(fields.password);\n\n  // this is an array because it would be by default if I ha\n  files.photos.forEach(function (formFile) {\n    // JSON.stringify ignores the non-enumerable properties of the underlying EventEmitter\n    console.log(JSON.stringify(formFile));\n  });\n\n  console.log('uploads complete');\n});\n```\n\nNOTE:\nI put a lot of thought (too much, in fact) into how to represent fields and files in a way which is both consistent and easy to use.\n\nIt makes sense to separate `fields` from `files`.\nTreating all fields as files would have unneccesary overhead in parsing.\nWhat you're likely to do with a field (store it in a database as metadata)\nis different from what you'll do with a file (store it in a file system).\n\nThe hybrid approach of mapping pure arrays makes it simple to ignore (and or error check)\nduplicate fields that should have been singular without the confusion of other common methodologies\n(see below).\n\nUsing maps where `username` and `categories` are sometimes treated as single-value fields\n(i.e. if only one `category` is selected in the browser UI)\nbut sometimes treated as arrays\n(i.e. a developer accidentally sends two `username` form parts)\nis inconsistent and likely to cause wierd breakage in your app.\n\nUsing pure arrays where you have to `.forEach`\nand handle the fields in a `switch` is ugly / cumbersome.\n\nAnother workaround is to require php-style field naming conventions such as `categories[]` and `username`, but PHP is &lt;insert-profanity-here&gt; and self-respecting individuals have a hard time taking anything that started with PHP seriously, even though it's atually not a terribly profane solution.\nThe downside to this solution is that it requires parsing field names.\n\n## Future Enhancements (TODO)\n\nThe following are abbreviated security concerns for a form handler with generous and reasonable defaults\n\n  * `error` - abstract `req.on('error')` and `poorForm.on('error', fn)` as to handle malformed requests\n  * `maxHeaderSize` - default 256 Bytes - prevent memory attacks\n  * `maxUniqueFieldNames` - default 1000 - prevent hash collision attacks\n  * `maxFieldSize` - default 4KB - prevent memory attacks\n  * `maxFieldTotalSize` - default 1MB - prevent memory attacks\n  * `maxFileSize` - default 4 GiB - prevent storage attacks\n  * `maxUploadSize` - default 16 GiB - prevent memory / storage attacks\n  * `removeIncomplete` - default true - ignore unless creating a resumable upload service\n\n# LICENSE\n\n  * Apache 2\n  * MIT\n","homepage":"https://github.com/rootslab/formaline","keywords":["formaline","formidable","good-form","poor-form","multipart","upload","form","connect","express","post","parser"],"contributors":[{"name":"AJ ONeal","email":"coolaj86@gmail.com","url":"http://coolaj86.com"},{"name":"Guglielmo Ferri","email":"44gatti@gmail.com","url":"http://rootslab.it"}],"bugs":{"url":"https://github.com/rootslab/formaline/issues"},"license":"MIT","readmeFilename":"README.md"}