@remix-run/node 1.0.4 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/base64.js +1 -1
- package/cookieSigning.js +1 -1
- package/errors.js +1 -1
- package/fetch.d.ts +13 -6
- package/fetch.js +100 -12
- package/{form-data.d.ts → formData.d.ts} +15 -3
- package/formData.js +108 -0
- package/globals.d.ts +6 -0
- package/globals.js +6 -1
- package/index.d.ts +5 -0
- package/index.js +15 -1
- package/magicExports/{browser → esm}/platform.js +2 -2
- package/magicExports/platform.d.ts +1 -1
- package/magicExports/platform.js +15 -3
- package/package.json +18 -3
- package/parseMultipartFormData.d.ts +6 -0
- package/parseMultipartFormData.js +104 -0
- package/sessions/fileStorage.js +1 -1
- package/upload/fileUploadHandler.d.ts +60 -0
- package/upload/fileUploadHandler.js +159 -0
- package/upload/memoryUploadHandler.d.ts +21 -0
- package/upload/memoryUploadHandler.js +80 -0
- package/upload/meter.d.ts +15 -0
- package/upload/meter.js +47 -0
- package/form-data.js +0 -74
package/README.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Welcome to Remix!
|
|
2
|
+
|
|
3
|
+
[Remix](https://remix.run) is a web framework that helps you build better websites with React.
|
|
4
|
+
|
|
5
|
+
To get started, open a new shell and run:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
$ npx create-remix@latest
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Then follow the prompts you see in your terminal.
|
|
12
|
+
|
|
13
|
+
For more information about Remix, [visit remix.run](https://remix.run)!
|
package/base64.js
CHANGED
package/cookieSigning.js
CHANGED
package/errors.js
CHANGED
package/fetch.d.ts
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
import type AbortController from "abort-controller";
|
|
1
2
|
import type { RequestInfo, RequestInit, Response } from "node-fetch";
|
|
2
|
-
import { Request as
|
|
3
|
-
import {
|
|
4
|
-
export type { HeadersInit, RequestInfo,
|
|
3
|
+
import { Request as BaseNodeRequest } from "node-fetch";
|
|
4
|
+
import type { UploadHandler } from "./formData";
|
|
5
|
+
export type { HeadersInit, RequestInfo, ResponseInit } from "node-fetch";
|
|
5
6
|
export { Headers, Response } from "node-fetch";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
formData(): Promise<RemixFormData>;
|
|
7
|
+
interface NodeRequestInit extends RequestInit {
|
|
8
|
+
abortController?: AbortController;
|
|
9
9
|
}
|
|
10
|
+
declare class NodeRequest extends BaseNodeRequest {
|
|
11
|
+
private abortController?;
|
|
12
|
+
constructor(input: RequestInfo, init?: NodeRequestInit | undefined);
|
|
13
|
+
formData(uploadHandler?: UploadHandler): Promise<FormData>;
|
|
14
|
+
clone(): NodeRequest;
|
|
15
|
+
}
|
|
16
|
+
export { NodeRequest as Request, NodeRequestInit as RequestInit };
|
|
10
17
|
/**
|
|
11
18
|
* A `fetch` function for node that matches the web Fetch API. Based on
|
|
12
19
|
* `node-fetch`.
|
package/fetch.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/node v1.
|
|
2
|
+
* @remix-run/node v1.1.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -12,21 +12,99 @@
|
|
|
12
12
|
|
|
13
13
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
14
14
|
|
|
15
|
+
var stream = require('stream');
|
|
16
|
+
var FormStream = require('form-data');
|
|
15
17
|
var nodeFetch = require('node-fetch');
|
|
16
|
-
var formData = require('./
|
|
18
|
+
var formData = require('./formData.js');
|
|
19
|
+
var parseMultipartFormData = require('./parseMultipartFormData.js');
|
|
17
20
|
|
|
18
21
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
19
22
|
|
|
23
|
+
var FormStream__default = /*#__PURE__*/_interopDefaultLegacy(FormStream);
|
|
20
24
|
var nodeFetch__default = /*#__PURE__*/_interopDefaultLegacy(nodeFetch);
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
function formDataToStream(formData$1) {
|
|
27
|
+
let formStream = new FormStream__default["default"]();
|
|
28
|
+
|
|
29
|
+
function toNodeStream(input) {
|
|
30
|
+
// The input is either a Node stream or a web stream, if it has
|
|
31
|
+
// a `on` method it's a node stream so we can just return it
|
|
32
|
+
if (typeof (input === null || input === void 0 ? void 0 : input.on) === "function") {
|
|
33
|
+
return input;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let passthrough = new stream.PassThrough();
|
|
37
|
+
let stream$1 = input;
|
|
38
|
+
let reader = stream$1.getReader();
|
|
39
|
+
reader.read().then(async ({
|
|
40
|
+
done,
|
|
41
|
+
value
|
|
42
|
+
}) => {
|
|
43
|
+
while (!done) {
|
|
44
|
+
passthrough.push(value);
|
|
45
|
+
({
|
|
46
|
+
done,
|
|
47
|
+
value
|
|
48
|
+
} = await reader.read());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
passthrough.push(null);
|
|
52
|
+
}).catch(error => {
|
|
53
|
+
passthrough.emit("error", error);
|
|
54
|
+
});
|
|
55
|
+
return passthrough;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (let [key, value] of formData$1.entries()) {
|
|
59
|
+
if (typeof value === "string") {
|
|
60
|
+
formStream.append(key, value);
|
|
61
|
+
} else if (formData.isFile(value)) {
|
|
62
|
+
let stream = toNodeStream(value.stream());
|
|
63
|
+
formStream.append(key, stream, {
|
|
64
|
+
filename: value.name,
|
|
65
|
+
contentType: value.type,
|
|
66
|
+
knownLength: value.size
|
|
67
|
+
});
|
|
68
|
+
} else {
|
|
69
|
+
let file = value;
|
|
70
|
+
let stream = toNodeStream(file.stream());
|
|
71
|
+
formStream.append(key, stream, {
|
|
72
|
+
filename: "unknown"
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return formStream;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
class NodeRequest extends nodeFetch.Request {
|
|
23
81
|
constructor(input, init) {
|
|
82
|
+
var _init;
|
|
83
|
+
|
|
84
|
+
if (((_init = init) === null || _init === void 0 ? void 0 : _init.body) instanceof formData.FormData) {
|
|
85
|
+
init = { ...init,
|
|
86
|
+
body: formDataToStream(init.body)
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
24
90
|
super(input, init);
|
|
91
|
+
let anyInput = input;
|
|
92
|
+
let anyInit = init;
|
|
93
|
+
this.abortController = (anyInput === null || anyInput === void 0 ? void 0 : anyInput.abortController) || (anyInit === null || anyInit === void 0 ? void 0 : anyInit.abortController);
|
|
25
94
|
}
|
|
26
95
|
|
|
27
|
-
async formData() {
|
|
28
|
-
let
|
|
29
|
-
|
|
96
|
+
async formData(uploadHandler) {
|
|
97
|
+
let contentType = this.headers.get("Content-Type");
|
|
98
|
+
|
|
99
|
+
if (contentType) {
|
|
100
|
+
return await parseMultipartFormData.internalParseFormData(contentType, this.body, this.abortController, uploadHandler);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
throw new Error("Invalid MIME type");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
clone() {
|
|
107
|
+
return new NodeRequest(this);
|
|
30
108
|
}
|
|
31
109
|
|
|
32
110
|
}
|
|
@@ -39,13 +117,23 @@ class Request extends nodeFetch.Request {
|
|
|
39
117
|
*/
|
|
40
118
|
|
|
41
119
|
function fetch(input, init) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return nodeFetch__default["default"](input, {
|
|
120
|
+
var _init2;
|
|
121
|
+
|
|
122
|
+
init = {
|
|
46
123
|
compress: false,
|
|
47
124
|
...init
|
|
48
|
-
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
if (((_init2 = init) === null || _init2 === void 0 ? void 0 : _init2.body) instanceof formData.FormData) {
|
|
128
|
+
init = { ...init,
|
|
129
|
+
body: formDataToStream(init.body)
|
|
130
|
+
};
|
|
131
|
+
} // Default to { compress: false } so responses can be proxied through more
|
|
132
|
+
// easily in loaders. Otherwise the response stream encoding will not match
|
|
133
|
+
// the Content-Encoding response header.
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
return nodeFetch__default["default"](input, init);
|
|
49
137
|
}
|
|
50
138
|
|
|
51
139
|
Object.defineProperty(exports, 'Headers', {
|
|
@@ -56,5 +144,5 @@ Object.defineProperty(exports, 'Response', {
|
|
|
56
144
|
enumerable: true,
|
|
57
145
|
get: function () { return nodeFetch.Response; }
|
|
58
146
|
});
|
|
59
|
-
exports.Request =
|
|
147
|
+
exports.Request = NodeRequest;
|
|
60
148
|
exports.fetch = fetch;
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { Readable } from "stream";
|
|
3
|
+
export declare type UploadHandlerArgs = {
|
|
4
|
+
name: string;
|
|
5
|
+
stream: Readable;
|
|
6
|
+
filename: string;
|
|
7
|
+
encoding: string;
|
|
8
|
+
mimetype: string;
|
|
9
|
+
};
|
|
10
|
+
export declare type UploadHandler = (args: UploadHandlerArgs) => Promise<string | File | undefined>;
|
|
11
|
+
export declare function isFile(blob: Blob): blob is File;
|
|
12
|
+
declare class NodeFormData implements FormData {
|
|
13
|
+
private _fields;
|
|
14
|
+
constructor(form?: any);
|
|
4
15
|
append(name: string, value: string | Blob, fileName?: string): void;
|
|
5
16
|
delete(name: string): void;
|
|
6
17
|
get(name: string): FormDataEntryValue | null;
|
|
@@ -13,3 +24,4 @@ export declare class RemixFormData implements FormData {
|
|
|
13
24
|
values(): IterableIterator<FormDataEntryValue>;
|
|
14
25
|
[Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>;
|
|
15
26
|
}
|
|
27
|
+
export { NodeFormData as FormData };
|
package/formData.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @remix-run/node v1.1.1
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
14
|
+
|
|
15
|
+
function isBlob(value) {
|
|
16
|
+
return typeof value === "object" && (typeof value.arrayBuffer === "function" || typeof value.size === "number" || typeof value.slice === "function" || typeof value.stream === "function" || typeof value.text === "function" || typeof value.type === "string");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isFile(blob) {
|
|
20
|
+
let file = blob;
|
|
21
|
+
return typeof file.name === "string";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class NodeFormData {
|
|
25
|
+
constructor(form) {
|
|
26
|
+
if (typeof form !== "undefined") {
|
|
27
|
+
throw new Error("Form data on the server is not supported.");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this._fields = {};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
append(name, value, fileName) {
|
|
34
|
+
if (typeof value !== "string" && !isBlob(value)) {
|
|
35
|
+
throw new Error("formData.append can only accept a string or Blob");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this._fields[name] = this._fields[name] || [];
|
|
39
|
+
|
|
40
|
+
if (typeof value === "string" || isFile(value)) {
|
|
41
|
+
this._fields[name].push(value);
|
|
42
|
+
} else {
|
|
43
|
+
this._fields[name].push(new File([value], fileName || "unknown"));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
delete(name) {
|
|
48
|
+
delete this._fields[name];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get(name) {
|
|
52
|
+
let arr = this._fields[name];
|
|
53
|
+
return (arr === null || arr === void 0 ? void 0 : arr.slice(-1)[0]) || null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getAll(name) {
|
|
57
|
+
let arr = this._fields[name];
|
|
58
|
+
return arr || [];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
has(name) {
|
|
62
|
+
return name in this._fields;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
set(name, value, fileName) {
|
|
66
|
+
if (typeof value !== "string" && !isBlob(value)) {
|
|
67
|
+
throw new Error("formData.set can only accept a string or Blob");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (typeof value === "string" || isFile(value)) {
|
|
71
|
+
this._fields[name] = [value];
|
|
72
|
+
} else {
|
|
73
|
+
this._fields[name] = [new File([value], fileName || "unknown")];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
forEach(callbackfn, thisArg) {
|
|
78
|
+
Object.entries(this._fields).forEach(([name, values]) => {
|
|
79
|
+
values.forEach(value => callbackfn(value, name, thisArg), thisArg);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
entries() {
|
|
84
|
+
return Object.entries(this._fields).reduce((entries, [name, values]) => {
|
|
85
|
+
values.forEach(value => entries.push([name, value]));
|
|
86
|
+
return entries;
|
|
87
|
+
}, []).values();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
keys() {
|
|
91
|
+
return Object.keys(this._fields).values();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
values() {
|
|
95
|
+
return Object.entries(this._fields).reduce((results, [name, values]) => {
|
|
96
|
+
values.forEach(value => results.push(value));
|
|
97
|
+
return results;
|
|
98
|
+
}, []).values();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
*[Symbol.iterator]() {
|
|
102
|
+
yield* this.entries();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
exports.FormData = NodeFormData;
|
|
108
|
+
exports.isFile = isFile;
|
package/globals.d.ts
CHANGED
|
@@ -2,13 +2,19 @@ import type { InternalSignFunctionDoNotUseMe, InternalUnsignFunctionDoNotUseMe }
|
|
|
2
2
|
import { atob, btoa } from "./base64";
|
|
3
3
|
declare global {
|
|
4
4
|
namespace NodeJS {
|
|
5
|
+
interface ProcessEnv {
|
|
6
|
+
NODE_ENV: "development" | "production" | "test";
|
|
7
|
+
}
|
|
5
8
|
interface Global {
|
|
6
9
|
atob: typeof atob;
|
|
7
10
|
btoa: typeof btoa;
|
|
11
|
+
Blob: typeof Blob;
|
|
12
|
+
File: typeof File;
|
|
8
13
|
Headers: typeof Headers;
|
|
9
14
|
Request: typeof Request;
|
|
10
15
|
Response: typeof Response;
|
|
11
16
|
fetch: typeof fetch;
|
|
17
|
+
FormData: typeof FormData;
|
|
12
18
|
sign: InternalSignFunctionDoNotUseMe;
|
|
13
19
|
unsign: InternalUnsignFunctionDoNotUseMe;
|
|
14
20
|
}
|
package/globals.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/node v1.
|
|
2
|
+
* @remix-run/node v1.1.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -12,18 +12,23 @@
|
|
|
12
12
|
|
|
13
13
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
14
14
|
|
|
15
|
+
var file = require('@web-std/file');
|
|
15
16
|
var base64 = require('./base64.js');
|
|
16
17
|
var cookieSigning = require('./cookieSigning.js');
|
|
17
18
|
var fetch = require('./fetch.js');
|
|
19
|
+
var formData = require('./formData.js');
|
|
18
20
|
var nodeFetch = require('node-fetch');
|
|
19
21
|
|
|
20
22
|
function installGlobals() {
|
|
21
23
|
global.atob = base64.atob;
|
|
22
24
|
global.btoa = base64.btoa;
|
|
25
|
+
global.Blob = file.Blob;
|
|
26
|
+
global.File = file.File;
|
|
23
27
|
global.Headers = nodeFetch.Headers;
|
|
24
28
|
global.Request = fetch.Request;
|
|
25
29
|
global.Response = nodeFetch.Response;
|
|
26
30
|
global.fetch = fetch.fetch;
|
|
31
|
+
global.FormData = formData.FormData;
|
|
27
32
|
global.sign = cookieSigning.sign;
|
|
28
33
|
global.unsign = cookieSigning.unsign;
|
|
29
34
|
}
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
export { AbortController } from "abort-controller";
|
|
1
2
|
export { formatServerError } from "./errors";
|
|
2
3
|
export type { HeadersInit, RequestInfo, RequestInit, ResponseInit } from "./fetch";
|
|
3
4
|
export { Headers, Request, Response, fetch } from "./fetch";
|
|
5
|
+
export { FormData } from "./formData";
|
|
4
6
|
export { installGlobals } from "./globals";
|
|
7
|
+
export { parseMultipartFormData as unstable_parseMultipartFormData } from "./parseMultipartFormData";
|
|
5
8
|
export { createFileSessionStorage } from "./sessions/fileStorage";
|
|
9
|
+
export { createFileUploadHandler as unstable_createFileUploadHandler, NodeOnDiskFile } from "./upload/fileUploadHandler";
|
|
10
|
+
export { createMemoryUploadHandler as unstable_createMemoryUploadHandler } from "./upload/memoryUploadHandler";
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/node v1.
|
|
2
|
+
* @remix-run/node v1.1.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -12,19 +12,33 @@
|
|
|
12
12
|
|
|
13
13
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
14
14
|
|
|
15
|
+
var abortController = require('abort-controller');
|
|
15
16
|
var errors = require('./errors.js');
|
|
16
17
|
var fetch = require('./fetch.js');
|
|
18
|
+
var formData = require('./formData.js');
|
|
17
19
|
var globals = require('./globals.js');
|
|
20
|
+
var parseMultipartFormData = require('./parseMultipartFormData.js');
|
|
18
21
|
var fileStorage = require('./sessions/fileStorage.js');
|
|
22
|
+
var fileUploadHandler = require('./upload/fileUploadHandler.js');
|
|
23
|
+
var memoryUploadHandler = require('./upload/memoryUploadHandler.js');
|
|
19
24
|
var nodeFetch = require('node-fetch');
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
|
|
28
|
+
Object.defineProperty(exports, 'AbortController', {
|
|
29
|
+
enumerable: true,
|
|
30
|
+
get: function () { return abortController.AbortController; }
|
|
31
|
+
});
|
|
23
32
|
exports.formatServerError = errors.formatServerError;
|
|
24
33
|
exports.Request = fetch.Request;
|
|
25
34
|
exports.fetch = fetch.fetch;
|
|
35
|
+
exports.FormData = formData.FormData;
|
|
26
36
|
exports.installGlobals = globals.installGlobals;
|
|
37
|
+
exports.unstable_parseMultipartFormData = parseMultipartFormData.parseMultipartFormData;
|
|
27
38
|
exports.createFileSessionStorage = fileStorage.createFileSessionStorage;
|
|
39
|
+
exports.NodeOnDiskFile = fileUploadHandler.NodeOnDiskFile;
|
|
40
|
+
exports.unstable_createFileUploadHandler = fileUploadHandler.createFileUploadHandler;
|
|
41
|
+
exports.unstable_createMemoryUploadHandler = memoryUploadHandler.createMemoryUploadHandler;
|
|
28
42
|
Object.defineProperty(exports, 'Headers', {
|
|
29
43
|
enumerable: true,
|
|
30
44
|
get: function () { return nodeFetch.Headers; }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/node v1.
|
|
2
|
+
* @remix-run/node v1.1.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -8,4 +8,4 @@
|
|
|
8
8
|
*
|
|
9
9
|
* @license MIT
|
|
10
10
|
*/
|
|
11
|
-
export { createFileSessionStorage } from '@remix-run/node';
|
|
11
|
+
export { createFileSessionStorage, unstable_createFileUploadHandler, unstable_createMemoryUploadHandler, unstable_parseMultipartFormData } from '@remix-run/node';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { createFileSessionStorage } from "@remix-run/node";
|
|
1
|
+
export { createFileSessionStorage, unstable_createFileUploadHandler, unstable_createMemoryUploadHandler, unstable_parseMultipartFormData } from "@remix-run/node";
|
package/magicExports/platform.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/node v1.
|
|
2
|
+
* @remix-run/node v1.1.1
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -17,6 +17,18 @@ var node = require('@remix-run/node');
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
Object.defineProperty(exports, 'createFileSessionStorage', {
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return node.createFileSessionStorage; }
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports, 'unstable_createFileUploadHandler', {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return node.unstable_createFileUploadHandler; }
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(exports, 'unstable_createMemoryUploadHandler', {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function () { return node.unstable_createMemoryUploadHandler; }
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(exports, 'unstable_parseMultipartFormData', {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
get: function () { return node.unstable_parseMultipartFormData; }
|
|
22
34
|
});
|
package/package.json
CHANGED
|
@@ -1,16 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remix-run/node",
|
|
3
3
|
"description": "Node.js platform abstractions for Remix",
|
|
4
|
-
"version": "1.
|
|
5
|
-
"
|
|
4
|
+
"version": "1.1.1",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/remix-run/remix",
|
|
9
|
+
"directory": "packages/remix-node"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/remix-run/remix/issues"
|
|
13
|
+
},
|
|
6
14
|
"dependencies": {
|
|
7
|
-
"@remix-run/server-runtime": "1.
|
|
15
|
+
"@remix-run/server-runtime": "1.1.1",
|
|
16
|
+
"@types/busboy": "^0.3.1",
|
|
8
17
|
"@types/node-fetch": "^2.5.12",
|
|
18
|
+
"@web-std/file": "^3.0.0",
|
|
19
|
+
"abort-controller": "^3.0.0",
|
|
20
|
+
"blob-stream": "^0.1.3",
|
|
21
|
+
"busboy": "^0.3.1",
|
|
9
22
|
"cookie-signature": "^1.1.0",
|
|
23
|
+
"form-data": "^4.0.0",
|
|
10
24
|
"node-fetch": "^2.6.1",
|
|
11
25
|
"source-map": "^0.7.3"
|
|
12
26
|
},
|
|
13
27
|
"devDependencies": {
|
|
28
|
+
"@types/blob-stream": "^0.1.30",
|
|
14
29
|
"@types/cookie-signature": "^1.0.3"
|
|
15
30
|
},
|
|
16
31
|
"sideEffects": false
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Readable } from "stream";
|
|
3
|
+
import type { UploadHandler } from "./formData";
|
|
4
|
+
import { FormData as NodeFormData } from "./formData";
|
|
5
|
+
export declare function parseMultipartFormData(request: Request, uploadHandler: UploadHandler): Promise<FormData>;
|
|
6
|
+
export declare function internalParseFormData(contentType: string, body: string | Buffer | Readable, abortController?: AbortController, uploadHandler?: UploadHandler): Promise<NodeFormData>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @remix-run/node v1.1.1
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
14
|
+
|
|
15
|
+
var stream = require('stream');
|
|
16
|
+
var Busboy = require('busboy');
|
|
17
|
+
var formData = require('./formData.js');
|
|
18
|
+
|
|
19
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
20
|
+
|
|
21
|
+
var Busboy__default = /*#__PURE__*/_interopDefaultLegacy(Busboy);
|
|
22
|
+
|
|
23
|
+
function parseMultipartFormData(request, uploadHandler) {
|
|
24
|
+
return request.formData(uploadHandler);
|
|
25
|
+
}
|
|
26
|
+
async function internalParseFormData(contentType, body, abortController, uploadHandler) {
|
|
27
|
+
let formData$1 = new formData.FormData();
|
|
28
|
+
let fileWorkQueue = [];
|
|
29
|
+
let stream$1;
|
|
30
|
+
|
|
31
|
+
if (typeof body === "string" || Buffer.isBuffer(body)) {
|
|
32
|
+
stream$1 = stream.Readable.from(body.toString());
|
|
33
|
+
} else {
|
|
34
|
+
stream$1 = body;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await new Promise(async (resolve, reject) => {
|
|
38
|
+
let busboy = new Busboy__default["default"]({
|
|
39
|
+
highWaterMark: 2 * 1024 * 1024,
|
|
40
|
+
headers: {
|
|
41
|
+
"content-type": contentType
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
let aborted = false;
|
|
45
|
+
|
|
46
|
+
function abort(error) {
|
|
47
|
+
if (aborted) return;
|
|
48
|
+
aborted = true;
|
|
49
|
+
stream$1.unpipe();
|
|
50
|
+
stream$1.removeAllListeners();
|
|
51
|
+
busboy.removeAllListeners();
|
|
52
|
+
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
53
|
+
reject(error || new Error("failed to parse form data"));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
busboy.on("field", (name, value) => {
|
|
57
|
+
formData$1.append(name, value);
|
|
58
|
+
});
|
|
59
|
+
busboy.on("file", (name, filestream, filename, encoding, mimetype) => {
|
|
60
|
+
if (uploadHandler) {
|
|
61
|
+
fileWorkQueue.push((async () => {
|
|
62
|
+
try {
|
|
63
|
+
let value = await uploadHandler({
|
|
64
|
+
name,
|
|
65
|
+
stream: filestream,
|
|
66
|
+
filename,
|
|
67
|
+
encoding,
|
|
68
|
+
mimetype
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (typeof value !== "undefined") {
|
|
72
|
+
formData$1.append(name, value);
|
|
73
|
+
}
|
|
74
|
+
} catch (error) {
|
|
75
|
+
// Emit error to busboy to bail early if possible
|
|
76
|
+
busboy.emit("error", error); // It's possible that the handler is doing stuff and fails
|
|
77
|
+
// *after* busboy has finished. Rethrow the error for surfacing
|
|
78
|
+
// in the Promise.all(fileWorkQueue) below.
|
|
79
|
+
|
|
80
|
+
throw error;
|
|
81
|
+
} finally {
|
|
82
|
+
filestream.resume();
|
|
83
|
+
}
|
|
84
|
+
})());
|
|
85
|
+
} else {
|
|
86
|
+
filestream.resume();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!uploadHandler) {
|
|
90
|
+
console.warn(`Tried to parse multipart file upload for field "${name}" but no uploadHandler was provided.` + " Read more here: https://remix.run/api/remix#parseMultipartFormData-node");
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
stream$1.on("error", abort);
|
|
94
|
+
stream$1.on("aborted", abort);
|
|
95
|
+
busboy.on("error", abort);
|
|
96
|
+
busboy.on("finish", resolve);
|
|
97
|
+
stream$1.pipe(busboy);
|
|
98
|
+
});
|
|
99
|
+
await Promise.all(fileWorkQueue);
|
|
100
|
+
return formData$1;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
exports.internalParseFormData = internalParseFormData;
|
|
104
|
+
exports.parseMultipartFormData = parseMultipartFormData;
|
package/sessions/fileStorage.js
CHANGED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { UploadHandler } from "../formData";
|
|
3
|
+
export declare type FileUploadHandlerFilterArgs = {
|
|
4
|
+
filename: string;
|
|
5
|
+
encoding: string;
|
|
6
|
+
mimetype: string;
|
|
7
|
+
};
|
|
8
|
+
export declare type FileUploadHandlerPathResolverArgs = {
|
|
9
|
+
filename: string;
|
|
10
|
+
encoding: string;
|
|
11
|
+
mimetype: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Chooses the path of the file to be uploaded. If a string is not
|
|
15
|
+
* returned the file will not be written.
|
|
16
|
+
*/
|
|
17
|
+
export declare type FileUploadHandlerPathResolver = (args: FileUploadHandlerPathResolverArgs) => string | undefined;
|
|
18
|
+
export declare type FileUploadHandlerOptions = {
|
|
19
|
+
/**
|
|
20
|
+
* Avoid file conflicts by appending a count on the end of the filename
|
|
21
|
+
* if it already exists on disk. Defaults to `true`.
|
|
22
|
+
*/
|
|
23
|
+
avoidFileConflicts?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* The directory to write the upload.
|
|
26
|
+
*/
|
|
27
|
+
directory?: string | FileUploadHandlerPathResolver;
|
|
28
|
+
/**
|
|
29
|
+
* The name of the file in the directory. Can be a relative path, the directory
|
|
30
|
+
* structure will be created if it does not exist.
|
|
31
|
+
*/
|
|
32
|
+
file?: FileUploadHandlerPathResolver;
|
|
33
|
+
/**
|
|
34
|
+
* The maximum upload size allowed. If the size is exceeded an error will be thrown.
|
|
35
|
+
* Defaults to 3000000B (3MB).
|
|
36
|
+
*/
|
|
37
|
+
maxFileSize?: number;
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
* @param filename
|
|
41
|
+
* @param mimetype
|
|
42
|
+
* @param encoding
|
|
43
|
+
*/
|
|
44
|
+
filter?(args: FileUploadHandlerFilterArgs): boolean | Promise<boolean>;
|
|
45
|
+
};
|
|
46
|
+
export declare function createFileUploadHandler({ directory, avoidFileConflicts, file, filter, maxFileSize }: FileUploadHandlerOptions): UploadHandler;
|
|
47
|
+
export declare class NodeOnDiskFile implements File {
|
|
48
|
+
private filepath;
|
|
49
|
+
size: number;
|
|
50
|
+
type: string;
|
|
51
|
+
name: string;
|
|
52
|
+
lastModified: number;
|
|
53
|
+
webkitRelativePath: string;
|
|
54
|
+
constructor(filepath: string, size: number, type: string);
|
|
55
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
56
|
+
slice(start?: any, end?: any, contentType?: any): Blob;
|
|
57
|
+
stream(): ReadableStream<any>;
|
|
58
|
+
stream(): NodeJS.ReadableStream;
|
|
59
|
+
text(): Promise<string>;
|
|
60
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @remix-run/node v1.1.1
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
14
|
+
|
|
15
|
+
var crypto = require('crypto');
|
|
16
|
+
var fs = require('fs');
|
|
17
|
+
var fsp = require('fs/promises');
|
|
18
|
+
var os = require('os');
|
|
19
|
+
var path = require('path');
|
|
20
|
+
var meter = require('./meter.js');
|
|
21
|
+
|
|
22
|
+
let defaultFilePathResolver = ({
|
|
23
|
+
filename
|
|
24
|
+
}) => {
|
|
25
|
+
let ext = filename ? path.extname(filename) : "";
|
|
26
|
+
return "upload_" + crypto.randomBytes(4).readUInt32LE(0) + ext;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
async function uniqueFile(filepath) {
|
|
30
|
+
let ext = path.extname(filepath);
|
|
31
|
+
let uniqueFilepath = filepath;
|
|
32
|
+
|
|
33
|
+
for (let i = 1; await fsp.stat(uniqueFilepath).then(() => true).catch(() => false); i++) {
|
|
34
|
+
uniqueFilepath = (ext ? filepath.slice(0, -ext.length) : filepath) + `-${new Date().getTime()}${ext}`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return uniqueFilepath;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function createFileUploadHandler({
|
|
41
|
+
directory = os.tmpdir(),
|
|
42
|
+
avoidFileConflicts = true,
|
|
43
|
+
file = defaultFilePathResolver,
|
|
44
|
+
filter,
|
|
45
|
+
maxFileSize = 3000000
|
|
46
|
+
}) {
|
|
47
|
+
return async ({
|
|
48
|
+
name,
|
|
49
|
+
stream,
|
|
50
|
+
filename,
|
|
51
|
+
encoding,
|
|
52
|
+
mimetype
|
|
53
|
+
}) => {
|
|
54
|
+
if (filter && !(await filter({
|
|
55
|
+
filename,
|
|
56
|
+
encoding,
|
|
57
|
+
mimetype
|
|
58
|
+
}))) {
|
|
59
|
+
stream.resume();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let dir = typeof directory === "string" ? directory : directory({
|
|
64
|
+
filename,
|
|
65
|
+
encoding,
|
|
66
|
+
mimetype
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
if (!dir) {
|
|
70
|
+
stream.resume();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let filedir = path.resolve(dir);
|
|
75
|
+
let path$1 = typeof file === "string" ? file : file({
|
|
76
|
+
filename,
|
|
77
|
+
encoding,
|
|
78
|
+
mimetype
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (!path$1) {
|
|
82
|
+
stream.resume();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let filepath = path.resolve(filedir, path$1);
|
|
87
|
+
|
|
88
|
+
if (avoidFileConflicts) {
|
|
89
|
+
filepath = await uniqueFile(filepath);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
await fsp.mkdir(path.dirname(filepath), {
|
|
93
|
+
recursive: true
|
|
94
|
+
}).catch(() => {});
|
|
95
|
+
let meter$1 = new meter.Meter(name, maxFileSize);
|
|
96
|
+
await new Promise((resolve, reject) => {
|
|
97
|
+
let writeFileStream = fs.createWriteStream(filepath);
|
|
98
|
+
let aborted = false;
|
|
99
|
+
|
|
100
|
+
async function abort(error) {
|
|
101
|
+
if (aborted) return;
|
|
102
|
+
aborted = true;
|
|
103
|
+
stream.unpipe();
|
|
104
|
+
meter$1.unpipe();
|
|
105
|
+
stream.removeAllListeners();
|
|
106
|
+
meter$1.removeAllListeners();
|
|
107
|
+
writeFileStream.removeAllListeners();
|
|
108
|
+
await fsp.rm(filepath, {
|
|
109
|
+
force: true
|
|
110
|
+
}).catch(() => {});
|
|
111
|
+
reject(error);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
stream.on("error", abort);
|
|
115
|
+
meter$1.on("error", abort);
|
|
116
|
+
writeFileStream.on("error", abort);
|
|
117
|
+
writeFileStream.on("finish", resolve);
|
|
118
|
+
stream.pipe(meter$1).pipe(writeFileStream);
|
|
119
|
+
});
|
|
120
|
+
return new NodeOnDiskFile(filepath, meter$1.bytes, mimetype);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
class NodeOnDiskFile {
|
|
124
|
+
lastModified = 0;
|
|
125
|
+
webkitRelativePath = "";
|
|
126
|
+
|
|
127
|
+
constructor(filepath, size, type) {
|
|
128
|
+
this.filepath = filepath;
|
|
129
|
+
this.size = size;
|
|
130
|
+
this.type = type;
|
|
131
|
+
this.name = path.basename(filepath);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async arrayBuffer() {
|
|
135
|
+
let stream = fs.createReadStream(this.filepath);
|
|
136
|
+
return new Promise((resolve, reject) => {
|
|
137
|
+
const buf = [];
|
|
138
|
+
stream.on("data", chunk => buf.push(chunk));
|
|
139
|
+
stream.on("end", () => resolve(Buffer.concat(buf)));
|
|
140
|
+
stream.on("error", err => reject(err));
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
slice(start, end, contentType) {
|
|
145
|
+
throw new Error("Method not implemented.");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
stream() {
|
|
149
|
+
return fs.createReadStream(this.filepath);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
text() {
|
|
153
|
+
return fsp.readFile(this.filepath, "utf-8");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
exports.NodeOnDiskFile = NodeOnDiskFile;
|
|
159
|
+
exports.createFileUploadHandler = createFileUploadHandler;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { UploadHandler } from "../formData";
|
|
2
|
+
export declare type MemoryUploadHandlerFilterArgs = {
|
|
3
|
+
filename: string;
|
|
4
|
+
encoding: string;
|
|
5
|
+
mimetype: string;
|
|
6
|
+
};
|
|
7
|
+
export declare type MemoryUploadHandlerOptions = {
|
|
8
|
+
/**
|
|
9
|
+
* The maximum upload size allowed. If the size is exceeded an error will be thrown.
|
|
10
|
+
* Defaults to 3000000B (3MB).
|
|
11
|
+
*/
|
|
12
|
+
maxFileSize?: number;
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* @param filename
|
|
16
|
+
* @param mimetype
|
|
17
|
+
* @param encoding
|
|
18
|
+
*/
|
|
19
|
+
filter?(args: MemoryUploadHandlerFilterArgs): boolean | Promise<boolean>;
|
|
20
|
+
};
|
|
21
|
+
export declare function createMemoryUploadHandler({ filter, maxFileSize }: MemoryUploadHandlerOptions): UploadHandler;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @remix-run/node v1.1.1
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
14
|
+
|
|
15
|
+
var stream = require('stream');
|
|
16
|
+
var file = require('@web-std/file');
|
|
17
|
+
var meter = require('./meter.js');
|
|
18
|
+
|
|
19
|
+
function createMemoryUploadHandler({
|
|
20
|
+
filter,
|
|
21
|
+
maxFileSize = 3000000
|
|
22
|
+
}) {
|
|
23
|
+
return async ({
|
|
24
|
+
name,
|
|
25
|
+
stream,
|
|
26
|
+
filename,
|
|
27
|
+
encoding,
|
|
28
|
+
mimetype
|
|
29
|
+
}) => {
|
|
30
|
+
if (filter && !(await filter({
|
|
31
|
+
filename,
|
|
32
|
+
encoding,
|
|
33
|
+
mimetype
|
|
34
|
+
}))) {
|
|
35
|
+
stream.resume();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let bufferStream = new BufferStream();
|
|
40
|
+
await new Promise((resolve, reject) => {
|
|
41
|
+
let meter$1 = new meter.Meter(name, maxFileSize);
|
|
42
|
+
let aborted = false;
|
|
43
|
+
|
|
44
|
+
async function abort(error) {
|
|
45
|
+
if (aborted) return;
|
|
46
|
+
aborted = true;
|
|
47
|
+
stream.unpipe();
|
|
48
|
+
meter$1.unpipe();
|
|
49
|
+
stream.removeAllListeners();
|
|
50
|
+
meter$1.removeAllListeners();
|
|
51
|
+
bufferStream.removeAllListeners();
|
|
52
|
+
reject(error);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
stream.on("error", abort);
|
|
56
|
+
meter$1.on("error", abort);
|
|
57
|
+
bufferStream.on("error", abort);
|
|
58
|
+
bufferStream.on("finish", resolve);
|
|
59
|
+
stream.pipe(meter$1).pipe(bufferStream);
|
|
60
|
+
});
|
|
61
|
+
return new file.File(bufferStream.data, filename, {
|
|
62
|
+
type: mimetype
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
class BufferStream extends stream.Transform {
|
|
68
|
+
constructor() {
|
|
69
|
+
super();
|
|
70
|
+
this.data = [];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
_transform(chunk, _, callback) {
|
|
74
|
+
this.data.push(chunk);
|
|
75
|
+
callback();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
exports.createMemoryUploadHandler = createMemoryUploadHandler;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type { TransformCallback } from "stream";
|
|
3
|
+
import { Transform } from "stream";
|
|
4
|
+
export declare class Meter extends Transform {
|
|
5
|
+
field: string;
|
|
6
|
+
maxBytes: number | undefined;
|
|
7
|
+
bytes: number;
|
|
8
|
+
constructor(field: string, maxBytes: number | undefined);
|
|
9
|
+
_transform(chunk: any, _: BufferEncoding, callback: TransformCallback): void;
|
|
10
|
+
}
|
|
11
|
+
export declare class MeterError extends Error {
|
|
12
|
+
field: string;
|
|
13
|
+
maxBytes: number;
|
|
14
|
+
constructor(field: string, maxBytes: number);
|
|
15
|
+
}
|
package/upload/meter.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @remix-run/node v1.1.1
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) Remix Software Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
+
*
|
|
9
|
+
* @license MIT
|
|
10
|
+
*/
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
14
|
+
|
|
15
|
+
var stream = require('stream');
|
|
16
|
+
|
|
17
|
+
class Meter extends stream.Transform {
|
|
18
|
+
constructor(field, maxBytes) {
|
|
19
|
+
super();
|
|
20
|
+
this.field = field;
|
|
21
|
+
this.maxBytes = maxBytes;
|
|
22
|
+
this.bytes = 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
_transform(chunk, _, callback) {
|
|
26
|
+
this.bytes += chunk.length;
|
|
27
|
+
this.push(chunk);
|
|
28
|
+
|
|
29
|
+
if (typeof this.maxBytes === "number" && this.bytes > this.maxBytes) {
|
|
30
|
+
return callback(new MeterError(this.field, this.maxBytes));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
callback();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
class MeterError extends Error {
|
|
38
|
+
constructor(field, maxBytes) {
|
|
39
|
+
super(`Field "${field}" exceeded upload size of ${maxBytes} bytes.`);
|
|
40
|
+
this.field = field;
|
|
41
|
+
this.maxBytes = maxBytes;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
exports.Meter = Meter;
|
|
47
|
+
exports.MeterError = MeterError;
|
package/form-data.js
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @remix-run/node v1.0.4
|
|
3
|
-
*
|
|
4
|
-
* Copyright (c) Remix Software Inc.
|
|
5
|
-
*
|
|
6
|
-
* This source code is licensed under the MIT license found in the
|
|
7
|
-
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
-
*
|
|
9
|
-
* @license MIT
|
|
10
|
-
*/
|
|
11
|
-
'use strict';
|
|
12
|
-
|
|
13
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
14
|
-
|
|
15
|
-
class RemixFormData {
|
|
16
|
-
constructor(body) {
|
|
17
|
-
this._params = new URLSearchParams(body);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
append(name, value, fileName) {
|
|
21
|
-
if (typeof value !== "string") {
|
|
22
|
-
throw new Error("formData.append can only accept a string");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
this._params.append(name, value);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
delete(name) {
|
|
29
|
-
this._params.delete(name);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get(name) {
|
|
33
|
-
return this._params.get(name);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
getAll(name) {
|
|
37
|
-
return this._params.getAll(name);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
has(name) {
|
|
41
|
-
return this._params.has(name);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
set(name, value, fileName) {
|
|
45
|
-
if (typeof value !== "string") {
|
|
46
|
-
throw new Error("formData.set can only accept a string");
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
this._params.set(name, value);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
forEach(callbackfn, thisArg) {
|
|
53
|
-
this._params.forEach(callbackfn, thisArg);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
entries() {
|
|
57
|
-
return this._params.entries();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
keys() {
|
|
61
|
-
return this._params.keys();
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
values() {
|
|
65
|
-
return this._params.values();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
*[Symbol.iterator]() {
|
|
69
|
-
yield* this._params;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
exports.RemixFormData = RemixFormData;
|