@balena/pinejs 16.0.0-build--batch-09b8c466600d7df13e6df3eacabaf463d96f652f-1 → 16.0.0-build-fisehara-update-sbvr-types-b58e72aca3193964afac96c955fde178fe39d077-1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. package/.pinejs-cache.json +1 -1
  2. package/.versionbot/CHANGELOG.yml +2164 -15
  3. package/CHANGELOG.md +815 -3
  4. package/Gruntfile.ts +9 -6
  5. package/README.md +10 -0
  6. package/build/browser.ts +2 -2
  7. package/build/config.ts +1 -1
  8. package/build/module.ts +2 -2
  9. package/build/server.ts +2 -2
  10. package/docker-compose.npm-test.yml +21 -3
  11. package/out/bin/abstract-sql-compiler.js +5 -5
  12. package/out/bin/abstract-sql-compiler.js.map +1 -1
  13. package/out/bin/odata-compiler.js +10 -10
  14. package/out/bin/odata-compiler.js.map +1 -1
  15. package/out/bin/sbvr-compiler.js +34 -11
  16. package/out/bin/sbvr-compiler.js.map +1 -1
  17. package/out/bin/utils.js +25 -2
  18. package/out/bin/utils.js.map +1 -1
  19. package/out/config-loader/config-loader.d.ts +4 -2
  20. package/out/config-loader/config-loader.js +54 -13
  21. package/out/config-loader/config-loader.js.map +1 -1
  22. package/out/config-loader/env.d.ts +2 -1
  23. package/out/config-loader/env.js +5 -2
  24. package/out/config-loader/env.js.map +1 -1
  25. package/out/data-server/sbvr-server.d.ts +1 -1
  26. package/out/data-server/sbvr-server.js +3 -1
  27. package/out/data-server/sbvr-server.js.map +1 -1
  28. package/out/database-layer/db.js +40 -14
  29. package/out/database-layer/db.js.map +1 -1
  30. package/out/express-emulator/express.js +5 -3
  31. package/out/express-emulator/express.js.map +1 -1
  32. package/out/http-transactions/transactions.d.ts +1 -1
  33. package/out/http-transactions/transactions.js +10 -5
  34. package/out/http-transactions/transactions.js.map +1 -1
  35. package/out/migrator/async.js +32 -5
  36. package/out/migrator/async.js.map +1 -1
  37. package/out/migrator/sync.d.ts +2 -1
  38. package/out/migrator/sync.js +29 -3
  39. package/out/migrator/sync.js.map +1 -1
  40. package/out/migrator/utils.d.ts +6 -3
  41. package/out/migrator/utils.js +30 -4
  42. package/out/migrator/utils.js.map +1 -1
  43. package/out/odata-metadata/odata-metadata-generator.js +4 -1
  44. package/out/odata-metadata/odata-metadata-generator.js.map +1 -1
  45. package/out/passport-pinejs/mount-login-router.d.ts +3 -0
  46. package/out/passport-pinejs/mount-login-router.js +65 -0
  47. package/out/passport-pinejs/mount-login-router.js.map +1 -0
  48. package/out/passport-pinejs/passport-pinejs.d.ts +2 -1
  49. package/out/passport-pinejs/passport-pinejs.js +28 -2
  50. package/out/passport-pinejs/passport-pinejs.js.map +1 -1
  51. package/out/pinejs-session-store/pinejs-session-store.js +30 -7
  52. package/out/pinejs-session-store/pinejs-session-store.js.map +1 -1
  53. package/out/sbvr-api/abstract-sql.d.ts +2 -2
  54. package/out/sbvr-api/abstract-sql.js +35 -9
  55. package/out/sbvr-api/abstract-sql.js.map +1 -1
  56. package/out/sbvr-api/cached-compile.js +9 -6
  57. package/out/sbvr-api/cached-compile.js.map +1 -1
  58. package/out/sbvr-api/common-types.d.ts +1 -1
  59. package/out/sbvr-api/control-flow.js +5 -2
  60. package/out/sbvr-api/control-flow.js.map +1 -1
  61. package/out/sbvr-api/express-extension.d.ts +10 -7
  62. package/out/sbvr-api/express-extension.js +1 -0
  63. package/out/sbvr-api/hooks.d.ts +5 -1
  64. package/out/sbvr-api/hooks.js +12 -10
  65. package/out/sbvr-api/hooks.js.map +1 -1
  66. package/out/sbvr-api/odata-response.d.ts +5 -2
  67. package/out/sbvr-api/odata-response.js +36 -6
  68. package/out/sbvr-api/odata-response.js.map +1 -1
  69. package/out/sbvr-api/permissions.d.ts +6 -7
  70. package/out/sbvr-api/permissions.js +69 -38
  71. package/out/sbvr-api/permissions.js.map +1 -1
  72. package/out/sbvr-api/sbvr-utils.d.ts +21 -10
  73. package/out/sbvr-api/sbvr-utils.js +128 -124
  74. package/out/sbvr-api/sbvr-utils.js.map +1 -1
  75. package/out/sbvr-api/translations.d.ts +2 -2
  76. package/out/sbvr-api/translations.js +17 -10
  77. package/out/sbvr-api/translations.js.map +1 -1
  78. package/out/sbvr-api/uri-parser.d.ts +10 -12
  79. package/out/sbvr-api/uri-parser.js +46 -19
  80. package/out/sbvr-api/uri-parser.js.map +1 -1
  81. package/out/server-glue/global-ext.d.ts +2 -1
  82. package/out/server-glue/module.d.ts +3 -1
  83. package/out/server-glue/module.js +40 -13
  84. package/out/server-glue/module.js.map +1 -1
  85. package/out/server-glue/sbvr-loader.js.map +1 -1
  86. package/out/server-glue/server.js +31 -39
  87. package/out/server-glue/server.js.map +1 -1
  88. package/out/webresource-handler/handlers/NoopHandler.d.ts +7 -0
  89. package/out/webresource-handler/handlers/NoopHandler.js +20 -0
  90. package/out/webresource-handler/handlers/NoopHandler.js.map +1 -0
  91. package/out/webresource-handler/handlers/S3Handler.d.ts +28 -0
  92. package/out/webresource-handler/handlers/S3Handler.js +97 -0
  93. package/out/webresource-handler/handlers/S3Handler.js.map +1 -0
  94. package/out/webresource-handler/handlers/index.d.ts +2 -0
  95. package/out/webresource-handler/handlers/index.js +19 -0
  96. package/out/webresource-handler/handlers/index.js.map +1 -0
  97. package/out/webresource-handler/index.d.ts +34 -0
  98. package/out/webresource-handler/index.js +307 -0
  99. package/out/webresource-handler/index.js.map +1 -0
  100. package/package.json +68 -62
  101. package/src/bin/abstract-sql-compiler.ts +7 -9
  102. package/src/bin/odata-compiler.ts +12 -15
  103. package/src/bin/sbvr-compiler.ts +14 -18
  104. package/src/bin/utils.ts +1 -1
  105. package/src/config-loader/config-loader.ts +44 -10
  106. package/src/config-loader/env.ts +1 -1
  107. package/src/data-server/sbvr-server.js +3 -1
  108. package/src/database-layer/db.ts +23 -19
  109. package/src/express-emulator/express.js +5 -3
  110. package/src/extended-sbvr-parser/extended-sbvr-parser.ts +1 -1
  111. package/src/http-transactions/transactions.js +10 -5
  112. package/src/migrator/async.ts +7 -6
  113. package/src/migrator/sync.ts +10 -7
  114. package/src/migrator/utils.ts +11 -5
  115. package/src/odata-metadata/odata-metadata-generator.ts +2 -2
  116. package/src/passport-pinejs/mount-login-router.ts +46 -0
  117. package/src/passport-pinejs/passport-pinejs.ts +7 -3
  118. package/src/pinejs-session-store/pinejs-session-store.ts +6 -6
  119. package/src/sbvr-api/abstract-sql.ts +5 -5
  120. package/src/sbvr-api/cached-compile.ts +1 -2
  121. package/src/sbvr-api/common-types.ts +1 -1
  122. package/src/sbvr-api/control-flow.ts +1 -1
  123. package/src/sbvr-api/express-extension.ts +12 -8
  124. package/src/sbvr-api/hooks.ts +11 -11
  125. package/src/sbvr-api/odata-response.ts +56 -9
  126. package/src/sbvr-api/permissions.ts +44 -35
  127. package/src/sbvr-api/sbvr-utils.ts +117 -165
  128. package/src/sbvr-api/translations.ts +9 -6
  129. package/src/sbvr-api/uri-parser.ts +25 -30
  130. package/src/server-glue/global-ext.d.ts +2 -1
  131. package/src/server-glue/module.ts +8 -2
  132. package/src/server-glue/sbvr-loader.ts +1 -1
  133. package/src/server-glue/server.ts +11 -49
  134. package/src/webresource-handler/handlers/NoopHandler.ts +21 -0
  135. package/src/webresource-handler/handlers/S3Handler.ts +143 -0
  136. package/src/webresource-handler/handlers/index.ts +2 -0
  137. package/src/webresource-handler/index.ts +450 -0
  138. package/tsconfig.dev.json +2 -1
  139. package/tsconfig.json +1 -1
  140. package/typings/lf-to-abstract-sql.d.ts +1 -1
  141. package/typings/memoizee.d.ts +3 -4
