edge.libx.js 0.0.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/LICENSE +21 -0
- package/README.md +49 -0
- package/bin/cli.sh +7 -0
- package/bin/set-secrets.ts +70 -0
- package/bin/test.ts +18 -0
- package/build/Main.d.ts +1 -0
- package/build/Main.js +6 -0
- package/build/Main.js.map +1 -0
- package/build/helpers/EdgeNetwork.d.ts +13 -0
- package/build/helpers/EdgeNetwork.js +100 -0
- package/build/helpers/EdgeNetwork.js.map +1 -0
- package/build/helpers/Exceptions.d.ts +37 -0
- package/build/helpers/Exceptions.js +100 -0
- package/build/helpers/Exceptions.js.map +1 -0
- package/build/helpers/getExpress.d.ts +4 -0
- package/build/helpers/getExpress.js +25 -0
- package/build/helpers/getExpress.js.map +1 -0
- package/build/helpers/index.d.ts +12 -0
- package/build/helpers/index.js +70 -0
- package/build/helpers/index.js.map +1 -0
- package/build/helpers/jwt.d.ts +57 -0
- package/build/helpers/jwt.js +227 -0
- package/build/helpers/jwt.js.map +1 -0
- package/build/helpers/localServer.d.ts +1 -0
- package/build/helpers/localServer.js +54 -0
- package/build/helpers/localServer.js.map +1 -0
- package/build/helpers/require.d.ts +1 -0
- package/build/helpers/require.js +219 -0
- package/build/helpers/require.js.map +1 -0
- package/build/modules/@module.d.ts +6 -0
- package/build/modules/@module.js +16 -0
- package/build/modules/@module.js.map +1 -0
- package/build/modules/RouterWrapper.d.ts +21 -0
- package/build/modules/RouterWrapper.js +62 -0
- package/build/modules/RouterWrapper.js.map +1 -0
- package/build/modules/cors.d.ts +15 -0
- package/build/modules/cors.js +117 -0
- package/build/modules/cors.js.map +1 -0
- package/jest.config.js +26 -0
- package/package.json +65 -0
- package/src/Main.ts +1 -0
- package/src/helpers/EdgeNetwork.ts +113 -0
- package/src/helpers/Exceptions.ts +102 -0
- package/src/helpers/getExpress.ts +25 -0
- package/src/helpers/index.ts +61 -0
- package/src/helpers/jwt.ts +287 -0
- package/src/helpers/localServer.ts +75 -0
- package/src/helpers/require.ts +331 -0
- package/src/modules/@module.ts +13 -0
- package/src/modules/RouterWrapper.ts +68 -0
- package/src/modules/cors.ts +153 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"@module.js","sourceRoot":"","sources":["../../src/modules/@module.ts"],"names":[],"mappings":";;;AAAA,uEAA2D;AAE3D,MAAa,MAAM;IAClB,YAA0B,OAAgC;QAAhC,YAAO,GAAP,OAAO,CAAyB;QACzD,IAAI,CAAC,OAAO,mCAAQ,IAAI,aAAa,EAAE,GAAK,OAAO,CAAE,CAAC;QACtD,oBAAI,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IAC3B,CAAC;CAED;AAND,wBAMC;AAED,MAAa,aAAa;CAEzB;AAFD,sCAEC","sourcesContent":["import { libx } from 'libx.js/build/bundles/essentials.js';\n\nexport class Module {\n\tpublic constructor(public options?: Partial<ModuleOptions>) {\n\t\tthis.options = { ...new ModuleOptions(), ...options };\n\t\tlibx.log.v('Module:ctor');\n\t}\n\t\n}\n\nexport class ModuleOptions {\n\n}"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { RouterType, IRequest } from 'itty-router';
|
|
2
|
+
type BaseRouterInitializer = (string: any) => {
|
|
3
|
+
base: string;
|
|
4
|
+
router: RouterType<IRequest, any[]>;
|
|
5
|
+
};
|
|
6
|
+
export declare class RouterWrapper<TCtx = any> {
|
|
7
|
+
base: string;
|
|
8
|
+
router: RouterType<Request, [], any>;
|
|
9
|
+
private static cors;
|
|
10
|
+
private static preflight;
|
|
11
|
+
private static corsify;
|
|
12
|
+
constructor(base: string, router: RouterType<Request, [], any>);
|
|
13
|
+
private static tryCors;
|
|
14
|
+
static getNew(base: string): RouterWrapper<any>;
|
|
15
|
+
static errorHandler(error: any): Response;
|
|
16
|
+
registerRoute(newBase: string, baseRouterInitializer: BaseRouterInitializer): RouterType<Request, [], any>;
|
|
17
|
+
fetchHandler(request: IRequest, ctx: TCtx): Promise<Response>;
|
|
18
|
+
catchNotFound(): void;
|
|
19
|
+
createServerAdapter(): import("@whatwg-node/server").ServerAdapter<{}, import("@whatwg-node/server").ServerAdapterBaseObject<{}, any>>;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.RouterWrapper = void 0;
|
|
5
|
+
const essentials_js_1 = require("libx.js/build/bundles/essentials.js");
|
|
6
|
+
const itty_router_1 = require("itty-router");
|
|
7
|
+
const server_1 = require("@whatwg-node/server");
|
|
8
|
+
class RouterWrapper {
|
|
9
|
+
constructor(base, router) {
|
|
10
|
+
this.base = base;
|
|
11
|
+
this.router = router;
|
|
12
|
+
}
|
|
13
|
+
static tryCors(response, request) {
|
|
14
|
+
try {
|
|
15
|
+
return this.corsify(response, request);
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
essentials_js_1.libx.log.w('tryCors: failed to perform CORS', err);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
static getNew(base) {
|
|
22
|
+
const router = (0, itty_router_1.Router)({
|
|
23
|
+
base,
|
|
24
|
+
before: [this.preflight],
|
|
25
|
+
catch: this.errorHandler,
|
|
26
|
+
finally: [this.tryCors],
|
|
27
|
+
});
|
|
28
|
+
router.all('*', itty_router_1.withParams);
|
|
29
|
+
return new _a(base, router);
|
|
30
|
+
}
|
|
31
|
+
static errorHandler(error) {
|
|
32
|
+
var _b, _c, _d, _e, _f;
|
|
33
|
+
const isObject = essentials_js_1.libx.isObject(error);
|
|
34
|
+
const errMessage = (_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error;
|
|
35
|
+
const msg = 'Error: ' + (!isObject ? (errMessage !== null && errMessage !== void 0 ? errMessage : 'Server Error') : JSON.stringify(error));
|
|
36
|
+
const status = parseInt((_e = (_d = (_c = error === null || error === void 0 ? void 0 : error.status) !== null && _c !== void 0 ? _c : error === null || error === void 0 ? void 0 : error.statusCode) !== null && _d !== void 0 ? _d : error === null || error === void 0 ? void 0 : error.code) !== null && _e !== void 0 ? _e : (_f = error === null || error === void 0 ? void 0 : error.error) === null || _f === void 0 ? void 0 : _f.code) || 500;
|
|
37
|
+
console.error('Server error: ', error, status);
|
|
38
|
+
return new Response(msg, { status });
|
|
39
|
+
}
|
|
40
|
+
registerRoute(newBase, baseRouterInitializer) {
|
|
41
|
+
const route = baseRouterInitializer(`${this.base}${newBase}`);
|
|
42
|
+
this.router.all(newBase + '/*', route.router.fetch);
|
|
43
|
+
return this.router;
|
|
44
|
+
}
|
|
45
|
+
;
|
|
46
|
+
fetchHandler(request, ctx) {
|
|
47
|
+
return this.router.fetch(request, ctx).then(itty_router_1.json).catch(_a.errorHandler);
|
|
48
|
+
}
|
|
49
|
+
catchNotFound() {
|
|
50
|
+
this.router.all('*', () => (0, itty_router_1.error)(404));
|
|
51
|
+
}
|
|
52
|
+
createServerAdapter() {
|
|
53
|
+
const ittyServer = (0, server_1.createServerAdapter)(this.fetchHandler.bind(this));
|
|
54
|
+
return ittyServer;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.RouterWrapper = RouterWrapper;
|
|
58
|
+
_a = RouterWrapper;
|
|
59
|
+
RouterWrapper.cors = (0, itty_router_1.cors)({ origin: ['*'], allowMethods: ['POST'] });
|
|
60
|
+
RouterWrapper.preflight = _a.cors.preflight;
|
|
61
|
+
RouterWrapper.corsify = _a.cors.corsify;
|
|
62
|
+
//# sourceMappingURL=RouterWrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RouterWrapper.js","sourceRoot":"","sources":["../../src/modules/RouterWrapper.ts"],"names":[],"mappings":"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","sourcesContent":["import { libx } from 'libx.js/build/bundles/essentials.js';\nimport { Route, Router, RouterType, error, json, cors, withParams, IRequest, text, ResponseHandler } from 'itty-router';\nimport { createServerAdapter } from '@whatwg-node/server';\n\ntype BaseRouterInitializer = (string) => { base: string; router: RouterType<IRequest, any[]> };\n\nexport class RouterWrapper<TCtx = any> {\n\tprivate static cors = cors({ origin: ['*'], allowMethods: ['POST'] });\n\tprivate static preflight = this.cors.preflight;\n\tprivate static corsify = this.cors.corsify;\n\n\tpublic constructor(public base: string, public router: RouterType<Request, [], any>) {\n\n\t}\n\n\tprivate static tryCors(response, request): Response {\n\t\ttry {\n\t\t\treturn this.corsify(response, request);\n\t\t} catch (err) {\n\t\t\tlibx.log.w('tryCors: failed to perform CORS', err);\n\t\t}\n\t}\n\n\tpublic static getNew(base: string) {\n\t\tconst router = Router({\n\t\t\tbase,\n\t\t\tbefore: [this.preflight],\n\t\t\tcatch: this.errorHandler,\n\t\t\tfinally: [this.tryCors],\n\t\t});\n\t\trouter.all('*', withParams);\n\t\t// router.finally.push(this.corsify);\n\n\t\t// router.all('*', () => error(404));\n\n\t\treturn new RouterWrapper(base, router);\n\t}\n\n\n\tpublic static errorHandler(error) {\n\t\tconst isObject = libx.isObject(error);\n\t\tconst errMessage = error?.message ?? error;\n\t\tconst msg = 'Error: ' + (!isObject ? (errMessage ?? 'Server Error') : JSON.stringify(error));\n\t\tconst status = parseInt(error?.status ?? error?.statusCode ?? error?.code ?? error?.error?.code) || 500;\n\t\tconsole.error('Server error: ', error, status);\n\t\treturn new Response(msg, { status })\n\t}\n\n\tpublic registerRoute(newBase: string, baseRouterInitializer: BaseRouterInitializer) {\n\t\tconst route = baseRouterInitializer(`${this.base}${newBase}`);\n\t\tthis.router.all(newBase + '/*', route.router.fetch);\n\t\treturn this.router;\n\t};\n\n\tpublic fetchHandler(request: IRequest, ctx: TCtx) {\n\t\t// return this.router.fetch(request, ctx).then(json).then(RouterWrapper.corsify).catch(this.errorHandler);\n\t\treturn this.router.fetch(request, ctx).then(json).catch(RouterWrapper.errorHandler);\n\t}\n\n\tpublic catchNotFound() {\n\t\tthis.router.all('*', () => error(404));\n\t}\n\n\tpublic createServerAdapter() {\n\t\tconst ittyServer = createServerAdapter(this.fetchHandler.bind(this));\n\t\treturn ittyServer;\n\t}\n}"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type StaticOrigin = boolean | string | RegExp | (boolean | string | RegExp)[];
|
|
2
|
+
type OriginFn = (origin: string | undefined, req: Request) => StaticOrigin | Promise<StaticOrigin>;
|
|
3
|
+
interface CorsOptions {
|
|
4
|
+
origin?: StaticOrigin | OriginFn;
|
|
5
|
+
methods?: string | string[];
|
|
6
|
+
allowedHeaders?: string | string[];
|
|
7
|
+
exposedHeaders?: string | string[];
|
|
8
|
+
credentials?: boolean;
|
|
9
|
+
maxAge?: number;
|
|
10
|
+
preflightContinue?: boolean;
|
|
11
|
+
optionsSuccessStatus?: number;
|
|
12
|
+
}
|
|
13
|
+
export default function cors(req: Request, res: Response, options?: CorsOptions): Promise<Response>;
|
|
14
|
+
export declare function initCors(options?: CorsOptions): (req: Request, res: Response) => Promise<Response>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.default = cors;
|
|
13
|
+
exports.initCors = initCors;
|
|
14
|
+
const defaultOptions = {
|
|
15
|
+
origin: '*',
|
|
16
|
+
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
|
17
|
+
preflightContinue: false,
|
|
18
|
+
optionsSuccessStatus: 204,
|
|
19
|
+
};
|
|
20
|
+
function isOriginAllowed(origin, allowed) {
|
|
21
|
+
return Array.isArray(allowed)
|
|
22
|
+
? allowed.some((o) => isOriginAllowed(origin, o))
|
|
23
|
+
: typeof allowed === 'string'
|
|
24
|
+
? origin === allowed
|
|
25
|
+
: allowed instanceof RegExp
|
|
26
|
+
? allowed.test(origin)
|
|
27
|
+
: !!allowed;
|
|
28
|
+
}
|
|
29
|
+
function getOriginHeaders(reqOrigin, origin) {
|
|
30
|
+
const headers = new Headers();
|
|
31
|
+
if (origin === '*') {
|
|
32
|
+
headers.set('Access-Control-Allow-Origin', '*');
|
|
33
|
+
}
|
|
34
|
+
else if (typeof origin === 'string') {
|
|
35
|
+
headers.set('Access-Control-Allow-Origin', origin);
|
|
36
|
+
headers.append('Vary', 'Origin');
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const allowed = isOriginAllowed(reqOrigin !== null && reqOrigin !== void 0 ? reqOrigin : '', origin);
|
|
40
|
+
if (allowed && reqOrigin) {
|
|
41
|
+
headers.set('Access-Control-Allow-Origin', reqOrigin);
|
|
42
|
+
}
|
|
43
|
+
headers.append('Vary', 'Origin');
|
|
44
|
+
}
|
|
45
|
+
return headers;
|
|
46
|
+
}
|
|
47
|
+
function originHeadersFromReq(req, origin) {
|
|
48
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
49
|
+
const reqOrigin = req.headers.get('Origin') || undefined;
|
|
50
|
+
const value = typeof origin === 'function' ? yield origin(reqOrigin, req) : origin;
|
|
51
|
+
if (!value)
|
|
52
|
+
return;
|
|
53
|
+
return getOriginHeaders(reqOrigin, value);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function getAllowedHeaders(req, allowed) {
|
|
57
|
+
const headers = new Headers();
|
|
58
|
+
if (!allowed) {
|
|
59
|
+
allowed = req.headers.get('Access-Control-Request-Headers');
|
|
60
|
+
headers.append('Vary', 'Access-Control-Request-Headers');
|
|
61
|
+
}
|
|
62
|
+
else if (Array.isArray(allowed)) {
|
|
63
|
+
allowed = allowed.join(',');
|
|
64
|
+
}
|
|
65
|
+
if (allowed) {
|
|
66
|
+
headers.set('Access-Control-Allow-Headers', allowed);
|
|
67
|
+
}
|
|
68
|
+
return headers;
|
|
69
|
+
}
|
|
70
|
+
function cors(req, res, options) {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
var _a;
|
|
73
|
+
const opts = Object.assign(Object.assign({}, defaultOptions), options);
|
|
74
|
+
const { headers } = res;
|
|
75
|
+
const originHeaders = yield originHeadersFromReq(req, (_a = opts.origin) !== null && _a !== void 0 ? _a : false);
|
|
76
|
+
const mergeHeaders = (v, k) => {
|
|
77
|
+
if (k === 'Vary')
|
|
78
|
+
headers.append(k, v);
|
|
79
|
+
else
|
|
80
|
+
headers.set(k, v);
|
|
81
|
+
};
|
|
82
|
+
if (!originHeaders)
|
|
83
|
+
return res;
|
|
84
|
+
originHeaders.forEach(mergeHeaders);
|
|
85
|
+
if (opts.credentials) {
|
|
86
|
+
headers.set('Access-Control-Allow-Credentials', 'true');
|
|
87
|
+
}
|
|
88
|
+
const exposed = Array.isArray(opts.exposedHeaders)
|
|
89
|
+
? opts.exposedHeaders.join(',')
|
|
90
|
+
: opts.exposedHeaders;
|
|
91
|
+
if (exposed) {
|
|
92
|
+
headers.set('Access-Control-Expose-Headers', exposed);
|
|
93
|
+
}
|
|
94
|
+
debugger;
|
|
95
|
+
if (req.method === 'OPTIONS') {
|
|
96
|
+
if (opts.methods) {
|
|
97
|
+
const methods = Array.isArray(opts.methods)
|
|
98
|
+
? opts.methods.join(',')
|
|
99
|
+
: opts.methods;
|
|
100
|
+
headers.set('Access-Control-Allow-Methods', methods);
|
|
101
|
+
}
|
|
102
|
+
getAllowedHeaders(req, opts.allowedHeaders).forEach(mergeHeaders);
|
|
103
|
+
if (typeof opts.maxAge === 'number') {
|
|
104
|
+
headers.set('Access-Control-Max-Age', String(opts.maxAge));
|
|
105
|
+
}
|
|
106
|
+
if (opts.preflightContinue)
|
|
107
|
+
return res;
|
|
108
|
+
headers.set('Content-Length', '0');
|
|
109
|
+
return new Response(null, { status: opts.optionsSuccessStatus, headers });
|
|
110
|
+
}
|
|
111
|
+
return res;
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
function initCors(options) {
|
|
115
|
+
return (req, res) => cors(req, res, options);
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=cors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../../src/modules/cors.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Multi purpose CORS lib.\n * Note: Based on the `cors` package in npm but using only\n * web APIs. Feel free to use it in your own projects.\n */\n\ntype StaticOrigin = boolean | string | RegExp | (boolean | string | RegExp)[]\n\ntype OriginFn = (\n origin: string | undefined,\n req: Request\n) => StaticOrigin | Promise<StaticOrigin>\n\ninterface CorsOptions {\n origin?: StaticOrigin | OriginFn\n methods?: string | string[]\n allowedHeaders?: string | string[]\n exposedHeaders?: string | string[]\n credentials?: boolean\n maxAge?: number\n preflightContinue?: boolean\n optionsSuccessStatus?: number\n}\n\nconst defaultOptions: CorsOptions = {\n origin: '*',\n methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',\n preflightContinue: false,\n optionsSuccessStatus: 204,\n}\n\nfunction isOriginAllowed(origin: string, allowed: StaticOrigin): boolean {\n return Array.isArray(allowed)\n ? allowed.some((o) => isOriginAllowed(origin, o))\n : typeof allowed === 'string'\n ? origin === allowed\n : allowed instanceof RegExp\n ? allowed.test(origin)\n : !!allowed\n}\n\nfunction getOriginHeaders(reqOrigin: string | undefined, origin: StaticOrigin) {\n const headers = new Headers()\n\n if (origin === '*') {\n // Allow any origin\n headers.set('Access-Control-Allow-Origin', '*')\n } else if (typeof origin === 'string') {\n // Fixed origin\n headers.set('Access-Control-Allow-Origin', origin)\n headers.append('Vary', 'Origin')\n } else {\n const allowed = isOriginAllowed(reqOrigin ?? '', origin)\n\n if (allowed && reqOrigin) {\n headers.set('Access-Control-Allow-Origin', reqOrigin)\n }\n headers.append('Vary', 'Origin')\n }\n\n return headers\n}\n\n// originHeadersFromReq\n\nasync function originHeadersFromReq(\n req: Request,\n origin: StaticOrigin | OriginFn\n) {\n const reqOrigin = req.headers.get('Origin') || undefined\n const value =\n typeof origin === 'function' ? await origin(reqOrigin, req) : origin\n\n if (!value) return\n return getOriginHeaders(reqOrigin, value)\n}\n\nfunction getAllowedHeaders(req: Request, allowed?: string | string[]) {\n const headers = new Headers()\n\n if (!allowed) {\n allowed = req.headers.get('Access-Control-Request-Headers')!\n headers.append('Vary', 'Access-Control-Request-Headers')\n } else if (Array.isArray(allowed)) {\n // If the allowed headers is an array, turn it into a string\n allowed = allowed.join(',')\n }\n if (allowed) {\n headers.set('Access-Control-Allow-Headers', allowed)\n }\n\n return headers\n}\n\nexport default async function cors(\n req: Request,\n res: Response,\n options?: CorsOptions\n) {\n const opts = { ...defaultOptions, ...options }\n const { headers } = res\n const originHeaders = await originHeadersFromReq(req, opts.origin ?? false)\n const mergeHeaders = (v: string, k: string) => {\n if (k === 'Vary') headers.append(k, v)\n else headers.set(k, v)\n }\n\n // If there's no origin we won't touch the response\n if (!originHeaders) return res\n\n originHeaders.forEach(mergeHeaders)\n\n if (opts.credentials) {\n headers.set('Access-Control-Allow-Credentials', 'true')\n }\n\n const exposed = Array.isArray(opts.exposedHeaders)\n ? opts.exposedHeaders.join(',')\n : opts.exposedHeaders\n\n if (exposed) {\n headers.set('Access-Control-Expose-Headers', exposed)\n }\n debugger\n // Handle the preflight request\n if (req.method === 'OPTIONS') {\n if (opts.methods) {\n const methods = Array.isArray(opts.methods)\n ? opts.methods.join(',')\n : opts.methods\n\n headers.set('Access-Control-Allow-Methods', methods)\n }\n\n getAllowedHeaders(req, opts.allowedHeaders).forEach(mergeHeaders)\n\n if (typeof opts.maxAge === 'number') {\n headers.set('Access-Control-Max-Age', String(opts.maxAge))\n }\n\n if (opts.preflightContinue) return res\n\n headers.set('Content-Length', '0')\n return new Response(null, { status: opts.optionsSuccessStatus, headers })\n }\n\n // If we got here, it's a normal request\n return res\n}\n\nexport function initCors(options?: CorsOptions) {\n return (req: Request, res: Response) => cors(req, res, options)\n}"]}
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// process.env.TZ = 'UTC';
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
roots: [
|
|
5
|
+
"<rootDir>"
|
|
6
|
+
],
|
|
7
|
+
transform: {
|
|
8
|
+
"^.+\\.jsx?$": "babel-jest",
|
|
9
|
+
"^.+\\.ts?$": "ts-jest"
|
|
10
|
+
},
|
|
11
|
+
testRegex: "(/__tests__/.*|/tests/.*(\\.|/)(test|spec))\\.ts$|/src/.*\.test\.ts",
|
|
12
|
+
moduleFileExtensions: [
|
|
13
|
+
"ts",
|
|
14
|
+
"tsx",
|
|
15
|
+
"js",
|
|
16
|
+
"jsx",
|
|
17
|
+
"json",
|
|
18
|
+
"node"
|
|
19
|
+
],
|
|
20
|
+
verbose: true,
|
|
21
|
+
reporters: ["default", "jest-junit"],
|
|
22
|
+
coverageDirectory: ".tmp/coverage",
|
|
23
|
+
transformIgnorePatterns: [
|
|
24
|
+
"<rootDir>/node_modules/(?!libx\.js/.*)"
|
|
25
|
+
],
|
|
26
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "edge.libx.js",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"main": "build/main.js",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Elya Livshitz",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"format": "prettier --config .prettierrc 'src/**/*.ts' 'tests/**/*.ts' --write",
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"watch": "tsc -w",
|
|
11
|
+
"main": "node build/Main.js",
|
|
12
|
+
"test": "jest",
|
|
13
|
+
"test:debug": "node --inspect ./node_modules/jest/bin/jest.js --runInBand --colors --verbose",
|
|
14
|
+
"test:ci": "jest --ci --reporters=default --reporters=jest-junit --coverage --coverageReporters=cobertura --coverageReporters=html",
|
|
15
|
+
"set-secrets:debug": "bun nodemon --watch '**/*.ts' --exec tsx --inspect set-secrets .env preview \"vercel env add\" remove",
|
|
16
|
+
"bump": "./bump.sh"
|
|
17
|
+
},
|
|
18
|
+
"bin": {
|
|
19
|
+
"set-secrets": "bin/set-secrets.ts"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"bin/**",
|
|
23
|
+
"build/**",
|
|
24
|
+
"dist/**",
|
|
25
|
+
"src/**",
|
|
26
|
+
"*.js",
|
|
27
|
+
"*.ts"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@vercel/edge": "^1.1.2",
|
|
31
|
+
"@whatwg-node/server": "^0.9.49",
|
|
32
|
+
"body-parser": "^1.20.3",
|
|
33
|
+
"express": "^4.21.1",
|
|
34
|
+
"isomorphic-fetch": "^3.0.0",
|
|
35
|
+
"itty-router": "^5.0.18",
|
|
36
|
+
"js-base64": "^3.7.7",
|
|
37
|
+
"libx.js": "^4.4.0",
|
|
38
|
+
"ua-parser-js": "^1.0.39"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/jest": "^29.5.5",
|
|
42
|
+
"@types/node": "^20.8.0",
|
|
43
|
+
"jest": "^29.7.0",
|
|
44
|
+
"jest-junit": "^16.0.0",
|
|
45
|
+
"jest-junit-reporter": "^1.1.0",
|
|
46
|
+
"prettier": "^3.0.3",
|
|
47
|
+
"ts-jest": "^29.1.1",
|
|
48
|
+
"typescript": "^5.2.2"
|
|
49
|
+
},
|
|
50
|
+
"jest": {
|
|
51
|
+
"coverageReporters": [
|
|
52
|
+
"cobertura",
|
|
53
|
+
"html"
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
"jest-junit": {
|
|
57
|
+
"suiteName": "jest tests",
|
|
58
|
+
"outputDirectory": "build/test_reports",
|
|
59
|
+
"output": "./.tmp/test/TEST-RESULTS.xml",
|
|
60
|
+
"classNameTemplate": "{classname} - {title}",
|
|
61
|
+
"titleTemplate": "{classname} - {title}",
|
|
62
|
+
"ancestorSeparator": " > ",
|
|
63
|
+
"usePathForSuiteName": "true"
|
|
64
|
+
}
|
|
65
|
+
}
|
package/src/Main.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { RouterWrapper } from "./modules/RouterWrapper";
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { libx } from "libx.js/build/bundles/essentials.js";
|
|
2
|
+
|
|
3
|
+
class EdgeNetwork {
|
|
4
|
+
public async fetch(url: string, method: "GET" | "POST" | any, options?: RequestInit) {
|
|
5
|
+
url = this.cleanUrl(url);
|
|
6
|
+
const p = libx.newPromise();
|
|
7
|
+
const _p = fetch(url, {
|
|
8
|
+
method,
|
|
9
|
+
// credentials: "include",
|
|
10
|
+
//@ts-ignore
|
|
11
|
+
// withCredentials: true,
|
|
12
|
+
redirect: "follow",
|
|
13
|
+
...options,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
_p.catch(err=>{
|
|
17
|
+
return p.reject(err);
|
|
18
|
+
});
|
|
19
|
+
_p.then(async res=>{
|
|
20
|
+
if (res.status < 200 || res.status > 299) {
|
|
21
|
+
let body = null;
|
|
22
|
+
try {
|
|
23
|
+
body = await res.json();
|
|
24
|
+
} catch {}
|
|
25
|
+
const msg = `Fetch error: "${res?.status} - ${body?.error ?? body?.message ?? res?.statusText}"`;
|
|
26
|
+
libx.log.w(msg, body);
|
|
27
|
+
return p.reject(msg);
|
|
28
|
+
}
|
|
29
|
+
else p.resolve(res);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return p;
|
|
33
|
+
}
|
|
34
|
+
public async httpGet(url: string, options?: RequestInit) {
|
|
35
|
+
return await this.fetch(url, 'GET', options);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public async httpGetText(url: string, options?: RequestInit) {
|
|
39
|
+
const res = await this.httpGet(url, options);
|
|
40
|
+
return await res.text();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public async httpGetJson<T=any>(url: string, options?: RequestInit): Promise<T> {
|
|
44
|
+
const res = await this.httpGet(url, options);
|
|
45
|
+
return await res.json();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public async httpPost(url: string, data: any, _options?: any) {
|
|
49
|
+
const res = await this.fetch(url, "POST", {
|
|
50
|
+
body: data,
|
|
51
|
+
headers: {
|
|
52
|
+
..._options?.headers,
|
|
53
|
+
// 'content-type': 'application/json',
|
|
54
|
+
},
|
|
55
|
+
..._options,
|
|
56
|
+
});
|
|
57
|
+
return res;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public async httpPostText(url: string, data: any, _options?: {}) {
|
|
61
|
+
const res = await this.httpPost(url, data, _options);
|
|
62
|
+
return res.text();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public async httpPostJson(url: string, data: any, _options?: {}) {
|
|
66
|
+
const res = await this.httpPost(url, JSON.stringify(data), {
|
|
67
|
+
headers: {
|
|
68
|
+
// 'content-type': 'application/json',
|
|
69
|
+
// 'content-length': '0',
|
|
70
|
+
},
|
|
71
|
+
withCredentials: true,
|
|
72
|
+
..._options
|
|
73
|
+
});
|
|
74
|
+
// const res = await this.fetch(url, "POST", {
|
|
75
|
+
// body: JSON.stringify(data),
|
|
76
|
+
// headers: {
|
|
77
|
+
// 'content-type': 'application/json',
|
|
78
|
+
// },
|
|
79
|
+
// ..._options,
|
|
80
|
+
// });
|
|
81
|
+
|
|
82
|
+
return res.json();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
public fixUrl(url: string, prefixUrl?: string) {
|
|
86
|
+
var sep = '://';
|
|
87
|
+
var pos = url.indexOf(sep);
|
|
88
|
+
if (pos > -1) {
|
|
89
|
+
var startOfUrl = url.slice(0, pos);
|
|
90
|
+
var restOfUrl = url.slice(pos + 3);
|
|
91
|
+
restOfUrl = restOfUrl.replace(/([^:]\/)\/+/g, '$1');
|
|
92
|
+
url = startOfUrl + sep + restOfUrl;
|
|
93
|
+
} else {
|
|
94
|
+
url = url.replace(/([^:]\/)\/+/g, '$1');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
prefixUrl = prefixUrl || '';
|
|
98
|
+
|
|
99
|
+
var isAbsoluteUrl = pos > -1; // url.contains("//");
|
|
100
|
+
url = this.cleanUrl((!isAbsoluteUrl ? prefixUrl : '') + url);
|
|
101
|
+
|
|
102
|
+
return url;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public cleanUrl(url: string) {
|
|
106
|
+
if (url == null) return null;
|
|
107
|
+
//return url.replace('/(?<!http:)\/\//g', '/');
|
|
108
|
+
return url.replace(new RegExp('([^:]/)/+', 'g'), '$1');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const network = new EdgeNetwork();
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export class Exception extends Error {
|
|
2
|
+
public message: string;
|
|
3
|
+
public metadata: string;
|
|
4
|
+
public stack: string;
|
|
5
|
+
// public metadataObj: string;
|
|
6
|
+
|
|
7
|
+
constructor(message, metadata?, stack?) {
|
|
8
|
+
let json = '';
|
|
9
|
+
try {
|
|
10
|
+
json = JSON.stringify(metadata); //, null, 2);
|
|
11
|
+
} catch {}
|
|
12
|
+
let msg = message;
|
|
13
|
+
if (json != '') msg += '\nMetadata: ' + json;
|
|
14
|
+
super(msg);
|
|
15
|
+
this.name = 'Exception';
|
|
16
|
+
this.message = message;
|
|
17
|
+
// this.metadataObj = metadata;
|
|
18
|
+
this.metadata = metadata ?? json; //json;
|
|
19
|
+
this.stack = stack;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public metadataPretty() {
|
|
23
|
+
return JSON.stringify(this.metadata, null, 2);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public static fromError(err: Error) {
|
|
27
|
+
return new Exception(err.message, err, err.stack);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public static assert(condition: any | any[], message?: string, metadata?, exceptionType: typeof Exception = Exception) {
|
|
31
|
+
let conditions = condition;
|
|
32
|
+
if (!Array.isArray(condition)) conditions = [condition];
|
|
33
|
+
|
|
34
|
+
for (let cond of conditions) {
|
|
35
|
+
let isNull = cond === null;
|
|
36
|
+
let isFalse = typeof cond == 'boolean' && cond !== true;
|
|
37
|
+
|
|
38
|
+
if (isNull || isFalse) throw new exceptionType(message, metadata);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public toString() {
|
|
43
|
+
return (this.message += '\n\tMetadata: ' + this.metadata);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class ErrorNotFound extends Exception {
|
|
48
|
+
constructor(message, metadata?, stack?) {
|
|
49
|
+
super('Requested item not found', metadata, stack);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class ErrorDuplicate extends Exception {
|
|
54
|
+
constructor(message, metadata?, stack?) {
|
|
55
|
+
super(message || 'Requested item conflicts with exists', { metadata }, stack);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export class HttpError extends Exception {
|
|
60
|
+
constructor(public statusCode: number, message, metadata?, stack?) {
|
|
61
|
+
super(message, metadata, stack);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public static tryGetErrorCode(error: any, defaultCode: number): number {
|
|
65
|
+
if (error == null) return defaultCode;
|
|
66
|
+
|
|
67
|
+
if (error instanceof HttpError) return (<HttpError>error).statusCode;
|
|
68
|
+
if (error instanceof ErrorNotFound) return new HttpErrorNotFound(error.message, error.metadata, error.stack).statusCode;
|
|
69
|
+
if (error instanceof ErrorDuplicate) return new HttpErrorDuplicate(error.message, error.metadata, error.stack).statusCode;
|
|
70
|
+
|
|
71
|
+
return defaultCode;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export class HttpErrorBadRequest extends HttpError {
|
|
76
|
+
public statusCode: number = 400;
|
|
77
|
+
constructor(message, metadata?, stack?) {
|
|
78
|
+
super(400, message, metadata, stack);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export class HttpErrorNotFound extends HttpError {
|
|
83
|
+
public statusCode: number = 404;
|
|
84
|
+
constructor(message, metadata?, stack?) {
|
|
85
|
+
super(404, message, metadata, stack);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export class HttpErrorDuplicate extends HttpError {
|
|
90
|
+
public statusCode: number = 409;
|
|
91
|
+
constructor(message, metadata?, stack?) {
|
|
92
|
+
super(409, message, metadata, stack);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export class NotImplemented extends Exception {
|
|
97
|
+
constructor() {
|
|
98
|
+
super('Not Implemented!');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export default Exception;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import bodyParser from 'body-parser';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import cors from 'cors';
|
|
4
|
+
|
|
5
|
+
export function getExpress() {
|
|
6
|
+
const app = express();
|
|
7
|
+
|
|
8
|
+
app.set('json spaces', 4);
|
|
9
|
+
|
|
10
|
+
var rawBodySaver = function (req, res, buf, encoding) {
|
|
11
|
+
if (buf && buf.length) {
|
|
12
|
+
req.rawBody = buf.toString(encoding || 'utf8');
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
app.use(bodyParser.json({ verify: rawBodySaver }));
|
|
17
|
+
app.use(bodyParser.urlencoded({ verify: rawBodySaver, extended: true }));
|
|
18
|
+
app.use(bodyParser.raw({ verify: rawBodySaver, type: '*/*' }));
|
|
19
|
+
|
|
20
|
+
app.use(cors());
|
|
21
|
+
|
|
22
|
+
const router = express.Router();
|
|
23
|
+
|
|
24
|
+
return { app, router };
|
|
25
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { IRequest } from 'itty-router';
|
|
2
|
+
import { libx } from 'libx.js/build/bundles/essentials.js';
|
|
3
|
+
import { IFirebaseTokenPayload, JwtHelper } from './jwt.js';
|
|
4
|
+
|
|
5
|
+
export class Helpers {
|
|
6
|
+
public constructor(public options?: Partial<ModuleOptions>) {
|
|
7
|
+
this.options = { ...new ModuleOptions(), ...options };
|
|
8
|
+
libx.log.v('Helpers:ctor');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public async verifyRequestToken(request: IRequest, expectedAud: string) {
|
|
12
|
+
const token = request.headers.get('authorization')?.replace('Bearer ', '');
|
|
13
|
+
if (token == null) throw 'verifyRequestToken: token is empty';
|
|
14
|
+
const tokenPayload = await JwtHelper.verifyFirebaseToken(token, expectedAud);
|
|
15
|
+
return tokenPayload;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public async gatherResponse(response: Response) {
|
|
19
|
+
const { headers } = response;
|
|
20
|
+
const contentType = headers.get("content-type") || "";
|
|
21
|
+
if (contentType.includes("application/json")) {
|
|
22
|
+
return JSON.stringify(await response.json());
|
|
23
|
+
}
|
|
24
|
+
else if (contentType.includes("image")) {
|
|
25
|
+
return await this.readStream(response.body);
|
|
26
|
+
}
|
|
27
|
+
return await response.text();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public async readStream(stream: ReadableStream<Uint8Array>): Promise<Uint8Array> {
|
|
31
|
+
const reader = stream.getReader();
|
|
32
|
+
const chunks: Uint8Array[] = [];
|
|
33
|
+
|
|
34
|
+
while (true) {
|
|
35
|
+
const { done, value } = await reader.read();
|
|
36
|
+
|
|
37
|
+
if (done) {
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
chunks.push(value);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Concatenate the chunks and decode them into a string using TextDecoder
|
|
45
|
+
const concatenatedChunks = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0));
|
|
46
|
+
let offset = 0;
|
|
47
|
+
|
|
48
|
+
for (const chunk of chunks) {
|
|
49
|
+
concatenatedChunks.set(chunk, offset);
|
|
50
|
+
offset += chunk.length;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return concatenatedChunks;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class ModuleOptions {
|
|
58
|
+
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const helpers = new Helpers();
|