@faasjs/http 8.0.0-beta.0 → 8.0.0-beta.2
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 +11 -0
- package/dist/index.cjs +66 -18
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +67 -19
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# @faasjs/http
|
|
2
2
|
|
|
3
|
+
FaasJS's http plugin.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/faasjs/faasjs/blob/main/packages/http/LICENSE)
|
|
6
|
+
[](https://www.npmjs.com/package/@faasjs/http)
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npm install @faasjs/http
|
|
12
|
+
```
|
|
13
|
+
|
|
3
14
|
## Functions
|
|
4
15
|
|
|
5
16
|
- [useHttp](functions/useHttp.md)
|
package/dist/index.cjs
CHANGED
|
@@ -202,12 +202,25 @@ var HttpError = class _HttpError extends Error {
|
|
|
202
202
|
}
|
|
203
203
|
};
|
|
204
204
|
var Name = "http";
|
|
205
|
+
function stringToStream(text) {
|
|
206
|
+
return new ReadableStream({
|
|
207
|
+
start(controller) {
|
|
208
|
+
try {
|
|
209
|
+
const encoder = new TextEncoder();
|
|
210
|
+
controller.enqueue(encoder.encode(text));
|
|
211
|
+
controller.close();
|
|
212
|
+
} catch (error) {
|
|
213
|
+
controller.error(error);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
205
218
|
function deepClone(obj) {
|
|
206
219
|
if (obj === null || typeof obj !== "object") return obj;
|
|
207
220
|
if (Array.isArray(obj)) return JSON.parse(JSON.stringify(obj));
|
|
208
221
|
const clone = {};
|
|
209
222
|
for (const key in obj) {
|
|
210
|
-
if (!
|
|
223
|
+
if (!Object.hasOwn(obj, key)) continue;
|
|
211
224
|
if (typeof obj[key] === "function") {
|
|
212
225
|
clone[key] = obj[key];
|
|
213
226
|
continue;
|
|
@@ -216,6 +229,30 @@ function deepClone(obj) {
|
|
|
216
229
|
}
|
|
217
230
|
return clone;
|
|
218
231
|
}
|
|
232
|
+
function createCompressedStream(body, encoding) {
|
|
233
|
+
const compressStream = encoding === "br" ? zlib.createBrotliCompress() : encoding === "gzip" ? zlib.createGzip() : zlib.createDeflate();
|
|
234
|
+
return new ReadableStream({
|
|
235
|
+
async start(controller) {
|
|
236
|
+
try {
|
|
237
|
+
const compressed = await new Promise((resolve, reject) => {
|
|
238
|
+
const chunks = [];
|
|
239
|
+
compressStream.on("data", (chunk) => chunks.push(chunk));
|
|
240
|
+
compressStream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
241
|
+
compressStream.on("error", reject);
|
|
242
|
+
compressStream.write(Buffer.from(body));
|
|
243
|
+
compressStream.end();
|
|
244
|
+
});
|
|
245
|
+
const chunkSize = 16 * 1024;
|
|
246
|
+
for (let i = 0; i < compressed.length; i += chunkSize) {
|
|
247
|
+
controller.enqueue(compressed.subarray(i, i + chunkSize));
|
|
248
|
+
}
|
|
249
|
+
controller.close();
|
|
250
|
+
} catch (error) {
|
|
251
|
+
controller.error(error);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
219
256
|
var Http = class {
|
|
220
257
|
type = "http";
|
|
221
258
|
name = Name;
|
|
@@ -301,6 +338,9 @@ var Http = class {
|
|
|
301
338
|
data.response = error;
|
|
302
339
|
}
|
|
303
340
|
this.session.update();
|
|
341
|
+
if (this.response.body && !data.response) {
|
|
342
|
+
data.response = this.response.body;
|
|
343
|
+
}
|
|
304
344
|
if (data.response)
|
|
305
345
|
if (data.response instanceof Error || data.response.constructor?.name === "Error") {
|
|
306
346
|
data.logger.error(data.response);
|
|
@@ -315,12 +355,17 @@ var Http = class {
|
|
|
315
355
|
}
|
|
316
356
|
} else if (Object.prototype.toString.call(data.response) === "[object Object]" && data.response.statusCode && data.response.headers)
|
|
317
357
|
this.response = data.response;
|
|
318
|
-
else
|
|
358
|
+
else if (data.response instanceof ReadableStream)
|
|
359
|
+
this.response.body = data.response;
|
|
360
|
+
else
|
|
361
|
+
this.response.body = JSON.stringify({
|
|
362
|
+
data: data.response === void 0 ? null : data.response
|
|
363
|
+
});
|
|
319
364
|
if (!this.response.statusCode)
|
|
320
|
-
this.response.statusCode =
|
|
365
|
+
this.response.statusCode = data.response ? 200 : 204;
|
|
321
366
|
this.response.headers = Object.assign(
|
|
322
367
|
{
|
|
323
|
-
"content-type": "application/json; charset=utf-8",
|
|
368
|
+
"content-type": this.response.body instanceof ReadableStream ? "text/plain; charset=utf-8" : "application/json; charset=utf-8",
|
|
324
369
|
"cache-control": "no-cache, no-store",
|
|
325
370
|
"x-faasjs-request-id": data.context.request_id
|
|
326
371
|
},
|
|
@@ -330,26 +375,29 @@ var Http = class {
|
|
|
330
375
|
data.response = Object.assign({}, data.response, this.response);
|
|
331
376
|
const originBody = data.response.body;
|
|
332
377
|
data.response.originBody = originBody;
|
|
333
|
-
if (
|
|
378
|
+
if (data.response.body instanceof ReadableStream) {
|
|
379
|
+
data.response.isBase64Encoded = true;
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (originBody === void 0 && data.response.statusCode === 204) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
if (originBody && typeof originBody !== "string")
|
|
334
386
|
data.response.body = JSON.stringify(originBody);
|
|
335
|
-
if (
|
|
387
|
+
else if (originBody === void 0)
|
|
388
|
+
data.response.body = JSON.stringify({ data: null });
|
|
389
|
+
if (!data.response.body || typeof data.response.body !== "string" || data.response.body.length < 1024) {
|
|
390
|
+
data.response.body = stringToStream(data.response.body);
|
|
336
391
|
return;
|
|
392
|
+
}
|
|
337
393
|
const acceptEncoding = this.headers["accept-encoding"] || this.headers["Accept-Encoding"];
|
|
338
394
|
if (!acceptEncoding || !/(br|gzip|deflate)/.test(acceptEncoding)) return;
|
|
339
395
|
try {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
} else if (acceptEncoding.includes("gzip")) {
|
|
344
|
-
data.response.headers["Content-Encoding"] = "gzip";
|
|
345
|
-
data.response.body = zlib.gzipSync(originBody).toString("base64");
|
|
346
|
-
} else if (acceptEncoding.includes("deflate")) {
|
|
347
|
-
data.response.headers["Content-Encoding"] = "deflate";
|
|
348
|
-
data.response.body = zlib.deflateSync(originBody).toString("base64");
|
|
349
|
-
} else throw Error("No matched compression.");
|
|
350
|
-
data.response.isBase64Encoded = true;
|
|
396
|
+
const encoding = acceptEncoding.includes("br") ? "br" : acceptEncoding.includes("gzip") ? "gzip" : "deflate";
|
|
397
|
+
data.response.headers["Content-Encoding"] = encoding;
|
|
398
|
+
data.response.body = createCompressedStream(originBody, encoding);
|
|
351
399
|
} catch (error) {
|
|
352
|
-
|
|
400
|
+
data.logger.error("Compression failed: %s", error.message);
|
|
353
401
|
data.response.body = originBody;
|
|
354
402
|
delete data.response.headers["Content-Encoding"];
|
|
355
403
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createBrotliCompress, createGzip, createDeflate } from 'zlib';
|
|
2
2
|
import { deepMerge } from '@faasjs/deep_merge';
|
|
3
3
|
import { usePlugin, useFunc } from '@faasjs/func';
|
|
4
4
|
import { randomBytes, pbkdf2Sync, createCipheriv, createHmac, createDecipheriv } from 'crypto';
|
|
@@ -200,12 +200,25 @@ var HttpError = class _HttpError extends Error {
|
|
|
200
200
|
}
|
|
201
201
|
};
|
|
202
202
|
var Name = "http";
|
|
203
|
+
function stringToStream(text) {
|
|
204
|
+
return new ReadableStream({
|
|
205
|
+
start(controller) {
|
|
206
|
+
try {
|
|
207
|
+
const encoder = new TextEncoder();
|
|
208
|
+
controller.enqueue(encoder.encode(text));
|
|
209
|
+
controller.close();
|
|
210
|
+
} catch (error) {
|
|
211
|
+
controller.error(error);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
203
216
|
function deepClone(obj) {
|
|
204
217
|
if (obj === null || typeof obj !== "object") return obj;
|
|
205
218
|
if (Array.isArray(obj)) return JSON.parse(JSON.stringify(obj));
|
|
206
219
|
const clone = {};
|
|
207
220
|
for (const key in obj) {
|
|
208
|
-
if (!
|
|
221
|
+
if (!Object.hasOwn(obj, key)) continue;
|
|
209
222
|
if (typeof obj[key] === "function") {
|
|
210
223
|
clone[key] = obj[key];
|
|
211
224
|
continue;
|
|
@@ -214,6 +227,30 @@ function deepClone(obj) {
|
|
|
214
227
|
}
|
|
215
228
|
return clone;
|
|
216
229
|
}
|
|
230
|
+
function createCompressedStream(body, encoding) {
|
|
231
|
+
const compressStream = encoding === "br" ? createBrotliCompress() : encoding === "gzip" ? createGzip() : createDeflate();
|
|
232
|
+
return new ReadableStream({
|
|
233
|
+
async start(controller) {
|
|
234
|
+
try {
|
|
235
|
+
const compressed = await new Promise((resolve, reject) => {
|
|
236
|
+
const chunks = [];
|
|
237
|
+
compressStream.on("data", (chunk) => chunks.push(chunk));
|
|
238
|
+
compressStream.on("end", () => resolve(Buffer.concat(chunks)));
|
|
239
|
+
compressStream.on("error", reject);
|
|
240
|
+
compressStream.write(Buffer.from(body));
|
|
241
|
+
compressStream.end();
|
|
242
|
+
});
|
|
243
|
+
const chunkSize = 16 * 1024;
|
|
244
|
+
for (let i = 0; i < compressed.length; i += chunkSize) {
|
|
245
|
+
controller.enqueue(compressed.subarray(i, i + chunkSize));
|
|
246
|
+
}
|
|
247
|
+
controller.close();
|
|
248
|
+
} catch (error) {
|
|
249
|
+
controller.error(error);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
}
|
|
217
254
|
var Http = class {
|
|
218
255
|
type = "http";
|
|
219
256
|
name = Name;
|
|
@@ -299,6 +336,9 @@ var Http = class {
|
|
|
299
336
|
data.response = error;
|
|
300
337
|
}
|
|
301
338
|
this.session.update();
|
|
339
|
+
if (this.response.body && !data.response) {
|
|
340
|
+
data.response = this.response.body;
|
|
341
|
+
}
|
|
302
342
|
if (data.response)
|
|
303
343
|
if (data.response instanceof Error || data.response.constructor?.name === "Error") {
|
|
304
344
|
data.logger.error(data.response);
|
|
@@ -313,12 +353,17 @@ var Http = class {
|
|
|
313
353
|
}
|
|
314
354
|
} else if (Object.prototype.toString.call(data.response) === "[object Object]" && data.response.statusCode && data.response.headers)
|
|
315
355
|
this.response = data.response;
|
|
316
|
-
else
|
|
356
|
+
else if (data.response instanceof ReadableStream)
|
|
357
|
+
this.response.body = data.response;
|
|
358
|
+
else
|
|
359
|
+
this.response.body = JSON.stringify({
|
|
360
|
+
data: data.response === void 0 ? null : data.response
|
|
361
|
+
});
|
|
317
362
|
if (!this.response.statusCode)
|
|
318
|
-
this.response.statusCode =
|
|
363
|
+
this.response.statusCode = data.response ? 200 : 204;
|
|
319
364
|
this.response.headers = Object.assign(
|
|
320
365
|
{
|
|
321
|
-
"content-type": "application/json; charset=utf-8",
|
|
366
|
+
"content-type": this.response.body instanceof ReadableStream ? "text/plain; charset=utf-8" : "application/json; charset=utf-8",
|
|
322
367
|
"cache-control": "no-cache, no-store",
|
|
323
368
|
"x-faasjs-request-id": data.context.request_id
|
|
324
369
|
},
|
|
@@ -328,26 +373,29 @@ var Http = class {
|
|
|
328
373
|
data.response = Object.assign({}, data.response, this.response);
|
|
329
374
|
const originBody = data.response.body;
|
|
330
375
|
data.response.originBody = originBody;
|
|
331
|
-
if (
|
|
376
|
+
if (data.response.body instanceof ReadableStream) {
|
|
377
|
+
data.response.isBase64Encoded = true;
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
if (originBody === void 0 && data.response.statusCode === 204) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
if (originBody && typeof originBody !== "string")
|
|
332
384
|
data.response.body = JSON.stringify(originBody);
|
|
333
|
-
if (
|
|
385
|
+
else if (originBody === void 0)
|
|
386
|
+
data.response.body = JSON.stringify({ data: null });
|
|
387
|
+
if (!data.response.body || typeof data.response.body !== "string" || data.response.body.length < 1024) {
|
|
388
|
+
data.response.body = stringToStream(data.response.body);
|
|
334
389
|
return;
|
|
390
|
+
}
|
|
335
391
|
const acceptEncoding = this.headers["accept-encoding"] || this.headers["Accept-Encoding"];
|
|
336
392
|
if (!acceptEncoding || !/(br|gzip|deflate)/.test(acceptEncoding)) return;
|
|
337
393
|
try {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
} else if (acceptEncoding.includes("gzip")) {
|
|
342
|
-
data.response.headers["Content-Encoding"] = "gzip";
|
|
343
|
-
data.response.body = gzipSync(originBody).toString("base64");
|
|
344
|
-
} else if (acceptEncoding.includes("deflate")) {
|
|
345
|
-
data.response.headers["Content-Encoding"] = "deflate";
|
|
346
|
-
data.response.body = deflateSync(originBody).toString("base64");
|
|
347
|
-
} else throw Error("No matched compression.");
|
|
348
|
-
data.response.isBase64Encoded = true;
|
|
394
|
+
const encoding = acceptEncoding.includes("br") ? "br" : acceptEncoding.includes("gzip") ? "gzip" : "deflate";
|
|
395
|
+
data.response.headers["Content-Encoding"] = encoding;
|
|
396
|
+
data.response.body = createCompressedStream(originBody, encoding);
|
|
349
397
|
} catch (error) {
|
|
350
|
-
|
|
398
|
+
data.logger.error("Compression failed: %s", error.message);
|
|
351
399
|
data.response.body = originBody;
|
|
352
400
|
delete data.response.headers["Content-Encoding"];
|
|
353
401
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faasjs/http",
|
|
3
|
-
"version": "v8.0.0-beta.
|
|
3
|
+
"version": "v8.0.0-beta.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
"dist"
|
|
31
31
|
],
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@faasjs/func": ">=v8.0.0-beta.
|
|
34
|
-
"@faasjs/logger": ">=v8.0.0-beta.
|
|
33
|
+
"@faasjs/func": ">=v8.0.0-beta.2",
|
|
34
|
+
"@faasjs/logger": ">=v8.0.0-beta.2"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@faasjs/func": ">=v8.0.0-beta.
|
|
38
|
-
"@faasjs/logger": ">=v8.0.0-beta.
|
|
37
|
+
"@faasjs/func": ">=v8.0.0-beta.2",
|
|
38
|
+
"@faasjs/logger": ">=v8.0.0-beta.2"
|
|
39
39
|
},
|
|
40
40
|
"engines": {
|
|
41
41
|
"node": ">=24.0.0",
|