@@ -0,0 +1,450 @@
1
+ import type * as Express from 'express';
2
+ import busboy from 'busboy';
3
+ import type * as stream from 'node:stream';
4
+ import * as uriParser from '../sbvr-api/uri-parser';
5
+ import * as sbvrUtils from '../sbvr-api/sbvr-utils';
6
+ import type { HookArgs } from '../sbvr-api/hooks';
7
+ import { getApiRoot, getModel } from '../sbvr-api/sbvr-utils';
8
+ import { checkPermissions } from '../sbvr-api/permissions';
9
+ import { NoopHandler } from './handlers/NoopHandler';
10
+ import {
11
+ odataNameToSqlName,
12
+ sqlNameToODataName,
13
+ } from '@balena/odata-to-abstract-sql';
14
+ import { errors, permissions } from '../server-glue/module';
15
+ import type { WebResourceType as WebResource } from '@balena/sbvr-types';
16
+ import { TypedError } from 'typed-error';
17
+
18
+ export * from './handlers';
19
+
20
+ export interface IncomingFile {
21
+ fieldname: string;
22
+ originalname: string;
23
+ encoding: string;
24
+ mimetype: string;
25
+ stream: stream.Readable;
26
+ }
27
+
28
+ export interface UploadResponse {
29
+ size: number;
30
+ filename: string;
31
+ }
32
+
33
+ export interface WebResourceHandler {
34
+ handleFile: (resource: IncomingFile) => Promise<UploadResponse>;
35
+ removeFile: (fileReference: string) => Promise<void>;
36
+ onPreRespond: (webResource: WebResource) => Promise<WebResource>;
37
+ }
38
+
39
+ export class WebResourceError extends TypedError {}
40
+
41
+ export class FileSizeExceededError extends WebResourceError {
42
+ name = 'FileSizeExceededError';
43
+ constructor(maxSize: number) {
44
+ super(`File size exceeded the limit of ${maxSize} bytes.`);
45
+ }
46
+ }
47
+
48
+ type WebResourcesDbResponse = {
49
+ [fieldname: string]: { href: string } | undefined | null;
50
+ };
51
+
52
+ const getLogger = (vocab?: string): Console => {
53
+ if (vocab) {
54
+ return sbvrUtils.api[vocab]?.logger ?? console;
55
+ }
56
+ return console;
57
+ };
58
+
59
+ let configuredWebResourceHandler: WebResourceHandler | undefined;
60
+ export const setupWebresourceHandler = (handler: WebResourceHandler): void => {
61
+ configuredWebResourceHandler = handler;
62
+ };
63
+ export const getWebresourceHandler = (): WebResourceHandler | undefined => {
64
+ return configuredWebResourceHandler;
65
+ };
66
+
67
+ const isFileInValidPath = async (
68
+ fieldname: string,
69
+ req: Express.Request,
70
+ ): Promise<boolean> => {
71
+ if (req.method !== 'POST' && req.method !== 'PATCH') {
72
+ return false;
73
+ }
74
+
75
+ const apiRoot = getApiRoot(req);
76
+ if (apiRoot == null) {
77
+ return false;
78
+ }
79
+ const model = getModel(apiRoot);
80
+ const odataRequest = uriParser.parseOData({
81
+ url: req.url,
82
+ method: req.method,
83
+ });
84
+ const sqlResourceName = sbvrUtils.resolveSynonym(odataRequest);
85
+
86
+ const table = model.abstractSql.tables[sqlResourceName];
87
+
88
+ if (table == null) {
89
+ return false;
90
+ }
91
+
92
+ const permission = req.method === 'POST' ? 'create' : 'update';
93
+ const vocab = model.versions[model.versions.length - 1];
94
+
95
+ // Checks if it has permissions on both the original resourceName or any synonym
96
+ const hasPermissions = await checkPermissions(
97
+ req,
98
+ permission,
99
+ odataRequest.resourceName,
100
+ vocab,
101
+ );
102
+
103
+ if (!hasPermissions) {
104
+ return false;
105
+ }
106
+
107
+ const dbFieldName = odataNameToSqlName(fieldname);
108
+ return table.fields.some(
109
+ (field) =>
110
+ field.fieldName === dbFieldName && field.dataType === 'WebResource',
111
+ );
112
+ };
113
+
114
+ export const getUploaderMiddlware = (
115
+ handler: WebResourceHandler,
116
+ ): Express.RequestHandler => {
117
+ return async (req, res, next) => {
118
+ if (!req.is('multipart')) {
119
+ return next();
120
+ }
121
+ const uploadedFilePaths: string[] = [];
122
+ const completeUploads: Array<Promise<void>> = [];
123
+
124
+ const bb = busboy({ headers: req.headers });
125
+ let isAborting = false;
126
+
127
+ const finishFileUpload = () => {
128
+ req.unpipe(bb);
129
+ req.on('readable', req.read.bind(req));
130
+ bb.removeAllListeners();
131
+ };
132
+
133
+ const clearFiles = async () => {
134
+ isAborting = true;
135
+ const deletions = uploadedFilePaths.map((file) =>
136
+ handler.removeFile(file),
137
+ );
138
+ // Best effort: We try to remove all uploaded files, but if this fails, there is not much to do
139
+ try {
140
+ return await Promise.all(deletions);
141
+ } catch (err) {
142
+ getLogger(getApiRoot(req)).error('Error deleting file', err);
143
+ }
144
+ };
145
+
146
+ bb.on('file', (fieldname, filestream, info) => {
147
+ if (isAborting) {
148
+ filestream.resume();
149
+ return;
150
+ }
151
+ completeUploads.push(
152
+ (async () => {
153
+ try {
154
+ if (!(await isFileInValidPath(fieldname, req))) {
155
+ filestream.resume();
156
+ return;
157
+ }
158
+ const file: IncomingFile = {
159
+ originalname: info.filename,
160
+ encoding: info.encoding,
161
+ mimetype: info.mimeType,
162
+ stream: filestream,
163
+ fieldname,
164
+ };
165
+ const result = await handler.handleFile(file);
166
+ req.body[fieldname] = {
167
+ filename: info.filename,
168
+ content_type: info.mimeType,
169
+ content_disposition: undefined,
170
+ size: result.size,
171
+ href: result.filename,
172
+ };
173
+ uploadedFilePaths.push(result.filename);
174
+ } catch (err: any) {
175
+ filestream.resume();
176
+ throw err;
177
+ }
178
+ })(),
179
+ );
180
+ });
181
+
182
+ // multipart requests will have two main parts, the file contents and the form fields
183
+ // This receives the form fields and transforms them into a standard JSON body
184
+ // This is a similar behavior as previous multer library did
185
+ bb.on('field', (name, val) => {
186
+ req.body[name] = val;
187
+ });
188
+
189
+ bb.on('finish', async () => {
190
+ try {
191
+ await Promise.all(completeUploads);
192
+ finishFileUpload();
193
+ next();
194
+ } catch (err: any) {
195
+ await clearFiles();
196
+
197
+ if (err instanceof FileSizeExceededError) {
198
+ return sbvrUtils.handleHttpErrors(
199
+ req,
200
+ res,
201
+ new errors.BadRequestError(err.message),
202
+ );
203
+ }
204
+
205
+ getLogger(getApiRoot(req)).error('Error uploading file', err);
206
+ next(err);
207
+ }
208
+ });
209
+
210
+ bb.on('error', async (err) => {
211
+ await clearFiles();
212
+ finishFileUpload();
213
+ next(err);
214
+ });
215
+ req.pipe(bb);
216
+ };
217
+ };
218
+
219
+ const getWebResourceFields = (
220
+ request: uriParser.ODataRequest,
221
+ useTranslations = true,
222
+ ): string[] => {
223
+ // Translations will use modifyFields(translated) rather than fields(original) so we need to
224
+ // account for it while finding if a webresrouce field was changed
225
+ // there are cases where we need to get the original resource name (not translated)
226
+ // therefore we can use useTranslations = false
227
+ const resourceName = sbvrUtils.resolveSynonym(request);
228
+ const sqlResourceName = odataNameToSqlName(resourceName);
229
+ const model = sbvrUtils.getAbstractSqlModel(request).tables[sqlResourceName];
230
+ const fields = useTranslations
231
+ ? model.modifyFields ?? model.fields
232
+ : model.fields;
233
+
234
+ return fields
235
+ .filter((f) => f.dataType === 'WebResource')
236
+ .map((f) => sqlNameToODataName(f.fieldName));
237
+ };
238
+
239
+ const deleteFiles = async (
240
+ keysToDelete: string[],
241
+ webResourceHandler: WebResourceHandler,
242
+ ) => {
243
+ const promises = keysToDelete.map((r) => webResourceHandler.removeFile(r));
244
+ await Promise.all(promises);
245
+ };
246
+
247
+ const throwIfWebresourceNotInMultipart = (
248
+ webResourceFields: string[],
249
+ { req, request }: HookArgs,
250
+ ) => {
251
+ if (
252
+ !req.is?.('multipart') &&
253
+ webResourceFields.some((field) => request.values[field] != null)
254
+ ) {
255
+ throw new errors.BadRequestError(
256
+ 'Use multipart requests to upload a file.',
257
+ );
258
+ }
259
+ };
260
+
261
+ const getCreateWebResourceHooks = (
262
+ webResourceHandler: WebResourceHandler,
263
+ ): sbvrUtils.Hooks => {
264
+ return {
265
+ PRERUN: (hookArgs) => {
266
+ const webResourceFields = getWebResourceFields(hookArgs.request);
267
+ throwIfWebresourceNotInMultipart(webResourceFields, hookArgs);
268
+ },
269
+ 'POSTRUN-ERROR': async ({ tx, request }) => {
270
+ tx.on('rollback', () => {
271
+ void deleteRollbackPendingFields(request, webResourceHandler);
272
+ });
273
+ },
274
+ };
275
+ };
276
+
277
+ const isDefined = <T>(x: T | undefined | null): x is T => x != null;
278
+
279
+ const getWebResourcesHrefs = (
280
+ webResources?: WebResourcesDbResponse[] | null,
281
+ ): string[] => {
282
+ const hrefs = (webResources ?? []).flatMap((resource) =>
283
+ Object.values(resource ?? {})
284
+ .filter(isDefined)
285
+ .map((resourceKey) => normalizeHref(resourceKey.href)),
286
+ );
287
+ return hrefs;
288
+ };
289
+
290
+ export const normalizeHref = (href: string) => {
291
+ return href.split('?')[0];
292
+ };
293
+
294
+ const getWebResourcesKeysFromRequest = (
295
+ webResourceFields: string[],
296
+ { values }: uriParser.ODataRequest,
297
+ ): string[] => {
298
+ return webResourceFields
299
+ .map((field) => values[field]?.href)
300
+ .filter(isDefined);
301
+ };
302
+
303
+ const getRemoveWebResourceHooks = (
304
+ webResourceHandler: WebResourceHandler,
305
+ ): sbvrUtils.Hooks => {
306
+ return {
307
+ PRERUN: async (args) => {
308
+ const { api, request, tx } = args;
309
+ let webResourceFields = getWebResourceFields(request);
310
+
311
+ throwIfWebresourceNotInMultipart(webResourceFields, args);
312
+
313
+ // Request failed on DB roundtrip (e.g. DB constraint) and pending files need to be deleted
314
+ tx.on('rollback', () => {
315
+ void deleteRollbackPendingFields(request, webResourceHandler);
316
+ });
317
+
318
+ if (request.method === 'PATCH') {
319
+ webResourceFields = Object.entries(request.values)
320
+ .filter(
321
+ ([key, value]) =>
322
+ value !== undefined && webResourceFields.includes(key),
323
+ )
324
+ .map(([key]) => key);
325
+ }
326
+
327
+ if (webResourceFields.length === 0) {
328
+ // No need to delete anything as no file is in the wire
329
+ // As there are no webresource fields in this request
330
+ return;
331
+ }
332
+
333
+ // This can only be validated here because we need to first ensure the
334
+ // request is actually modifying a webresource before erroring out
335
+ if (request.method === 'PATCH' && request.odataQuery?.key == null) {
336
+ // When we get here, files have already been uploaded. We need to mark them for deletion.
337
+ const keysToDelete = getWebResourcesKeysFromRequest(
338
+ webResourceFields,
339
+ request,
340
+ );
341
+
342
+ // Set deletion of files on the wire as request will throw
343
+ tx.on('end', () => {
344
+ deletePendingFiles(keysToDelete, request, webResourceHandler);
345
+ });
346
+
347
+ throw new errors.BadRequestError(
348
+ 'WebResources can only be updated when providing a resource key.',
349
+ );
350
+ }
351
+
352
+ // This can be > 1 in both DELETE requests or PATCH requests to not accessible IDs.
353
+ const ids = await sbvrUtils.getAffectedIds(args);
354
+ if (ids.length === 0) {
355
+ // Set deletion of files on the wire as no resource was affected
356
+ // Note that for DELETE requests it should not find any request on the wire
357
+ const keysToDelete = getWebResourcesKeysFromRequest(
358
+ webResourceFields,
359
+ request,
360
+ );
361
+ deletePendingFiles(keysToDelete, request, webResourceHandler);
362
+ return;
363
+ }
364
+
365
+ const webResources = (await api.get({
366
+ resource: request.resourceName,
367
+ passthrough: {
368
+ tx: args.tx,
369
+ req: permissions.root,
370
+ },
371
+ options: {
372
+ $select: webResourceFields,
373
+ $filter: {
374
+ id: {
375
+ $in: ids,
376
+ },
377
+ },
378
+ },
379
+ })) as WebResourcesDbResponse[] | undefined | null;
380
+
381
+ // Deletes previous stored resources in case they were patched or the whole entity was deleted
382
+ tx.on('end', () => {
383
+ deletePendingFiles(
384
+ getWebResourcesHrefs(webResources),
385
+ request,
386
+ webResourceHandler,
387
+ );
388
+ });
389
+ },
390
+ };
391
+ };
392
+
393
+ const deleteRollbackPendingFields = async (
394
+ request: uriParser.ODataRequest,
395
+ webResourceHandler: WebResourceHandler,
396
+ ) => {
397
+ const fields = getWebResourceFields(request);
398
+
399
+ if (fields.length === 0) {
400
+ return;
401
+ }
402
+
403
+ const keysToDelete = getWebResourcesKeysFromRequest(fields, request);
404
+ await deleteFiles(keysToDelete, webResourceHandler);
405
+ };
406
+
407
+ const deletePendingFiles = (
408
+ keysToDelete: string[],
409
+ request: uriParser.ODataRequest,
410
+ webResourceHandler: WebResourceHandler,
411
+ ): void => {
412
+ // on purpose does not await for this promise to resolve
413
+ try {
414
+ void deleteFiles(keysToDelete, webResourceHandler);
415
+ } catch (err) {
416
+ getLogger(request.vocabulary).error(`Failed to delete pending files`, err);
417
+ }
418
+ };
419
+
420
+ export const getDefaultHandler = (): WebResourceHandler => {
421
+ return new NoopHandler();
422
+ };
423
+
424
+ export const setupUploadHooks = (
425
+ handler: WebResourceHandler,
426
+ apiRoot: string,
427
+ resourceName: string,
428
+ ) => {
429
+ sbvrUtils.addPureHook(
430
+ 'DELETE',
431
+ apiRoot,
432
+ resourceName,
433
+ getRemoveWebResourceHooks(handler),
434
+ );
435
+
436
+ sbvrUtils.addPureHook(
437
+ 'PATCH',
438
+ apiRoot,
439
+ resourceName,
440
+ // PATCH also needs to remove the old resource in case a webresource was modified
441
+ getRemoveWebResourceHooks(handler),
442
+ );
443
+
444
+ sbvrUtils.addPureHook(
445
+ 'POST',
446
+ apiRoot,
447
+ resourceName,
448
+ getCreateWebResourceHooks(handler),
449
+ );
450
+ };
package/tsconfig.dev.json CHANGED
@@ -7,6 +7,7 @@
7
7
  "build/**/*",
