@balena/pinejs 16.0.0-build--batch-f2ffc3d6bcb9f3294fd4fc9de3c21bfe167e100d-1 → 16.0.0-build-fisehara-update-sbvr-types-cfbbecbb0387e87e17e14be8991be73d1a4efdd0-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
@@ -1,24 +1,21 @@
1
1
  import { version, writeAll, writeSqlModel } from './utils';
2
-
3
- import type * as SbvrUtils from '../sbvr-api/sbvr-utils';
4
-
5
2
  import { program } from 'commander';
6
3
  import * as fs from 'fs';
7
4
 
8
5
  const getSE = (inputFile: string) => fs.readFileSync(inputFile, 'utf8');
9
6
 
10
- const parse = (inputFile: string, outputFile?: string) => {
11
- const { generateLfModel } =
12
- require('../sbvr-api/sbvr-utils') as typeof SbvrUtils;
7
+ const parse = async (inputFile: string, outputFile?: string) => {
8
+ const { generateLfModel } = await import('../sbvr-api/sbvr-utils.js');
13
9
  const seModel = getSE(inputFile);
14
10
  const result = generateLfModel(seModel);
15
11
  const json = JSON.stringify(result, null, 2);
16
12
  writeAll(json, outputFile);
17
13
  };
18
14
 
19
- const transform = (inputFile: string, outputFile?: string) => {
20
- const { generateLfModel, generateAbstractSqlModel } =
21
- require('../sbvr-api/sbvr-utils') as typeof SbvrUtils;
15
+ const transform = async (inputFile: string, outputFile?: string) => {
16
+ const { generateLfModel, generateAbstractSqlModel } = await import(
17
+ '../sbvr-api/sbvr-utils.js'
18
+ );
22
19
  const seModel = getSE(inputFile);
23
20
  const lfModel = generateLfModel(seModel);
24
21
  const result = generateAbstractSqlModel(lfModel);
@@ -26,9 +23,8 @@ const transform = (inputFile: string, outputFile?: string) => {
26
23
  writeAll(json, outputFile);
27
24
  };
28
25
 
29
- const runCompile = (inputFile: string, outputFile?: string) => {
30
- const { generateModels } =
31
- require('../sbvr-api/sbvr-utils') as typeof SbvrUtils;
26
+ const runCompile = async (inputFile: string, outputFile?: string) => {
27
+ const { generateModels } = await import('../sbvr-api/sbvr-utils.js');
32
28
  const seModel = getSE(inputFile);
33
29
  const models = generateModels(
34
30
  { apiRoot: 'sbvr-compiler', modelText: seModel },
@@ -38,16 +34,16 @@ const runCompile = (inputFile: string, outputFile?: string) => {
38
34
  writeSqlModel(models.sql, outputFile);
39
35
  };
40
36
 
41
- const generateTypes = (inputFile: string, outputFile?: string) => {
42
- const { generateModels } =
43
- require('../sbvr-api/sbvr-utils') as typeof SbvrUtils;
37
+ const generateTypes = async (inputFile: string, outputFile?: string) => {
38
+ const { generateModels } = await import('../sbvr-api/sbvr-utils.js');
44
39
  const seModel = getSE(inputFile);
45
40
  const models = generateModels(
46
41
  { apiRoot: 'sbvr-compiler', modelText: seModel },
47
42
  program.opts().engine,
48
43
  );
49
- const { abstractSqlToTypescriptTypes } =
50
- require('@balena/abstract-sql-to-typescript') as typeof import('@balena/abstract-sql-to-typescript');
44
+ const { abstractSqlToTypescriptTypes } = await import(
45
+ '@balena/abstract-sql-to-typescript'
46
+ );
51
47
  const types = abstractSqlToTypescriptTypes(models.abstractSql);
52
48
 
53
49
  writeAll(types, outputFile);
@@ -93,4 +89,4 @@ if (process.argv.length === 2) {
93
89
  program.help();
94
90
  }
95
91
 
96
- program.parse(process.argv);
92
+ void program.parseAsync(process.argv);
package/src/bin/utils.ts CHANGED
@@ -10,7 +10,6 @@ import * as fs from 'fs';
10
10
  import * as path from 'path';
11
11
  import '../server-glue/sbvr-loader';
12
12
 
13
- // tslint:disable:no-var-requires
14
13
  export const { version } = JSON.parse(
15
14
  fs.readFileSync(require.resolve('../../package.json'), 'utf8'),
16
15
  );
@@ -83,6 +82,7 @@ export const getAbstractSqlModelFromFile = (
83
82
  throw new Error('Unrecognised config file');
84
83
  }
85
84
  const { generateLfModel, generateAbstractSqlModel } =
85
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
86
86
  require('../sbvr-api/sbvr-utils') as typeof SbvrUtils;
87
87
  let lfModel;
88
88
  try {
@@ -12,8 +12,8 @@ import type {
12
12
  } from '../sbvr-api/common-types';
13
13
 
14
14
  import {
15
- Migration,
16
- Migrations,
15
+ type Migration,
16
+ type Migrations,
17
17
  defaultMigrationCategory,
18
18
  MigrationCategories,
19
19
  isSyncMigration,
@@ -21,13 +21,20 @@ import {
21
21
  } from '../migrator/utils';
22
22
 
23
23
  import * as fs from 'fs';
24
- import * as _ from 'lodash';
24
+ import _ from 'lodash';
25
25
  import * as path from 'path';
26
26
 
27
27
  import * as sbvrUtils from '../sbvr-api/sbvr-utils';
28
28
 
29
29
  import * as permissions from '../sbvr-api/permissions';
30
- import { AliasValidNodeType } from '../sbvr-api/translations';
30
+ import {
31
+ getDefaultHandler,
32
+ getUploaderMiddlware,
33
+ type WebResourceHandler,
34
+ setupUploadHooks,
35
+ setupWebresourceHandler,
36
+ } from '../webresource-handler';
37
+ import type { AliasValidNodeType } from '../sbvr-api/translations';
31
38
 
32
39
  export type SetupFunction = (
33
40
  app: Express.Application,
@@ -64,6 +71,7 @@ export interface User {
64
71
  export interface Config {
65
72
  models: Model[];
66
73
  users?: User[];
74
+ webResourceHandler?: WebResourceHandler;
67
75
  }
68
76
 
69
77
  const getOrCreate = async (
@@ -195,16 +203,37 @@ export const setup = (app: Express.Application) => {
195
203
  );
196
204
 
197
205
  const apiRoute = `/${model.apiRoot}/*`;
206
+ const webResourceHandler =
207
+ data.webResourceHandler ?? getDefaultHandler();
208
+
209
+ setupWebresourceHandler(webResourceHandler);
210
+ const fileUploadMiddleware =
211
+ getUploaderMiddlware(webResourceHandler);
198
212
  app
199
213
  .route(apiRoute)
200
214
  .options((_req, res) => res.status(200).end())
201
215
  .get(sbvrUtils.handleODataRequest)
202
216
  .put(sbvrUtils.handleODataRequest)
203
- .post(sbvrUtils.handleODataRequest)
204
- .patch(sbvrUtils.handleODataRequest)
217
+ .post(fileUploadMiddleware, sbvrUtils.handleODataRequest)
218
+ .patch(fileUploadMiddleware, sbvrUtils.handleODataRequest)
205
219
  .merge(sbvrUtils.handleODataRequest)
206
220
  .delete(sbvrUtils.handleODataRequest);
207
221
 
222
+ const loadedModel = sbvrUtils.getModel(model.apiRoot!);
223
+ if (translateTo == null) {
224
+ const resourceNames = Object.values(
225
+ loadedModel.abstractSql.tables,
226
+ )
227
+ .filter((table) =>
228
+ table.fields.some((f) => f.dataType === 'WebResource'),
229
+ )
230
+ .map((table) => table.name);
231
+
232
+ for (const resource of new Set(resourceNames)) {
233
+ setupUploadHooks(webResourceHandler, model.apiRoot!, resource);
234
+ }
235
+ }
236
+
208
237
  console.info(
209
238
  'Successfully executed ' + model.modelName + ' model.',
210
239
  );
@@ -251,7 +280,8 @@ export const setup = (app: Express.Application) => {
251
280
  };
252
281
  const loadConfigFile = async (configPath: string): Promise<Config> => {
253
282
  console.info('Loading config:', configPath);
254
- return await import(configPath);
283
+ const { default: configObj } = await import(configPath);
284
+ return configObj;
255
285
  };
256
286
 
257
287
  const loadApplicationConfig = async (config: string | Config | undefined) => {
@@ -350,9 +380,12 @@ export const setup = (app: Express.Application) => {
350
380
  switch (fileExtension) {
351
381
  case '.coffee':
352
382
  case '.ts':
353
- case '.js':
354
- const loadeMigration = nodeRequire(filePath);
355
- const migration = loadeMigration.default ?? loadeMigration;
383
+ case '.js': {
384
+ const { default: loadedMigration } = await import(filePath);
385
+ const migration =
386
+ // This second check for `.default` is because it might be a commonjs file that was compiled from typescript with `export default`
387
+ // and typescript will add the `.default` but so will the `import()`
388
+ loadedMigration.default ?? loadedMigration;
356
389
 
357
390
  if (
358
391
  !isAsyncMigration(migration) &&
@@ -365,6 +398,7 @@ export const setup = (app: Express.Application) => {
365
398
 
366
399
  assignMigrationWithCategory(migrationKey, migration);
367
400
  break;
401
+ }
368
402
  case '.sql':
369
403
  if (migrationCategory === MigrationCategories.async) {
370
404
  console.error(
@@ -50,7 +50,7 @@ export const cache = {
50
50
  };
51
51
 
52
52
  import { boolVar } from '@balena/env-parsing';
53
- import * as memoize from 'memoizee';
53
+ import memoize from 'memoizee';
54
54
  import memoizeWeak = require('memoizee/weak');
55
55
  export const createCache = <T extends (...args: any[]) => any>(
56
56
  cacheName: keyof typeof cache,
@@ -48,7 +48,7 @@ const serverIsOnAir = async (_req, _res, next) => {
48
48
  };
49
49
 
50
50
  /** @type {import('../config-loader/config-loader').Config} */
51
- export let config = {
51
+ export const config = {
52
52
  models: [
53
53
  {
54
54
  modelName: 'ui',
@@ -267,6 +267,8 @@ export async function setup(app, sbvrUtils, db) {
267
267
  try {
268
268
  await tx.executeSql(query);
269
269
  } catch (err) {
270
+ // TODO: Consider changing this to a custom Error
271
+ // eslint-disable-next-line no-throw-literal
270
272
  throw [query, err];
271
273
  }
272
274
  }
@@ -6,7 +6,7 @@ import type { Dictionary, Resolvable } from '../sbvr-api/common-types';
6
6
 
7
7
  import { Engines } from '@balena/abstract-sql-compiler';
8
8
  import { EventEmitter } from 'eventemitter3';
9
- import * as _ from 'lodash';
9
+ import _ from 'lodash';
10
10
  import { TypedError } from 'typed-error';
11
11
  import * as env from '../config-loader/env';
12
12
  import { fromCallback, timeout } from '../sbvr-api/control-flow';
@@ -168,7 +168,7 @@ const atomicExecuteSql: Database['executeSql'] = async function (
168
168
  };
169
169
 
170
170
  const asyncTryFn = (fn: () => any) => {
171
- Promise.resolve().then(fn);
171
+ void Promise.resolve().then(fn);
172
172
  };
173
173
 
174
174
  type RejectedFunctions = (message: string) => {
@@ -189,7 +189,7 @@ const getRejectedFunctions: RejectedFunctions = env.DEBUG
189
189
  executeSql: rejectFn,
190
190
  rollback: rejectFn,
191
191
  };
192
- }
192
+ }
193
193
  : (message) => {
194
194
  const rejectFn = async () => {
195
195
  throw new TransactionClosedError(message);
@@ -198,7 +198,7 @@ const getRejectedFunctions: RejectedFunctions = env.DEBUG
198
198
  executeSql: rejectFn,
199
199
  rollback: rejectFn,
200
200
  };
201
- };
201
+ };
202
202
 
203
203
  const onEnd: Tx['on'] = (name: string, fn: () => void) => {
204
204
  if (name === 'end') {
@@ -215,7 +215,10 @@ class AutomaticClose {
215
215
  private automaticCloseTimeout: ReturnType<typeof setTimeout>;
216
216
  private automaticClose: () => void;
217
217
  private pending: false | number = 0;
218
- constructor(tx: Tx, private stackTraceErr?: Error) {
218
+ constructor(
219
+ tx: Tx,
220
+ private stackTraceErr?: Error,
221
+ ) {
219
222
  this.automaticClose = () => {
220
223
  console.error(
221
224
  `Transaction still open after ${env.db.timeoutMS}ms without an execute call.`,
@@ -223,7 +226,7 @@ class AutomaticClose {
223
226
  if (this.stackTraceErr) {
224
227
  console.error(this.stackTraceErr.stack);
225
228
  }
226
- tx.rollback();
229
+ void tx.rollback();
227
230
  };
228
231
  this.automaticCloseTimeout = setTimeout(
229
232
  this.automaticClose,
@@ -400,10 +403,13 @@ export abstract class Tx {
400
403
  protected abstract _rollback(): Promise<void>;
401
404
  protected abstract _commit(): Promise<void>;
402
405
 
406
+ // TODO: Re-enable the lint rule once eslint properly supports abstract class base implementations
403
407
  public async getTxLevelLock(
408
+ /* eslint-disable @typescript-eslint/no-unused-vars */
404
409
  _namespaceKey: string,
405
410
  _key: number,
406
411
  _blocking: boolean = true,
412
+ /* eslint-enable @typescript-eslint/no-unused-vars */
407
413
  ): Promise<boolean> {
408
414
  throw new Error(
409
415
  'The getTxLevelLock method is not implemented for the current engine.',
@@ -462,7 +468,6 @@ const createTransaction = (createFunc: CreateTransactionFn): TransactionFn => {
462
468
 
463
469
  let maybePg: typeof Pg | undefined;
464
470
  try {
465
- // tslint:disable-next-line:no-var-requires
466
471
  maybePg = require('pg');
467
472
  } catch (e) {
468
473
  // Ignore errors
@@ -497,7 +502,7 @@ if (maybePg != null) {
497
502
  const p = new pg.Pool(config);
498
503
  if (PG_SCHEMA != null) {
499
504
  p.on('connect', (client) => {
500
- client.query({ text: `SET search_path TO "${PG_SCHEMA}"` });
505
+ void client.query({ text: `SET search_path TO "${PG_SCHEMA}"` });
501
506
  });
502
507
  }
503
508
  p.on('connect', (client) => {
@@ -519,6 +524,7 @@ if (maybePg != null) {
519
524
  let pool: Pg.Pool;
520
525
  let replica: Pg.Pool;
521
526
  if (typeof connectString === 'string') {
527
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
522
528
  const pgConnectionString: typeof PgConnectionString = require('pg-connection-string');
523
529
  // We have to cast because of the use of null vs undefined
524
530
  const config = pgConnectionString.parse(connectString) as Pg.PoolConfig;
@@ -540,12 +546,12 @@ if (maybePg != null) {
540
546
  rowCount,
541
547
  rows,
542
548
  }: {
543
- rowCount: number;
549
+ rowCount: number | null;
544
550
  rows: Row[];
545
551
  }): Result => {
546
552
  return {
547
553
  rows,
548
- rowsAffected: rowCount,
554
+ rowsAffected: rowCount ?? 0,
549
555
  insertId: rows?.[0]?.id,
550
556
  };
551
557
  };
@@ -617,9 +623,9 @@ if (maybePg != null) {
617
623
  );
618
624
  this.db.release();
619
625
  } catch (err: any) {
620
- err = wrapDatabaseError(err);
621
- this.db.release(err);
622
- throw err;
626
+ const errorToReturn = wrapDatabaseError(err);
627
+ this.db.release(errorToReturn);
628
+ throw errorToReturn;
623
629
  }
624
630
  }
625
631
 
@@ -686,13 +692,13 @@ if (maybePg != null) {
686
692
  transaction: createTransaction(async (stackTraceErr) => {
687
693
  const client = await pool.connect();
688
694
  const tx = new PostgresTx(client, false, stackTraceErr);
689
- tx.executeSql('START TRANSACTION;');
695
+ void tx.executeSql('START TRANSACTION;');
690
696
  return tx;
691
697
  }),
692
698
  readTransaction: createTransaction(async (stackTraceErr) => {
693
699
  const client = await replica.connect();
694
700
  const tx = new PostgresTx(client, false, stackTraceErr);
695
- tx.executeSql('START TRANSACTION READ ONLY;');
701
+ void tx.executeSql('START TRANSACTION READ ONLY;');
696
702
  return tx.asReadOnly();
697
703
  }),
698
704
  ...alwaysExport,
@@ -702,7 +708,6 @@ if (maybePg != null) {
702
708
 
703
709
  let maybeMysql: typeof Mysql | undefined;
704
710
  try {
705
- // tslint:disable-next-line:no-var-requires
706
711
  maybeMysql = require('mysql');
707
712
  } catch (e) {
708
713
  // Ignore errors
@@ -809,14 +814,14 @@ if (maybeMysql != null) {
809
814
  const client = await getConnectionAsync();
810
815
  const close = () => client.release();
811
816
  const tx = new MySqlTx(client, close, false, stackTraceErr);
812
- tx.executeSql('START TRANSACTION;');
817
+ void tx.executeSql('START TRANSACTION;');
813
818
  return tx;
814
819
  }),
815
820
  readTransaction: createTransaction(async (stackTraceErr) => {
816
821
  const client = await getConnectionAsync();
817
822
  const close = () => client.release();
818
823
  const tx = new MySqlTx(client, close, false, stackTraceErr);
819
- tx.executeSql('START TRANSACTION READ ONLY;');
824
+ void tx.executeSql('START TRANSACTION READ ONLY;');
820
825
  return tx.asReadOnly();
821
826
  }),
822
827
  ...alwaysExport,
@@ -935,7 +940,6 @@ if (typeof window !== 'undefined' && window.openDatabase != null) {
935
940
  // allowing us to use async calls within the API.
936
941
  private asyncRecurse = () => {
937
942
  let args: AsyncQuery | undefined;
938
- // tslint:disable-next-line no-conditional-assignment
939
943
  while ((args = this.queue.pop())) {
940
944
  console.debug('Running', args[0]);
941
945
  this.tx.executeSql(args[0], args[1], args[2], args[3]);
@@ -1,4 +1,4 @@
1
- import * as _ from 'lodash';
1
+ import _ from 'lodash';
2
2
 
3
3
  /**
4
4
  * @typedef {Partial<Window> & {GLOBAL_PERMISSIONS?: string[]}} ExtendedWindow
@@ -34,10 +34,10 @@ const app = (function () {
34
34
  /** @type {string} */ match,
35
35
  /** @type import('express').Handler[] */ ...middleware
36
36
  ) {
37
- //Strip wildcard
37
+ // Strip wildcard
38
38
  let paramName;
39
39
  match = match.toLowerCase();
40
- const newMatch = match.replace(/[\/\*]*$/, '');
40
+ const newMatch = match.replace(/[/*]*$/, '');
41
41
  if (newMatch !== match) {
42
42
  match = newMatch;
43
43
  paramName = '*';
@@ -59,6 +59,8 @@ const app = (function () {
59
59
  /** @type any */ body = '',
60
60
  ) {
61
61
  if (!handlers[method]) {
62
+ // TODO: Consider changing this to a custom Error
63
+ // eslint-disable-next-line no-throw-literal
62
64
  throw [404, null, null];
63
65
  }
64
66
  const req = {
@@ -1,5 +1,5 @@
1
1
  import { SBVRParser } from '@balena/sbvr-parser';
2
- // tslint:disable-next-line:no-var-requires
2
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
3
3
  const Types: string = require('@balena/sbvr-types/Type.sbvr');
4
4
  import { version as sbvrParserVersion } from '@balena/sbvr-parser/package.json';
5
5
  import { version } from '@balena/sbvr-parser/package.json';
@@ -1,10 +1,10 @@
1
- import * as _ from 'lodash';
2
1
  import { odataNameToSqlName } from '@balena/odata-to-abstract-sql';
3
- // @ts-ignore
2
+ // @ts-expect-error b/c TS doesn't know what the result of requiring an sbvr file would be
3
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
4
4
  const transactionModel = require('./transaction.sbvr');
5
5
 
6
6
  /** @type {import('../config-loader/config-loader').Config} */
7
- export let config = {
7
+ export const config = {
8
8
  models: [
9
9
  {
10
10
  apiRoot: 'transaction',
@@ -130,7 +130,12 @@ WHERE "conditional field"."conditional resource" = ?;`,
130
130
  modelField.dataType === 'ForeignKey' &&
131
131
  Number.isNaN(Number(fieldValue))
132
132
  ) {
133
- if (!placeholders.hasOwnProperty(fieldValue)) {
133
+ if (
134
+ !Object.prototype.hasOwnProperty.call(
135
+ placeholders,
136
+ fieldValue,
137
+ )
138
+ ) {
134
139
  throw new Error('Cannot resolve placeholder' + fieldValue);
135
140
  } else {
136
141
  try {
@@ -170,7 +175,7 @@ WHERE "conditional resource"."transaction" = ?;\
170
175
  resolve = $resolve;
171
176
  reject = $reject;
172
177
  });
173
- // @ts-ignore
178
+ // @ts-expect-error we use resolve & reject before they are assigned b/c we treat them as a deferred.
174
179
  placeholders[placeholder] = { promise, resolve, reject };
175
180
  }
176
181
  }
@@ -1,7 +1,7 @@
1
1
  import type { Tx } from '../database-layer/db';
2
2
  import type { Model } from '../config-loader/config-loader';
3
3
 
4
- import * as _ from 'lodash';
4
+ import _ from 'lodash';
5
5
  import * as sbvrUtils from '../sbvr-api/sbvr-utils';
6
6
 
7
7
  type ApiRootModel = Model & { apiRoot: string };
@@ -12,18 +12,18 @@ type InitialMigrationStatus = MigrationStatus &
12
12
  >;
13
13
 
14
14
  import {
15
- MigrationTuple,
15
+ type MigrationTuple,
16
16
  getExecutedMigrations,
17
17
  migratorEnv,
18
18
  lockMigrations,
19
19
  initMigrationStatus,
20
20
  readMigrationStatus,
21
21
  updateMigrationStatus,
22
- RunnableAsyncMigrations,
22
+ type RunnableAsyncMigrations,
23
23
  getRunnableAsyncMigrations,
24
24
  filterAndSortPendingMigrations,
25
- MigrationStatus,
26
- BaseAsyncMigration,
25
+ type MigrationStatus,
26
+ type BaseAsyncMigration,
27
27
  } from './utils';
28
28
  import { booleanToEnabledString } from '../config-loader/env';
29
29
 
@@ -220,7 +220,8 @@ const $run = async (
220
220
  // skip execution
221
221
  if (migrationState.last_run_time) {
222
222
  const durationSinceLastRun =
223
- Date.now() - migrationState.last_run_time.getTime();
223
+ Date.now() -
224
+ new Date(migrationState.last_run_time).getTime();
224
225
  const delayMs = migrationState.is_backing_off
225
226
  ? initMigrationState.backoffDelayMS
226
227
  : initMigrationState.delayMS;
@@ -1,20 +1,21 @@
1
1
  import {
2
- MigrationTuple,
2
+ type MigrationTuple,
3
3
  MigrationError,
4
+ type MigrationExecutionResult,
4
5
  setExecutedMigrations,
5
6
  getExecutedMigrations,
6
7
  lockMigrations,
7
- RunnableMigrations,
8
+ type RunnableMigrations,
8
9
  filterAndSortPendingMigrations,
9
10
  getRunnableSyncMigrations,
10
11
  } from './utils';
11
12
  import type { Tx } from '../database-layer/db';
12
13
  import type { Config, Model } from '../config-loader/config-loader';
13
14
 
14
- import * as _ from 'lodash';
15
+ import _ from 'lodash';
15
16
  import * as sbvrUtils from '../sbvr-api/sbvr-utils';
16
17
 
17
- // tslint:disable-next-line:no-var-requires
18
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
18
19
  const modelText = require('./migrations.sbvr');
19
20
 
20
21
  type ApiRootModel = Model & { apiRoot: string };
@@ -45,7 +46,10 @@ export const postRun = async (tx: Tx, model: ApiRootModel): Promise<void> => {
45
46
  }
46
47
  };
47
48
 
48
- export const run = async (tx: Tx, model: ApiRootModel): Promise<void> => {
49
+ export const run = async (
50
+ tx: Tx,
51
+ model: ApiRootModel,
52
+ ): Promise<MigrationExecutionResult> => {
49
53
  const { migrations } = model;
50
54
  if (migrations == null || _.isEmpty(migrations)) {
51
55
  return;
@@ -58,7 +62,7 @@ const $run = async (
58
62
  tx: Tx,
59
63
  model: ApiRootModel,
60
64
  migrations: RunnableMigrations,
61
- ): Promise<void> => {
65
+ ): Promise<MigrationExecutionResult> => {
62
66
  const modelName = model.apiRoot;
63
67
 
64
68
  // migrations only run if the model has been executed before,
@@ -68,7 +72,6 @@ const $run = async (
68
72
  (sbvrUtils.api.migrations?.logger.info ?? console.info)(
69
73
  `First time model '${modelName}' has executed, skipping migrations`,
70
74
  );
71
-
72
75
  return await setExecutedMigrations(tx, modelName, Object.keys(migrations));
73
76
  }
74
77
  await lockMigrations({ tx, modelName, blocking: true }, async () => {
@@ -3,7 +3,7 @@ import type { Resolvable } from '../sbvr-api/common-types';
3
3
 
4
4
  import { createHash } from 'crypto';
5
5
  import { Engines } from '@balena/abstract-sql-compiler';
6
- import * as _ from 'lodash';
6
+ import _ from 'lodash';
7
7
  import { TypedError } from 'typed-error';
8
8
  import { migrator as migratorEnv } from '../config-loader/env';
9
9
  export { migrator as migratorEnv } from '../config-loader/env';
@@ -32,12 +32,12 @@ export type AsyncMigrationFn = (
32
32
  sbvrUtils: SbvrUtils,
33
33
  ) => Resolvable<number>;
34
34
 
35
- type AddFn<T extends {}, x extends 'sync' | 'async'> = T & {
35
+ type AddFn<T extends object, x extends 'sync' | 'async'> = T & {
36
36
  [key in `${x}Fn`]: key extends 'syncFn' ? MigrationFn : AsyncMigrationFn;
37
37
  } & {
38
38
  [key in `${x}Sql`]?: undefined;
39
39
  };
40
- type AddSql<T extends {}, x extends 'sync' | 'async'> = T & {
40
+ type AddSql<T extends object, x extends 'sync' | 'async'> = T & {
41
41
  [key in `${x}Fn`]?: undefined;
42
42
  } & {
43
43
  [key in `${x}Sql`]: string;
@@ -105,6 +105,12 @@ export type MigrationStatus = {
105
105
  is_backing_off: boolean;
106
106
  };
107
107
 
108
+ export type MigrationExecutionResult =
109
+ | undefined
110
+ | {
111
+ pendingUnsetMigrations: string[];
112
+ };
113
+
108
114
  export const getRunnableAsyncMigrations = (
109
115
  $migrations: Migrations,
110
116
  ): RunnableAsyncMigrations | undefined => {
@@ -270,9 +276,9 @@ export const setExecutedMigrations = async (
270
276
  tx: Tx,
271
277
  modelName: string,
272
278
  executedMigrations: string[],
273
- ): Promise<void> => {
279
+ ): Promise<MigrationExecutionResult> => {
274
280
  if (!(await migrationTablesExist(tx))) {
275
- return;
281
+ return { pendingUnsetMigrations: executedMigrations };
276
282
  }
277
283
 
278
284
  const stringifiedMigrations = await sbvrUtils.sbvrTypes.JSON.validate(
@@ -3,9 +3,9 @@ import type {
3
3
  AbstractSqlTable,
4
4
  } from '@balena/abstract-sql-compiler';
5
5
 
6
- import sbvrTypes, { SbvrType } from '@balena/sbvr-types';
6
+ import sbvrTypes, { type SbvrType } from '@balena/sbvr-types';
7
7
 
8
- // tslint:disable-next-line:no-var-requires
8
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
9
9
  const { version }: { version: string } = require('../../package.json');
10
10
 
11
11
  const getResourceName = (resourceName: string): string =>
@@ -0,0 +1,46 @@
1
+ import * as passportPinejs from './passport-pinejs';
2
+ import type { Express } from 'express';
3
+ import { PinejsSessionStore } from '../pinejs-session-store/pinejs-session-store';
4
+ import type { setup } from '../config-loader/config-loader';
5
+
6
+ export const mountLoginRouter = async (
7
+ configLoader: ReturnType<typeof setup>,
8
+ expressApp: Express,
9
+ ) => {
10
+ await Promise.all([
11
+ configLoader.loadConfig(passportPinejs.config),
12
+ configLoader.loadConfig(PinejsSessionStore.config),
13
+ ]);
14
+
15
+ if (
16
+ typeof process === 'undefined' ||
17
+ process == null ||
18
+ !process.env.DISABLE_DEFAULT_AUTH
19
+ ) {
20
+ expressApp.post(
21
+ '/login',
22
+ passportPinejs.login((err, user, req, res) => {
23
+ if (err) {
24
+ console.error('Error logging in', err);
25
+ res.status(500).end();
26
+ } else if (user === false) {
27
+ if (req.xhr === true) {
28
+ res.status(401).end();
29
+ } else {
30
+ res.redirect('/login.html');
31
+ }
32
+ } else {
33
+ if (req.xhr === true) {
34
+ res.status(200).end();
35
+ } else {
36
+ res.redirect('/');
37
+ }
38
+ }
39
+ }),
40
+ );
41
+
42
+ expressApp.get('/logout', passportPinejs.logout, (_req, res) => {
43
+ res.redirect('/');
44
+ });
45
+ }
46
+ };