@flowerforce/flowerbase 1.4.1 → 1.4.2-beta.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/dist/features/functions/controller.d.ts.map +1 -1
- package/dist/features/functions/controller.js +12 -0
- package/dist/features/triggers/interface.d.ts +1 -1
- package/dist/features/triggers/interface.d.ts.map +1 -1
- package/dist/features/triggers/utils.d.ts.map +1 -1
- package/dist/features/triggers/utils.js +44 -3
- package/dist/utils/context/index.d.ts.map +1 -1
- package/dist/utils/context/index.js +51 -63
- package/package.json +1 -1
- package/src/features/functions/controller.ts +11 -0
- package/src/features/triggers/interface.ts +1 -1
- package/src/features/triggers/utils.ts +42 -1
- package/src/utils/context/index.ts +81 -88
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/features/functions/controller.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/features/functions/controller.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AA2ChD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,kBAwJjC,CAAA"}
|
|
@@ -38,6 +38,14 @@ const formatFunctionExecutionError = (error) => {
|
|
|
38
38
|
const name = typeof (err === null || err === void 0 ? void 0 : err.name) === 'string' ? err.name : 'Error';
|
|
39
39
|
return JSON.stringify({ message, name });
|
|
40
40
|
};
|
|
41
|
+
const isReturnedError = (value) => {
|
|
42
|
+
if (value instanceof Error)
|
|
43
|
+
return true;
|
|
44
|
+
if (!value || typeof value !== 'object')
|
|
45
|
+
return false;
|
|
46
|
+
const candidate = value;
|
|
47
|
+
return typeof candidate.message === 'string' && typeof candidate.name === 'string';
|
|
48
|
+
};
|
|
41
49
|
/**
|
|
42
50
|
* > Creates a pre handler for every query
|
|
43
51
|
* @param app -> the fastify instance
|
|
@@ -96,6 +104,10 @@ const functionsController = (app_1, _a) => __awaiter(void 0, [app_1, _a], void 0
|
|
|
96
104
|
functionsList,
|
|
97
105
|
services: services_1.services
|
|
98
106
|
});
|
|
107
|
+
if (isReturnedError(result)) {
|
|
108
|
+
res.type('application/json');
|
|
109
|
+
return JSON.stringify({ message: result.message, name: result.name });
|
|
110
|
+
}
|
|
99
111
|
res.type('application/json');
|
|
100
112
|
return JSON.stringify(result);
|
|
101
113
|
}
|
|
@@ -22,7 +22,7 @@ type Config = {
|
|
|
22
22
|
isAutoTrigger?: boolean;
|
|
23
23
|
match: Record<string, unknown>;
|
|
24
24
|
operation_types: string[];
|
|
25
|
-
operation_type?: 'CREATE' | 'DELETE';
|
|
25
|
+
operation_type?: 'CREATE' | 'DELETE' | 'LOGOUT';
|
|
26
26
|
project: Record<string, unknown>;
|
|
27
27
|
service_name: string;
|
|
28
28
|
skip_catchup_events: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../../src/features/triggers/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAE5D,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE;QAChB,QAAQ,EAAE;YACR,MAAM,EAAE;gBACN,aAAa,EAAE,MAAM,CAAA;aACtB,CAAA;SACF,CAAA;KACF,CAAA;CACF;AAED,KAAK,MAAM,GAAG;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,OAAO,CAAA;IACtB,2BAA2B,EAAE,OAAO,CAAA;IACpC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,cAAc,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../../src/features/triggers/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAE5D,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,EAAE;QAChB,QAAQ,EAAE;YACR,MAAM,EAAE;gBACN,aAAa,EAAE,MAAM,CAAA;aACtB,CAAA;SACF,CAAA;KACF,CAAA;CACF;AAED,KAAK,MAAM,GAAG;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,OAAO,CAAA;IACtB,2BAA2B,EAAE,OAAO,CAAA;IACpC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,eAAe,EAAE,MAAM,EAAE,CAAA;IACzB,cAAc,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAA;IAC/C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,YAAY,EAAE,MAAM,CAAA;IACpB,mBAAmB,EAAE,OAAO,CAAA;IAC5B,sBAAsB,EAAE,OAAO,CAAA;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG,UAAU,GAAG,gBAAgB,CAAA;AACrE,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,EAAE,CAAA;AAE/D,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,QAAQ,CAAA;IACxB,GAAG,EAAE,eAAe,CAAA;IACpB,QAAQ,EAAE,QAAQ,CAAA;IAClB,aAAa,EAAE,SAAS,CAAA;CACzB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/features/triggers/utils.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAA;AAqC9D;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GAAU,gBAAuB,KAAG,OAAO,CAAC,QAAQ,CAkB5E,CAAA;
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/features/triggers/utils.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,aAAa,EAAW,QAAQ,EAAE,MAAM,aAAa,CAAA;AAqC9D;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GAAU,gBAAuB,KAAG,OAAO,CAAC,QAAQ,CAkB5E,CAAA;AAuYD,eAAO,MAAM,gBAAgB;0EAnX1B,aAAa;yEA8Tb,aAAa;+EAnSb,aAAa;CA4Vf,CAAA"}
|
|
@@ -120,6 +120,7 @@ const handleCronTrigger = (_a) => __awaiter(void 0, [_a], void 0, function* ({ c
|
|
|
120
120
|
const mapOpInverse = {
|
|
121
121
|
CREATE: ['insert', 'update', 'replace'],
|
|
122
122
|
DELETE: ['delete'],
|
|
123
|
+
LOGOUT: ['update'],
|
|
123
124
|
};
|
|
124
125
|
const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, function* ({ config, triggerHandler, functionsList, services, app }) {
|
|
125
126
|
var _b;
|
|
@@ -150,7 +151,7 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
|
|
|
150
151
|
});
|
|
151
152
|
changeStream.on('change', function (change) {
|
|
152
153
|
return __awaiter(this, void 0, void 0, function* () {
|
|
153
|
-
var _a
|
|
154
|
+
var _a;
|
|
154
155
|
const operationType = change['operationType'];
|
|
155
156
|
const documentKey = change['documentKey'];
|
|
156
157
|
const fullDocument = change['fullDocument'];
|
|
@@ -159,11 +160,13 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
|
|
|
159
160
|
return;
|
|
160
161
|
}
|
|
161
162
|
const updateDescription = change['updateDescription'];
|
|
162
|
-
const
|
|
163
|
+
const updatedFields = updateDescription === null || updateDescription === void 0 ? void 0 : updateDescription.updatedFields;
|
|
164
|
+
const updatedStatus = updatedFields === null || updatedFields === void 0 ? void 0 : updatedFields.status;
|
|
163
165
|
const isInsert = operationType === 'insert';
|
|
164
166
|
const isUpdate = operationType === 'update';
|
|
165
167
|
const isReplace = operationType === 'replace';
|
|
166
168
|
const isDelete = operationType === 'delete';
|
|
169
|
+
const isLogoutUpdate = isUpdate && !!updatedFields && 'lastLogoutAt' in updatedFields;
|
|
167
170
|
let confirmedCandidate = false;
|
|
168
171
|
let confirmedDocument = fullDocument;
|
|
169
172
|
const buildUserData = (document) => {
|
|
@@ -189,6 +192,44 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
|
|
|
189
192
|
email: currentUser.email
|
|
190
193
|
} });
|
|
191
194
|
};
|
|
195
|
+
if (operation_type === 'LOGOUT') {
|
|
196
|
+
if (!isLogoutUpdate) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
let logoutDocument = fullDocument !== null && fullDocument !== void 0 ? fullDocument : confirmedDocument;
|
|
200
|
+
if (!logoutDocument && (documentKey === null || documentKey === void 0 ? void 0 : documentKey._id)) {
|
|
201
|
+
logoutDocument = (yield collection.findOne({
|
|
202
|
+
_id: documentKey._id
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
const userData = buildUserData(logoutDocument);
|
|
206
|
+
if (!userData) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const op = {
|
|
210
|
+
operationType: 'LOGOUT',
|
|
211
|
+
fullDocument,
|
|
212
|
+
fullDocumentBeforeChange,
|
|
213
|
+
documentKey,
|
|
214
|
+
updateDescription
|
|
215
|
+
};
|
|
216
|
+
try {
|
|
217
|
+
yield (0, context_1.GenerateContext)({
|
|
218
|
+
args: [Object.assign({ user: userData }, op)],
|
|
219
|
+
app,
|
|
220
|
+
rules: state_1.StateManager.select("rules"),
|
|
221
|
+
user: {}, // TODO from currentUser ??
|
|
222
|
+
currentFunction: triggerHandler,
|
|
223
|
+
functionsList,
|
|
224
|
+
services,
|
|
225
|
+
runAsSystem: true
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error);
|
|
230
|
+
}
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
192
233
|
if (isDelete) {
|
|
193
234
|
if (isAutoTrigger || operation_type !== 'DELETE') {
|
|
194
235
|
return;
|
|
@@ -279,7 +320,7 @@ const handleAuthenticationTrigger = (_a) => __awaiter(void 0, [_a], void 0, func
|
|
|
279
320
|
}, {
|
|
280
321
|
returnDocument: 'after'
|
|
281
322
|
});
|
|
282
|
-
const document = (
|
|
323
|
+
const document = (_a = updateResult === null || updateResult === void 0 ? void 0 : updateResult.value) !== null && _a !== void 0 ? _a : confirmedDocument;
|
|
283
324
|
if (!document) {
|
|
284
325
|
return;
|
|
285
326
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/context/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AA0GnD;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,EACpC,IAAI,EACJ,GAAG,EACH,KAAK,EACL,IAAI,EACJ,eAAe,EACf,aAAa,EACb,QAAQ,EACR,WAAW,EACX,eAAsB,EACtB,OAAO,EACP,OAAO,EACR,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/context/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AA0GnD;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,EACpC,IAAI,EACJ,GAAG,EACH,KAAK,EACL,IAAI,EACJ,eAAe,EACf,aAAa,EACb,QAAQ,EACR,WAAW,EACX,eAAsB,EACtB,OAAO,EACP,OAAO,EACR,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,CAAC,CAuJ1C"}
|
|
@@ -157,78 +157,66 @@ function GenerateContext(_a) {
|
|
|
157
157
|
return (_e = getDefaultExport(moduleExports)) !== null && _e !== void 0 ? _e : getDefaultExport(contextExports);
|
|
158
158
|
};
|
|
159
159
|
const sandboxModule = { exports: {} };
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
exportNames.push('default');
|
|
180
|
-
}
|
|
181
|
-
const syntheticModule = new vmModules.SyntheticModule(exportNames, function () {
|
|
182
|
-
for (const name of exportNames) {
|
|
183
|
-
this.setExport(name, namespace[name]);
|
|
184
|
-
}
|
|
185
|
-
}, { context: vmContext, identifier: importTarget });
|
|
186
|
-
moduleCache.set(importTarget, syntheticModule);
|
|
187
|
-
return syntheticModule;
|
|
188
|
-
});
|
|
189
|
-
const importModuleDynamically = ((specifier) => loadModule(specifier));
|
|
190
|
-
const sourceModule = new vmModules.SourceTextModule(wrapEsmModule(functionToRun.code), {
|
|
191
|
-
context: vmContext,
|
|
192
|
-
identifier: entryFile,
|
|
193
|
-
initializeImportMeta: (meta) => {
|
|
194
|
-
meta.url = (0, node_url_1.pathToFileURL)(entryFile).href;
|
|
195
|
-
},
|
|
196
|
-
importModuleDynamically
|
|
197
|
-
});
|
|
198
|
-
yield sourceModule.link(loadModule);
|
|
199
|
-
yield sourceModule.evaluate();
|
|
200
|
-
usedVmModules = true;
|
|
201
|
-
}
|
|
202
|
-
catch (error) {
|
|
203
|
-
if (!shouldFallbackFromVmModules(error)) {
|
|
204
|
-
throw error;
|
|
160
|
+
const entryFile = (_b = (_a = require.main) === null || _a === void 0 ? void 0 : _a.filename) !== null && _b !== void 0 ? _b : process.cwd();
|
|
161
|
+
const customRequire = (0, node_module_1.createRequire)(entryFile);
|
|
162
|
+
const vmContext = vm_1.default.createContext(Object.assign(Object.assign({}, contextData), { require: customRequire, exports: sandboxModule.exports, module: sandboxModule, __filename,
|
|
163
|
+
__dirname, __fb_require: customRequire, __fb_filename: __filename, __fb_dirname: __dirname }));
|
|
164
|
+
const vmModules = vm_1.default;
|
|
165
|
+
const hasStaticImport = /\bimport\s+/.test(functionToRun.code);
|
|
166
|
+
let usedVmModules = false;
|
|
167
|
+
if (hasStaticImport && vmModules.SourceTextModule && vmModules.SyntheticModule) {
|
|
168
|
+
try {
|
|
169
|
+
const moduleCache = new Map();
|
|
170
|
+
const loadModule = (specifier) => __awaiter(this, void 0, void 0, function* () {
|
|
171
|
+
const importTarget = resolveImportTarget(specifier, customRequire);
|
|
172
|
+
const cached = moduleCache.get(importTarget);
|
|
173
|
+
if (cached)
|
|
174
|
+
return cached;
|
|
175
|
+
const namespace = yield dynamicImport(importTarget);
|
|
176
|
+
const exportNames = Object.keys(namespace);
|
|
177
|
+
if ('default' in namespace && !exportNames.includes('default')) {
|
|
178
|
+
exportNames.push('default');
|
|
205
179
|
}
|
|
206
|
-
|
|
180
|
+
const syntheticModule = new vmModules.SyntheticModule(exportNames, function () {
|
|
181
|
+
for (const name of exportNames) {
|
|
182
|
+
this.setExport(name, namespace[name]);
|
|
183
|
+
}
|
|
184
|
+
}, { context: vmContext, identifier: importTarget });
|
|
185
|
+
moduleCache.set(importTarget, syntheticModule);
|
|
186
|
+
return syntheticModule;
|
|
187
|
+
});
|
|
188
|
+
const importModuleDynamically = ((specifier) => loadModule(specifier));
|
|
189
|
+
const sourceModule = new vmModules.SourceTextModule(wrapEsmModule(functionToRun.code), {
|
|
190
|
+
context: vmContext,
|
|
191
|
+
identifier: entryFile,
|
|
192
|
+
initializeImportMeta: (meta) => {
|
|
193
|
+
meta.url = (0, node_url_1.pathToFileURL)(entryFile).href;
|
|
194
|
+
},
|
|
195
|
+
importModuleDynamically
|
|
196
|
+
});
|
|
197
|
+
yield sourceModule.link(loadModule);
|
|
198
|
+
yield sourceModule.evaluate();
|
|
199
|
+
usedVmModules = true;
|
|
207
200
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
vm_1.default.runInContext(codeToRun, vmContext);
|
|
201
|
+
catch (error) {
|
|
202
|
+
if (!shouldFallbackFromVmModules(error)) {
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
213
205
|
}
|
|
214
|
-
sandboxModule.exports = (_c = resolveExport(vmContext)) !== null && _c !== void 0 ? _c : sandboxModule.exports;
|
|
215
206
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
207
|
+
if (!usedVmModules) {
|
|
208
|
+
const codeToRun = functionToRun.code.includes('import ')
|
|
209
|
+
? transformImportsToRequire(functionToRun.code)
|
|
210
|
+
: functionToRun.code;
|
|
211
|
+
vm_1.default.runInContext(codeToRun, vmContext);
|
|
219
212
|
}
|
|
213
|
+
sandboxModule.exports = (_c = resolveExport(vmContext)) !== null && _c !== void 0 ? _c : sandboxModule.exports;
|
|
220
214
|
if (deserializeArgs) {
|
|
221
215
|
return yield sandboxModule.exports(...bson_1.EJSON.deserialize(args));
|
|
222
216
|
}
|
|
223
217
|
return yield sandboxModule.exports(...args);
|
|
224
218
|
});
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return res;
|
|
228
|
-
}
|
|
229
|
-
catch (error) {
|
|
230
|
-
console.error(error);
|
|
231
|
-
throw error;
|
|
232
|
-
}
|
|
219
|
+
const res = yield functionsQueue.add(run, enqueue);
|
|
220
|
+
return res;
|
|
233
221
|
});
|
|
234
222
|
}
|
package/package.json
CHANGED
|
@@ -41,6 +41,13 @@ const formatFunctionExecutionError = (error: unknown) => {
|
|
|
41
41
|
return JSON.stringify({ message, name })
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
const isReturnedError = (value: unknown): value is { message: string; name: string } => {
|
|
45
|
+
if (value instanceof Error) return true
|
|
46
|
+
if (!value || typeof value !== 'object') return false
|
|
47
|
+
const candidate = value as { message?: unknown; name?: unknown }
|
|
48
|
+
return typeof candidate.message === 'string' && typeof candidate.name === 'string'
|
|
49
|
+
}
|
|
50
|
+
|
|
44
51
|
/**
|
|
45
52
|
* > Creates a pre handler for every query
|
|
46
53
|
* @param app -> the fastify instance
|
|
@@ -122,6 +129,10 @@ export const functionsController: FunctionController = async (
|
|
|
122
129
|
functionsList,
|
|
123
130
|
services
|
|
124
131
|
})
|
|
132
|
+
if (isReturnedError(result)) {
|
|
133
|
+
res.type('application/json')
|
|
134
|
+
return JSON.stringify({ message: result.message, name: result.name })
|
|
135
|
+
}
|
|
125
136
|
res.type('application/json')
|
|
126
137
|
return JSON.stringify(result)
|
|
127
138
|
} catch (error) {
|
|
@@ -24,7 +24,7 @@ type Config = {
|
|
|
24
24
|
isAutoTrigger?: boolean
|
|
25
25
|
match: Record<string, unknown>
|
|
26
26
|
operation_types: string[]
|
|
27
|
-
operation_type?: 'CREATE' | 'DELETE'
|
|
27
|
+
operation_type?: 'CREATE' | 'DELETE' | 'LOGOUT'
|
|
28
28
|
project: Record<string, unknown>
|
|
29
29
|
service_name: string
|
|
30
30
|
skip_catchup_events: boolean
|
|
@@ -106,6 +106,7 @@ const handleCronTrigger = async ({
|
|
|
106
106
|
const mapOpInverse = {
|
|
107
107
|
CREATE: ['insert', 'update', 'replace'],
|
|
108
108
|
DELETE: ['delete'],
|
|
109
|
+
LOGOUT: ['update'],
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
const handleAuthenticationTrigger = async ({
|
|
@@ -161,11 +162,13 @@ const handleAuthenticationTrigger = async ({
|
|
|
161
162
|
const updateDescription = change[
|
|
162
163
|
'updateDescription' as keyof typeof change
|
|
163
164
|
] as { updatedFields?: Record<string, unknown> } | undefined
|
|
164
|
-
const
|
|
165
|
+
const updatedFields = updateDescription?.updatedFields
|
|
166
|
+
const updatedStatus = updatedFields?.status
|
|
165
167
|
const isInsert = operationType === 'insert'
|
|
166
168
|
const isUpdate = operationType === 'update'
|
|
167
169
|
const isReplace = operationType === 'replace'
|
|
168
170
|
const isDelete = operationType === 'delete'
|
|
171
|
+
const isLogoutUpdate = isUpdate && !!updatedFields && 'lastLogoutAt' in updatedFields
|
|
169
172
|
|
|
170
173
|
let confirmedCandidate = false
|
|
171
174
|
let confirmedDocument =
|
|
@@ -199,6 +202,44 @@ const handleAuthenticationTrigger = async ({
|
|
|
199
202
|
}
|
|
200
203
|
}
|
|
201
204
|
|
|
205
|
+
if (operation_type === 'LOGOUT') {
|
|
206
|
+
if (!isLogoutUpdate) {
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
let logoutDocument = fullDocument ?? confirmedDocument
|
|
210
|
+
if (!logoutDocument && documentKey?._id) {
|
|
211
|
+
logoutDocument = await collection.findOne({
|
|
212
|
+
_id: documentKey._id
|
|
213
|
+
}) as Record<string, unknown> | null
|
|
214
|
+
}
|
|
215
|
+
const userData = buildUserData(logoutDocument)
|
|
216
|
+
if (!userData) {
|
|
217
|
+
return
|
|
218
|
+
}
|
|
219
|
+
const op = {
|
|
220
|
+
operationType: 'LOGOUT',
|
|
221
|
+
fullDocument,
|
|
222
|
+
fullDocumentBeforeChange,
|
|
223
|
+
documentKey,
|
|
224
|
+
updateDescription
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
await GenerateContext({
|
|
228
|
+
args: [{ user: userData, ...op }],
|
|
229
|
+
app,
|
|
230
|
+
rules: StateManager.select("rules"),
|
|
231
|
+
user: {}, // TODO from currentUser ??
|
|
232
|
+
currentFunction: triggerHandler,
|
|
233
|
+
functionsList,
|
|
234
|
+
services,
|
|
235
|
+
runAsSystem: true
|
|
236
|
+
})
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.log("🚀 ~ handleAuthenticationTrigger ~ error:", error)
|
|
239
|
+
}
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
|
|
202
243
|
if (isDelete) {
|
|
203
244
|
if (isAutoTrigger || operation_type !== 'DELETE') {
|
|
204
245
|
return
|
|
@@ -186,97 +186,93 @@ export async function GenerateContext({
|
|
|
186
186
|
|
|
187
187
|
const sandboxModule: SandboxModule = { exports: {} }
|
|
188
188
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
exportNames.push('default')
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const syntheticModule = new vmModules.SyntheticModule(
|
|
228
|
-
exportNames,
|
|
229
|
-
function () {
|
|
230
|
-
for (const name of exportNames) {
|
|
231
|
-
this.setExport(name, namespace[name])
|
|
232
|
-
}
|
|
233
|
-
},
|
|
234
|
-
{ context: vmContext, identifier: importTarget }
|
|
235
|
-
)
|
|
236
|
-
|
|
237
|
-
moduleCache.set(importTarget, syntheticModule)
|
|
238
|
-
return syntheticModule
|
|
189
|
+
const entryFile = require.main?.filename ?? process.cwd()
|
|
190
|
+
const customRequire = createRequire(entryFile)
|
|
191
|
+
|
|
192
|
+
const vmContext: SandboxContext = vm.createContext({
|
|
193
|
+
...contextData,
|
|
194
|
+
require: customRequire,
|
|
195
|
+
exports: sandboxModule.exports,
|
|
196
|
+
module: sandboxModule,
|
|
197
|
+
__filename,
|
|
198
|
+
__dirname,
|
|
199
|
+
__fb_require: customRequire,
|
|
200
|
+
__fb_filename: __filename,
|
|
201
|
+
__fb_dirname: __dirname
|
|
202
|
+
}) as SandboxContext
|
|
203
|
+
|
|
204
|
+
const vmModules = vm as typeof vm & {
|
|
205
|
+
SourceTextModule?: typeof vm.SourceTextModule
|
|
206
|
+
SyntheticModule?: typeof vm.SyntheticModule
|
|
207
|
+
}
|
|
208
|
+
const hasStaticImport = /\bimport\s+/.test(functionToRun.code)
|
|
209
|
+
let usedVmModules = false
|
|
210
|
+
|
|
211
|
+
if (hasStaticImport && vmModules.SourceTextModule && vmModules.SyntheticModule) {
|
|
212
|
+
try {
|
|
213
|
+
const moduleCache = new Map<string, vm.Module>()
|
|
214
|
+
|
|
215
|
+
const loadModule = async (specifier: string): Promise<vm.Module> => {
|
|
216
|
+
const importTarget = resolveImportTarget(specifier, customRequire)
|
|
217
|
+
const cached = moduleCache.get(importTarget)
|
|
218
|
+
if (cached) return cached
|
|
219
|
+
|
|
220
|
+
const namespace = await dynamicImport(importTarget)
|
|
221
|
+
const exportNames = Object.keys(namespace)
|
|
222
|
+
if ('default' in namespace && !exportNames.includes('default')) {
|
|
223
|
+
exportNames.push('default')
|
|
239
224
|
}
|
|
240
225
|
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
identifier: entryFile,
|
|
250
|
-
initializeImportMeta: (meta) => {
|
|
251
|
-
meta.url = pathToFileURL(entryFile).href
|
|
252
|
-
},
|
|
253
|
-
importModuleDynamically
|
|
254
|
-
}
|
|
226
|
+
const syntheticModule = new vmModules.SyntheticModule(
|
|
227
|
+
exportNames,
|
|
228
|
+
function () {
|
|
229
|
+
for (const name of exportNames) {
|
|
230
|
+
this.setExport(name, namespace[name])
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
{ context: vmContext, identifier: importTarget }
|
|
255
234
|
)
|
|
256
235
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
usedVmModules = true
|
|
260
|
-
} catch (error) {
|
|
261
|
-
if (!shouldFallbackFromVmModules(error)) {
|
|
262
|
-
throw error
|
|
263
|
-
}
|
|
236
|
+
moduleCache.set(importTarget, syntheticModule)
|
|
237
|
+
return syntheticModule
|
|
264
238
|
}
|
|
265
|
-
}
|
|
266
239
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
240
|
+
const importModuleDynamically =
|
|
241
|
+
((specifier: string) => loadModule(specifier) as unknown as vm.Module) as unknown as
|
|
242
|
+
vm.SourceTextModuleOptions['importModuleDynamically']
|
|
243
|
+
|
|
244
|
+
const sourceModule = new vmModules.SourceTextModule(
|
|
245
|
+
wrapEsmModule(functionToRun.code),
|
|
246
|
+
{
|
|
247
|
+
context: vmContext,
|
|
248
|
+
identifier: entryFile,
|
|
249
|
+
initializeImportMeta: (meta) => {
|
|
250
|
+
meta.url = pathToFileURL(entryFile).href
|
|
251
|
+
},
|
|
252
|
+
importModuleDynamically
|
|
253
|
+
}
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
await sourceModule.link(loadModule)
|
|
257
|
+
await sourceModule.evaluate()
|
|
258
|
+
usedVmModules = true
|
|
259
|
+
} catch (error) {
|
|
260
|
+
if (!shouldFallbackFromVmModules(error)) {
|
|
261
|
+
throw error
|
|
262
|
+
}
|
|
272
263
|
}
|
|
264
|
+
}
|
|
273
265
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
266
|
+
if (!usedVmModules) {
|
|
267
|
+
const codeToRun = functionToRun.code.includes('import ')
|
|
268
|
+
? transformImportsToRequire(functionToRun.code)
|
|
269
|
+
: functionToRun.code
|
|
270
|
+
vm.runInContext(codeToRun, vmContext)
|
|
278
271
|
}
|
|
279
272
|
|
|
273
|
+
sandboxModule.exports = resolveExport(vmContext) ?? sandboxModule.exports
|
|
274
|
+
|
|
275
|
+
|
|
280
276
|
if (deserializeArgs) {
|
|
281
277
|
return await (sandboxModule.exports as ExportedFunction)(
|
|
282
278
|
...EJSON.deserialize(args)
|
|
@@ -285,11 +281,8 @@ export async function GenerateContext({
|
|
|
285
281
|
|
|
286
282
|
return await (sandboxModule.exports as ExportedFunction)(...args)
|
|
287
283
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
console.error(error)
|
|
293
|
-
throw error
|
|
294
|
-
}
|
|
284
|
+
|
|
285
|
+
const res = await functionsQueue.add(run, enqueue)
|
|
286
|
+
return res
|
|
287
|
+
|
|
295
288
|
}
|