@mxpicture/gcp-functions 0.1.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.
Files changed (38) hide show
  1. package/README.md +38 -0
  2. package/dist/cjs/FunctionHandlers.js +18 -0
  3. package/dist/cjs/api/IApi.js +52 -0
  4. package/dist/cjs/common/firebase.js +174 -0
  5. package/dist/cjs/common/http.js +147 -0
  6. package/dist/cjs/common/types.common.js +30 -0
  7. package/dist/cjs/handler/HttpHandler.js +41 -0
  8. package/dist/cjs/handler/IHttpHandlerItem.js +169 -0
  9. package/dist/cjs/index.js +42 -0
  10. package/dist/cjs/lib.js +25 -0
  11. package/dist/cjs/package.js +21 -0
  12. package/dist/cjs/store/IStore.js +107 -0
  13. package/dist/cjs/store/types.store.js +15 -0
  14. package/dist/esm/FunctionHandlers.js +18 -0
  15. package/dist/esm/api/IApi.js +52 -0
  16. package/dist/esm/common/firebase.js +174 -0
  17. package/dist/esm/common/http.js +147 -0
  18. package/dist/esm/common/types.common.js +30 -0
  19. package/dist/esm/handler/HttpHandler.js +41 -0
  20. package/dist/esm/handler/IHttpHandlerItem.js +169 -0
  21. package/dist/esm/index.js +42 -0
  22. package/dist/esm/lib.js +25 -0
  23. package/dist/esm/package.js +21 -0
  24. package/dist/esm/store/IStore.js +107 -0
  25. package/dist/esm/store/types.store.js +15 -0
  26. package/dist/types/FunctionHandlers.d.ts +12 -0
  27. package/dist/types/api/IApi.d.ts +27 -0
  28. package/dist/types/common/firebase.d.ts +11 -0
  29. package/dist/types/common/http.d.ts +20 -0
  30. package/dist/types/common/types.common.d.ts +31 -0
  31. package/dist/types/handler/HttpHandler.d.ts +15 -0
  32. package/dist/types/handler/IHttpHandlerItem.d.ts +23 -0
  33. package/dist/types/index.d.ts +3 -0
  34. package/dist/types/lib.d.ts +11 -0
  35. package/dist/types/package.d.ts +1 -0
  36. package/dist/types/store/IStore.d.ts +25 -0
  37. package/dist/types/store/types.store.d.ts +23 -0
  38. package/package.json +74 -0
