@mionjs/platform-gcloud 0.8.0-alpha.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/cjs/index.cjs +9 -0
- package/.dist/cjs/index.cjs.map +1 -0
- package/.dist/cjs/index.d.ts +3 -0
- package/.dist/cjs/package.json +1 -0
- package/.dist/cjs/src/constants.cjs +7 -0
- package/.dist/cjs/src/constants.cjs.map +1 -0
- package/.dist/cjs/src/constants.d.ts +2 -0
- package/.dist/cjs/src/googleCF.cjs +100 -0
- package/.dist/cjs/src/googleCF.cjs.map +1 -0
- package/.dist/cjs/src/googleCF.d.ts +5 -0
- package/.dist/cjs/src/headers.cjs +51 -0
- package/.dist/cjs/src/headers.cjs.map +1 -0
- package/.dist/cjs/src/headers.d.ts +4 -0
- package/.dist/cjs/src/types.cjs +2 -0
- package/.dist/cjs/src/types.cjs.map +1 -0
- package/.dist/cjs/src/types.d.ts +4 -0
- package/.dist/esm/index.d.ts +3 -0
- package/.dist/esm/index.js +9 -0
- package/.dist/esm/index.js.map +1 -0
- package/.dist/esm/src/constants.d.ts +2 -0
- package/.dist/esm/src/constants.js +7 -0
- package/.dist/esm/src/constants.js.map +1 -0
- package/.dist/esm/src/googleCF.d.ts +5 -0
- package/.dist/esm/src/googleCF.js +100 -0
- package/.dist/esm/src/googleCF.js.map +1 -0
- package/.dist/esm/src/headers.d.ts +4 -0
- package/.dist/esm/src/headers.js +51 -0
- package/.dist/esm/src/headers.js.map +1 -0
- package/.dist/esm/src/types.d.ts +4 -0
- package/.dist/esm/src/types.js +2 -0
- package/.dist/esm/src/types.js.map +1 -0
- package/LICENSE +21 -0
- package/README.md +29 -0
- package/package.json +64 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const src_googleCF = require("./src/googleCF.cjs");
|
|
4
|
+
const src_constants = require("./src/constants.cjs");
|
|
5
|
+
exports.googleCFHandler = src_googleCF.googleCFHandler;
|
|
6
|
+
exports.resetGoogleCFOpts = src_googleCF.resetGoogleCFOpts;
|
|
7
|
+
exports.setGoogleCFOpts = src_googleCF.setGoogleCFOpts;
|
|
8
|
+
exports.DEFAULT_GOOGLE_CF_OPTIONS = src_constants.DEFAULT_GOOGLE_CF_OPTIONS;
|
|
9
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"commonjs"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.cjs","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 {GoogleCFOptions} from './types.ts';\n\nexport const DEFAULT_GOOGLE_CF_OPTIONS: GoogleCFOptions = {\n defaultResponseHeaders: {},\n};\n"],"names":[],"mappings":";;AASO,MAAM,4BAA6C;AAAA,EACtD,wBAAwB,CAAA;AAC5B;;"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const core = require("@mionjs/core");
|
|
4
|
+
const router = require("@mionjs/router");
|
|
5
|
+
const src_constants = require("./constants.cjs");
|
|
6
|
+
const src_headers = require("./headers.cjs");
|
|
7
|
+
let googleCFOptions = { ...src_constants.DEFAULT_GOOGLE_CF_OPTIONS };
|
|
8
|
+
function resetGoogleCFOpts() {
|
|
9
|
+
googleCFOptions = { ...src_constants.DEFAULT_GOOGLE_CF_OPTIONS };
|
|
10
|
+
router.resetRouter();
|
|
11
|
+
}
|
|
12
|
+
function setGoogleCFOpts(routerOptions) {
|
|
13
|
+
googleCFOptions = {
|
|
14
|
+
...googleCFOptions,
|
|
15
|
+
...routerOptions
|
|
16
|
+
};
|
|
17
|
+
return googleCFOptions;
|
|
18
|
+
}
|
|
19
|
+
async function googleCFHandler(rawRequest, rawResponse) {
|
|
20
|
+
rawResponse.setHeader("server", "@mionjs");
|
|
21
|
+
const reqHeaders = src_headers.headersFromIncomingMessage(rawRequest);
|
|
22
|
+
const respHeaders = src_headers.headersFromServerResponse(rawResponse, googleCFOptions.defaultResponseHeaders);
|
|
23
|
+
const contentType = rawRequest.headers["content-type"] || "";
|
|
24
|
+
const isBinary = contentType.startsWith("application/octet-stream");
|
|
25
|
+
let rawBody = isBinary ? rawRequest.rawBody : rawRequest.body;
|
|
26
|
+
let reqBodyType = isBinary ? core.SerializerModes.binary : typeof rawBody === "string" ? core.SerializerModes.stringifyJson : core.SerializerModes.json;
|
|
27
|
+
const urlQuery = rawRequest.originalUrl?.includes("?") ? rawRequest.originalUrl.split("?")[1] : void 0;
|
|
28
|
+
const queryBody = router.decodeQueryBody(urlQuery, rawBody);
|
|
29
|
+
if (queryBody) {
|
|
30
|
+
rawBody = queryBody.rawBody;
|
|
31
|
+
reqBodyType = queryBody.bodyType;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const routeResponse = await router.dispatchRoute(
|
|
35
|
+
rawRequest.path,
|
|
36
|
+
rawBody,
|
|
37
|
+
reqHeaders,
|
|
38
|
+
respHeaders,
|
|
39
|
+
rawRequest,
|
|
40
|
+
rawResponse,
|
|
41
|
+
reqBodyType,
|
|
42
|
+
urlQuery
|
|
43
|
+
);
|
|
44
|
+
reply(routeResponse, rawResponse);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
const error = err instanceof core.RpcError ? err : new core.RpcError({
|
|
47
|
+
publicMessage: "Internal Error",
|
|
48
|
+
originalError: err,
|
|
49
|
+
type: "unknown-error"
|
|
50
|
+
});
|
|
51
|
+
const routeResponse = router.getRouterFatalErrorResponse(error, respHeaders);
|
|
52
|
+
reply(routeResponse, rawResponse);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function reply(mionResp, resp) {
|
|
56
|
+
resp.status(mionResp.statusCode);
|
|
57
|
+
const bodyType = mionResp.serializer;
|
|
58
|
+
switch (bodyType) {
|
|
59
|
+
case core.SerializerModes.stringifyJson: {
|
|
60
|
+
const buffer = Buffer.from(mionResp.rawBody, "utf8");
|
|
61
|
+
resp.set("content-length", `${buffer.byteLength}`);
|
|
62
|
+
resp.end(buffer);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
case core.SerializerModes.json: {
|
|
66
|
+
const jsonString = JSON.stringify(mionResp.body);
|
|
67
|
+
const buffer = Buffer.from(jsonString, "utf8");
|
|
68
|
+
resp.set("content-type", "application/json; charset=utf-8");
|
|
69
|
+
resp.set("content-length", `${buffer.byteLength}`);
|
|
70
|
+
resp.end(buffer);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
case core.SerializerModes.binary: {
|
|
74
|
+
const serializer = mionResp.binSerializer;
|
|
75
|
+
resp.set("content-length", `${serializer.getLength()}`);
|
|
76
|
+
resp.end(Buffer.from(serializer.getBufferView()));
|
|
77
|
+
const onFinish = () => serializer.markAsEnded();
|
|
78
|
+
resp.on("finish", onFinish);
|
|
79
|
+
resp.on("close", onFinish);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
default: {
|
|
83
|
+
const error = new core.RpcError({
|
|
84
|
+
publicMessage: "unknown-mion-response-format",
|
|
85
|
+
type: "unknown-error",
|
|
86
|
+
errorData: { bodyType }
|
|
87
|
+
});
|
|
88
|
+
unexpectedFail(resp, mionResp.headers, error);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function unexpectedFail(resp, respHeaders, error) {
|
|
93
|
+
if (resp.writableEnded) return;
|
|
94
|
+
const routeResponse = router.getRouterFatalErrorResponse(error, respHeaders);
|
|
95
|
+
reply(routeResponse, resp);
|
|
96
|
+
}
|
|
97
|
+
exports.googleCFHandler = googleCFHandler;
|
|
98
|
+
exports.resetGoogleCFOpts = resetGoogleCFOpts;
|
|
99
|
+
exports.setGoogleCFOpts = setGoogleCFOpts;
|
|
100
|
+
//# sourceMappingURL=googleCF.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"googleCF.cjs","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 {RpcError, SerializerModes} from '@mionjs/core';\nimport type {SerializerCode} from '@mionjs/core';\nimport {dispatchRoute, getRouterFatalErrorResponse, resetRouter, decodeQueryBody} from '@mionjs/router';\nimport type {MionHeaders, 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 return googleCFOptions;\n}\n\nexport async function googleCFHandler(rawRequest: Request, rawResponse: Response): Promise<void> {\n // Express in Google Cloud Functions might parse the body automatically when Content-Type is application/json\n // We handle both cases: string body and already-parsed object body\n // For binary requests, we need to handle the raw buffer\n\n // TODO use its own express headers wrapper instead headers from record\n rawResponse.setHeader('server', '@mionjs');\n const reqHeaders = headersFromIncomingMessage(rawRequest);\n const respHeaders = headersFromServerResponse(rawResponse, googleCFOptions.defaultResponseHeaders);\n const contentType = rawRequest.headers['content-type'] || '';\n const isBinary = contentType.startsWith('application/octet-stream');\n let rawBody = isBinary ? (rawRequest as any).rawBody : rawRequest.body;\n let reqBodyType: SerializerCode = isBinary\n ? SerializerModes.binary\n : typeof rawBody === 'string'\n ? SerializerModes.stringifyJson\n : SerializerModes.json;\n // Extract query string from Express request\n const urlQuery = rawRequest.originalUrl?.includes('?') ? rawRequest.originalUrl.split('?')[1] : undefined;\n const queryBody = decodeQueryBody(urlQuery, rawBody);\n if (queryBody) {\n rawBody = queryBody.rawBody;\n reqBodyType = queryBody.bodyType;\n }\n\n try {\n const routeResponse = await dispatchRoute(\n rawRequest.path,\n rawBody,\n reqHeaders,\n respHeaders,\n rawRequest,\n rawResponse,\n reqBodyType,\n urlQuery\n );\n reply(routeResponse, rawResponse);\n } catch (err) {\n const error =\n err instanceof RpcError\n ? err\n : new RpcError({\n publicMessage: 'Internal Error',\n originalError: err as Error,\n type: 'unknown-error',\n });\n const routeResponse = getRouterFatalErrorResponse(error, respHeaders);\n reply(routeResponse, rawResponse);\n }\n}\n\n// ############# PRIVATE METHODS #############\n\nfunction reply(mionResp: MionResponse, resp: Response): void {\n resp.status(mionResp.statusCode);\n const bodyType = mionResp.serializer;\n switch (bodyType) {\n case SerializerModes.stringifyJson: {\n const buffer = Buffer.from(mionResp.rawBody as string, 'utf8');\n resp.set('content-length', `${buffer.byteLength}`);\n // content-type already set by serializer\n resp.end(buffer);\n break;\n }\n case SerializerModes.json: {\n // Platform adapter stringifies the prepared body object\n const jsonString = JSON.stringify(mionResp.body);\n const buffer = Buffer.from(jsonString, 'utf8');\n resp.set('content-type', 'application/json; charset=utf-8');\n resp.set('content-length', `${buffer.byteLength}`);\n resp.end(buffer);\n break;\n }\n case SerializerModes.binary: {\n const serializer = mionResp.binSerializer!;\n resp.set('content-length', `${serializer.getLength()}`);\n // content-type already set by serializer\n resp.end(Buffer.from(serializer.getBufferView()));\n\n // Release buffer when response is finished\n const onFinish = () => serializer.markAsEnded();\n resp.on('finish', onFinish);\n resp.on('close', onFinish); // Fallback for aborted connection\n break;\n }\n default: {\n const error = new RpcError({\n publicMessage: 'unknown-mion-response-format',\n type: 'unknown-error',\n errorData: {bodyType},\n });\n unexpectedFail(resp, mionResp.headers, error);\n }\n }\n}\n\nfunction unexpectedFail(resp: Response, respHeaders: MionHeaders, error: RpcError<string>) {\n if (resp.writableEnded) return;\n const routeResponse = getRouterFatalErrorResponse(error, respHeaders);\n reply(routeResponse, resp);\n}\n"],"names":["DEFAULT_GOOGLE_CF_OPTIONS","resetRouter","headersFromIncomingMessage","headersFromServerResponse","SerializerModes","decodeQueryBody","dispatchRoute","RpcError","getRouterFatalErrorResponse"],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
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 googleCFHandler(rawRequest: Request, rawResponse: Response): Promise<void>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const router = require("@mionjs/router");
|
|
4
|
+
function headersFromIncomingMessage(rawRequest) {
|
|
5
|
+
return router.headersFromRecord(rawRequest.headers);
|
|
6
|
+
}
|
|
7
|
+
class ServerResponseHeadersImpl {
|
|
8
|
+
constructor(resp) {
|
|
9
|
+
this.resp = resp;
|
|
10
|
+
}
|
|
11
|
+
append(name, value) {
|
|
12
|
+
this.resp.appendHeader(name, value);
|
|
13
|
+
}
|
|
14
|
+
delete(name) {
|
|
15
|
+
this.resp.removeHeader(name);
|
|
16
|
+
}
|
|
17
|
+
get(name) {
|
|
18
|
+
const value = this.resp.getHeader(name);
|
|
19
|
+
if (Array.isArray(value)) return value.join(", ");
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
has(name) {
|
|
23
|
+
return this.resp.hasHeader(name);
|
|
24
|
+
}
|
|
25
|
+
set(name, value) {
|
|
26
|
+
this.resp.setHeader(name, value);
|
|
27
|
+
}
|
|
28
|
+
entries() {
|
|
29
|
+
return getSingleHeadersObj(this.resp).entries();
|
|
30
|
+
}
|
|
31
|
+
keys() {
|
|
32
|
+
return new Set(this.resp.getHeaderNames()).values();
|
|
33
|
+
}
|
|
34
|
+
values() {
|
|
35
|
+
return getSingleHeadersObj(this.resp).values();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function headersFromServerResponse(resp, initialHeaders) {
|
|
39
|
+
if (initialHeaders) Object.entries(initialHeaders).forEach(([name, value]) => resp.setHeader(name, value));
|
|
40
|
+
return new ServerResponseHeadersImpl(resp);
|
|
41
|
+
}
|
|
42
|
+
function getSingleHeadersObj(resp) {
|
|
43
|
+
const entries = Object.entries(resp.getHeaders()).map(([name, value]) => [
|
|
44
|
+
name,
|
|
45
|
+
Array.isArray(value) ? value.join(", ") : value
|
|
46
|
+
]);
|
|
47
|
+
return Object.fromEntries(entries);
|
|
48
|
+
}
|
|
49
|
+
exports.headersFromIncomingMessage = headersFromIncomingMessage;
|
|
50
|
+
exports.headersFromServerResponse = headersFromServerResponse;
|
|
51
|
+
//# sourceMappingURL=headers.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headers.cjs","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 return headersFromRecord(rawRequest.headers as Record<string, string>);\n}\n\n/**\n * Reusable class for managing HTTP response headers with ServerResponse integration\n * Provides a MionHeaders interface that wraps Node.js ServerResponse header methods\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 getSingleHeadersObj(this.resp).entries();\n }\n\n keys(): IterableIterator<string> {\n return new Set(this.resp.getHeaderNames()).values();\n }\n\n values(): IterableIterator<string> {\n return getSingleHeadersObj(this.resp).values();\n }\n}\n\nexport function headersFromServerResponse(resp: ServerResponse, initialHeaders: Record<string, string> | null): MionHeaders {\n if (initialHeaders) Object.entries(initialHeaders).forEach(([name, value]) => resp.setHeader(name, value));\n return new ServerResponseHeadersImpl(resp);\n}\n\nfunction getSingleHeadersObj(resp: ServerResponse) {\n const entries = Object.entries(resp.getHeaders()).map(([name, value]) => [\n name,\n Array.isArray(value) ? value.join(', ') : (value as string),\n ]);\n return Object.fromEntries(entries);\n}\n"],"names":["headersFromRecord"],"mappings":";;;AAUO,SAAS,2BAA2B,YAA0C;AACjF,SAAOA,OAAAA,kBAAkB,WAAW,OAAiC;AACzE;AAMA,MAAM,0BAAiD;AAAA,EACnD,YAAoB,MAAsB;AAAtB,SAAA,OAAA;AAAA,EAAuB;AAAA,EAE3C,OAAO,MAAc,OAAqB;AACtC,SAAK,KAAK,aAAa,MAAM,KAAK;AAAA,EACtC;AAAA,EAEA,OAAO,MAAoB;AACvB,SAAK,KAAK,aAAa,IAAI;AAAA,EAC/B;AAAA,EAEA,IAAI,MAAyC;AACzC,UAAM,QAAQ,KAAK,KAAK,UAAU,IAAI;AACtC,QAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,KAAK,IAAI;AAChD,WAAO;AAAA,EACX;AAAA,EAEA,IAAI,MAAuB;AACvB,WAAO,KAAK,KAAK,UAAU,IAAI;AAAA,EACnC;AAAA,EAEA,IAAI,MAAc,OAAqB;AACnC,SAAK,KAAK,UAAU,MAAM,KAAK;AAAA,EACnC;AAAA,EAEA,UAA8C;AAC1C,WAAO,oBAAoB,KAAK,IAAI,EAAE,QAAA;AAAA,EAC1C;AAAA,EAEA,OAAiC;AAC7B,WAAO,IAAI,IAAI,KAAK,KAAK,eAAA,CAAgB,EAAE,OAAA;AAAA,EAC/C;AAAA,EAEA,SAAmC;AAC/B,WAAO,oBAAoB,KAAK,IAAI,EAAE,OAAA;AAAA,EAC1C;AACJ;AAEO,SAAS,0BAA0B,MAAsB,gBAA4D;AACxH,MAAI,eAAgB,QAAO,QAAQ,cAAc,EAAE,QAAQ,CAAC,CAAC,MAAM,KAAK,MAAM,KAAK,UAAU,MAAM,KAAK,CAAC;AACzG,SAAO,IAAI,0BAA0B,IAAI;AAC7C;AAEA,SAAS,oBAAoB,MAAsB;AAC/C,QAAM,UAAU,OAAO,QAAQ,KAAK,YAAY,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;AAAA,IACrE;AAAA,IACA,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,IAAK;AAAA,EAAA,CAC9C;AACD,SAAO,OAAO,YAAY,OAAO;AACrC;;;"}
|
|
@@ -0,0 +1,4 @@
|
|
|
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;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { googleCFHandler, resetGoogleCFOpts, setGoogleCFOpts } from "./src/googleCF.js";
|
|
2
|
+
import { DEFAULT_GOOGLE_CF_OPTIONS } from "./src/constants.js";
|
|
3
|
+
export {
|
|
4
|
+
DEFAULT_GOOGLE_CF_OPTIONS,
|
|
5
|
+
googleCFHandler,
|
|
6
|
+
resetGoogleCFOpts,
|
|
7
|
+
setGoogleCFOpts
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","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 {GoogleCFOptions} from './types.ts';\n\nexport const DEFAULT_GOOGLE_CF_OPTIONS: GoogleCFOptions = {\n defaultResponseHeaders: {},\n};\n"],"names":[],"mappings":"AASO,MAAM,4BAA6C;AAAA,EACtD,wBAAwB,CAAA;AAC5B;"}
|
|
@@ -0,0 +1,5 @@
|
|
|
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 googleCFHandler(rawRequest: Request, rawResponse: Response): Promise<void>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { SerializerModes, RpcError } from "@mionjs/core";
|
|
2
|
+
import { decodeQueryBody, dispatchRoute, getRouterFatalErrorResponse, resetRouter } from "@mionjs/router";
|
|
3
|
+
import { DEFAULT_GOOGLE_CF_OPTIONS } from "./constants.js";
|
|
4
|
+
import { headersFromIncomingMessage, headersFromServerResponse } from "./headers.js";
|
|
5
|
+
let googleCFOptions = { ...DEFAULT_GOOGLE_CF_OPTIONS };
|
|
6
|
+
function resetGoogleCFOpts() {
|
|
7
|
+
googleCFOptions = { ...DEFAULT_GOOGLE_CF_OPTIONS };
|
|
8
|
+
resetRouter();
|
|
9
|
+
}
|
|
10
|
+
function setGoogleCFOpts(routerOptions) {
|
|
11
|
+
googleCFOptions = {
|
|
12
|
+
...googleCFOptions,
|
|
13
|
+
...routerOptions
|
|
14
|
+
};
|
|
15
|
+
return googleCFOptions;
|
|
16
|
+
}
|
|
17
|
+
async function googleCFHandler(rawRequest, rawResponse) {
|
|
18
|
+
rawResponse.setHeader("server", "@mionjs");
|
|
19
|
+
const reqHeaders = headersFromIncomingMessage(rawRequest);
|
|
20
|
+
const respHeaders = headersFromServerResponse(rawResponse, googleCFOptions.defaultResponseHeaders);
|
|
21
|
+
const contentType = rawRequest.headers["content-type"] || "";
|
|
22
|
+
const isBinary = contentType.startsWith("application/octet-stream");
|
|
23
|
+
let rawBody = isBinary ? rawRequest.rawBody : rawRequest.body;
|
|
24
|
+
let reqBodyType = isBinary ? SerializerModes.binary : typeof rawBody === "string" ? SerializerModes.stringifyJson : SerializerModes.json;
|
|
25
|
+
const urlQuery = rawRequest.originalUrl?.includes("?") ? rawRequest.originalUrl.split("?")[1] : void 0;
|
|
26
|
+
const queryBody = decodeQueryBody(urlQuery, rawBody);
|
|
27
|
+
if (queryBody) {
|
|
28
|
+
rawBody = queryBody.rawBody;
|
|
29
|
+
reqBodyType = queryBody.bodyType;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const routeResponse = await dispatchRoute(
|
|
33
|
+
rawRequest.path,
|
|
34
|
+
rawBody,
|
|
35
|
+
reqHeaders,
|
|
36
|
+
respHeaders,
|
|
37
|
+
rawRequest,
|
|
38
|
+
rawResponse,
|
|
39
|
+
reqBodyType,
|
|
40
|
+
urlQuery
|
|
41
|
+
);
|
|
42
|
+
reply(routeResponse, rawResponse);
|
|
43
|
+
} catch (err) {
|
|
44
|
+
const error = err instanceof RpcError ? err : new RpcError({
|
|
45
|
+
publicMessage: "Internal Error",
|
|
46
|
+
originalError: err,
|
|
47
|
+
type: "unknown-error"
|
|
48
|
+
});
|
|
49
|
+
const routeResponse = getRouterFatalErrorResponse(error, respHeaders);
|
|
50
|
+
reply(routeResponse, rawResponse);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function reply(mionResp, resp) {
|
|
54
|
+
resp.status(mionResp.statusCode);
|
|
55
|
+
const bodyType = mionResp.serializer;
|
|
56
|
+
switch (bodyType) {
|
|
57
|
+
case SerializerModes.stringifyJson: {
|
|
58
|
+
const buffer = Buffer.from(mionResp.rawBody, "utf8");
|
|
59
|
+
resp.set("content-length", `${buffer.byteLength}`);
|
|
60
|
+
resp.end(buffer);
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case SerializerModes.json: {
|
|
64
|
+
const jsonString = JSON.stringify(mionResp.body);
|
|
65
|
+
const buffer = Buffer.from(jsonString, "utf8");
|
|
66
|
+
resp.set("content-type", "application/json; charset=utf-8");
|
|
67
|
+
resp.set("content-length", `${buffer.byteLength}`);
|
|
68
|
+
resp.end(buffer);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case SerializerModes.binary: {
|
|
72
|
+
const serializer = mionResp.binSerializer;
|
|
73
|
+
resp.set("content-length", `${serializer.getLength()}`);
|
|
74
|
+
resp.end(Buffer.from(serializer.getBufferView()));
|
|
75
|
+
const onFinish = () => serializer.markAsEnded();
|
|
76
|
+
resp.on("finish", onFinish);
|
|
77
|
+
resp.on("close", onFinish);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
default: {
|
|
81
|
+
const error = new RpcError({
|
|
82
|
+
publicMessage: "unknown-mion-response-format",
|
|
83
|
+
type: "unknown-error",
|
|
84
|
+
errorData: { bodyType }
|
|
85
|
+
});
|
|
86
|
+
unexpectedFail(resp, mionResp.headers, error);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function unexpectedFail(resp, respHeaders, error) {
|
|
91
|
+
if (resp.writableEnded) return;
|
|
92
|
+
const routeResponse = getRouterFatalErrorResponse(error, respHeaders);
|
|
93
|
+
reply(routeResponse, resp);
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
googleCFHandler,
|
|
97
|
+
resetGoogleCFOpts,
|
|
98
|
+
setGoogleCFOpts
|
|
99
|
+
};
|
|
100
|
+
//# sourceMappingURL=googleCF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"googleCF.js","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 {RpcError, SerializerModes} from '@mionjs/core';\nimport type {SerializerCode} from '@mionjs/core';\nimport {dispatchRoute, getRouterFatalErrorResponse, resetRouter, decodeQueryBody} from '@mionjs/router';\nimport type {MionHeaders, 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 return googleCFOptions;\n}\n\nexport async function googleCFHandler(rawRequest: Request, rawResponse: Response): Promise<void> {\n // Express in Google Cloud Functions might parse the body automatically when Content-Type is application/json\n // We handle both cases: string body and already-parsed object body\n // For binary requests, we need to handle the raw buffer\n\n // TODO use its own express headers wrapper instead headers from record\n rawResponse.setHeader('server', '@mionjs');\n const reqHeaders = headersFromIncomingMessage(rawRequest);\n const respHeaders = headersFromServerResponse(rawResponse, googleCFOptions.defaultResponseHeaders);\n const contentType = rawRequest.headers['content-type'] || '';\n const isBinary = contentType.startsWith('application/octet-stream');\n let rawBody = isBinary ? (rawRequest as any).rawBody : rawRequest.body;\n let reqBodyType: SerializerCode = isBinary\n ? SerializerModes.binary\n : typeof rawBody === 'string'\n ? SerializerModes.stringifyJson\n : SerializerModes.json;\n // Extract query string from Express request\n const urlQuery = rawRequest.originalUrl?.includes('?') ? rawRequest.originalUrl.split('?')[1] : undefined;\n const queryBody = decodeQueryBody(urlQuery, rawBody);\n if (queryBody) {\n rawBody = queryBody.rawBody;\n reqBodyType = queryBody.bodyType;\n }\n\n try {\n const routeResponse = await dispatchRoute(\n rawRequest.path,\n rawBody,\n reqHeaders,\n respHeaders,\n rawRequest,\n rawResponse,\n reqBodyType,\n urlQuery\n );\n reply(routeResponse, rawResponse);\n } catch (err) {\n const error =\n err instanceof RpcError\n ? err\n : new RpcError({\n publicMessage: 'Internal Error',\n originalError: err as Error,\n type: 'unknown-error',\n });\n const routeResponse = getRouterFatalErrorResponse(error, respHeaders);\n reply(routeResponse, rawResponse);\n }\n}\n\n// ############# PRIVATE METHODS #############\n\nfunction reply(mionResp: MionResponse, resp: Response): void {\n resp.status(mionResp.statusCode);\n const bodyType = mionResp.serializer;\n switch (bodyType) {\n case SerializerModes.stringifyJson: {\n const buffer = Buffer.from(mionResp.rawBody as string, 'utf8');\n resp.set('content-length', `${buffer.byteLength}`);\n // content-type already set by serializer\n resp.end(buffer);\n break;\n }\n case SerializerModes.json: {\n // Platform adapter stringifies the prepared body object\n const jsonString = JSON.stringify(mionResp.body);\n const buffer = Buffer.from(jsonString, 'utf8');\n resp.set('content-type', 'application/json; charset=utf-8');\n resp.set('content-length', `${buffer.byteLength}`);\n resp.end(buffer);\n break;\n }\n case SerializerModes.binary: {\n const serializer = mionResp.binSerializer!;\n resp.set('content-length', `${serializer.getLength()}`);\n // content-type already set by serializer\n resp.end(Buffer.from(serializer.getBufferView()));\n\n // Release buffer when response is finished\n const onFinish = () => serializer.markAsEnded();\n resp.on('finish', onFinish);\n resp.on('close', onFinish); // Fallback for aborted connection\n break;\n }\n default: {\n const error = new RpcError({\n publicMessage: 'unknown-mion-response-format',\n type: 'unknown-error',\n errorData: {bodyType},\n });\n unexpectedFail(resp, mionResp.headers, error);\n }\n }\n}\n\nfunction unexpectedFail(resp: Response, respHeaders: MionHeaders, error: RpcError<string>) {\n if (resp.writableEnded) return;\n const routeResponse = getRouterFatalErrorResponse(error, respHeaders);\n reply(routeResponse, resp);\n}\n"],"names":[],"mappings":";;;;AAkBA,IAAI,kBAA6C,EAAC,GAAG,0BAAA;AAI9C,SAAS,oBAAoB;AAChC,oBAAkB,EAAC,GAAG,0BAAA;AACtB,cAAA;AACJ;AAEO,SAAS,gBAAgB,eAA0C;AACtE,oBAAkB;AAAA,IACd,GAAG;AAAA,IACH,GAAG;AAAA,EAAA;AAEP,SAAO;AACX;AAEA,eAAsB,gBAAgB,YAAqB,aAAsC;AAM7F,cAAY,UAAU,UAAU,SAAS;AACzC,QAAM,aAAa,2BAA2B,UAAU;AACxD,QAAM,cAAc,0BAA0B,aAAa,gBAAgB,sBAAsB;AACjG,QAAM,cAAc,WAAW,QAAQ,cAAc,KAAK;AAC1D,QAAM,WAAW,YAAY,WAAW,0BAA0B;AAClE,MAAI,UAAU,WAAY,WAAmB,UAAU,WAAW;AAClE,MAAI,cAA8B,WAC5B,gBAAgB,SAChB,OAAO,YAAY,WACjB,gBAAgB,gBAChB,gBAAgB;AAExB,QAAM,WAAW,WAAW,aAAa,SAAS,GAAG,IAAI,WAAW,YAAY,MAAM,GAAG,EAAE,CAAC,IAAI;AAChG,QAAM,YAAY,gBAAgB,UAAU,OAAO;AACnD,MAAI,WAAW;AACX,cAAU,UAAU;AACpB,kBAAc,UAAU;AAAA,EAC5B;AAEA,MAAI;AACA,UAAM,gBAAgB,MAAM;AAAA,MACxB,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAEJ,UAAM,eAAe,WAAW;AAAA,EACpC,SAAS,KAAK;AACV,UAAM,QACF,eAAe,WACT,MACA,IAAI,SAAS;AAAA,MACT,eAAe;AAAA,MACf,eAAe;AAAA,MACf,MAAM;AAAA,IAAA,CACT;AACX,UAAM,gBAAgB,4BAA4B,OAAO,WAAW;AACpE,UAAM,eAAe,WAAW;AAAA,EACpC;AACJ;AAIA,SAAS,MAAM,UAAwB,MAAsB;AACzD,OAAK,OAAO,SAAS,UAAU;AAC/B,QAAM,WAAW,SAAS;AAC1B,UAAQ,UAAA;AAAA,IACJ,KAAK,gBAAgB,eAAe;AAChC,YAAM,SAAS,OAAO,KAAK,SAAS,SAAmB,MAAM;AAC7D,WAAK,IAAI,kBAAkB,GAAG,OAAO,UAAU,EAAE;AAEjD,WAAK,IAAI,MAAM;AACf;AAAA,IACJ;AAAA,IACA,KAAK,gBAAgB,MAAM;AAEvB,YAAM,aAAa,KAAK,UAAU,SAAS,IAAI;AAC/C,YAAM,SAAS,OAAO,KAAK,YAAY,MAAM;AAC7C,WAAK,IAAI,gBAAgB,iCAAiC;AAC1D,WAAK,IAAI,kBAAkB,GAAG,OAAO,UAAU,EAAE;AACjD,WAAK,IAAI,MAAM;AACf;AAAA,IACJ;AAAA,IACA,KAAK,gBAAgB,QAAQ;AACzB,YAAM,aAAa,SAAS;AAC5B,WAAK,IAAI,kBAAkB,GAAG,WAAW,UAAA,CAAW,EAAE;AAEtD,WAAK,IAAI,OAAO,KAAK,WAAW,cAAA,CAAe,CAAC;AAGhD,YAAM,WAAW,MAAM,WAAW,YAAA;AAClC,WAAK,GAAG,UAAU,QAAQ;AAC1B,WAAK,GAAG,SAAS,QAAQ;AACzB;AAAA,IACJ;AAAA,IACA,SAAS;AACL,YAAM,QAAQ,IAAI,SAAS;AAAA,QACvB,eAAe;AAAA,QACf,MAAM;AAAA,QACN,WAAW,EAAC,SAAA;AAAA,MAAQ,CACvB;AACD,qBAAe,MAAM,SAAS,SAAS,KAAK;AAAA,IAChD;AAAA,EAAA;AAER;AAEA,SAAS,eAAe,MAAgB,aAA0B,OAAyB;AACvF,MAAI,KAAK,cAAe;AACxB,QAAM,gBAAgB,4BAA4B,OAAO,WAAW;AACpE,QAAM,eAAe,IAAI;AAC7B;"}
|
|
@@ -0,0 +1,4 @@
|
|
|
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;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { headersFromRecord } from "@mionjs/router";
|
|
2
|
+
function headersFromIncomingMessage(rawRequest) {
|
|
3
|
+
return headersFromRecord(rawRequest.headers);
|
|
4
|
+
}
|
|
5
|
+
class ServerResponseHeadersImpl {
|
|
6
|
+
constructor(resp) {
|
|
7
|
+
this.resp = resp;
|
|
8
|
+
}
|
|
9
|
+
append(name, value) {
|
|
10
|
+
this.resp.appendHeader(name, value);
|
|
11
|
+
}
|
|
12
|
+
delete(name) {
|
|
13
|
+
this.resp.removeHeader(name);
|
|
14
|
+
}
|
|
15
|
+
get(name) {
|
|
16
|
+
const value = this.resp.getHeader(name);
|
|
17
|
+
if (Array.isArray(value)) return value.join(", ");
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
has(name) {
|
|
21
|
+
return this.resp.hasHeader(name);
|
|
22
|
+
}
|
|
23
|
+
set(name, value) {
|
|
24
|
+
this.resp.setHeader(name, value);
|
|
25
|
+
}
|
|
26
|
+
entries() {
|
|
27
|
+
return getSingleHeadersObj(this.resp).entries();
|
|
28
|
+
}
|
|
29
|
+
keys() {
|
|
30
|
+
return new Set(this.resp.getHeaderNames()).values();
|
|
31
|
+
}
|
|
32
|
+
values() {
|
|
33
|
+
return getSingleHeadersObj(this.resp).values();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function headersFromServerResponse(resp, initialHeaders) {
|
|
37
|
+
if (initialHeaders) Object.entries(initialHeaders).forEach(([name, value]) => resp.setHeader(name, value));
|
|
38
|
+
return new ServerResponseHeadersImpl(resp);
|
|
39
|
+
}
|
|
40
|
+
function getSingleHeadersObj(resp) {
|
|
41
|
+
const entries = Object.entries(resp.getHeaders()).map(([name, value]) => [
|
|
42
|
+
name,
|
|
43
|
+
Array.isArray(value) ? value.join(", ") : value
|
|
44
|
+
]);
|
|
45
|
+
return Object.fromEntries(entries);
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
headersFromIncomingMessage,
|
|
49
|
+
headersFromServerResponse
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=headers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"headers.js","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 return headersFromRecord(rawRequest.headers as Record<string, string>);\n}\n\n/**\n * Reusable class for managing HTTP response headers with ServerResponse integration\n * Provides a MionHeaders interface that wraps Node.js ServerResponse header methods\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 getSingleHeadersObj(this.resp).entries();\n }\n\n keys(): IterableIterator<string> {\n return new Set(this.resp.getHeaderNames()).values();\n }\n\n values(): IterableIterator<string> {\n return getSingleHeadersObj(this.resp).values();\n }\n}\n\nexport function headersFromServerResponse(resp: ServerResponse, initialHeaders: Record<string, string> | null): MionHeaders {\n if (initialHeaders) Object.entries(initialHeaders).forEach(([name, value]) => resp.setHeader(name, value));\n return new ServerResponseHeadersImpl(resp);\n}\n\nfunction getSingleHeadersObj(resp: ServerResponse) {\n const entries = Object.entries(resp.getHeaders()).map(([name, value]) => [\n name,\n Array.isArray(value) ? value.join(', ') : (value as string),\n ]);\n return Object.fromEntries(entries);\n}\n"],"names":[],"mappings":";AAUO,SAAS,2BAA2B,YAA0C;AACjF,SAAO,kBAAkB,WAAW,OAAiC;AACzE;AAMA,MAAM,0BAAiD;AAAA,EACnD,YAAoB,MAAsB;AAAtB,SAAA,OAAA;AAAA,EAAuB;AAAA,EAE3C,OAAO,MAAc,OAAqB;AACtC,SAAK,KAAK,aAAa,MAAM,KAAK;AAAA,EACtC;AAAA,EAEA,OAAO,MAAoB;AACvB,SAAK,KAAK,aAAa,IAAI;AAAA,EAC/B;AAAA,EAEA,IAAI,MAAyC;AACzC,UAAM,QAAQ,KAAK,KAAK,UAAU,IAAI;AACtC,QAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,KAAK,IAAI;AAChD,WAAO;AAAA,EACX;AAAA,EAEA,IAAI,MAAuB;AACvB,WAAO,KAAK,KAAK,UAAU,IAAI;AAAA,EACnC;AAAA,EAEA,IAAI,MAAc,OAAqB;AACnC,SAAK,KAAK,UAAU,MAAM,KAAK;AAAA,EACnC;AAAA,EAEA,UAA8C;AAC1C,WAAO,oBAAoB,KAAK,IAAI,EAAE,QAAA;AAAA,EAC1C;AAAA,EAEA,OAAiC;AAC7B,WAAO,IAAI,IAAI,KAAK,KAAK,eAAA,CAAgB,EAAE,OAAA;AAAA,EAC/C;AAAA,EAEA,SAAmC;AAC/B,WAAO,oBAAoB,KAAK,IAAI,EAAE,OAAA;AAAA,EAC1C;AACJ;AAEO,SAAS,0BAA0B,MAAsB,gBAA4D;AACxH,MAAI,eAAgB,QAAO,QAAQ,cAAc,EAAE,QAAQ,CAAC,CAAC,MAAM,KAAK,MAAM,KAAK,UAAU,MAAM,KAAK,CAAC;AACzG,SAAO,IAAI,0BAA0B,IAAI;AAC7C;AAEA,SAAS,oBAAoB,MAAsB;AAC/C,QAAM,UAAU,OAAO,QAAQ,KAAK,YAAY,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM;AAAA,IACrE;AAAA,IACA,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,IAAK;AAAA,EAAA,CAC9C;AACD,SAAO,OAAO,YAAY,OAAO;AACrC;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Mion
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/MionKit/mion/master/assets/public/bannerx90-dark.png">
|
|
4
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/MionKit/mion/master/assets/public/bannerx90.png">
|
|
5
|
+
<img alt='mion, a mikro kit for Typescript Serverless APIs' src='https://raw.githubusercontent.com/MionKit/mion/master/assets/public/bannerx90.png'>
|
|
6
|
+
</picture>
|
|
7
|
+
</p>
|
|
8
|
+
<p align="center">
|
|
9
|
+
<strong>Full Stack APIs at the speed of light 🚀
|
|
10
|
+
</strong>
|
|
11
|
+
</p>
|
|
12
|
+
<p align=center>
|
|
13
|
+
<img src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square&maxAge=99999999" alt="npm" style="max-width:100%;">
|
|
14
|
+
<img src="https://img.shields.io/badge/license-MIT-97ca00.svg?style=flat-square&maxAge=99999999" alt="npm" style="max-width:100%;">
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
# `@mionjs/platform-gcloud`
|
|
18
|
+
|
|
19
|
+
ent.
|
|
20
|
+
|
|
21
|
+
This package contains handler functions to run mion on [Google Cloud functions](https://cloud.google.com/functions/docs/concepts/nodejs-runtimG).
|
|
22
|
+
|
|
23
|
+
## Check Out The [Website And Documentation](http://mion.io) 📚
|
|
24
|
+
|
|
25
|
+
[](http://mion.io)
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
_[MIT](../../LICENSE) LICENSE_
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mionjs/platform-gcloud",
|
|
3
|
+
"version": "0.8.0-alpha.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Google Cloud functions wrapper for mion router.",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"typescript",
|
|
8
|
+
"API",
|
|
9
|
+
"RPC",
|
|
10
|
+
"json",
|
|
11
|
+
"schema",
|
|
12
|
+
"generate",
|
|
13
|
+
"server",
|
|
14
|
+
"serverless",
|
|
15
|
+
"framework",
|
|
16
|
+
"node"
|
|
17
|
+
],
|
|
18
|
+
"author": "ma jerez",
|
|
19
|
+
"homepage": "https://mion.io/",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"source": "./index.ts",
|
|
24
|
+
"types": "./.dist/esm/index.d.ts",
|
|
25
|
+
"require": "./.dist/cjs/index.cjs",
|
|
26
|
+
"default": "./.dist/esm/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"directories": {
|
|
30
|
+
"lib": ".dist"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
".dist"
|
|
34
|
+
],
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/MionKit/mion.git"
|
|
38
|
+
},
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"dev": "vite build --watch",
|
|
45
|
+
"dev:test": "vitest watch",
|
|
46
|
+
"lint": "npx eslint src",
|
|
47
|
+
"format": "prettier --write src/**/*.ts",
|
|
48
|
+
"build": "vite build",
|
|
49
|
+
"clean": "rimraf .dist & rimraf .coverage",
|
|
50
|
+
"fresh-start": "npm run clean && rimraf node_modules"
|
|
51
|
+
},
|
|
52
|
+
"bugs": {
|
|
53
|
+
"url": "https://github.com/MionKit/mion/issues"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@google-cloud/functions-framework": "^3.3.0",
|
|
57
|
+
"@mionjs/core": "^0.8.0-alpha.0",
|
|
58
|
+
"@mionjs/router": "^0.8.0-alpha.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/express": "^4.17.20"
|
|
62
|
+
},
|
|
63
|
+
"gitHead": "5d2ec524ba39d040338ce8946d8edf78aa7291a3"
|
|
64
|
+
}
|