@balena/pinejs 16.0.0-build--batch-09b8c466600d7df13e6df3eacabaf463d96f652f-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.
- package/.pinejs-cache.json +1 -1
- package/.versionbot/CHANGELOG.yml +2164 -15
- package/CHANGELOG.md +815 -3
- package/Gruntfile.ts +9 -6
- package/README.md +10 -0
- package/build/browser.ts +2 -2
- package/build/config.ts +1 -1
- package/build/module.ts +2 -2
- package/build/server.ts +2 -2
- package/docker-compose.npm-test.yml +21 -3
- package/out/bin/abstract-sql-compiler.js +5 -5
- package/out/bin/abstract-sql-compiler.js.map +1 -1
- package/out/bin/odata-compiler.js +10 -10
- package/out/bin/odata-compiler.js.map +1 -1
- package/out/bin/sbvr-compiler.js +34 -11
- package/out/bin/sbvr-compiler.js.map +1 -1
- package/out/bin/utils.js +25 -2
- package/out/bin/utils.js.map +1 -1
- package/out/config-loader/config-loader.d.ts +4 -2
- package/out/config-loader/config-loader.js +54 -13
- package/out/config-loader/config-loader.js.map +1 -1
- package/out/config-loader/env.d.ts +2 -1
- package/out/config-loader/env.js +5 -2
- package/out/config-loader/env.js.map +1 -1
- package/out/data-server/sbvr-server.d.ts +1 -1
- package/out/data-server/sbvr-server.js +3 -1
- package/out/data-server/sbvr-server.js.map +1 -1
- package/out/database-layer/db.js +40 -14
- package/out/database-layer/db.js.map +1 -1
- package/out/express-emulator/express.js +5 -3
- package/out/express-emulator/express.js.map +1 -1
- package/out/http-transactions/transactions.d.ts +1 -1
- package/out/http-transactions/transactions.js +10 -5
- package/out/http-transactions/transactions.js.map +1 -1
- package/out/migrator/async.js +32 -5
- package/out/migrator/async.js.map +1 -1
- package/out/migrator/sync.d.ts +2 -1
- package/out/migrator/sync.js +29 -3
- package/out/migrator/sync.js.map +1 -1
- package/out/migrator/utils.d.ts +6 -3
- package/out/migrator/utils.js +30 -4
- package/out/migrator/utils.js.map +1 -1
- package/out/odata-metadata/odata-metadata-generator.js +4 -1
- package/out/odata-metadata/odata-metadata-generator.js.map +1 -1
- package/out/passport-pinejs/mount-login-router.d.ts +3 -0
- package/out/passport-pinejs/mount-login-router.js +65 -0
- package/out/passport-pinejs/mount-login-router.js.map +1 -0
- package/out/passport-pinejs/passport-pinejs.d.ts +2 -1
- package/out/passport-pinejs/passport-pinejs.js +28 -2
- package/out/passport-pinejs/passport-pinejs.js.map +1 -1
- package/out/pinejs-session-store/pinejs-session-store.js +30 -7
- package/out/pinejs-session-store/pinejs-session-store.js.map +1 -1
- package/out/sbvr-api/abstract-sql.d.ts +2 -2
- package/out/sbvr-api/abstract-sql.js +35 -9
- package/out/sbvr-api/abstract-sql.js.map +1 -1
- package/out/sbvr-api/cached-compile.js +9 -6
- package/out/sbvr-api/cached-compile.js.map +1 -1
- package/out/sbvr-api/common-types.d.ts +1 -1
- package/out/sbvr-api/control-flow.js +5 -2
- package/out/sbvr-api/control-flow.js.map +1 -1
- package/out/sbvr-api/express-extension.d.ts +10 -7
- package/out/sbvr-api/express-extension.js +1 -0
- package/out/sbvr-api/hooks.d.ts +5 -1
- package/out/sbvr-api/hooks.js +12 -10
- package/out/sbvr-api/hooks.js.map +1 -1
- package/out/sbvr-api/odata-response.d.ts +5 -2
- package/out/sbvr-api/odata-response.js +36 -6
- package/out/sbvr-api/odata-response.js.map +1 -1
- package/out/sbvr-api/permissions.d.ts +6 -7
- package/out/sbvr-api/permissions.js +69 -38
- package/out/sbvr-api/permissions.js.map +1 -1
- package/out/sbvr-api/sbvr-utils.d.ts +21 -10
- package/out/sbvr-api/sbvr-utils.js +128 -124
- package/out/sbvr-api/sbvr-utils.js.map +1 -1
- package/out/sbvr-api/translations.d.ts +2 -2
- package/out/sbvr-api/translations.js +17 -10
- package/out/sbvr-api/translations.js.map +1 -1
- package/out/sbvr-api/uri-parser.d.ts +10 -12
- package/out/sbvr-api/uri-parser.js +46 -19
- package/out/sbvr-api/uri-parser.js.map +1 -1
- package/out/server-glue/global-ext.d.ts +2 -1
- package/out/server-glue/module.d.ts +3 -1
- package/out/server-glue/module.js +40 -13
- package/out/server-glue/module.js.map +1 -1
- package/out/server-glue/sbvr-loader.js.map +1 -1
- package/out/server-glue/server.js +31 -39
- package/out/server-glue/server.js.map +1 -1
- package/out/webresource-handler/handlers/NoopHandler.d.ts +7 -0
- package/out/webresource-handler/handlers/NoopHandler.js +20 -0
- package/out/webresource-handler/handlers/NoopHandler.js.map +1 -0
- package/out/webresource-handler/handlers/S3Handler.d.ts +28 -0
- package/out/webresource-handler/handlers/S3Handler.js +97 -0
- package/out/webresource-handler/handlers/S3Handler.js.map +1 -0
- package/out/webresource-handler/handlers/index.d.ts +2 -0
- package/out/webresource-handler/handlers/index.js +19 -0
- package/out/webresource-handler/handlers/index.js.map +1 -0
- package/out/webresource-handler/index.d.ts +34 -0
- package/out/webresource-handler/index.js +307 -0
- package/out/webresource-handler/index.js.map +1 -0
- package/package.json +68 -62
- package/src/bin/abstract-sql-compiler.ts +7 -9
- package/src/bin/odata-compiler.ts +12 -15
- package/src/bin/sbvr-compiler.ts +14 -18
- package/src/bin/utils.ts +1 -1
- package/src/config-loader/config-loader.ts +44 -10
- package/src/config-loader/env.ts +1 -1
- package/src/data-server/sbvr-server.js +3 -1
- package/src/database-layer/db.ts +23 -19
- package/src/express-emulator/express.js +5 -3
- package/src/extended-sbvr-parser/extended-sbvr-parser.ts +1 -1
- package/src/http-transactions/transactions.js +10 -5
- package/src/migrator/async.ts +7 -6
- package/src/migrator/sync.ts +10 -7
- package/src/migrator/utils.ts +11 -5
- package/src/odata-metadata/odata-metadata-generator.ts +2 -2
- package/src/passport-pinejs/mount-login-router.ts +46 -0
- package/src/passport-pinejs/passport-pinejs.ts +7 -3
- package/src/pinejs-session-store/pinejs-session-store.ts +6 -6
- package/src/sbvr-api/abstract-sql.ts +5 -5
- package/src/sbvr-api/cached-compile.ts +1 -2
- package/src/sbvr-api/common-types.ts +1 -1
- package/src/sbvr-api/control-flow.ts +1 -1
- package/src/sbvr-api/express-extension.ts +12 -8
- package/src/sbvr-api/hooks.ts +11 -11
- package/src/sbvr-api/odata-response.ts +56 -9
- package/src/sbvr-api/permissions.ts +44 -35
- package/src/sbvr-api/sbvr-utils.ts +117 -165
- package/src/sbvr-api/translations.ts +9 -6
- package/src/sbvr-api/uri-parser.ts +25 -30
- package/src/server-glue/global-ext.d.ts +2 -1
- package/src/server-glue/module.ts +8 -2
- package/src/server-glue/sbvr-loader.ts +1 -1
- package/src/server-glue/server.ts +11 -49
- package/src/webresource-handler/handlers/NoopHandler.ts +21 -0
- package/src/webresource-handler/handlers/S3Handler.ts +143 -0
- package/src/webresource-handler/handlers/index.ts +2 -0
- package/src/webresource-handler/index.ts +450 -0
- package/tsconfig.dev.json +2 -1
- package/tsconfig.json +1 -1
- package/typings/lf-to-abstract-sql.d.ts +1 -1
- package/typings/memoizee.d.ts +3 -4
package/src/bin/sbvr-compiler.ts
CHANGED
@@ -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
|
-
|
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
|
-
|
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.
|
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
|
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 {
|
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
|
-
|
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
|
355
|
-
const migration =
|
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(
|
package/src/config-loader/env.ts
CHANGED
@@ -50,7 +50,7 @@ export const cache = {
|
|
50
50
|
};
|
51
51
|
|
52
52
|
import { boolVar } from '@balena/env-parsing';
|
53
|
-
import
|
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
|
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
|
}
|
package/src/database-layer/db.ts
CHANGED
@@ -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
|
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(
|
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
|
-
|
621
|
-
this.db.release(
|
622
|
-
throw
|
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
|
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
|
-
//
|
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-
|
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
|
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 (
|
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-
|
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
|
}
|
package/src/migrator/async.ts
CHANGED
@@ -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
|
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() -
|
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;
|
package/src/migrator/sync.ts
CHANGED
@@ -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
|
15
|
+
import _ from 'lodash';
|
15
16
|
import * as sbvrUtils from '../sbvr-api/sbvr-utils';
|
16
17
|
|
17
|
-
//
|
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 (
|
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<
|
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 () => {
|
package/src/migrator/utils.ts
CHANGED
@@ -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
|
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
|
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
|
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<
|
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
|
-
//
|
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
|
+
};
|