@@ -0,0 +1,169 @@
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;
@@ -0,0 +1,42 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
19
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
+ };
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ __exportStar(require("./lib"), exports);
40
+ // A default export can help some consumers using require()
41
+ const _all = __importStar(require("./lib"));
42
+ exports.default = _all;
@@ -0,0 +1,25 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./FunctionHandlers"), exports);
18
+ __exportStar(require("./handler/IHttpHandlerItem"), exports);
19
+ __exportStar(require("./handler/HttpHandler"), exports);
20
+ __exportStar(require("./common/firebase"), exports);
21
+ __exportStar(require("./common/http"), exports);
22
+ __exportStar(require("./common/types.common"), exports);
23
+ __exportStar(require("./api/IApi"), exports);
24
+ __exportStar(require("./store/IStore"), exports);
25
+ __exportStar(require("./store/types.store"), exports);
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
3
+ /// <reference path="./types/express.d.ts" />
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
17
+ };
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ // Re-export your public types/exports so this file becomes the root .d.ts for the package.
20
+ // Adjust the relative path if your source layout differs.
21
+ __exportStar(require("./lib"), exports);
@@ -0,0 +1,107 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.IStore = exports.convertDocObject = void 0;
37
+ const firebase_js_1 = require("../common/firebase.js");
38
+ const uuid = __importStar(require("short-uuid"));
39
+ const convertDocObject = (doc) => {
40
+ if (typeof doc.data !== "function")
41
+ return doc;
42
+ return {
43
+ ...doc.data(),
44
+ createTime: doc.createTime,
45
+ updateTime: doc.updateTime,
46
+ id: doc.id,
47
+ };
48
+ };
49
+ exports.convertDocObject = convertDocObject;
50
+ class IStore {
51
+ constructor(collectionName) {
52
+ this.collectionName = collectionName;
53
+ }
54
+ db() {
55
+ if (!this._db)
56
+ this._db = firebase_js_1.db
57
+ .collection(`picpad.${this.collectionName}`)
58
+ .withConverter(this.createConverter());
59
+ return this._db;
60
+ }
61
+ async query(p) {
62
+ const snapshot = p && p.parentId
63
+ ? await this.refByParent(p.parentId).get()
64
+ : await this.db().get();
65
+ return snapshot.docs.map((exports.convertDocObject));
66
+ }
67
+ async count(p) {
68
+ const snapshot = p && p.parentId
69
+ ? await this.refByParent(p.parentId).count().get()
70
+ : await this.db().count().get();
71
+ return snapshot.data().count;
72
+ }
73
+ ref(id) {
74
+ return this.db().doc(id);
75
+ }
76
+ async get(id) {
77
+ const snapshot = await this.ref(id).get();
78
+ if (!snapshot.exists)
79
+ throw new Error(`Id ${id} does not exist`);
80
+ return (0, exports.convertDocObject)(snapshot);
81
+ }
82
+ async exists(id) {
83
+ return (await this.ref(id).get()).exists;
84
+ }
85
+ async create(doc) {
86
+ doc.id = uuid.generate();
87
+ const ref = this.ref(doc.id);
88
+ await ref.set(doc);
89
+ return this.get(doc.id);
90
+ }
91
+ async update(id, doc) {
92
+ const entry = this.ref(id);
93
+ await entry.update({ ...doc });
94
+ return this.get(id);
95
+ }
96
+ async delete(...ids) {
97
+ await Promise.all(ids.map((id) => this.ref(id).delete()));
98
+ }
99
+ async deleteByParent(parentId) {
100
+ const snapshot = await this.refByParent(parentId).get();
101
+ await this.delete(...snapshot.docs.map((doc) => doc.id));
102
+ }
103
+ refByParent(parentId) {
104
+ return this.db().where("parentId", "==", parentId);
105
+ }
106
+ }
107
+ exports.IStore = IStore;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.storePersistSchema = exports.storeBaseSchema = exports.storePersistSchemaShape = exports.storeBaseSchemaShape = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.storeBaseSchemaShape = {
6
+ id: zod_1.z.string().optional(),
7
+ createTime: zod_1.z.date().optional(),
8
+ updateTime: zod_1.z.date().optional(),
9
+ };
10
+ exports.storePersistSchemaShape = {
11
+ ...exports.storeBaseSchemaShape,
12
+ id: zod_1.z.string(),
13
+ };
14
+ exports.storeBaseSchema = zod_1.z.object(exports.storeBaseSchemaShape);
15
+ exports.storePersistSchema = zod_1.z.object(exports.storePersistSchemaShape);
@@ -0,0 +1,12 @@
1
+ import { HttpsFunction } from "firebase-functions/v2/https";
2
+ import { HttpHandler } from "./handler/HttpHandler.js";
3
+ export declare class FunctionHandlers {
4
+ protected items: {
5
+ [name: string]: HttpHandler;
6
+ };
7
+ constructor();
8
+ add(handler: HttpHandler): void;
9
+ functions(): {
10
+ [name: string]: HttpsFunction;
11
+ };
12
+ }
@@ -0,0 +1,27 @@
1
+ import { ZodRawShape, ZodSafeParseResult } from "zod";
2
+ import { IStore } from "../store/IStore.js";
3
+ import { StoreBaseDoc, StorePersistDoc } from "../store/types.store.js";
4
+ import { MetaItem } from "@mxpicture/zod-meta";
5
+ export type AdditionalParams = {
6
+ [key: string]: string;
7
+ };
8
+ export declare abstract class IApi<DOC extends StoreBaseDoc, STORE_DOC extends StorePersistDoc> {
9
+ protected store: IStore<DOC, STORE_DOC>;
10
+ protected shape: ZodRawShape;
11
+ constructor(store: IStore<DOC, STORE_DOC>, shape: ZodRawShape);
12
+ abstract validate(doc: Partial<DOC>): Promise<ZodSafeParseResult<DOC>>;
13
+ abstract validatePartial(doc: Partial<DOC>): Promise<ZodSafeParseResult<Partial<DOC>>>;
14
+ abstract toStore(doc: DOC): Promise<STORE_DOC>;
15
+ abstract toStorePartial(doc: Partial<DOC>): Promise<Partial<STORE_DOC>>;
16
+ abstract fromStore(store: STORE_DOC): Promise<DOC>;
17
+ abstract fromStorePartial(store: Partial<STORE_DOC>): Promise<Partial<DOC>>;
18
+ metaItems(): MetaItem[];
19
+ create(doc: DOC, params?: AdditionalParams): Promise<DOC>;
20
+ get(id: string, params?: AdditionalParams): Promise<DOC>;
21
+ query(params?: AdditionalParams): Promise<DOC[]>;
22
+ count(params?: AdditionalParams): Promise<number>;
23
+ update(id: string, doc: DOC, params?: AdditionalParams): Promise<DOC>;
24
+ updatePartial(id: string, doc: Partial<DOC>): Promise<DOC>;
25
+ delete(id: string, params?: AdditionalParams): Promise<void>;
26
+ exists(id: string, params?: AdditionalParams): Promise<boolean>;
27
+ }
@@ -0,0 +1,11 @@
1
+ import * as express from "express";
2
+ export declare const app: import("firebase-admin/app").App;
3
+ export declare const db: FirebaseFirestore.Firestore;
4
+ export declare const extractToken: (request: express.Request) => string | undefined;
5
+ export declare const verifyToken: (request: express.Request, response: express.Response, next: express.NextFunction) => void;
6
+ export declare const verifySessionCookie: (request: express.Request, response: express.Response, next: express.NextFunction) => void;
7
+ export declare const verifyAuthAll: (token: () => string) => (request: express.Request, response: express.Response, next: express.NextFunction) => void | express.Response<any, Record<string, any>>;
8
+ export declare const sessionLogin: (request: express.Request, response: express.Response) => void;
9
+ export declare const sessionLogout: (request: express.Request, response: express.Response) => void;
10
+ export declare const verifyConnectionToken: (token: () => string) => (request: express.Request, response: express.Response, next: express.NextFunction) => Promise<void>;
11
+ export declare const round: (value: number, digits?: number) => number;
@@ -0,0 +1,20 @@
1
+ import * as express from "express";
2
+ import * as http from "http";
3
+ import { Inflate, Deflate, Gunzip, BrotliDecompress } from "zlib";
4
+ import { DocumentData } from "./types.common.js";
5
+ export type Streams = Inflate | Gunzip | Deflate | BrotliDecompress | http.IncomingMessage;
6
+ /**
7
+ * Get the content stream of the request.
8
+ *
9
+ * @param {object} req
10
+ * @param {function} debug
11
+ * @param {boolean} [inflate=true]
12
+ * @return {object}
13
+ * @api private
14
+ */
15
+ export declare const contentstream: (req: express.Request, inflate: boolean, debug?: Console) => Streams;
16
+ export declare const hasBody: (request: http.IncomingMessage) => boolean;
17
+ /**
18
+ * Fix proxied body if bodyParser is involved.
19
+ */
20
+ export declare const fixRequestBody: (proxyReq: http.ClientRequest, requestBody: DocumentData | DocumentData[] | undefined) => void;
@@ -0,0 +1,31 @@
1
+ export declare enum HttpProtocol {
2
+ http = "http",
3
+ https = "https"
4
+ }
5
+ export declare enum HttpMethod {
6
+ POST = "POST",
7
+ PATCH = "PATCH",
8
+ PUT = "PUT",
9
+ GET = "GET",
10
+ DELETE = "DELETE"
11
+ }
12
+ export declare enum PrimitiveType {
13
+ string = "string",
14
+ number = "number",
15
+ boolean = "boolean"
16
+ }
17
+ export type primitive = string | number | boolean | Date;
18
+ export type DocumentFieldValue = any;
19
+ export type DocumentData = {
20
+ [field: string]: DocumentFieldValue;
21
+ };
22
+ export interface HttpError {
23
+ message: string;
24
+ context?: string;
25
+ }
26
+ export interface HttpResult {
27
+ errors?: HttpError[];
28
+ statusCode: number;
29
+ payload?: object | object[];
30
+ }
31
+ export declare const castHttpError: (error: Partial<HttpError>) => HttpError | undefined;
@@ -0,0 +1,15 @@
1
+ import express from "express";
2
+ import { StoreBaseDoc, StorePersistDoc } from "../store/types.store.js";
3
+ import { HttpsFunction } from "firebase-functions/v2/https";
4
+ import { IHttpHandlerItem } from "./IHttpHandlerItem.js";
5
+ export declare class HttpHandler {
6
+ readonly name: string;
7
+ readonly exp: express.Express;
8
+ readonly corsAllowList: string[];
9
+ protected readonly items: IHttpHandlerItem<StoreBaseDoc, StorePersistDoc>[];
10
+ constructor(name: string);
11
+ add<DOC extends StoreBaseDoc, STORE_DOC extends StorePersistDoc>(...items: IHttpHandlerItem<DOC, STORE_DOC>[]): HttpHandler;
12
+ protected baseSetup(): void;
13
+ setup(): HttpsFunction;
14
+ protected createFunction(): HttpsFunction;
15
+ }
@@ -0,0 +1,23 @@
1
+ import express from "express";
2
+ import { StoreBaseDoc, StorePersistDoc } from "../store/types.store.js";
3
+ import { IApi } from "../api/IApi.js";
4
+ import { HttpsFunction } from "firebase-functions/v2/https";
5
+ import { HttpError } from "../common/types.common.js";
6
+ import { StatusCodes } from "@mxpicture/http-status-codes";
7
+ import { $ZodErrorTree } from "zod/v4/core";
8
+ export declare abstract class IHttpHandlerItem<DOC extends StoreBaseDoc, STORE_DOC extends StorePersistDoc> {
9
+ readonly name: string;
10
+ readonly api: IApi<DOC, STORE_DOC>;
11
+ readonly corsAllowList: string[];
12
+ constructor(name: string, api: IApi<DOC, STORE_DOC>);
13
+ setup(exp: express.Express): void;
14
+ protected httpSuccess(res: express.Response, payload: object | object[], statusCode?: StatusCodes): express.Response;
15
+ protected httpError(res: express.Response, errors: HttpError[], statusCode?: StatusCodes): express.Response;
16
+ protected httpErrorUnnown(res: express.Response, error: unknown, statusCode?: StatusCodes): express.Response;
17
+ protected extractZodError<T>(tree: Partial<$ZodErrorTree<T, string>>, ...contexts: (string | number)[]): HttpError[];
18
+ protected contextPath(...parts: (string | number | undefined)[]): string;
19
+ protected createFunction(exp: express.Express): HttpsFunction;
20
+ protected extractBody(req: express.Request): Promise<Partial<DOC> | Partial<DOC>[]>;
21
+ protected extractBodyItem(req: express.Request): Promise<Partial<DOC>>;
22
+ protected extractBodyItems(req: express.Request): Promise<Partial<DOC>[]>;
23
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./lib";
2
+ import * as _all from "./lib";
3
+ export default _all;
@@ -0,0 +1,11 @@
1
+ export * from "./FunctionHandlers";
2
+ export * from "./handler/IHttpHandlerItem";
3
+ export * from "./handler/HttpHandler";
4
+ export * from "./common/firebase";
5
+ export * from "./common/http";
6
+ export * from "./common/types.common";
7
+ export * from "./api/IApi";
8
+ export * from "./store/IStore";
9
+ export * from "./store/types.store";
10
+ export { ZodRawShape, ZodSafeParseResult } from "zod";
11
+ export { HttpsFunction } from "firebase-functions/v2/https";
@@ -0,0 +1 @@
1
+ export * from "./lib";
@@ -0,0 +1,25 @@
1
+ import { CollectionReference, DocumentReference, DocumentSnapshot, FirestoreDataConverter } from "firebase-admin/firestore";
2
+ import { StoreBaseDoc, StorePersistDoc } from "./types.store.js";
3
+ import { DocumentData } from "../common/types.common.js";
4
+ export declare const convertDocObject: <T extends StoreBaseDoc>(doc: DocumentData | DocumentSnapshot) => T;
5
+ export declare abstract class IStore<DOC extends StoreBaseDoc, STORE_DOC extends StorePersistDoc> {
6
+ readonly collectionName: string;
7
+ protected _db?: CollectionReference<STORE_DOC>;
8
+ protected constructor(collectionName: string);
9
+ protected abstract createConverter(): FirestoreDataConverter<STORE_DOC>;
10
+ db(): CollectionReference<STORE_DOC>;
11
+ query(p?: {
12
+ parentId?: string;
13
+ }): Promise<STORE_DOC[]>;
14
+ count(p?: {
15
+ parentId?: string;
16
+ }): Promise<number>;
17
+ ref(id: string): DocumentReference;
18
+ get(id: string): Promise<STORE_DOC>;
19
+ exists(id: string): Promise<boolean>;
20
+ create(doc: DOC): Promise<STORE_DOC>;
21
+ update(id: string, doc: Partial<STORE_DOC>): Promise<STORE_DOC>;
22
+ delete(...ids: string[]): Promise<void>;
23
+ deleteByParent(parentId: string): Promise<void>;
24
+ refByParent(parentId: string): FirebaseFirestore.Query<STORE_DOC, FirebaseFirestore.DocumentData>;
25
+ }
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ export declare const storeBaseSchemaShape: {
3
+ id: z.ZodOptional<z.ZodString>;
4
+ createTime: z.ZodOptional<z.ZodDate>;
5
+ updateTime: z.ZodOptional<z.ZodDate>;
6
+ };
7
+ export declare const storePersistSchemaShape: {
8
+ id: z.ZodString;
9
+ createTime: z.ZodOptional<z.ZodDate>;
10
+ updateTime: z.ZodOptional<z.ZodDate>;
11
+ };
12
+ export declare const storeBaseSchema: z.ZodObject<{
13
+ id: z.ZodOptional<z.ZodString>;
14
+ createTime: z.ZodOptional<z.ZodDate>;
15
+ updateTime: z.ZodOptional<z.ZodDate>;
16
+ }, z.core.$strip>;
17
+ export type StoreBaseDoc = z.infer<typeof storeBaseSchema>;
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>;