@mionjs/platform-gcloud 0.13.2 → 0.14.0
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/.dist/esm/src/googleCF.js +5 -10
- package/.dist/esm/src/googleCF.js.map +1 -1
- package/package.json +6 -5
- package/.dist/cjs/index.cjs +0 -9
- package/.dist/cjs/index.d.ts +0 -4
- package/.dist/cjs/package.json +0 -1
- package/.dist/cjs/src/constants.cjs +0 -14
- package/.dist/cjs/src/constants.cjs.map +0 -1
- package/.dist/cjs/src/constants.d.ts +0 -4
- package/.dist/cjs/src/googleCF.cjs +0 -81
- package/.dist/cjs/src/googleCF.cjs.map +0 -1
- package/.dist/cjs/src/googleCF.d.ts +0 -7
- package/.dist/cjs/src/headers.cjs +0 -52
- package/.dist/cjs/src/headers.cjs.map +0 -1
- package/.dist/cjs/src/headers.d.ts +0 -5
- package/.dist/cjs/src/types.cjs +0 -0
- package/.dist/cjs/src/types.d.ts +0 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_GOOGLE_CF_OPTIONS } from "./constants.js";
|
|
2
2
|
import { headersFromIncomingMessage, headersFromServerResponse } from "./headers.js";
|
|
3
3
|
import { SerializerModes } from "@mionjs/core";
|
|
4
|
-
import { createContextFromChain,
|
|
4
|
+
import { createContextFromChain, dispatchPlatformError, dispatchWithContext, getResponseDefaults, getRouterFatalErrorResponse, requestPayloadTooLarge, resetRouter, resolveExecutionChain, setPlatformConfig, toHttpMethod, toRpcError } from "@mionjs/router";
|
|
5
5
|
//#region src/googleCF.ts
|
|
6
6
|
var googleCFOptions = { ...DEFAULT_GOOGLE_CF_OPTIONS };
|
|
7
7
|
function resetGoogleCFOpts() {
|
|
@@ -24,8 +24,8 @@ function createGoogleCFHandler(options) {
|
|
|
24
24
|
async function googleCFHandler(rawRequest, rawResponse) {
|
|
25
25
|
const reqHeaders = headersFromIncomingMessage(rawRequest);
|
|
26
26
|
const respHeaders = headersFromServerResponse(rawResponse, getResponseDefaults());
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
const rawBody = rawRequest.body;
|
|
28
|
+
const reqBodyType = typeof rawBody === "string" ? SerializerModes.stringifyJson : SerializerModes.json;
|
|
29
29
|
const originalUrl = rawRequest.originalUrl;
|
|
30
30
|
const queryIndex = originalUrl ? originalUrl.indexOf("?") : -1;
|
|
31
31
|
const urlQuery = queryIndex === -1 ? void 0 : originalUrl.slice(queryIndex + 1);
|
|
@@ -34,14 +34,9 @@ async function googleCFHandler(rawRequest, rawResponse) {
|
|
|
34
34
|
try {
|
|
35
35
|
rejectOversizedRequest(rawRequest, rawBody, chain.maxBodySize);
|
|
36
36
|
} catch (refusal) {
|
|
37
|
-
return reply(await dispatchPlatformError(chain, rawRequest.path, urlQuery, toRpcError(refusal), reqHeaders, respHeaders, rawRequest, rawResponse), rawResponse);
|
|
37
|
+
return reply(await dispatchPlatformError(chain, rawRequest.path, urlQuery, toHttpMethod(rawRequest.method), toRpcError(refusal), reqHeaders, respHeaders, rawRequest, rawResponse), rawResponse);
|
|
38
38
|
}
|
|
39
|
-
|
|
40
|
-
if (queryBody) {
|
|
41
|
-
rawBody = queryBody.rawBody;
|
|
42
|
-
reqBodyType = queryBody.bodyType;
|
|
43
|
-
}
|
|
44
|
-
reply(await dispatchWithContext(createContextFromChain(chain, rawRequest.path, urlQuery, reqHeaders, respHeaders, rawBody, reqBodyType), rawRequest, rawResponse), rawResponse);
|
|
39
|
+
reply(await dispatchWithContext(createContextFromChain(chain, rawRequest.path, urlQuery, toHttpMethod(rawRequest.method), reqHeaders, respHeaders, bodyOrUndefined(rawBody), reqBodyType), rawRequest, rawResponse), rawResponse);
|
|
45
40
|
} catch (err) {
|
|
46
41
|
reply(getRouterFatalErrorResponse(toRpcError(err), respHeaders), rawResponse);
|
|
47
42
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"googleCF.js","names":[],"sources":["../../../src/googleCF.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {SerializerModes} from '@mionjs/core';\nimport type {SerializerCode} from '@mionjs/core';\nimport {\n dispatchWithContext,\n dispatchPlatformError,\n toRpcError,\n resolveExecutionChain,\n createContextFromChain,\n getRouterFatalErrorResponse,\n requestPayloadTooLarge,\n resetRouter,\n
|
|
1
|
+
{"version":3,"file":"googleCF.js","names":[],"sources":["../../../src/googleCF.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {SerializerModes} from '@mionjs/core';\nimport type {SerializerCode} from '@mionjs/core';\nimport {\n dispatchWithContext,\n dispatchPlatformError,\n toRpcError,\n resolveExecutionChain,\n createContextFromChain,\n getRouterFatalErrorResponse,\n requestPayloadTooLarge,\n resetRouter,\n setPlatformConfig,\n getResponseDefaults,\n toHttpMethod,\n} from '@mionjs/router';\nimport type {MionResponse, RawRequestBody} from '@mionjs/router';\nimport {Request, Response} from 'express';\nimport {DEFAULT_GOOGLE_CF_OPTIONS} from './constants.ts';\nimport {GoogleCFOptions} from './types.ts';\nimport {headersFromIncomingMessage, headersFromServerResponse} from './headers.ts';\n\n// ############# STATE #############\n\nlet googleCFOptions: Readonly<GoogleCFOptions> = {...DEFAULT_GOOGLE_CF_OPTIONS};\n\n// ############# PUBLIC METHODS #############\n\nexport function resetGoogleCFOpts() {\n googleCFOptions = {...DEFAULT_GOOGLE_CF_OPTIONS};\n resetRouter();\n}\n\nexport function setGoogleCFOpts(routerOptions?: Partial<GoogleCFOptions>) {\n googleCFOptions = {\n ...googleCFOptions,\n ...routerOptions,\n };\n setPlatformConfig({...googleCFOptions});\n return googleCFOptions;\n}\n\n/** Creates a Google Cloud Functions handler with optional platform config */\nexport function createGoogleCFHandler(options?: Partial<GoogleCFOptions>) {\n setGoogleCFOpts(options);\n return googleCFHandler;\n}\n\nexport async function googleCFHandler(rawRequest: Request, rawResponse: Response): Promise<void> {\n // express may hand the body over already parsed, so both a string and an object body are accepted\n\n // TODO use its own express headers wrapper instead headers from record\n const reqHeaders = headersFromIncomingMessage(rawRequest);\n const respHeaders = headersFromServerResponse(rawResponse, getResponseDefaults());\n const rawBody = rawRequest.body;\n const reqBodyType: SerializerCode = typeof rawBody === 'string' ? SerializerModes.stringifyJson : SerializerModes.json;\n // everything after the FIRST `?`: a second one is legal inside a query, so splitting on it would drop parameters\n const originalUrl = rawRequest.originalUrl;\n const queryIndex = originalUrl ? originalUrl.indexOf('?') : -1;\n const urlQuery = queryIndex === -1 ? undefined : originalUrl.slice(queryIndex + 1);\n\n try {\n // express already read the body, so the chain's limit is resolved first and the size check runs before the router sees it\n const chain = resolveExecutionChain(rawRequest.path, urlQuery, rawRequest);\n try {\n rejectOversizedRequest(rawRequest, rawBody, chain.maxBodySize);\n } catch (refusal) {\n // the route resolved, so the refusal still runs the chain's alwaysRun members\n const refused = await dispatchPlatformError(\n chain,\n rawRequest.path,\n urlQuery,\n toHttpMethod(rawRequest.method),\n toRpcError(refusal),\n reqHeaders,\n respHeaders,\n rawRequest,\n rawResponse\n );\n return reply(refused, rawResponse);\n }\n const context = createContextFromChain(\n chain,\n rawRequest.path,\n urlQuery,\n toHttpMethod(rawRequest.method),\n reqHeaders,\n respHeaders,\n bodyOrUndefined(rawBody),\n reqBodyType\n );\n const routeResponse = await dispatchWithContext(context, rawRequest, rawResponse);\n reply(routeResponse, rawResponse);\n } catch (err) {\n const routeResponse = getRouterFatalErrorResponse(toRpcError(err), respHeaders);\n reply(routeResponse, rawResponse);\n }\n}\n\n// ############# PRIVATE METHODS #############\n\n/** express parses a body-less request into an EMPTY object, which is truthy, so `?data=` would never be read without this. */\nfunction bodyOrUndefined(rawBody: unknown): RawRequestBody | undefined {\n if (!rawBody) return undefined;\n if (typeof rawBody !== 'object') return rawBody as string;\n for (const key in rawBody) return rawBody as RawRequestBody;\n return undefined;\n}\n\n/** express hands a JSON request over parsed and the router only measures strings, so the wire size is found here instead.\n * `rawBody` is the exact bytes the Google functions framework keeps; a plain express host leaves only the parsed body. */\nfunction rejectOversizedRequest(rawRequest: Request, rawBody: unknown, maxBodySize: number): void {\n const declaredLength = rawRequest.headers['content-length'];\n if (declaredLength !== undefined) {\n if (Number(declaredLength) > maxBodySize) throw requestPayloadTooLarge();\n return;\n }\n // a string body is measured again by the router, so only a parsed one still needs a size here\n if (typeof rawBody !== 'object' || rawBody === null) return;\n const wireBytes = (rawRequest as {rawBody?: Buffer}).rawBody;\n const size = wireBytes ? wireBytes.byteLength : Buffer.byteLength(JSON.stringify(rawBody), 'utf8');\n if (size > maxBodySize) throw requestPayloadTooLarge();\n}\n\nfunction reply(mionResp: MionResponse, resp: Response): void {\n resp.status(mionResp.statusCode);\n const jsonString = JSON.stringify(mionResp.body);\n resp.set('content-type', mionResp.contentType);\n // byteLength measures without copying the response into a Buffer\n resp.set('content-length', `${Buffer.byteLength(jsonString, 'utf8')}`);\n resp.end(jsonString, 'utf8');\n}\n"],"mappings":";;;;;AA8BA,IAAI,kBAA6C,EAAC,GAAG,0BAAyB;AAI9E,SAAgB,oBAAoB;CAClC,kBAAkB,EAAC,GAAG,0BAAyB;CAC/C,YAAY;AACd;AAEA,SAAgB,gBAAgB,eAA0C;CACxE,kBAAkB;EAChB,GAAG;EACH,GAAG;CACL;CACA,kBAAkB,EAAC,GAAG,gBAAe,CAAC;CACtC,OAAO;AACT;;AAGA,SAAgB,sBAAsB,SAAoC;CACxE,gBAAgB,OAAO;CACvB,OAAO;AACT;AAEA,eAAsB,gBAAgB,YAAqB,aAAsC;CAI/F,MAAM,aAAa,2BAA2B,UAAU;CACxD,MAAM,cAAc,0BAA0B,aAAa,oBAAoB,CAAC;CAChF,MAAM,UAAU,WAAW;CAC3B,MAAM,cAA8B,OAAO,YAAY,WAAW,gBAAgB,gBAAgB,gBAAgB;CAElH,MAAM,cAAc,WAAW;CAC/B,MAAM,aAAa,cAAc,YAAY,QAAQ,GAAG,IAAI;CAC5D,MAAM,WAAW,eAAe,KAAK,KAAA,IAAY,YAAY,MAAM,aAAa,CAAC;CAEjF,IAAI;EAEF,MAAM,QAAQ,sBAAsB,WAAW,MAAM,UAAU,UAAU;EACzE,IAAI;GACF,uBAAuB,YAAY,SAAS,MAAM,WAAW;EAC/D,SAAS,SAAS;GAahB,OAAO,MAAM,MAXS,sBACpB,OACA,WAAW,MACX,UACA,aAAa,WAAW,MAAM,GAC9B,WAAW,OAAO,GAClB,YACA,aACA,YACA,WACF,GACsB,WAAW;EACnC;EAYA,MAAM,MADsB,oBAVZ,uBACd,OACA,WAAW,MACX,UACA,aAAa,WAAW,MAAM,GAC9B,YACA,aACA,gBAAgB,OAAO,GACvB,WAE8C,GAAS,YAAY,WAAW,GAC3D,WAAW;CAClC,SAAS,KAAK;EAEZ,MADsB,4BAA4B,WAAW,GAAG,GAAG,WAC7D,GAAe,WAAW;CAClC;AACF;;AAKA,SAAS,gBAAgB,SAA8C;CACrE,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,IAAI,OAAO,YAAY,UAAU,OAAO;CACxC,KAAK,MAAM,OAAO,SAAS,OAAO;AAEpC;;;AAIA,SAAS,uBAAuB,YAAqB,SAAkB,aAA2B;CAChG,MAAM,iBAAiB,WAAW,QAAQ;CAC1C,IAAI,mBAAmB,KAAA,GAAW;EAChC,IAAI,OAAO,cAAc,IAAI,aAAa,MAAM,uBAAuB;EACvE;CACF;CAEA,IAAI,OAAO,YAAY,YAAY,YAAY,MAAM;CACrD,MAAM,YAAa,WAAkC;CAErD,KADa,YAAY,UAAU,aAAa,OAAO,WAAW,KAAK,UAAU,OAAO,GAAG,MAAM,KACtF,aAAa,MAAM,uBAAuB;AACvD;AAEA,SAAS,MAAM,UAAwB,MAAsB;CAC3D,KAAK,OAAO,SAAS,UAAU;CAC/B,MAAM,aAAa,KAAK,UAAU,SAAS,IAAI;CAC/C,KAAK,IAAI,gBAAgB,SAAS,WAAW;CAE7C,KAAK,IAAI,kBAAkB,GAAG,OAAO,WAAW,YAAY,MAAM,GAAG;CACrE,KAAK,IAAI,YAAY,MAAM;AAC7B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mionjs/platform-gcloud",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Google Cloud functions wrapper for mion router.",
|
|
6
6
|
"keywords": [
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
23
23
|
"types": "./.dist/esm/index.d.ts",
|
|
24
|
-
"require": "./.dist/cjs/index.cjs",
|
|
25
24
|
"default": "./.dist/esm/index.js"
|
|
26
25
|
}
|
|
27
26
|
},
|
|
@@ -45,17 +44,19 @@
|
|
|
45
44
|
},
|
|
46
45
|
"dependencies": {
|
|
47
46
|
"@google-cloud/functions-framework": "3.5.1",
|
|
48
|
-
"@mionjs/core": "0.
|
|
49
|
-
"@mionjs/router": "0.
|
|
47
|
+
"@mionjs/core": "0.14.0",
|
|
48
|
+
"@mionjs/router": "0.14.0"
|
|
50
49
|
},
|
|
51
50
|
"gitHead": "afd6e1d61525b4bf11bb84b3f85089038d70062d",
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=24"
|
|
53
|
+
},
|
|
52
54
|
"scripts": {
|
|
53
55
|
"typecheck:test": "tsc -p tsconfig.json --noEmit",
|
|
54
56
|
"test": "vitest run",
|
|
55
57
|
"dev": "vite build --watch",
|
|
56
58
|
"dev:test": "vitest watch",
|
|
57
59
|
"lint": "eslint src",
|
|
58
|
-
"format": "prettier --write src/**/*.ts",
|
|
59
60
|
"build": "vite build",
|
|
60
61
|
"clean": "rimraf .dist .coverage .mion",
|
|
61
62
|
"fresh-start": "pnpm run clean && rimraf node_modules"
|
package/.dist/cjs/index.cjs
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_src_constants = require("./src/constants.cjs");
|
|
3
|
-
const require_src_googleCF = require("./src/googleCF.cjs");
|
|
4
|
-
exports.DEFAULT_GOOGLE_CF_OPTIONS = require_src_constants.DEFAULT_GOOGLE_CF_OPTIONS;
|
|
5
|
-
exports.GOOGLE_CF_MAX_BODY_SIZE_CAP = require_src_constants.GOOGLE_CF_MAX_BODY_SIZE_CAP;
|
|
6
|
-
exports.createGoogleCFHandler = require_src_googleCF.createGoogleCFHandler;
|
|
7
|
-
exports.googleCFHandler = require_src_googleCF.googleCFHandler;
|
|
8
|
-
exports.resetGoogleCFOpts = require_src_googleCF.resetGoogleCFOpts;
|
|
9
|
-
exports.setGoogleCFOpts = require_src_googleCF.setGoogleCFOpts;
|
package/.dist/cjs/index.d.ts
DELETED
package/.dist/cjs/package.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"type":"commonjs"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
let _mionjs_core = require("@mionjs/core");
|
|
3
|
-
//#region src/constants.ts
|
|
4
|
-
/** Google's 10 MB ceiling on a 1st gen function, which no option can raise; override `maxBodySizeCap` on 2nd gen (32 MB). */
|
|
5
|
-
var GOOGLE_CF_MAX_BODY_SIZE_CAP = 1e7;
|
|
6
|
-
var DEFAULT_GOOGLE_CF_OPTIONS = {
|
|
7
|
-
maxBodySize: _mionjs_core.DEFAULT_MAX_BODY_SIZE,
|
|
8
|
-
maxBodySizeCap: GOOGLE_CF_MAX_BODY_SIZE_CAP
|
|
9
|
-
};
|
|
10
|
-
//#endregion
|
|
11
|
-
exports.DEFAULT_GOOGLE_CF_OPTIONS = DEFAULT_GOOGLE_CF_OPTIONS;
|
|
12
|
-
exports.GOOGLE_CF_MAX_BODY_SIZE_CAP = GOOGLE_CF_MAX_BODY_SIZE_CAP;
|
|
13
|
-
|
|
14
|
-
//# sourceMappingURL=constants.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.cjs","names":[],"sources":["../../../src/constants.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {DEFAULT_MAX_BODY_SIZE} from '@mionjs/core';\nimport {GoogleCFOptions} from './types.ts';\n\n/** Google's 10 MB ceiling on a 1st gen function, which no option can raise; override `maxBodySizeCap` on 2nd gen (32 MB). */\nexport const GOOGLE_CF_MAX_BODY_SIZE_CAP = 10_000_000;\n\nexport const DEFAULT_GOOGLE_CF_OPTIONS: GoogleCFOptions = {\n maxBodySize: DEFAULT_MAX_BODY_SIZE,\n maxBodySizeCap: GOOGLE_CF_MAX_BODY_SIZE_CAP,\n};\n"],"mappings":";;;;AAWA,IAAa,8BAA8B;AAE3C,IAAa,4BAA6C;CACxD,aAAa,aAAA;CACb,gBAAgB;AAClB"}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_src_constants = require("./constants.cjs");
|
|
3
|
-
const require_src_headers = require("./headers.cjs");
|
|
4
|
-
let _mionjs_core = require("@mionjs/core");
|
|
5
|
-
let _mionjs_router = require("@mionjs/router");
|
|
6
|
-
//#region src/googleCF.ts
|
|
7
|
-
var googleCFOptions = { ...require_src_constants.DEFAULT_GOOGLE_CF_OPTIONS };
|
|
8
|
-
function resetGoogleCFOpts() {
|
|
9
|
-
googleCFOptions = { ...require_src_constants.DEFAULT_GOOGLE_CF_OPTIONS };
|
|
10
|
-
(0, _mionjs_router.resetRouter)();
|
|
11
|
-
}
|
|
12
|
-
function setGoogleCFOpts(routerOptions) {
|
|
13
|
-
googleCFOptions = {
|
|
14
|
-
...googleCFOptions,
|
|
15
|
-
...routerOptions
|
|
16
|
-
};
|
|
17
|
-
(0, _mionjs_router.setPlatformConfig)({ ...googleCFOptions });
|
|
18
|
-
return googleCFOptions;
|
|
19
|
-
}
|
|
20
|
-
/** Creates a Google Cloud Functions handler with optional platform config */
|
|
21
|
-
function createGoogleCFHandler(options) {
|
|
22
|
-
setGoogleCFOpts(options);
|
|
23
|
-
return googleCFHandler;
|
|
24
|
-
}
|
|
25
|
-
async function googleCFHandler(rawRequest, rawResponse) {
|
|
26
|
-
const reqHeaders = require_src_headers.headersFromIncomingMessage(rawRequest);
|
|
27
|
-
const respHeaders = require_src_headers.headersFromServerResponse(rawResponse, (0, _mionjs_router.getResponseDefaults)());
|
|
28
|
-
let rawBody = rawRequest.body;
|
|
29
|
-
let reqBodyType = typeof rawBody === "string" ? _mionjs_core.SerializerModes.stringifyJson : _mionjs_core.SerializerModes.json;
|
|
30
|
-
const originalUrl = rawRequest.originalUrl;
|
|
31
|
-
const queryIndex = originalUrl ? originalUrl.indexOf("?") : -1;
|
|
32
|
-
const urlQuery = queryIndex === -1 ? void 0 : originalUrl.slice(queryIndex + 1);
|
|
33
|
-
try {
|
|
34
|
-
const chain = (0, _mionjs_router.resolveExecutionChain)(rawRequest.path, urlQuery, rawRequest);
|
|
35
|
-
try {
|
|
36
|
-
rejectOversizedRequest(rawRequest, rawBody, chain.maxBodySize);
|
|
37
|
-
} catch (refusal) {
|
|
38
|
-
return reply(await (0, _mionjs_router.dispatchPlatformError)(chain, rawRequest.path, urlQuery, (0, _mionjs_router.toRpcError)(refusal), reqHeaders, respHeaders, rawRequest, rawResponse), rawResponse);
|
|
39
|
-
}
|
|
40
|
-
const queryBody = (0, _mionjs_router.decodeQueryBody)(urlQuery, bodyOrUndefined(rawBody));
|
|
41
|
-
if (queryBody) {
|
|
42
|
-
rawBody = queryBody.rawBody;
|
|
43
|
-
reqBodyType = queryBody.bodyType;
|
|
44
|
-
}
|
|
45
|
-
reply(await (0, _mionjs_router.dispatchWithContext)((0, _mionjs_router.createContextFromChain)(chain, rawRequest.path, urlQuery, reqHeaders, respHeaders, rawBody, reqBodyType), rawRequest, rawResponse), rawResponse);
|
|
46
|
-
} catch (err) {
|
|
47
|
-
reply((0, _mionjs_router.getRouterFatalErrorResponse)((0, _mionjs_router.toRpcError)(err), respHeaders), rawResponse);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
/** express parses a body-less request into an EMPTY object, which is truthy, so `?data=` would never be read without this. */
|
|
51
|
-
function bodyOrUndefined(rawBody) {
|
|
52
|
-
if (!rawBody) return void 0;
|
|
53
|
-
if (typeof rawBody !== "object") return rawBody;
|
|
54
|
-
for (const key in rawBody) return rawBody;
|
|
55
|
-
}
|
|
56
|
-
/** express hands a JSON request over parsed and the router only measures strings, so the wire size is found here instead.
|
|
57
|
-
* `rawBody` is the exact bytes the Google functions framework keeps; a plain express host leaves only the parsed body. */
|
|
58
|
-
function rejectOversizedRequest(rawRequest, rawBody, maxBodySize) {
|
|
59
|
-
const declaredLength = rawRequest.headers["content-length"];
|
|
60
|
-
if (declaredLength !== void 0) {
|
|
61
|
-
if (Number(declaredLength) > maxBodySize) throw (0, _mionjs_router.requestPayloadTooLarge)();
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
if (typeof rawBody !== "object" || rawBody === null) return;
|
|
65
|
-
const wireBytes = rawRequest.rawBody;
|
|
66
|
-
if ((wireBytes ? wireBytes.byteLength : Buffer.byteLength(JSON.stringify(rawBody), "utf8")) > maxBodySize) throw (0, _mionjs_router.requestPayloadTooLarge)();
|
|
67
|
-
}
|
|
68
|
-
function reply(mionResp, resp) {
|
|
69
|
-
resp.status(mionResp.statusCode);
|
|
70
|
-
const jsonString = JSON.stringify(mionResp.body);
|
|
71
|
-
resp.set("content-type", mionResp.contentType);
|
|
72
|
-
resp.set("content-length", `${Buffer.byteLength(jsonString, "utf8")}`);
|
|
73
|
-
resp.end(jsonString, "utf8");
|
|
74
|
-
}
|
|
75
|
-
//#endregion
|
|
76
|
-
exports.createGoogleCFHandler = createGoogleCFHandler;
|
|
77
|
-
exports.googleCFHandler = googleCFHandler;
|
|
78
|
-
exports.resetGoogleCFOpts = resetGoogleCFOpts;
|
|
79
|
-
exports.setGoogleCFOpts = setGoogleCFOpts;
|
|
80
|
-
|
|
81
|
-
//# sourceMappingURL=googleCF.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"googleCF.cjs","names":[],"sources":["../../../src/googleCF.ts"],"sourcesContent":["/* ########\n * 2023 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {SerializerModes} from '@mionjs/core';\nimport type {SerializerCode} from '@mionjs/core';\nimport {\n dispatchWithContext,\n dispatchPlatformError,\n toRpcError,\n resolveExecutionChain,\n createContextFromChain,\n getRouterFatalErrorResponse,\n requestPayloadTooLarge,\n resetRouter,\n decodeQueryBody,\n setPlatformConfig,\n getResponseDefaults,\n} from '@mionjs/router';\nimport type {MionResponse} from '@mionjs/router';\nimport {Request, Response} from 'express';\nimport {DEFAULT_GOOGLE_CF_OPTIONS} from './constants.ts';\nimport {GoogleCFOptions} from './types.ts';\nimport {headersFromIncomingMessage, headersFromServerResponse} from './headers.ts';\n\n// ############# STATE #############\n\nlet googleCFOptions: Readonly<GoogleCFOptions> = {...DEFAULT_GOOGLE_CF_OPTIONS};\n\n// ############# PUBLIC METHODS #############\n\nexport function resetGoogleCFOpts() {\n googleCFOptions = {...DEFAULT_GOOGLE_CF_OPTIONS};\n resetRouter();\n}\n\nexport function setGoogleCFOpts(routerOptions?: Partial<GoogleCFOptions>) {\n googleCFOptions = {\n ...googleCFOptions,\n ...routerOptions,\n };\n setPlatformConfig({...googleCFOptions});\n return googleCFOptions;\n}\n\n/** Creates a Google Cloud Functions handler with optional platform config */\nexport function createGoogleCFHandler(options?: Partial<GoogleCFOptions>) {\n setGoogleCFOpts(options);\n return googleCFHandler;\n}\n\nexport async function googleCFHandler(rawRequest: Request, rawResponse: Response): Promise<void> {\n // express may hand the body over already parsed, so both a string and an object body are accepted\n\n // TODO use its own express headers wrapper instead headers from record\n const reqHeaders = headersFromIncomingMessage(rawRequest);\n const respHeaders = headersFromServerResponse(rawResponse, getResponseDefaults());\n let rawBody = rawRequest.body;\n let reqBodyType: SerializerCode = typeof rawBody === 'string' ? SerializerModes.stringifyJson : SerializerModes.json;\n // everything after the FIRST `?`: a second one is legal inside a query, so splitting on it would drop parameters\n const originalUrl = rawRequest.originalUrl;\n const queryIndex = originalUrl ? originalUrl.indexOf('?') : -1;\n const urlQuery = queryIndex === -1 ? undefined : originalUrl.slice(queryIndex + 1);\n\n try {\n // express already read the body, so the chain's limit is resolved first and the size check runs before the router sees it\n const chain = resolveExecutionChain(rawRequest.path, urlQuery, rawRequest);\n try {\n rejectOversizedRequest(rawRequest, rawBody, chain.maxBodySize);\n } catch (refusal) {\n // the route resolved, so the refusal still runs the chain's alwaysRun members\n const refused = await dispatchPlatformError(\n chain,\n rawRequest.path,\n urlQuery,\n toRpcError(refusal),\n reqHeaders,\n respHeaders,\n rawRequest,\n rawResponse\n );\n return reply(refused, rawResponse);\n }\n const queryBody = decodeQueryBody(urlQuery, bodyOrUndefined(rawBody));\n if (queryBody) {\n rawBody = queryBody.rawBody;\n reqBodyType = queryBody.bodyType;\n }\n const context = createContextFromChain(chain, rawRequest.path, urlQuery, reqHeaders, respHeaders, rawBody, reqBodyType);\n const routeResponse = await dispatchWithContext(context, rawRequest, rawResponse);\n reply(routeResponse, rawResponse);\n } catch (err) {\n const routeResponse = getRouterFatalErrorResponse(toRpcError(err), respHeaders);\n reply(routeResponse, rawResponse);\n }\n}\n\n// ############# PRIVATE METHODS #############\n\n/** express parses a body-less request into an EMPTY object, which is truthy, so `?data=` would never be read without this. */\nfunction bodyOrUndefined(rawBody: unknown): unknown {\n if (!rawBody) return undefined;\n if (typeof rawBody !== 'object') return rawBody;\n for (const key in rawBody) return rawBody;\n return undefined;\n}\n\n/** express hands a JSON request over parsed and the router only measures strings, so the wire size is found here instead.\n * `rawBody` is the exact bytes the Google functions framework keeps; a plain express host leaves only the parsed body. */\nfunction rejectOversizedRequest(rawRequest: Request, rawBody: unknown, maxBodySize: number): void {\n const declaredLength = rawRequest.headers['content-length'];\n if (declaredLength !== undefined) {\n if (Number(declaredLength) > maxBodySize) throw requestPayloadTooLarge();\n return;\n }\n // a string body is measured again by the router, so only a parsed one still needs a size here\n if (typeof rawBody !== 'object' || rawBody === null) return;\n const wireBytes = (rawRequest as {rawBody?: Buffer}).rawBody;\n const size = wireBytes ? wireBytes.byteLength : Buffer.byteLength(JSON.stringify(rawBody), 'utf8');\n if (size > maxBodySize) throw requestPayloadTooLarge();\n}\n\nfunction reply(mionResp: MionResponse, resp: Response): void {\n resp.status(mionResp.statusCode);\n const jsonString = JSON.stringify(mionResp.body);\n resp.set('content-type', mionResp.contentType);\n // byteLength measures without copying the response into a Buffer\n resp.set('content-length', `${Buffer.byteLength(jsonString, 'utf8')}`);\n resp.end(jsonString, 'utf8');\n}\n"],"mappings":";;;;;;AA8BA,IAAI,kBAA6C,EAAC,GAAG,sBAAA,0BAAyB;AAI9E,SAAgB,oBAAoB;CAClC,kBAAkB,EAAC,GAAG,sBAAA,0BAAyB;CAC/C,CAAA,GAAA,eAAA,aAAY;AACd;AAEA,SAAgB,gBAAgB,eAA0C;CACxE,kBAAkB;EAChB,GAAG;EACH,GAAG;CACL;CACA,CAAA,GAAA,eAAA,mBAAkB,EAAC,GAAG,gBAAe,CAAC;CACtC,OAAO;AACT;;AAGA,SAAgB,sBAAsB,SAAoC;CACxE,gBAAgB,OAAO;CACvB,OAAO;AACT;AAEA,eAAsB,gBAAgB,YAAqB,aAAsC;CAI/F,MAAM,aAAa,oBAAA,2BAA2B,UAAU;CACxD,MAAM,cAAc,oBAAA,0BAA0B,cAAA,GAAA,eAAA,qBAAiC,CAAC;CAChF,IAAI,UAAU,WAAW;CACzB,IAAI,cAA8B,OAAO,YAAY,WAAW,aAAA,gBAAgB,gBAAgB,aAAA,gBAAgB;CAEhH,MAAM,cAAc,WAAW;CAC/B,MAAM,aAAa,cAAc,YAAY,QAAQ,GAAG,IAAI;CAC5D,MAAM,WAAW,eAAe,KAAK,KAAA,IAAY,YAAY,MAAM,aAAa,CAAC;CAEjF,IAAI;EAEF,MAAM,SAAA,GAAA,eAAA,uBAA8B,WAAW,MAAM,UAAU,UAAU;EACzE,IAAI;GACF,uBAAuB,YAAY,SAAS,MAAM,WAAW;EAC/D,SAAS,SAAS;GAYhB,OAAO,MAAM,OAAA,GAAA,eAAA,uBATX,OACA,WAAW,MACX,WAAA,GAAA,eAAA,YACW,OAAO,GAClB,YACA,aACA,YACA,WACF,GACsB,WAAW;EACnC;EACA,MAAM,aAAA,GAAA,eAAA,iBAA4B,UAAU,gBAAgB,OAAO,CAAC;EACpE,IAAI,WAAW;GACb,UAAU,UAAU;GACpB,cAAc,UAAU;EAC1B;EAGA,MAAM,OAAA,GAAA,eAAA,sBAAA,GAAA,eAAA,wBAFiC,OAAO,WAAW,MAAM,UAAU,YAAY,aAAa,SAAS,WAC3D,GAAS,YAAY,WAAW,GAC3D,WAAW;CAClC,SAAS,KAAK;EAEZ,OAAA,GAAA,eAAA,8BAAA,GAAA,eAAA,YAD6D,GAAG,GAAG,WAC7D,GAAe,WAAW;CAClC;AACF;;AAKA,SAAS,gBAAgB,SAA2B;CAClD,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,IAAI,OAAO,YAAY,UAAU,OAAO;CACxC,KAAK,MAAM,OAAO,SAAS,OAAO;AAEpC;;;AAIA,SAAS,uBAAuB,YAAqB,SAAkB,aAA2B;CAChG,MAAM,iBAAiB,WAAW,QAAQ;CAC1C,IAAI,mBAAmB,KAAA,GAAW;EAChC,IAAI,OAAO,cAAc,IAAI,aAAa,OAAA,GAAA,eAAA,wBAA6B;EACvE;CACF;CAEA,IAAI,OAAO,YAAY,YAAY,YAAY,MAAM;CACrD,MAAM,YAAa,WAAkC;CAErD,KADa,YAAY,UAAU,aAAa,OAAO,WAAW,KAAK,UAAU,OAAO,GAAG,MAAM,KACtF,aAAa,OAAA,GAAA,eAAA,wBAA6B;AACvD;AAEA,SAAS,MAAM,UAAwB,MAAsB;CAC3D,KAAK,OAAO,SAAS,UAAU;CAC/B,MAAM,aAAa,KAAK,UAAU,SAAS,IAAI;CAC/C,KAAK,IAAI,gBAAgB,SAAS,WAAW;CAE7C,KAAK,IAAI,kBAAkB,GAAG,OAAO,WAAW,YAAY,MAAM,GAAG;CACrE,KAAK,IAAI,YAAY,MAAM;AAC7B"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { Request, Response } from 'express';
|
|
2
|
-
import { GoogleCFOptions } from './types.ts';
|
|
3
|
-
export declare function resetGoogleCFOpts(): void;
|
|
4
|
-
export declare function setGoogleCFOpts(routerOptions?: Partial<GoogleCFOptions>): Readonly<GoogleCFOptions>;
|
|
5
|
-
export declare function createGoogleCFHandler(options?: Partial<GoogleCFOptions>): typeof googleCFHandler;
|
|
6
|
-
export declare function googleCFHandler(rawRequest: Request, rawResponse: Response): Promise<void>;
|
|
7
|
-
//# sourceMappingURL=googleCF.d.ts.map
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
let _mionjs_router = require("@mionjs/router");
|
|
3
|
-
//#region src/headers.ts
|
|
4
|
-
function headersFromIncomingMessage(rawRequest) {
|
|
5
|
-
return (0, _mionjs_router.headersFromRecord)(rawRequest.headers, true);
|
|
6
|
-
}
|
|
7
|
-
var ServerResponseHeadersImpl = class {
|
|
8
|
-
resp;
|
|
9
|
-
constructor(resp) {
|
|
10
|
-
this.resp = resp;
|
|
11
|
-
}
|
|
12
|
-
append(name, value) {
|
|
13
|
-
this.resp.appendHeader(name, value);
|
|
14
|
-
}
|
|
15
|
-
delete(name) {
|
|
16
|
-
this.resp.removeHeader(name);
|
|
17
|
-
}
|
|
18
|
-
get(name) {
|
|
19
|
-
const value = this.resp.getHeader(name);
|
|
20
|
-
if (Array.isArray(value)) return value.join(", ");
|
|
21
|
-
return value;
|
|
22
|
-
}
|
|
23
|
-
has(name) {
|
|
24
|
-
return this.resp.hasHeader(name);
|
|
25
|
-
}
|
|
26
|
-
set(name, value) {
|
|
27
|
-
this.resp.setHeader(name, value);
|
|
28
|
-
}
|
|
29
|
-
entries() {
|
|
30
|
-
return new Map(singleHeaderEntries(this.resp)).entries();
|
|
31
|
-
}
|
|
32
|
-
keys() {
|
|
33
|
-
return new Map(singleHeaderEntries(this.resp)).keys();
|
|
34
|
-
}
|
|
35
|
-
values() {
|
|
36
|
-
return new Map(singleHeaderEntries(this.resp)).values();
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
function headersFromServerResponse(resp, initialHeaders) {
|
|
40
|
-
if (initialHeaders) {
|
|
41
|
-
for (const name in initialHeaders) if (name !== "content-type") resp.setHeader(name, initialHeaders[name]);
|
|
42
|
-
}
|
|
43
|
-
return new ServerResponseHeadersImpl(resp);
|
|
44
|
-
}
|
|
45
|
-
function singleHeaderEntries(resp) {
|
|
46
|
-
return Object.entries(resp.getHeaders()).filter(([, value]) => value !== void 0).map(([name, value]) => [name, Array.isArray(value) ? value.join(", ") : String(value)]);
|
|
47
|
-
}
|
|
48
|
-
//#endregion
|
|
49
|
-
exports.headersFromIncomingMessage = headersFromIncomingMessage;
|
|
50
|
-
exports.headersFromServerResponse = headersFromServerResponse;
|
|
51
|
-
|
|
52
|
-
//# sourceMappingURL=headers.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"headers.cjs","names":[],"sources":["../../../src/headers.ts"],"sourcesContent":["/* ########\n * 2022 mion\n * Author: Ma-jerez\n * License: MIT\n * The software is provided \"as is\", without warranty of any kind.\n * ######## */\n\nimport {MionHeaders, headersFromRecord} from '@mionjs/router';\nimport {IncomingMessage, ServerResponse} from 'http';\n\nexport function headersFromIncomingMessage(rawRequest: IncomingMessage): MionHeaders {\n // node already lower-cased these and express passes its object straight through; NOT safe on API Gateway, which keeps case\n return headersFromRecord(rawRequest.headers as Record<string, string>, true);\n}\n\nclass ServerResponseHeadersImpl implements MionHeaders {\n constructor(private resp: ServerResponse) {}\n\n append(name: string, value: string): void {\n this.resp.appendHeader(name, value);\n }\n\n delete(name: string): void {\n this.resp.removeHeader(name);\n }\n\n get(name: string): string | undefined | null {\n const value = this.resp.getHeader(name);\n if (Array.isArray(value)) return value.join(', ');\n return value as string;\n }\n\n has(name: string): boolean {\n return this.resp.hasHeader(name);\n }\n\n set(name: string, value: string): void {\n this.resp.setHeader(name, value);\n }\n\n entries(): IterableIterator<[string, string]> {\n return new Map(singleHeaderEntries(this.resp)).entries();\n }\n\n keys(): IterableIterator<string> {\n return new Map(singleHeaderEntries(this.resp)).keys();\n }\n\n values(): IterableIterator<string> {\n return new Map(singleHeaderEntries(this.resp)).values();\n }\n}\n\nexport function headersFromServerResponse(resp: ServerResponse, initialHeaders: Record<string, string> | null): MionHeaders {\n // for...in allocates no entries array and no closure\n // content-type is the reply's: a raw middleware that ends the response itself must not send the JSON one\n if (initialHeaders) for (const name in initialHeaders) if (name !== 'content-type') resp.setHeader(name, initialHeaders[name]);\n return new ServerResponseHeadersImpl(resp);\n}\n\nfunction singleHeaderEntries(resp: ServerResponse): [string, string][] {\n return Object.entries(resp.getHeaders())\n .filter(([, value]) => value !== undefined)\n .map(([name, value]) => [name, Array.isArray(value) ? value.join(', ') : String(value)]);\n}\n"],"mappings":";;;AAUA,SAAgB,2BAA2B,YAA0C;CAEnF,QAAA,GAAA,eAAA,mBAAyB,WAAW,SAAmC,IAAI;AAC7E;AAEA,IAAM,4BAAN,MAAuD;CACjC;CAApB,YAAY,MAA8B;EAAtB,KAAA,OAAA;CAAuB;CAE3C,OAAO,MAAc,OAAqB;EACxC,KAAK,KAAK,aAAa,MAAM,KAAK;CACpC;CAEA,OAAO,MAAoB;EACzB,KAAK,KAAK,aAAa,IAAI;CAC7B;CAEA,IAAI,MAAyC;EAC3C,MAAM,QAAQ,KAAK,KAAK,UAAU,IAAI;EACtC,IAAI,MAAM,QAAQ,KAAK,GAAG,OAAO,MAAM,KAAK,IAAI;EAChD,OAAO;CACT;CAEA,IAAI,MAAuB;EACzB,OAAO,KAAK,KAAK,UAAU,IAAI;CACjC;CAEA,IAAI,MAAc,OAAqB;EACrC,KAAK,KAAK,UAAU,MAAM,KAAK;CACjC;CAEA,UAA8C;EAC5C,OAAO,IAAI,IAAI,oBAAoB,KAAK,IAAI,CAAC,EAAE,QAAQ;CACzD;CAEA,OAAiC;EAC/B,OAAO,IAAI,IAAI,oBAAoB,KAAK,IAAI,CAAC,EAAE,KAAK;CACtD;CAEA,SAAmC;EACjC,OAAO,IAAI,IAAI,oBAAoB,KAAK,IAAI,CAAC,EAAE,OAAO;CACxD;AACF;AAEA,SAAgB,0BAA0B,MAAsB,gBAA4D;CAG1H,IAAI;OAAqB,MAAM,QAAQ,gBAAgB,IAAI,SAAS,gBAAgB,KAAK,UAAU,MAAM,eAAe,KAAK;CAAA;CAC7H,OAAO,IAAI,0BAA0B,IAAI;AAC3C;AAEA,SAAS,oBAAoB,MAA0C;CACrE,OAAO,OAAO,QAAQ,KAAK,WAAW,CAAC,EACpC,QAAQ,GAAG,WAAW,UAAU,KAAA,CAAS,EACzC,KAAK,CAAC,MAAM,WAAW,CAAC,MAAM,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,KAAK,CAAC,CAAC;AAC3F"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { MionHeaders } from '@mionjs/router';
|
|
2
|
-
import { IncomingMessage, ServerResponse } from 'http';
|
|
3
|
-
export declare function headersFromIncomingMessage(rawRequest: IncomingMessage): MionHeaders;
|
|
4
|
-
export declare function headersFromServerResponse(resp: ServerResponse, initialHeaders: Record<string, string> | null): MionHeaders;
|
|
5
|
-
//# sourceMappingURL=headers.d.ts.map
|
package/.dist/cjs/src/types.cjs
DELETED
|
File without changes
|