@mxpicture/gcp-functions 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/base/BaseApi.js +38 -0
- package/dist/cjs/base/BaseFunction.js +23 -0
- package/dist/cjs/base/BaseHttp.js +106 -0
- package/dist/cjs/common/firebase.js +1 -168
- package/dist/cjs/demo/User.js +31 -0
- package/dist/cjs/lib.js +10 -9
- package/dist/{esm/store/IStore.js → cjs/store/Store.js} +28 -23
- package/dist/cjs/store/types.store.js +3 -8
- package/dist/cjs/types/types.apiRoutes.js +2 -0
- package/dist/cjs/types/types.common.js +2 -0
- package/dist/cjs/types/types.function.js +2 -0
- package/dist/cjs/types/types.httpHandler.js +2 -0
- package/dist/cjs/validation/Validation.js +38 -0
- package/dist/esm/base/BaseApi.js +38 -0
- package/dist/esm/base/BaseFunction.js +23 -0
- package/dist/esm/base/BaseHttp.js +106 -0
- package/dist/esm/common/firebase.js +1 -168
- package/dist/esm/demo/User.js +31 -0
- package/dist/esm/lib.js +10 -9
- package/dist/{cjs/store/IStore.js → esm/store/Store.js} +28 -23
- package/dist/esm/store/types.store.js +3 -8
- package/dist/esm/types/types.apiRoutes.js +2 -0
- package/dist/esm/types/types.common.js +2 -0
- package/dist/esm/types/types.function.js +2 -0
- package/dist/esm/types/types.httpHandler.js +2 -0
- package/dist/esm/validation/Validation.js +38 -0
- package/dist/types/base/BaseApi.d.ts +26 -0
- package/dist/types/base/BaseFunction.d.ts +11 -0
- package/dist/types/base/BaseHttp.d.ts +21 -0
- package/dist/types/common/firebase.d.ts +0 -9
- package/dist/types/demo/User.d.ts +24 -0
- package/dist/types/lib.d.ts +11 -10
- package/dist/types/store/Store.d.ts +24 -0
- package/dist/types/store/types.store.d.ts +3 -14
- package/dist/types/types/types.apiRoutes.d.ts +29 -0
- package/dist/types/types/types.common.d.ts +10 -0
- package/dist/types/types/types.function.d.ts +10 -0
- package/dist/types/types/types.httpHandler.d.ts +5 -0
- package/dist/types/validation/Validation.d.ts +14 -0
- package/package.json +3 -2
- package/dist/cjs/FunctionHandlers.js +0 -18
- package/dist/cjs/api/IApi.js +0 -52
- package/dist/cjs/common/http.js +0 -147
- package/dist/cjs/common/types.common.js +0 -30
- package/dist/cjs/handler/HttpHandler.js +0 -41
- package/dist/cjs/handler/IHttpHandlerItem.js +0 -169
- package/dist/esm/FunctionHandlers.js +0 -18
- package/dist/esm/api/IApi.js +0 -52
- package/dist/esm/common/http.js +0 -147
- package/dist/esm/common/types.common.js +0 -30
- package/dist/esm/handler/HttpHandler.js +0 -41
- package/dist/esm/handler/IHttpHandlerItem.js +0 -169
- package/dist/types/FunctionHandlers.d.ts +0 -12
- package/dist/types/api/IApi.d.ts +0 -27
- package/dist/types/common/http.d.ts +0 -20
- package/dist/types/common/types.common.d.ts +0 -31
- package/dist/types/handler/HttpHandler.d.ts +0 -15
- package/dist/types/handler/IHttpHandlerItem.d.ts +0 -23
- package/dist/types/store/IStore.d.ts +0 -25
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const storeSchemaShape: {
|
|
3
3
|
id: z.ZodOptional<z.ZodString>;
|
|
4
4
|
createTime: z.ZodOptional<z.ZodDate>;
|
|
5
5
|
updateTime: z.ZodOptional<z.ZodDate>;
|
|
6
6
|
};
|
|
7
|
-
export declare const
|
|
8
|
-
id: z.ZodString;
|
|
9
|
-
createTime: z.ZodOptional<z.ZodDate>;
|
|
10
|
-
updateTime: z.ZodOptional<z.ZodDate>;
|
|
11
|
-
};
|
|
12
|
-
export declare const storeBaseSchema: z.ZodObject<{
|
|
7
|
+
export declare const storeSchema: z.ZodObject<{
|
|
13
8
|
id: z.ZodOptional<z.ZodString>;
|
|
14
9
|
createTime: z.ZodOptional<z.ZodDate>;
|
|
15
10
|
updateTime: z.ZodOptional<z.ZodDate>;
|
|
16
11
|
}, z.core.$strip>;
|
|
17
|
-
export type
|
|
18
|
-
export declare const storePersistSchema: z.ZodObject<{
|
|
19
|
-
id: z.ZodString;
|
|
20
|
-
createTime: z.ZodOptional<z.ZodDate>;
|
|
21
|
-
updateTime: z.ZodOptional<z.ZodDate>;
|
|
22
|
-
}, z.core.$strip>;
|
|
23
|
-
export type StorePersistDoc = z.infer<typeof storePersistSchema>;
|
|
12
|
+
export type StoreDoc = z.infer<typeof storeSchema>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MetaItem } from "@mxpicture/zod-meta";
|
|
2
|
+
import { DocumentData, WithKey } from "./types.common.js";
|
|
3
|
+
export type ApiRouteDef<KEYS, PAYLOAD, RESULT> = {
|
|
4
|
+
keys: KEYS;
|
|
5
|
+
payload: PAYLOAD;
|
|
6
|
+
result: RESULT;
|
|
7
|
+
};
|
|
8
|
+
export type ApiRoutesMap = Record<string, ApiRouteDef<any, any, any>>;
|
|
9
|
+
export type WithApiRoutes<R extends ApiRoutesMap> = R;
|
|
10
|
+
export interface ApiKey {
|
|
11
|
+
id: string;
|
|
12
|
+
}
|
|
13
|
+
export type ApiRoutes<DTO extends DocumentData> = WithApiRoutes<{
|
|
14
|
+
create: ApiRouteDef<never, DTO, WithKey<DTO>>;
|
|
15
|
+
update: ApiRouteDef<ApiKey, Partial<DTO>, WithKey<DTO>>;
|
|
16
|
+
delete: ApiRouteDef<ApiKey, never, void>;
|
|
17
|
+
get: ApiRouteDef<ApiKey, never, WithKey<DTO>>;
|
|
18
|
+
query: ApiRouteDef<never, never, WithKey<DTO>[]>;
|
|
19
|
+
count: ApiRouteDef<never, never, {
|
|
20
|
+
count: number;
|
|
21
|
+
}>;
|
|
22
|
+
exists: ApiRouteDef<ApiKey, never, {
|
|
23
|
+
exists: boolean;
|
|
24
|
+
}>;
|
|
25
|
+
meta: ApiRouteDef<never, never, MetaItem[]>;
|
|
26
|
+
}>;
|
|
27
|
+
export type ApiFromRoutes<R extends ApiRoutesMap> = {
|
|
28
|
+
[K in keyof R]: (...args: R[K]["keys"] extends never ? [payload: R[K]["payload"]] : [keys: R[K]["keys"], payload: R[K]["payload"]]) => Promise<R[K]["result"]>;
|
|
29
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type DocumentFieldValue = any;
|
|
2
|
+
export type DocumentData = {
|
|
3
|
+
[field: string]: DocumentFieldValue;
|
|
4
|
+
};
|
|
5
|
+
export interface DocumentKey {
|
|
6
|
+
id?: string;
|
|
7
|
+
createTime?: Date;
|
|
8
|
+
updateTime?: Date;
|
|
9
|
+
}
|
|
10
|
+
export type WithKey<DTO extends DocumentData> = DocumentKey & DTO;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { StoreDoc } from "../store/types.store";
|
|
2
|
+
import { ApiKey } from "./types.apiRoutes";
|
|
3
|
+
export interface FunctionPayload<DOC extends StoreDoc, KEYS extends ApiKey = never> {
|
|
4
|
+
route: string;
|
|
5
|
+
keys?: KEYS;
|
|
6
|
+
content?: DOC;
|
|
7
|
+
}
|
|
8
|
+
export interface FunctionResult<DOC extends StoreDoc> {
|
|
9
|
+
doc?: DOC | DOC[];
|
|
10
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Store } from "../store/Store";
|
|
2
|
+
import { ZodError, ZodObject, ZodRawShape } from "zod";
|
|
3
|
+
import { DocumentData, WithKey } from "../types/types.common";
|
|
4
|
+
export type ValidationFieldErrors = Record<string, string[]>;
|
|
5
|
+
export declare class Validation<DTO extends DocumentData> {
|
|
6
|
+
readonly store: Store<DTO>;
|
|
7
|
+
shape: ZodRawShape;
|
|
8
|
+
createSchema: ZodObject;
|
|
9
|
+
updateSchema: ZodObject;
|
|
10
|
+
constructor(store: Store<DTO>, shape: ZodRawShape);
|
|
11
|
+
validate(doc: Partial<WithKey<DTO>>): Promise<WithKey<DTO>>;
|
|
12
|
+
validatePartial(doc: Partial<WithKey<DTO>>): Promise<Partial<WithKey<DTO>>>;
|
|
13
|
+
protected issuesToFieldErrors(issues: ZodError["issues"]): ValidationFieldErrors;
|
|
14
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mxpicture/gcp-functions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Utils for google cloud functions, publishing both CommonJS and ESM builds",
|
|
5
5
|
"author": "MXPicture",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"firebase-admin": "^13.6.0",
|
|
50
50
|
"firebase-functions": "^7.0.3",
|
|
51
51
|
"short-uuid": "^6.0.3",
|
|
52
|
+
"ts-transformer-keys": "^0.4.4",
|
|
52
53
|
"zod": "^4.3.5"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
@@ -71,4 +72,4 @@
|
|
|
71
72
|
"husky": "^8.0.0",
|
|
72
73
|
"typescript": "^5.9.3"
|
|
73
74
|
}
|
|
74
|
-
}
|
|
75
|
+
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FunctionHandlers = void 0;
|
|
4
|
-
class FunctionHandlers {
|
|
5
|
-
constructor() {
|
|
6
|
-
this.items = {};
|
|
7
|
-
}
|
|
8
|
-
add(handler) {
|
|
9
|
-
this.items[handler.name] = handler;
|
|
10
|
-
}
|
|
11
|
-
functions() {
|
|
12
|
-
const result = {};
|
|
13
|
-
for (const [key, item] of Object.entries(this.items))
|
|
14
|
-
result[key] = item.setup();
|
|
15
|
-
return result;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
exports.FunctionHandlers = FunctionHandlers;
|
package/dist/cjs/api/IApi.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.IApi = void 0;
|
|
4
|
-
const zod_meta_1 = require("@mxpicture/zod-meta");
|
|
5
|
-
class IApi {
|
|
6
|
-
constructor(store, shape) {
|
|
7
|
-
this.store = store;
|
|
8
|
-
this.shape = shape;
|
|
9
|
-
}
|
|
10
|
-
metaItems() {
|
|
11
|
-
return new zod_meta_1.Meta(this.shape).items();
|
|
12
|
-
}
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
14
|
-
async create(doc, params) {
|
|
15
|
-
const storeDoc = await this.store.create(doc);
|
|
16
|
-
return this.fromStore(storeDoc);
|
|
17
|
-
}
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
19
|
-
async get(id, params) {
|
|
20
|
-
const storeDoc = await this.store.get(id);
|
|
21
|
-
return this.fromStore(storeDoc);
|
|
22
|
-
}
|
|
23
|
-
async query(params) {
|
|
24
|
-
const storeDocs = await this.store.query(params);
|
|
25
|
-
return await Promise.all(storeDocs.map((s) => this.fromStore(s)));
|
|
26
|
-
}
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
|
-
async count(params) {
|
|
29
|
-
return this.store.count();
|
|
30
|
-
}
|
|
31
|
-
async update(id, doc,
|
|
32
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
33
|
-
params) {
|
|
34
|
-
let storeDoc = await this.toStore(doc);
|
|
35
|
-
storeDoc = await this.store.update(id, storeDoc);
|
|
36
|
-
return this.fromStore(storeDoc);
|
|
37
|
-
}
|
|
38
|
-
async updatePartial(id, doc) {
|
|
39
|
-
const storeDoc = await this.toStorePartial(doc);
|
|
40
|
-
await this.store.update(id, storeDoc);
|
|
41
|
-
return this.get(id);
|
|
42
|
-
}
|
|
43
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
44
|
-
async delete(id, params) {
|
|
45
|
-
await this.store.delete(id);
|
|
46
|
-
}
|
|
47
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
48
|
-
async exists(id, params) {
|
|
49
|
-
return this.store.exists(id);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
exports.IApi = IApi;
|
package/dist/cjs/common/http.js
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.fixRequestBody = exports.hasBody = exports.contentstream = void 0;
|
|
40
|
-
const querystring = __importStar(require("querystring"));
|
|
41
|
-
const zlib_1 = require("zlib");
|
|
42
|
-
const zlib = __importStar(require("zlib"));
|
|
43
|
-
const http_errors_1 = __importDefault(require("http-errors"));
|
|
44
|
-
// export const handleErrorMessage = (
|
|
45
|
-
// response: express.Response,
|
|
46
|
-
// error: unknown,
|
|
47
|
-
// code: number = StatusCodes.BAD_REQUEST,
|
|
48
|
-
// ) => {
|
|
49
|
-
// // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
-
// const ae = error as any;
|
|
51
|
-
// const result = { message: "" };
|
|
52
|
-
// if (error instanceof Error) result.message = error.message;
|
|
53
|
-
// else if (typeof error === "string") result.message = error;
|
|
54
|
-
// else if (ae.message) result.message = ae.message;
|
|
55
|
-
// else if (ae.payload) {
|
|
56
|
-
// if (ae.payload.message && typeof ae.payload.message === "string")
|
|
57
|
-
// result.message = ae.payload.message;
|
|
58
|
-
// else if (typeof ae.payload === "string") result.message = ae.payload;
|
|
59
|
-
// } else result.message = "unknown";
|
|
60
|
-
// return response.status(code).json(result);
|
|
61
|
-
// };
|
|
62
|
-
const hasBrotliSupport = "createBrotliDecompress" in zlib;
|
|
63
|
-
/**
|
|
64
|
-
* Get the content stream of the request.
|
|
65
|
-
*
|
|
66
|
-
* @param {object} req
|
|
67
|
-
* @param {function} debug
|
|
68
|
-
* @param {boolean} [inflate=true]
|
|
69
|
-
* @return {object}
|
|
70
|
-
* @api private
|
|
71
|
-
*/
|
|
72
|
-
const contentstream = (req, inflate, debug = console) => {
|
|
73
|
-
const encoding = (req.headers["content-encoding"] || "identity").toLowerCase();
|
|
74
|
-
// const length = req.headers["content-length"];
|
|
75
|
-
let stream;
|
|
76
|
-
debug?.log('content-encoding "%s"', encoding);
|
|
77
|
-
if (inflate === false && encoding !== "identity") {
|
|
78
|
-
throw (0, http_errors_1.default)(415, "content encoding unsupported", {
|
|
79
|
-
encoding: encoding,
|
|
80
|
-
type: "encoding.unsupported",
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
switch (encoding) {
|
|
84
|
-
case "deflate":
|
|
85
|
-
stream = (0, zlib_1.createInflate)();
|
|
86
|
-
debug?.log("inflate body");
|
|
87
|
-
req.pipe(stream);
|
|
88
|
-
break;
|
|
89
|
-
case "gzip":
|
|
90
|
-
stream = (0, zlib_1.createGunzip)();
|
|
91
|
-
debug?.log("gunzip body");
|
|
92
|
-
req.pipe(stream);
|
|
93
|
-
break;
|
|
94
|
-
case "identity":
|
|
95
|
-
stream = req;
|
|
96
|
-
// stream.length = length;
|
|
97
|
-
break;
|
|
98
|
-
case "br":
|
|
99
|
-
if (hasBrotliSupport) {
|
|
100
|
-
stream = (0, zlib_1.createBrotliDecompress)();
|
|
101
|
-
debug?.log("brotli decompress body");
|
|
102
|
-
req.pipe(stream);
|
|
103
|
-
}
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
if (stream === undefined) {
|
|
107
|
-
throw (0, http_errors_1.default)(415, 'unsupported content encoding "' + encoding + '"', {
|
|
108
|
-
encoding: encoding,
|
|
109
|
-
type: "encoding.unsupported",
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
return stream;
|
|
113
|
-
};
|
|
114
|
-
exports.contentstream = contentstream;
|
|
115
|
-
const hasBody = (request) => {
|
|
116
|
-
const contentType = request.headers["content-type"];
|
|
117
|
-
return contentType
|
|
118
|
-
? contentType.includes("application/json") ||
|
|
119
|
-
contentType.includes("+json") ||
|
|
120
|
-
contentType.includes("application/x-www-form-urlencoded")
|
|
121
|
-
: false;
|
|
122
|
-
};
|
|
123
|
-
exports.hasBody = hasBody;
|
|
124
|
-
/**
|
|
125
|
-
* Fix proxied body if bodyParser is involved.
|
|
126
|
-
*/
|
|
127
|
-
const fixRequestBody = (proxyReq, requestBody) => {
|
|
128
|
-
if (!requestBody) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
const contentType = proxyReq.getHeader("Content-Type");
|
|
132
|
-
const writeBody = (bodyData) => {
|
|
133
|
-
// deepcode ignore ContentLengthInCode: bodyParser fix
|
|
134
|
-
proxyReq.setHeader("Content-Length", `'${Buffer.byteLength(bodyData)}'`);
|
|
135
|
-
proxyReq.write(bodyData);
|
|
136
|
-
};
|
|
137
|
-
if (contentType &&
|
|
138
|
-
(contentType.includes("application/json") || contentType.includes("+json"))) {
|
|
139
|
-
writeBody(JSON.stringify(requestBody));
|
|
140
|
-
}
|
|
141
|
-
if (contentType &&
|
|
142
|
-
contentType.includes("application/x-www-form-urlencoded") &&
|
|
143
|
-
!Array.isArray(requestBody)) {
|
|
144
|
-
writeBody(querystring.stringify(requestBody));
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
exports.fixRequestBody = fixRequestBody;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.castHttpError = exports.PrimitiveType = exports.HttpMethod = exports.HttpProtocol = void 0;
|
|
4
|
-
var HttpProtocol;
|
|
5
|
-
(function (HttpProtocol) {
|
|
6
|
-
HttpProtocol["http"] = "http";
|
|
7
|
-
HttpProtocol["https"] = "https";
|
|
8
|
-
})(HttpProtocol || (exports.HttpProtocol = HttpProtocol = {}));
|
|
9
|
-
var HttpMethod;
|
|
10
|
-
(function (HttpMethod) {
|
|
11
|
-
HttpMethod["POST"] = "POST";
|
|
12
|
-
HttpMethod["PATCH"] = "PATCH";
|
|
13
|
-
HttpMethod["PUT"] = "PUT";
|
|
14
|
-
HttpMethod["GET"] = "GET";
|
|
15
|
-
HttpMethod["DELETE"] = "DELETE";
|
|
16
|
-
})(HttpMethod || (exports.HttpMethod = HttpMethod = {}));
|
|
17
|
-
var PrimitiveType;
|
|
18
|
-
(function (PrimitiveType) {
|
|
19
|
-
PrimitiveType["string"] = "string";
|
|
20
|
-
PrimitiveType["number"] = "number";
|
|
21
|
-
PrimitiveType["boolean"] = "boolean";
|
|
22
|
-
})(PrimitiveType || (exports.PrimitiveType = PrimitiveType = {}));
|
|
23
|
-
const castHttpError = (error) => {
|
|
24
|
-
if (!error.message || typeof error.message !== "string")
|
|
25
|
-
return;
|
|
26
|
-
if (error.context && typeof error.message !== "string")
|
|
27
|
-
return;
|
|
28
|
-
return { message: error.message, context: error.context };
|
|
29
|
-
};
|
|
30
|
-
exports.castHttpError = castHttpError;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.HttpHandler = void 0;
|
|
7
|
-
const express_1 = __importDefault(require("express"));
|
|
8
|
-
const cookie_parser_1 = __importDefault(require("cookie-parser"));
|
|
9
|
-
const cors_1 = __importDefault(require("cors"));
|
|
10
|
-
const https_1 = require("firebase-functions/v2/https");
|
|
11
|
-
// export interface HandlerEnv {
|
|
12
|
-
// connectionToken: () => string;
|
|
13
|
-
// }
|
|
14
|
-
class HttpHandler {
|
|
15
|
-
constructor(name) {
|
|
16
|
-
this.name = name;
|
|
17
|
-
this.corsAllowList = [];
|
|
18
|
-
this.items = [];
|
|
19
|
-
this.exp = (0, express_1.default)();
|
|
20
|
-
}
|
|
21
|
-
add(...items) {
|
|
22
|
-
this.items.push(...items);
|
|
23
|
-
return this;
|
|
24
|
-
}
|
|
25
|
-
baseSetup() {
|
|
26
|
-
this.exp.use((0, cors_1.default)({ credentials: true, origin: true }));
|
|
27
|
-
this.exp.use((0, cookie_parser_1.default)());
|
|
28
|
-
this.exp.disable("x-powered-by");
|
|
29
|
-
// this.exp.use(verifySessionCookie); // todo verify token (maybe connection token)
|
|
30
|
-
}
|
|
31
|
-
setup() {
|
|
32
|
-
this.baseSetup();
|
|
33
|
-
for (const item of this.items)
|
|
34
|
-
item.setup(this.exp);
|
|
35
|
-
return this.createFunction();
|
|
36
|
-
}
|
|
37
|
-
createFunction() {
|
|
38
|
-
return (0, https_1.onRequest)({ cors: [/firebase\.com$/, /web\.app$/] }, this.exp);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
exports.HttpHandler = HttpHandler;
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.IHttpHandlerItem = void 0;
|
|
7
|
-
const raw_body_1 = __importDefault(require("raw-body"));
|
|
8
|
-
const http_js_1 = require("../common/http.js");
|
|
9
|
-
const https_1 = require("firebase-functions/v2/https");
|
|
10
|
-
const zod_1 = require("zod");
|
|
11
|
-
const types_common_js_1 = require("../common/types.common.js");
|
|
12
|
-
const http_status_codes_1 = require("@mxpicture/http-status-codes");
|
|
13
|
-
// export interface HandlerEnv {
|
|
14
|
-
// connectionToken: () => string;
|
|
15
|
-
// }
|
|
16
|
-
class IHttpHandlerItem {
|
|
17
|
-
constructor(name, api) {
|
|
18
|
-
this.name = name;
|
|
19
|
-
this.api = api;
|
|
20
|
-
this.corsAllowList = [];
|
|
21
|
-
}
|
|
22
|
-
setup(exp) {
|
|
23
|
-
exp.get(`/api/${this.name}`, async (req, res) => {
|
|
24
|
-
try {
|
|
25
|
-
const items = await this.api.query();
|
|
26
|
-
return this.httpSuccess(res, items);
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
return this.httpErrorUnnown(res, error);
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
exp.get(`/api/${this.name}_meta`, async (req, res) => {
|
|
33
|
-
try {
|
|
34
|
-
const items = this.api.metaItems();
|
|
35
|
-
return this.httpSuccess(res, items);
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
return this.httpErrorUnnown(res, error);
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
exp.get(`/api/${this.name}/:id`, async (req, res) => {
|
|
42
|
-
try {
|
|
43
|
-
const item = await this.api.get(req.params.id);
|
|
44
|
-
return this.httpSuccess(res, item);
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
return this.httpErrorUnnown(res, error);
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
exp.post(`/api/${this.name}`, async (req, res) => {
|
|
51
|
-
try {
|
|
52
|
-
const item = await this.extractBodyItem(req);
|
|
53
|
-
const valResult = await this.api.validate(item);
|
|
54
|
-
if (!valResult.success)
|
|
55
|
-
throw (0, zod_1.treeifyError)(valResult.error);
|
|
56
|
-
const validated = await this.api.create(valResult.data);
|
|
57
|
-
return this.httpSuccess(res, validated);
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
return this.httpErrorUnnown(res, error);
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
exp.patch(`/api/${this.name}/:id`, async (req, res) => {
|
|
64
|
-
try {
|
|
65
|
-
const item = await this.extractBodyItem(req);
|
|
66
|
-
const valResult = await this.api.validatePartial(item);
|
|
67
|
-
if (!valResult.success)
|
|
68
|
-
throw (0, zod_1.treeifyError)(valResult.error);
|
|
69
|
-
const validated = await this.api.updatePartial(req.params.id, valResult.data);
|
|
70
|
-
return this.httpSuccess(res, validated);
|
|
71
|
-
}
|
|
72
|
-
catch (error) {
|
|
73
|
-
return this.httpErrorUnnown(res, error);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
httpSuccess(res, payload, statusCode = http_status_codes_1.StatusCodes.OK) {
|
|
78
|
-
const result = { statusCode, payload };
|
|
79
|
-
return res.status(statusCode).json(result);
|
|
80
|
-
}
|
|
81
|
-
httpError(res, errors, statusCode = http_status_codes_1.StatusCodes.BAD_REQUEST) {
|
|
82
|
-
const result = { statusCode, errors };
|
|
83
|
-
return res.status(statusCode).json(result);
|
|
84
|
-
}
|
|
85
|
-
httpErrorUnnown(res, error, statusCode = http_status_codes_1.StatusCodes.BAD_REQUEST) {
|
|
86
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
87
|
-
const ae = error;
|
|
88
|
-
const messages = [];
|
|
89
|
-
if (error instanceof Error) {
|
|
90
|
-
messages.push({ message: error.message });
|
|
91
|
-
}
|
|
92
|
-
else if (typeof error === "string") {
|
|
93
|
-
messages.push({ message: error });
|
|
94
|
-
}
|
|
95
|
-
else if (ae.message) {
|
|
96
|
-
const err = (0, types_common_js_1.castHttpError)(ae.message);
|
|
97
|
-
if (err)
|
|
98
|
-
messages.push(err);
|
|
99
|
-
}
|
|
100
|
-
else if (ae.errors) {
|
|
101
|
-
messages.push(...this.extractZodError(ae));
|
|
102
|
-
}
|
|
103
|
-
else if (ae.payload) {
|
|
104
|
-
if (ae.payload.message && typeof ae.payload.message === "string")
|
|
105
|
-
messages.push({ message: ae.payload.message });
|
|
106
|
-
else if (typeof ae.payload === "string")
|
|
107
|
-
messages.push({ message: ae.payload });
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
messages.push({ message: "unknown" });
|
|
111
|
-
}
|
|
112
|
-
return this.httpError(res, messages, statusCode);
|
|
113
|
-
}
|
|
114
|
-
extractZodError(tree, ...contexts) {
|
|
115
|
-
const errors = tree.errors?.map((e) => ({
|
|
116
|
-
message: e,
|
|
117
|
-
context: this.contextPath(...contexts),
|
|
118
|
-
})) ?? [];
|
|
119
|
-
const items = "items" in tree && tree.items
|
|
120
|
-
? tree.items
|
|
121
|
-
: "properties" in tree && tree.properties
|
|
122
|
-
? tree.properties
|
|
123
|
-
: [];
|
|
124
|
-
if (Array.isArray(items)) {
|
|
125
|
-
for (let i = 0; i < items.length; i++)
|
|
126
|
-
errors.push(...this.extractZodError(items[i], ...contexts, i));
|
|
127
|
-
}
|
|
128
|
-
else {
|
|
129
|
-
for (const [key, item] of Object.entries(items))
|
|
130
|
-
errors.push(...this.extractZodError(item, ...contexts, key));
|
|
131
|
-
}
|
|
132
|
-
return errors;
|
|
133
|
-
}
|
|
134
|
-
contextPath(...parts) {
|
|
135
|
-
const ps = parts
|
|
136
|
-
.filter((p) => !!p)
|
|
137
|
-
.map((p) => (typeof p === "string" ? p : `${p}`));
|
|
138
|
-
return ps.join(".");
|
|
139
|
-
}
|
|
140
|
-
createFunction(exp) {
|
|
141
|
-
return (0, https_1.onRequest)({ cors: [/firebase\.com$/, /web\.app$/] }, exp);
|
|
142
|
-
}
|
|
143
|
-
async extractBody(req) {
|
|
144
|
-
if (!req.headers["content-type"])
|
|
145
|
-
throw new Error("No content type provided");
|
|
146
|
-
const body = req.body ??
|
|
147
|
-
JSON.parse(await (0, raw_body_1.default)((0, http_js_1.contentstream)(req, false), {
|
|
148
|
-
encoding: "utf-8",
|
|
149
|
-
}));
|
|
150
|
-
if (Array.isArray(body))
|
|
151
|
-
return body;
|
|
152
|
-
if (body && Object.keys(body).length > 0)
|
|
153
|
-
return body;
|
|
154
|
-
throw new Error("Invalid / not existing body");
|
|
155
|
-
}
|
|
156
|
-
async extractBodyItem(req) {
|
|
157
|
-
const extr = await this.extractBody(req);
|
|
158
|
-
if (!extr || Array.isArray(extr))
|
|
159
|
-
throw new Error(`No item found in body`);
|
|
160
|
-
return extr;
|
|
161
|
-
}
|
|
162
|
-
async extractBodyItems(req) {
|
|
163
|
-
const extr = await this.extractBody(req);
|
|
164
|
-
if (!extr || !Array.isArray(extr))
|
|
165
|
-
throw new Error(`No items found in body`);
|
|
166
|
-
return extr;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
exports.IHttpHandlerItem = IHttpHandlerItem;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FunctionHandlers = void 0;
|
|
4
|
-
class FunctionHandlers {
|
|
5
|
-
constructor() {
|
|
6
|
-
this.items = {};
|
|
7
|
-
}
|
|
8
|
-
add(handler) {
|
|
9
|
-
this.items[handler.name] = handler;
|
|
10
|
-
}
|
|
11
|
-
functions() {
|
|
12
|
-
const result = {};
|
|
13
|
-
for (const [key, item] of Object.entries(this.items))
|
|
14
|
-
result[key] = item.setup();
|
|
15
|
-
return result;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
exports.FunctionHandlers = FunctionHandlers;
|
package/dist/esm/api/IApi.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.IApi = void 0;
|
|
4
|
-
const zod_meta_1 = require("@mxpicture/zod-meta");
|
|
5
|
-
class IApi {
|
|
6
|
-
constructor(store, shape) {
|
|
7
|
-
this.store = store;
|
|
8
|
-
this.shape = shape;
|
|
9
|
-
}
|
|
10
|
-
metaItems() {
|
|
11
|
-
return new zod_meta_1.Meta(this.shape).items();
|
|
12
|
-
}
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
14
|
-
async create(doc, params) {
|
|
15
|
-
const storeDoc = await this.store.create(doc);
|
|
16
|
-
return this.fromStore(storeDoc);
|
|
17
|
-
}
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
19
|
-
async get(id, params) {
|
|
20
|
-
const storeDoc = await this.store.get(id);
|
|
21
|
-
return this.fromStore(storeDoc);
|
|
22
|
-
}
|
|
23
|
-
async query(params) {
|
|
24
|
-
const storeDocs = await this.store.query(params);
|
|
25
|
-
return await Promise.all(storeDocs.map((s) => this.fromStore(s)));
|
|
26
|
-
}
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
28
|
-
async count(params) {
|
|
29
|
-
return this.store.count();
|
|
30
|
-
}
|
|
31
|
-
async update(id, doc,
|
|
32
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
33
|
-
params) {
|
|
34
|
-
let storeDoc = await this.toStore(doc);
|
|
35
|
-
storeDoc = await this.store.update(id, storeDoc);
|
|
36
|
-
return this.fromStore(storeDoc);
|
|
37
|
-
}
|
|
38
|
-
async updatePartial(id, doc) {
|
|
39
|
-
const storeDoc = await this.toStorePartial(doc);
|
|
40
|
-
await this.store.update(id, storeDoc);
|
|
41
|
-
return this.get(id);
|
|
42
|
-
}
|
|
43
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
44
|
-
async delete(id, params) {
|
|
45
|
-
await this.store.delete(id);
|
|
46
|
-
}
|
|
47
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
48
|
-
async exists(id, params) {
|
|
49
|
-
return this.store.exists(id);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
exports.IApi = IApi;
|