@nu-art/firebase-backend 0.400.5
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/ModuleBE_Firebase.d.ts +20 -0
- package/ModuleBE_Firebase.js +69 -0
- package/auth/FirebaseBaseWrapper.d.ts +19 -0
- package/auth/FirebaseBaseWrapper.js +39 -0
- package/auth/FirebaseSession_Admin.d.ts +19 -0
- package/auth/FirebaseSession_Admin.js +45 -0
- package/auth/firebase-session.d.ts +61 -0
- package/auth/firebase-session.js +93 -0
- package/database/DatabaseWrapperBE.d.ts +71 -0
- package/database/DatabaseWrapperBE.js +182 -0
- package/database/types.d.ts +4 -0
- package/database/types.js +18 -0
- package/firestore/FirestoreCollection.d.ts +71 -0
- package/firestore/FirestoreCollection.js +184 -0
- package/firestore/FirestoreInterface.d.ts +11 -0
- package/firestore/FirestoreInterface.js +111 -0
- package/firestore/FirestoreTransaction.d.ts +30 -0
- package/firestore/FirestoreTransaction.js +153 -0
- package/firestore/FirestoreWrapperBE.d.ts +16 -0
- package/firestore/FirestoreWrapperBE.js +53 -0
- package/firestore/types.d.ts +6 -0
- package/firestore/types.js +25 -0
- package/firestore-v3/DocWrapperV3.d.ts +32 -0
- package/firestore-v3/DocWrapperV3.js +148 -0
- package/firestore-v3/FirestoreCollectionV3.d.ts +154 -0
- package/firestore-v3/FirestoreCollectionV3.js +470 -0
- package/firestore-v3/FirestoreInterfaceV3.d.ts +10 -0
- package/firestore-v3/FirestoreInterfaceV3.js +107 -0
- package/firestore-v3/FirestoreWrapperBEV3.d.ts +16 -0
- package/firestore-v3/FirestoreWrapperBEV3.js +154 -0
- package/firestore-v3/consts.d.ts +13 -0
- package/firestore-v3/consts.js +18 -0
- package/firestore-v3/types.d.ts +6 -0
- package/firestore-v3/types.js +1 -0
- package/functions/firebase-function.d.ts +38 -0
- package/functions/firebase-function.js +53 -0
- package/functions-v2/ModuleBE_BaseFunction.d.ts +11 -0
- package/functions-v2/ModuleBE_BaseFunction.js +32 -0
- package/functions-v2/ModuleBE_ExpressFunction_V2.d.ts +11 -0
- package/functions-v2/ModuleBE_ExpressFunction_V2.js +29 -0
- package/functions-v2/ModuleBE_FirebaseDBListener.d.ts +10 -0
- package/functions-v2/ModuleBE_FirebaseDBListener.js +24 -0
- package/functions-v2/ModuleBE_FirebaseScheduler.d.ts +32 -0
- package/functions-v2/ModuleBE_FirebaseScheduler.js +57 -0
- package/functions-v2/ModuleBE_FirestoreListener.d.ts +13 -0
- package/functions-v2/ModuleBE_FirestoreListener.js +21 -0
- package/functions-v2/ModuleBE_PubSubFunction.d.ts +13 -0
- package/functions-v2/ModuleBE_PubSubFunction.js +47 -0
- package/functions-v2/ModuleBE_StorageListener.d.ts +13 -0
- package/functions-v2/ModuleBE_StorageListener.js +34 -0
- package/index.d.ts +21 -0
- package/index.js +38 -0
- package/package.json +75 -0
- package/push/PushMessagesWrapperBE.d.ts +14 -0
- package/push/PushMessagesWrapperBE.js +44 -0
- package/push/types.d.ts +3 -0
- package/push/types.js +18 -0
- package/storage/StorageWrapperBE.d.ts +63 -0
- package/storage/StorageWrapperBE.js +246 -0
- package/storage/emulator.d.ts +4 -0
- package/storage/emulator.js +46 -0
- package/storage/types.d.ts +4 -0
- package/storage/types.js +18 -0
- package/tools/lock-operation.d.ts +10 -0
- package/tools/lock-operation.js +35 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Firebase is a simpler Typescript wrapper to all of firebase services.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (C) 2020 Adam van der Kruk aka TacB0sS
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
import { FirestoreCollectionV3, } from './FirestoreCollectionV3.js';
|
|
19
|
+
import { FirebaseBaseWrapper } from '../auth/FirebaseBaseWrapper.js';
|
|
20
|
+
import { Promise_all_sequentially } from '@nu-art/ts-common';
|
|
21
|
+
import { DocumentReference, DocumentSnapshot, getFirestore, QuerySnapshot, } from 'firebase-admin/firestore';
|
|
22
|
+
export class FirestoreWrapperBEV3 extends FirebaseBaseWrapper {
|
|
23
|
+
firestore;
|
|
24
|
+
collections = {};
|
|
25
|
+
constructor(firebaseSession, dbName) {
|
|
26
|
+
super(firebaseSession);
|
|
27
|
+
if (dbName)
|
|
28
|
+
this.firestore = getFirestore(firebaseSession.app, dbName);
|
|
29
|
+
else
|
|
30
|
+
this.firestore = getFirestore(firebaseSession.app);
|
|
31
|
+
}
|
|
32
|
+
runTransaction = async (processor, transaction) => {
|
|
33
|
+
if (transaction) // if a transaction was provided to be used, use it
|
|
34
|
+
return processor(transaction);
|
|
35
|
+
const postTransactionActions = [];
|
|
36
|
+
const toRet = await this.firestore.runTransaction(async (transaction) => {
|
|
37
|
+
const writeActions = [];
|
|
38
|
+
const transactionUpdates = {};
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
transaction.postTransaction = (action) => {
|
|
41
|
+
return postTransactionActions.push(action);
|
|
42
|
+
};
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
transaction.__nu_art__WriteActions = writeActions;
|
|
45
|
+
const originSet = transaction.set.bind(transaction);
|
|
46
|
+
const originDelete = transaction.delete.bind(transaction);
|
|
47
|
+
const originCreate = transaction.create.bind(transaction);
|
|
48
|
+
const originGet = transaction.get.bind(transaction);
|
|
49
|
+
const originGetAll = transaction.getAll.bind(transaction);
|
|
50
|
+
const getMockDocumentSnapshot = (data, _id, exists = true) => {
|
|
51
|
+
return {
|
|
52
|
+
id: _id,
|
|
53
|
+
ref: {}, // Mock DocumentReference
|
|
54
|
+
exists,
|
|
55
|
+
data: () => (exists ? data : undefined),
|
|
56
|
+
get: (fieldPath) => data[fieldPath],
|
|
57
|
+
metadata: {}, // Mock metadata
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
const updateTransactionUpdates = async (data, exists = true) => {
|
|
61
|
+
let _data;
|
|
62
|
+
let _id;
|
|
63
|
+
if (data instanceof DocumentReference) {
|
|
64
|
+
_id = data.id;
|
|
65
|
+
_data = (await data.get()).data();
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
_id = data._id;
|
|
69
|
+
_data = data;
|
|
70
|
+
}
|
|
71
|
+
transactionUpdates[_id] = getMockDocumentSnapshot(_data, _id, exists);
|
|
72
|
+
};
|
|
73
|
+
transaction.set = (documentRef, data) => {
|
|
74
|
+
updateTransactionUpdates(data);
|
|
75
|
+
writeActions.push(() => originSet(documentRef, data));
|
|
76
|
+
return transaction;
|
|
77
|
+
};
|
|
78
|
+
transaction.create = (documentRef, data) => {
|
|
79
|
+
updateTransactionUpdates(data);
|
|
80
|
+
writeActions.push(() => originCreate(documentRef, data));
|
|
81
|
+
return transaction;
|
|
82
|
+
};
|
|
83
|
+
transaction.delete = (documentRef, precondition) => {
|
|
84
|
+
// update deletions
|
|
85
|
+
updateTransactionUpdates(documentRef, false);
|
|
86
|
+
writeActions.push(() => originDelete(documentRef, precondition));
|
|
87
|
+
return transaction;
|
|
88
|
+
};
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
transaction.get = async (args) => {
|
|
91
|
+
// @ts-ignore
|
|
92
|
+
const doc = await originGet(args);
|
|
93
|
+
// handle doc snapshot
|
|
94
|
+
if (doc instanceof DocumentSnapshot) {
|
|
95
|
+
const document = doc.data();
|
|
96
|
+
if (!document)
|
|
97
|
+
return doc;
|
|
98
|
+
return transactionUpdates[document._id] ?? doc;
|
|
99
|
+
}
|
|
100
|
+
// handle query snapshot
|
|
101
|
+
if (doc instanceof QuerySnapshot) {
|
|
102
|
+
const docs = doc.docs;
|
|
103
|
+
// @ts-ignore
|
|
104
|
+
return {
|
|
105
|
+
docs: docs.map(doc => {
|
|
106
|
+
const _doc = doc.data();
|
|
107
|
+
if (!_doc)
|
|
108
|
+
return doc;
|
|
109
|
+
return transactionUpdates[_doc._id] ?? doc;
|
|
110
|
+
})
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return doc;
|
|
114
|
+
};
|
|
115
|
+
// @ts-ignore
|
|
116
|
+
transaction.getAll = async (...documentRefsOrReadOptions) => {
|
|
117
|
+
const docs = await originGetAll(...documentRefsOrReadOptions);
|
|
118
|
+
return docs.map(doc => {
|
|
119
|
+
const _doc = doc.data();
|
|
120
|
+
if (!_doc)
|
|
121
|
+
return doc;
|
|
122
|
+
return transactionUpdates[_doc._id] ?? doc;
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
const toRet = await processor(transaction);
|
|
126
|
+
writeActions.forEach(action => action());
|
|
127
|
+
return toRet;
|
|
128
|
+
});
|
|
129
|
+
await Promise_all_sequentially(postTransactionActions);
|
|
130
|
+
return toRet;
|
|
131
|
+
};
|
|
132
|
+
getCollection(dbDef, hooks) {
|
|
133
|
+
const collection = this.collections[dbDef.dbKey];
|
|
134
|
+
if (collection)
|
|
135
|
+
return collection;
|
|
136
|
+
return this.collections[dbDef.dbKey] = new FirestoreCollectionV3(this, dbDef, hooks);
|
|
137
|
+
}
|
|
138
|
+
listen(collection, doc) {
|
|
139
|
+
collection.wrapper.firestore.doc(`${collection.collection.path}/${doc}`).onSnapshot(() => {
|
|
140
|
+
this.logInfo('received snapshot!');
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// public async deleteCollection(name: string) {
|
|
144
|
+
// return this.getCollection(name).deleteAll();
|
|
145
|
+
// }
|
|
146
|
+
async listCollections() {
|
|
147
|
+
if (!this.firestore.listCollections)
|
|
148
|
+
return [];
|
|
149
|
+
return this.firestore.listCollections();
|
|
150
|
+
}
|
|
151
|
+
isEmulator() {
|
|
152
|
+
return !!process.env.FIRESTORE_EMULATOR_HOST || false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Dispatcher, UniqueId } from '@nu-art/ts-common';
|
|
2
|
+
import { CanDeleteDBEntitiesProto } from './types.js';
|
|
3
|
+
import { MemKey } from '@nu-art/ts-common/mem-storage/MemStorage';
|
|
4
|
+
import { PotentialDependenciesToDelete } from '@nu-art/firebase-shared';
|
|
5
|
+
export declare const canDeleteDispatcherV3: Dispatcher<CanDeleteDBEntitiesProto, "__canDeleteEntitiesProto", [type: any, itemIds: string[], transaction?: FirebaseFirestore.Transaction | undefined], import("@nu-art/firebase-shared").DB_EntityDependencyV2>;
|
|
6
|
+
export type MemKey_DeletedDocs_Type = {
|
|
7
|
+
transaction: FirebaseFirestore.Transaction;
|
|
8
|
+
deleted: {
|
|
9
|
+
[dbKey: string]: Set<UniqueId>;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
export declare const MemKey_DeletedDocs: MemKey<MemKey_DeletedDocs_Type[]>;
|
|
13
|
+
export declare function addDeletedToTransaction(transaction: FirebaseFirestore.Transaction | undefined, deleted: PotentialDependenciesToDelete): void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Dispatcher } from '@nu-art/ts-common';
|
|
2
|
+
import { MemKey } from '@nu-art/ts-common/mem-storage/MemStorage';
|
|
3
|
+
export const canDeleteDispatcherV3 = new Dispatcher('__canDeleteEntitiesProto');
|
|
4
|
+
export const MemKey_DeletedDocs = new MemKey('deleted--docs');
|
|
5
|
+
export function addDeletedToTransaction(transaction, deleted) {
|
|
6
|
+
if (!transaction)
|
|
7
|
+
return;
|
|
8
|
+
const storage = MemKey_DeletedDocs.get([]);
|
|
9
|
+
let item = storage.find(i => i.transaction === transaction);
|
|
10
|
+
if (!item) {
|
|
11
|
+
item = { transaction, deleted: {} };
|
|
12
|
+
storage.push(item);
|
|
13
|
+
}
|
|
14
|
+
if (!item.deleted[deleted.dbKey])
|
|
15
|
+
item.deleted[deleted.dbKey] = new Set();
|
|
16
|
+
deleted.ids.forEach(id => item.deleted[deleted.dbKey].add(id));
|
|
17
|
+
MemKey_DeletedDocs.set(storage);
|
|
18
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { DBProto } from '@nu-art/ts-common';
|
|
2
|
+
import { DB_EntityDependencyV2 } from '@nu-art/firebase-shared';
|
|
3
|
+
import { Transaction } from 'firebase-admin/firestore';
|
|
4
|
+
export type CanDeleteDBEntitiesProto = {
|
|
5
|
+
__canDeleteEntitiesProto: <T extends DBProto<any>>(type: T['dbKey'], itemIds: string[], transaction?: Transaction) => Promise<DB_EntityDependencyV2>;
|
|
6
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Express } from 'express';
|
|
2
|
+
import { StringMap } from '@nu-art/ts-common';
|
|
3
|
+
import { HttpsFunction, HttpsOptions } from 'firebase-functions/v2/https';
|
|
4
|
+
export interface TBR_ExpressFunctionInterface {
|
|
5
|
+
getExpressFunction(): Firebase_ExpressFunction;
|
|
6
|
+
}
|
|
7
|
+
export interface FirebaseFunctionInterface {
|
|
8
|
+
getFunction(): HttpsFunction;
|
|
9
|
+
onFunctionReady(): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export declare class Firebase_ExpressFunction implements FirebaseFunctionInterface {
|
|
12
|
+
private readonly express;
|
|
13
|
+
private function;
|
|
14
|
+
private toBeExecuted;
|
|
15
|
+
private isReady;
|
|
16
|
+
private toBeResolved;
|
|
17
|
+
private name;
|
|
18
|
+
static config: HttpsOptions;
|
|
19
|
+
constructor(_express: Express);
|
|
20
|
+
setName(name: string): this;
|
|
21
|
+
static setConfig(config: HttpsOptions): void;
|
|
22
|
+
getName(): string;
|
|
23
|
+
getFunction: () => HttpsFunction;
|
|
24
|
+
onFunctionReady: () => Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export type FirestoreConfigs = {
|
|
27
|
+
runTimeOptions?: HttpsOptions;
|
|
28
|
+
configs: any;
|
|
29
|
+
};
|
|
30
|
+
export type BucketConfigs = {
|
|
31
|
+
runtimeOpts?: HttpsOptions;
|
|
32
|
+
path: string;
|
|
33
|
+
bucketName?: string;
|
|
34
|
+
};
|
|
35
|
+
export type TopicMessage = {
|
|
36
|
+
data: string;
|
|
37
|
+
attributes: StringMap;
|
|
38
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { addItemToArray } from '@nu-art/ts-common';
|
|
2
|
+
import { onRequest } from 'firebase-functions/v2/https';
|
|
3
|
+
export class Firebase_ExpressFunction {
|
|
4
|
+
express;
|
|
5
|
+
function;
|
|
6
|
+
toBeExecuted = [];
|
|
7
|
+
isReady = false;
|
|
8
|
+
toBeResolved;
|
|
9
|
+
name = 'api';
|
|
10
|
+
static config = {};
|
|
11
|
+
constructor(_express) {
|
|
12
|
+
this.express = _express;
|
|
13
|
+
}
|
|
14
|
+
setName(name) {
|
|
15
|
+
this.name = name;
|
|
16
|
+
return this;
|
|
17
|
+
}
|
|
18
|
+
static setConfig(config) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
}
|
|
21
|
+
getName() {
|
|
22
|
+
return this.name;
|
|
23
|
+
}
|
|
24
|
+
getFunction = () => {
|
|
25
|
+
if (this.function)
|
|
26
|
+
return this.function;
|
|
27
|
+
const realFunction = onRequest(Firebase_ExpressFunction.config, this.express);
|
|
28
|
+
return this.function = onRequest(Firebase_ExpressFunction.config, (req, res) => {
|
|
29
|
+
if (this.isReady) {
|
|
30
|
+
return realFunction(req, res);
|
|
31
|
+
}
|
|
32
|
+
return new Promise((resolve) => {
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
addItemToArray(this.toBeExecuted, () => realFunction(req, res));
|
|
35
|
+
this.toBeResolved = resolve;
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
onFunctionReady = async () => {
|
|
40
|
+
this.isReady = true;
|
|
41
|
+
const toBeExecuted = this.toBeExecuted;
|
|
42
|
+
this.toBeExecuted = [];
|
|
43
|
+
for (const toExecute of toBeExecuted) {
|
|
44
|
+
try {
|
|
45
|
+
await toExecute();
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
console.error('Error running function: ', e);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
this.toBeResolved && this.toBeResolved();
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Module } from '@nu-art/ts-common';
|
|
2
|
+
import { FirebaseFunctionInterface } from '../functions/firebase-function.js';
|
|
3
|
+
export declare abstract class ModuleBE_BaseFunction<Config = any> extends Module<Config> implements FirebaseFunctionInterface {
|
|
4
|
+
protected isReady: boolean;
|
|
5
|
+
protected toBeExecuted: (() => Promise<any>)[];
|
|
6
|
+
protected toBeResolved: (value?: (PromiseLike<any>)) => void;
|
|
7
|
+
protected constructor(tag?: string);
|
|
8
|
+
abstract getFunction(): any;
|
|
9
|
+
protected handleCallback(callback: () => Promise<any>): Promise<any>;
|
|
10
|
+
onFunctionReady: () => Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { addItemToArray, dispatch_onApplicationNotification, Module, ServerErrorSeverity } from '@nu-art/ts-common';
|
|
2
|
+
export class ModuleBE_BaseFunction extends Module {
|
|
3
|
+
isReady = false;
|
|
4
|
+
toBeExecuted = [];
|
|
5
|
+
toBeResolved;
|
|
6
|
+
constructor(tag) {
|
|
7
|
+
super(tag);
|
|
8
|
+
this.onFunctionReady = this.onFunctionReady.bind(this);
|
|
9
|
+
}
|
|
10
|
+
async handleCallback(callback) {
|
|
11
|
+
if (this.isReady)
|
|
12
|
+
return await callback();
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
addItemToArray(this.toBeExecuted, async () => await callback());
|
|
15
|
+
this.toBeResolved = resolve;
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
onFunctionReady = async () => {
|
|
19
|
+
this.isReady = true;
|
|
20
|
+
const toBeExecuted = this.toBeExecuted;
|
|
21
|
+
this.toBeExecuted = [];
|
|
22
|
+
for (const toExecute of toBeExecuted) {
|
|
23
|
+
try {
|
|
24
|
+
await toExecute();
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
await dispatch_onApplicationNotification.dispatchModuleAsync(ServerErrorSeverity.Critical, this, e.message);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
this.toBeResolved && this.toBeResolved();
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
2
|
+
import { Express } from 'express';
|
|
3
|
+
import { HttpsFunction, HttpsOptions } from 'firebase-functions/v2/https';
|
|
4
|
+
export declare class ModuleBE_ExpressFunction_V2<Config = {}> extends ModuleBE_BaseFunction<{
|
|
5
|
+
options: HttpsOptions;
|
|
6
|
+
} & Config> {
|
|
7
|
+
private function;
|
|
8
|
+
protected constructor(name?: string);
|
|
9
|
+
getFunction: () => HttpsFunction;
|
|
10
|
+
protected createFunction(_express: Express): HttpsFunction;
|
|
11
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
2
|
+
import { addItemToArray } from '@nu-art/ts-common';
|
|
3
|
+
import express from 'express';
|
|
4
|
+
import { onRequest } from 'firebase-functions/v2/https';
|
|
5
|
+
export class ModuleBE_ExpressFunction_V2 extends ModuleBE_BaseFunction {
|
|
6
|
+
function;
|
|
7
|
+
constructor(name = 'api') {
|
|
8
|
+
super(name);
|
|
9
|
+
}
|
|
10
|
+
getFunction = () => {
|
|
11
|
+
if (this.function)
|
|
12
|
+
return this.function;
|
|
13
|
+
const _express = express();
|
|
14
|
+
const realFunction = this.createFunction(_express);
|
|
15
|
+
return this.function = onRequest(this.config.options, (req, res) => {
|
|
16
|
+
if (this.isReady) { // @ts-ignore
|
|
17
|
+
return realFunction(req, res);
|
|
18
|
+
}
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
// @ts-ignore
|
|
21
|
+
addItemToArray(this.toBeExecuted, () => realFunction(req, res));
|
|
22
|
+
this.toBeResolved = resolve;
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
createFunction(_express) {
|
|
27
|
+
return onRequest(this.config.options, _express);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
2
|
+
export declare abstract class ModuleBE_FirebaseDBListener<DataType = any, ConfigType = any> extends ModuleBE_BaseFunction<ConfigType> {
|
|
3
|
+
private readonly listeningPath;
|
|
4
|
+
private function;
|
|
5
|
+
protected constructor(listeningPath: string, name?: string);
|
|
6
|
+
abstract processChanges(before: DataType, after: DataType, params: {
|
|
7
|
+
[param: string]: any;
|
|
8
|
+
}): Promise<any>;
|
|
9
|
+
getFunction: () => import("firebase-functions").CloudFunction<import("firebase-functions/database").DatabaseEvent<import("firebase-functions").Change<import("firebase-functions/database").DataSnapshot>, Record<string, string>>>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { deepClone } from '@nu-art/ts-common';
|
|
2
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
3
|
+
import { onValueWritten } from 'firebase-functions/v2/database';
|
|
4
|
+
export class ModuleBE_FirebaseDBListener extends ModuleBE_BaseFunction {
|
|
5
|
+
listeningPath;
|
|
6
|
+
function;
|
|
7
|
+
constructor(listeningPath, name) {
|
|
8
|
+
super();
|
|
9
|
+
if (name)
|
|
10
|
+
this.setName(name);
|
|
11
|
+
this.listeningPath = listeningPath;
|
|
12
|
+
}
|
|
13
|
+
getFunction = () => {
|
|
14
|
+
if (this.function)
|
|
15
|
+
return this.function;
|
|
16
|
+
const handler = (event) => {
|
|
17
|
+
const before = event.data.before && event.data.before.val();
|
|
18
|
+
const after = event.data.after && event.data.after.val();
|
|
19
|
+
const params = deepClone(event.params);
|
|
20
|
+
return this.handleCallback(() => this.processChanges(before, after, params));
|
|
21
|
+
};
|
|
22
|
+
return this.function = onValueWritten(this.listeningPath, handler);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
2
|
+
import { ScheduleFunction, ScheduleOptions } from 'firebase-functions/v2/scheduler';
|
|
3
|
+
/**
|
|
4
|
+
An abstract class representing a scheduled Firebase Cloud Function.
|
|
5
|
+
It extends the FirebaseFunction class and adds scheduling capabilities.
|
|
6
|
+
*/
|
|
7
|
+
export declare abstract class ModuleBE_FirebaseScheduler<ConfigType = any> extends ModuleBE_BaseFunction<ConfigType & ScheduleOptions> {
|
|
8
|
+
private function;
|
|
9
|
+
private runningCondition;
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* @param name
|
|
13
|
+
* @param tag
|
|
14
|
+
* @protected
|
|
15
|
+
*/
|
|
16
|
+
protected constructor(name?: string, tag?: string);
|
|
17
|
+
/**
|
|
18
|
+
* Add a running condition to the list of conditions that must pass in order for the backup to execute
|
|
19
|
+
*/
|
|
20
|
+
addRunningCondition(runningCondition: () => Promise<boolean>): this;
|
|
21
|
+
/**
|
|
22
|
+
* Set the schedule for this scheduled event
|
|
23
|
+
*/
|
|
24
|
+
setSchedule(schedule: string): this;
|
|
25
|
+
abstract onScheduledEvent(): Promise<any>;
|
|
26
|
+
/**
|
|
27
|
+
* Check all running conditions,
|
|
28
|
+
* return early if any fail
|
|
29
|
+
*/
|
|
30
|
+
private _onScheduledEvent;
|
|
31
|
+
getFunction: () => ScheduleFunction;
|
|
32
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { addItemToArray, ImplementationMissingException } from '@nu-art/ts-common';
|
|
2
|
+
import { MemStorage } from '@nu-art/ts-common/mem-storage/MemStorage';
|
|
3
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
4
|
+
import { onSchedule } from 'firebase-functions/v2/scheduler';
|
|
5
|
+
/**
|
|
6
|
+
An abstract class representing a scheduled Firebase Cloud Function.
|
|
7
|
+
It extends the FirebaseFunction class and adds scheduling capabilities.
|
|
8
|
+
*/
|
|
9
|
+
export class ModuleBE_FirebaseScheduler extends ModuleBE_BaseFunction {
|
|
10
|
+
function;
|
|
11
|
+
runningCondition = [async () => true];
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param name
|
|
15
|
+
* @param tag
|
|
16
|
+
* @protected
|
|
17
|
+
*/
|
|
18
|
+
constructor(name, tag) {
|
|
19
|
+
super(tag);
|
|
20
|
+
name && this.setName(name);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Add a running condition to the list of conditions that must pass in order for the backup to execute
|
|
24
|
+
*/
|
|
25
|
+
addRunningCondition(runningCondition) {
|
|
26
|
+
addItemToArray(this.runningCondition, runningCondition);
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Set the schedule for this scheduled event
|
|
31
|
+
*/
|
|
32
|
+
setSchedule(schedule) {
|
|
33
|
+
this.config.schedule = schedule;
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check all running conditions,
|
|
38
|
+
* return early if any fail
|
|
39
|
+
*/
|
|
40
|
+
_onScheduledEvent = async () => {
|
|
41
|
+
const results = await Promise.all(this.runningCondition.map(condition => condition()));
|
|
42
|
+
if (results.includes(false)) {
|
|
43
|
+
this.logDebug('will not execute backup.. running conditions didn\'t pass: ', results);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
return this.onScheduledEvent();
|
|
47
|
+
};
|
|
48
|
+
getFunction = () => {
|
|
49
|
+
if (!this.config.schedule)
|
|
50
|
+
throw new ImplementationMissingException('MUST set schedule !!');
|
|
51
|
+
if (this.function)
|
|
52
|
+
return this.function;
|
|
53
|
+
return this.function = onSchedule(this.config, async () => {
|
|
54
|
+
return this.handleCallback(() => new MemStorage().init(this._onScheduledEvent));
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TS_Object } from '@nu-art/ts-common';
|
|
2
|
+
import { FirestoreConfigs } from '../functions/firebase-function.js';
|
|
3
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
4
|
+
import { DocumentOptions, DocumentSnapshot, FirestoreEvent } from 'firebase-functions/v2/firestore';
|
|
5
|
+
import { Change, CloudFunction } from 'firebase-functions/v2';
|
|
6
|
+
export declare abstract class ModuleBE_FirestoreListener<DataType extends TS_Object, ConfigType extends FirestoreConfigs = FirestoreConfigs> extends ModuleBE_BaseFunction<ConfigType & DocumentOptions> {
|
|
7
|
+
private function;
|
|
8
|
+
protected constructor(collectionName: string, name?: string, tag?: string);
|
|
9
|
+
abstract processChanges(params: {
|
|
10
|
+
[param: string]: any;
|
|
11
|
+
}, before?: DataType, after?: DataType): Promise<any>;
|
|
12
|
+
getFunction: () => CloudFunction<FirestoreEvent<Change<DocumentSnapshot> | undefined, Record<string, string>>> | undefined;
|
|
13
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { deepClone } from '@nu-art/ts-common';
|
|
2
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
3
|
+
import { onDocumentWritten } from 'firebase-functions/v2/firestore';
|
|
4
|
+
export class ModuleBE_FirestoreListener extends ModuleBE_BaseFunction {
|
|
5
|
+
function;
|
|
6
|
+
constructor(collectionName, name, tag) {
|
|
7
|
+
super(tag);
|
|
8
|
+
name && this.setName(name);
|
|
9
|
+
this.setDefaultConfig({ document: `${collectionName}/{docId}` });
|
|
10
|
+
}
|
|
11
|
+
getFunction = () => {
|
|
12
|
+
if (this.function)
|
|
13
|
+
return this.function;
|
|
14
|
+
this.function = onDocumentWritten(this.config, event => {
|
|
15
|
+
const before = event.data?.before && event.data?.before.data();
|
|
16
|
+
const after = event.data?.after && event.data?.after.data();
|
|
17
|
+
const params = deepClone(event.params);
|
|
18
|
+
return this.handleCallback(() => this.processChanges(params, before, after));
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TS_Object } from '@nu-art/ts-common';
|
|
2
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
3
|
+
import { TopicMessage } from '../functions/firebase-function.js';
|
|
4
|
+
import { CloudEvent, CloudFunction } from 'firebase-functions/v2';
|
|
5
|
+
import { MessagePublishedData } from 'firebase-functions/v2/pubsub';
|
|
6
|
+
export declare abstract class ModuleBE_PubSubFunction<T extends TS_Object> extends ModuleBE_BaseFunction {
|
|
7
|
+
private function;
|
|
8
|
+
private readonly topic;
|
|
9
|
+
protected constructor(topic: string, tag?: string);
|
|
10
|
+
abstract onPublish(object: T | undefined, originalMessage: TopicMessage, event: CloudEvent<MessagePublishedData>): Promise<any>;
|
|
11
|
+
private _onPublish;
|
|
12
|
+
getFunction: () => CloudFunction<CloudEvent<MessagePublishedData<any>>>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { __stringify, dispatch_onApplicationNotification, ImplementationMissingException, ServerErrorSeverity } from '@nu-art/ts-common';
|
|
2
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
3
|
+
import { onMessagePublished } from 'firebase-functions/v2/pubsub';
|
|
4
|
+
export class ModuleBE_PubSubFunction extends ModuleBE_BaseFunction {
|
|
5
|
+
function;
|
|
6
|
+
topic;
|
|
7
|
+
constructor(topic, tag) {
|
|
8
|
+
super(tag);
|
|
9
|
+
this.topic = topic;
|
|
10
|
+
}
|
|
11
|
+
_onPublish = async (object, originalMessage, event) => {
|
|
12
|
+
try {
|
|
13
|
+
return await this.onPublish(object, originalMessage, event);
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
const _message = `Error publishing pub/sub message` + __stringify(object) +
|
|
17
|
+
'\n' + ` to topic ${this.topic}` + '\n with attributes: ' + __stringify(originalMessage.attributes) + '\n' + __stringify(e);
|
|
18
|
+
this.logError(_message);
|
|
19
|
+
try {
|
|
20
|
+
await dispatch_onApplicationNotification.dispatchModuleAsync(ServerErrorSeverity.Critical, this, { message: _message });
|
|
21
|
+
}
|
|
22
|
+
catch (_e) {
|
|
23
|
+
this.logError('Error while handing pubsub error', _e);
|
|
24
|
+
}
|
|
25
|
+
throw e;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
getFunction = () => {
|
|
29
|
+
if (!this.config.topic)
|
|
30
|
+
throw new ImplementationMissingException('MUST set a topic !!');
|
|
31
|
+
if (this.function)
|
|
32
|
+
return this.function;
|
|
33
|
+
return this.function = onMessagePublished(this.config, async (event) => {
|
|
34
|
+
// need to validate etc...
|
|
35
|
+
const originalMessage = event.data.message;
|
|
36
|
+
let data;
|
|
37
|
+
try {
|
|
38
|
+
data = JSON.parse(Buffer.from(originalMessage.data, 'base64').toString());
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
this.logError(`Error parsing the data attribute from pub/sub message to topic ${this.topic}` +
|
|
42
|
+
'\n' + __stringify(originalMessage.data) + '\n' + __stringify(e));
|
|
43
|
+
}
|
|
44
|
+
return this.handleCallback(() => this._onPublish(data, originalMessage, event));
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
2
|
+
import { StorageEvent, StorageOptions } from 'firebase-functions/v2/storage';
|
|
3
|
+
import { CloudFunction } from 'firebase-functions/v2';
|
|
4
|
+
type Created = {
|
|
5
|
+
path: string;
|
|
6
|
+
} & StorageOptions;
|
|
7
|
+
export declare abstract class ModuleBE_StorageListener<ConfigType> extends ModuleBE_BaseFunction<ConfigType & Created> {
|
|
8
|
+
private function;
|
|
9
|
+
protected constructor(path?: string, name?: string);
|
|
10
|
+
abstract onFinalize(event: StorageEvent): Promise<any>;
|
|
11
|
+
getFunction: () => CloudFunction<StorageEvent>;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { __stringify, dispatch_onApplicationNotification, ServerErrorSeverity } from '@nu-art/ts-common';
|
|
2
|
+
import { ModuleBE_BaseFunction } from './ModuleBE_BaseFunction.js';
|
|
3
|
+
import { onObjectFinalized } from 'firebase-functions/v2/storage';
|
|
4
|
+
export class ModuleBE_StorageListener extends ModuleBE_BaseFunction {
|
|
5
|
+
function;
|
|
6
|
+
constructor(path, name) {
|
|
7
|
+
super();
|
|
8
|
+
if (path)
|
|
9
|
+
this.setDefaultConfig({ path: path, timeoutSeconds: 300, memory: '2GB' });
|
|
10
|
+
name && this.setName(name);
|
|
11
|
+
}
|
|
12
|
+
getFunction = () => {
|
|
13
|
+
if (this.function)
|
|
14
|
+
return this.function;
|
|
15
|
+
const handler = async (event) => {
|
|
16
|
+
try {
|
|
17
|
+
return await this.handleCallback(() => this.onFinalize(event));
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
const _message = `Error handling callback to onFinalize bucket listener method on path:` + this.config.path +
|
|
21
|
+
'\n' + `File changed ${event.data.name}` + '\n with attributes: ' + __stringify(context) + '\n' + __stringify(e);
|
|
22
|
+
this.logError(_message);
|
|
23
|
+
try {
|
|
24
|
+
await dispatch_onApplicationNotification.dispatchModuleAsync(ServerErrorSeverity.Critical, this, { message: _message });
|
|
25
|
+
}
|
|
26
|
+
catch (_e) {
|
|
27
|
+
this.logError('Error while handing bucket listener error', _e);
|
|
28
|
+
}
|
|
29
|
+
throw e;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
return this.function = onObjectFinalized(this.config, handler);
|
|
33
|
+
};
|
|
34
|
+
}
|