@flowerforce/flowerbase 1.4.1 → 1.4.2-beta.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.
- package/dist/features/functions/controller.d.ts.map +1 -1
- package/dist/features/functions/controller.js +12 -0
- 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/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
|
}
|
|
@@ -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) {
|
|
@@ -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
|
}
|