8
8
  "src/**/*",
9
9
  "test/**/*",
10
- "typings/**/*.d.ts"
10
+ "typings/**/*.d.ts",
11
+ "Gruntfile.ts"
11
12
  ]
12
13
  }
package/tsconfig.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "compilerOptions": {
3
- "module": "commonjs",
3
+ "module": "Node16",
4
4
  "strict": true,
5
5
  "strictFunctionTypes": false,
6
6
  "noImplicitThis": false,
@@ -11,7 +11,7 @@ declare module '@balena/lf-to-abstract-sql' {
11
11
  };
12
12
  export const LF2AbstractSQLPrep: {
13
13
  match: (lfModel: LFModel, rule: 'Process') => LFModel;
14
- _extend({}): typeof LF2AbstractSQLPrep;
14
+ _extend(obj: object): typeof LF2AbstractSQLPrep;
15
15
  };
16
16
  export const createTranslator: (
17
17
  types: typeof sbvrTypes,
@@ -4,8 +4,7 @@ declare module 'memoizee/weak' {
4
4
  type FirstArg<T> = T extends (arg1: infer U) => any ? U : any;
5
5
  type RestArgs<T> = T extends (arg1: any, ...args: infer U) => any ? U : any[];
6
6
 
7
- // tslint:disable-next-line ban-types
8
- export interface MemoizeWeakOptions<F extends Function> {
7
+ export interface MemoizeWeakOptions<F extends (...args: any[]) => any> {
9
8
  length?: number | false;
10
9
  maxAge?: number;
11
10
  max?: number;
@@ -17,8 +16,8 @@ declare module 'memoizee/weak' {
17
16
  normalizer?(firstArg: FirstArg<F>, restArgs: RestArgs<F>): any;
18
17
  resolvers?: Array<(arg: any) => any>;
19
18
  }
20
- // tslint:disable-next-line ban-types
21
- function memoizeWeak<F extends Function>(
19
+
20
+ function memoizeWeak<F extends (...args: any[]) => any>(
22
21
  f: F,
23
22
  options?: MemoizeWeakOptions<F>,
24
23
  ): F & Memoize.Memoized<F>;