@balena/pinejs 16.0.0-build--batch-f2ffc3d6bcb9f3294fd4fc9de3c21bfe167e100d-1 → 16.0.0-build-fisehara-update-sbvr-types-b58e72aca3193964afac96c955fde178fe39d077-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.
Files changed (141) hide show
  1. package/.pinejs-cache.json +1 -1
  2. package/.versionbot/CHANGELOG.yml +2168 -11
  3. package/CHANGELOG.md +815 -2
  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 +20 -9
  73. package/out/sbvr-api/sbvr-utils.js +134 -136
  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 +7 -10
  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 +118 -172
  128. package/src/sbvr-api/translations.ts +9 -6
  129. package/src/sbvr-api/uri-parser.ts +22 -28
  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>;