@balena/pinejs 20.1.0-build-large-file-uploads-2-1a7d50e8660ff52fe7df8d6ef9ce8b6b707027dc-1 → 21.0.0-build-21-x-658ee19ce50a7abb157362062f95f9c0ec721330-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 +323 -17
- package/CHANGELOG.md +77 -5
- package/VERSION +1 -1
- package/build/browser.cts +0 -1
- package/build/module.cts +0 -1
- package/build/server.cts +0 -1
- package/out/config-loader/env.d.ts +0 -5
- package/out/config-loader/env.js +0 -7
- package/out/config-loader/env.js.map +1 -1
- package/out/migrator/async.js +6 -7
- package/out/migrator/async.js.map +1 -1
- package/out/sbvr-api/abstract-sql.js +19 -11
- package/out/sbvr-api/abstract-sql.js.map +1 -1
- package/out/sbvr-api/sbvr-utils.d.ts +0 -10
- package/out/sbvr-api/sbvr-utils.js +7 -48
- package/out/sbvr-api/sbvr-utils.js.map +1 -1
- package/out/sbvr-api/translations.js +4 -17
- package/out/sbvr-api/translations.js.map +1 -1
- package/out/sbvr-api/uri-parser.d.ts +7 -1
- package/out/sbvr-api/uri-parser.js +0 -2
- package/out/sbvr-api/uri-parser.js.map +1 -1
- package/out/server-glue/module.js +1 -13
- package/out/server-glue/module.js.map +1 -1
- package/out/tasks/worker.js +1 -0
- package/out/tasks/worker.js.map +1 -1
- package/out/webresource-handler/index.d.ts +0 -42
- package/out/webresource-handler/index.js +1 -24
- package/out/webresource-handler/index.js.map +1 -1
- package/package.json +30 -30
- package/src/config-loader/env.ts +0 -14
- package/src/migrator/async.ts +20 -21
- package/src/sbvr-api/abstract-sql.ts +30 -25
- package/src/sbvr-api/sbvr-utils.ts +9 -58
- package/src/sbvr-api/translations.ts +5 -18
- package/src/sbvr-api/uri-parser.ts +11 -4
- package/src/server-glue/module.ts +1 -15
- package/src/tasks/worker.ts +3 -0
- package/src/webresource-handler/index.ts +0 -85
- package/out/data-server/sbvr-server.d.ts +0 -17
- package/out/data-server/sbvr-server.js +0 -350
- package/out/data-server/sbvr-server.js.map +0 -1
- package/out/http-transactions/transaction.sbvr +0 -59
- package/out/http-transactions/transactions.d.ts +0 -3
- package/out/http-transactions/transactions.js +0 -305
- package/out/http-transactions/transactions.js.map +0 -1
- package/out/webresource-handler/multipartUpload.d.ts +0 -12
- package/out/webresource-handler/multipartUpload.js +0 -251
- package/out/webresource-handler/multipartUpload.js.map +0 -1
- package/out/webresource-handler/webresource.d.ts +0 -42
- package/out/webresource-handler/webresource.js +0 -2
- package/out/webresource-handler/webresource.js.map +0 -1
- package/out/webresource-handler/webresource.sbvr +0 -60
- package/src/data-server/sbvr-server.ts +0 -412
- package/src/http-transactions/transaction.sbvr +0 -59
- package/src/http-transactions/transactions.js +0 -305
- package/src/webresource-handler/multipartUpload.ts +0 -368
- package/src/webresource-handler/webresource.sbvr +0 -60
- package/src/webresource-handler/webresource.ts +0 -48
@@ -471,7 +471,7 @@ const bindsForAffectedIds = (
|
|
471
471
|
return odataBinds;
|
472
472
|
};
|
473
473
|
|
474
|
-
|
474
|
+
const validateModel = async (
|
475
475
|
tx: Db.Tx,
|
476
476
|
modelName: string,
|
477
477
|
request?: Pick<
|
@@ -770,6 +770,13 @@ export const executeModels = async (
|
|
770
770
|
await asyncMigrator.run(tx, model);
|
771
771
|
}),
|
772
772
|
);
|
773
|
+
// Allow the migrations to be GCed after we are done
|
774
|
+
// executing the models & their migrations.
|
775
|
+
for (const model of execModels) {
|
776
|
+
if (model.migrations != null) {
|
777
|
+
delete model.migrations;
|
778
|
+
}
|
779
|
+
}
|
773
780
|
} catch (err) {
|
774
781
|
for (const { apiRoot } of execModels) {
|
775
782
|
cleanupModel(apiRoot);
|
@@ -800,62 +807,6 @@ const cleanupModel = (vocab: string) => {
|
|
800
807
|
delete api[vocab];
|
801
808
|
};
|
802
809
|
|
803
|
-
export const deleteModel = async (vocabulary: string) => {
|
804
|
-
const { sql } = models[vocabulary];
|
805
|
-
if (sql) {
|
806
|
-
await db.transaction(async (tx) => {
|
807
|
-
const dropStatements: Array<Promise<any>> = sql.dropSchema.map(
|
808
|
-
(dropStatement) => tx.executeSql(dropStatement),
|
809
|
-
);
|
810
|
-
await Promise.all(
|
811
|
-
dropStatements.concat([
|
812
|
-
api.dev.delete({
|
813
|
-
resource: 'model',
|
814
|
-
passthrough: {
|
815
|
-
tx,
|
816
|
-
req: permissions.root,
|
817
|
-
},
|
818
|
-
options: {
|
819
|
-
$filter: {
|
820
|
-
is_of__vocabulary: vocabulary,
|
821
|
-
},
|
822
|
-
},
|
823
|
-
}),
|
824
|
-
]),
|
825
|
-
);
|
826
|
-
});
|
827
|
-
}
|
828
|
-
cleanupModel(vocabulary);
|
829
|
-
};
|
830
|
-
|
831
|
-
const isWhereNode = (
|
832
|
-
x: AbstractSQLCompiler.AbstractSqlType,
|
833
|
-
): x is AbstractSQLCompiler.WhereNode => x[0] === 'Where';
|
834
|
-
const isEqualsNode = (
|
835
|
-
x: AbstractSQLCompiler.AbstractSqlType,
|
836
|
-
): x is AbstractSQLCompiler.EqualsNode => x[0] === 'Equals';
|
837
|
-
export const getID = (vocab: string, request: uriParser.ODataRequest) => {
|
838
|
-
if (request.abstractSqlQuery == null) {
|
839
|
-
throw new Error('Can only get the id if an abstractSqlQuery is provided');
|
840
|
-
}
|
841
|
-
const { idField } = models[vocab].abstractSql.tables[request.resourceName];
|
842
|
-
for (const whereClause of request.abstractSqlQuery) {
|
843
|
-
if (isWhereNode(whereClause)) {
|
844
|
-
for (const comparison of whereClause.slice(1)) {
|
845
|
-
if (isEqualsNode(comparison)) {
|
846
|
-
if (comparison[1][2] === idField) {
|
847
|
-
return comparison[2][1];
|
848
|
-
}
|
849
|
-
if (comparison[2][2] === idField) {
|
850
|
-
return comparison[1][1];
|
851
|
-
}
|
852
|
-
}
|
853
|
-
}
|
854
|
-
}
|
855
|
-
}
|
856
|
-
return 0;
|
857
|
-
};
|
858
|
-
|
859
810
|
export const runRule = (() => {
|
860
811
|
const LF2AbstractSQLPrepHack = LF2AbstractSQL.LF2AbstractSQLPrep._extend({
|
861
812
|
CardinalityOptimisation() {
|
@@ -2064,7 +2015,7 @@ const devModelConfig = {
|
|
2064
2015
|
},
|
2065
2016
|
},
|
2066
2017
|
} as const satisfies ExecutableModel;
|
2067
|
-
|
2018
|
+
const executeStandardModels = async (tx: Db.Tx): Promise<void> => {
|
2068
2019
|
try {
|
2069
2020
|
// dev model must run first
|
2070
2021
|
await executeModel(tx, devModelConfig);
|
@@ -206,30 +206,17 @@ export const translateAbstractSqlModel = (
|
|
206
206
|
const { $toResource, ...definition } = translationDefinition;
|
207
207
|
const hasToResource = typeof $toResource === 'string';
|
208
208
|
|
209
|
-
const unaliasedToResource = hasToResource
|
210
|
-
? $toResource.endsWith(toVersionSuffix)
|
211
|
-
? // Ideally we want to rename to the unaliased resource of the next version
|
212
|
-
// so when the alias matches the next version we can just strip it
|
213
|
-
$toResource.slice(0, -toVersionSuffix.length)
|
214
|
-
: // But if we can't safely strip the suffix then we'll use as-is, at least until the next major
|
215
|
-
$toResource
|
216
|
-
: key;
|
217
|
-
let aliasedToResource;
|
209
|
+
const unaliasedToResource = hasToResource ? $toResource : key;
|
218
210
|
if (hasToResource) {
|
219
|
-
resourceRenames[key] = unaliasedToResource;
|
220
211
|
if ($toResource.includes('$')) {
|
221
|
-
|
222
|
-
console.warn(
|
212
|
+
throw new Error(
|
223
213
|
`'$toResource' should be the unaliased name of the resource in the subsequent model and not be targeting a specific model, got '${$toResource}'`,
|
224
|
-
$toResource,
|
225
214
|
);
|
226
|
-
aliasedToResource = $toResource;
|
227
|
-
} else {
|
228
|
-
aliasedToResource = `${$toResource}${toVersionSuffix}`;
|
229
215
|
}
|
230
|
-
|
231
|
-
aliasedToResource = `${key}${toVersionSuffix}`;
|
216
|
+
resourceRenames[key] = unaliasedToResource;
|
232
217
|
}
|
218
|
+
const aliasedToResource = `${unaliasedToResource}${toVersionSuffix}`;
|
219
|
+
|
233
220
|
const toTable = toAbstractSqlModel.tables[unaliasedToResource];
|
234
221
|
if (!toTable) {
|
235
222
|
if (hasToResource) {
|
@@ -16,7 +16,6 @@ import _ from 'lodash';
|
|
16
16
|
import memoizeWeak from 'memoizee/weak.js';
|
17
17
|
|
18
18
|
export { BadRequestError, ParsingError, TranslationError } from './errors.js';
|
19
|
-
import deepFreeze from 'deep-freeze';
|
20
19
|
import * as env from '../config-loader/env.js';
|
21
20
|
import {
|
22
21
|
BadRequestError,
|
@@ -53,11 +52,19 @@ export interface ParsedODataRequest {
|
|
53
52
|
id?: number | undefined;
|
54
53
|
_defer?: boolean;
|
55
54
|
}
|
55
|
+
export interface CachedSqlQuery extends Array<never> {
|
56
|
+
length: 0;
|
57
|
+
engine: AbstractSQLCompiler.Engines;
|
58
|
+
sqlQuery: AbstractSQLCompiler.SqlResult | AbstractSQLCompiler.SqlResult[];
|
59
|
+
modifiedFields?: ReturnType<
|
60
|
+
AbstractSQLCompiler.EngineInstance['getModifiedFields']
|
61
|
+
>;
|
62
|
+
}
|
56
63
|
export interface ODataRequest extends ParsedODataRequest {
|
57
64
|
translateVersions: string[];
|
58
65
|
abstractSqlModel?: AbstractSQLCompiler.AbstractSqlModel;
|
59
66
|
finalAbstractSqlModel?: AbstractSQLCompiler.AbstractSqlModel;
|
60
|
-
abstractSqlQuery?: AbstractSQLCompiler.AbstractSqlQuery;
|
67
|
+
abstractSqlQuery?: AbstractSQLCompiler.AbstractSqlQuery | CachedSqlQuery;
|
61
68
|
sqlQuery?: AbstractSQLCompiler.SqlResult | AbstractSQLCompiler.SqlResult[];
|
62
69
|
tx?: Tx;
|
63
70
|
modifiedFields?: ReturnType<
|
@@ -178,8 +185,8 @@ const memoizedOdata2AbstractSQL = (() => {
|
|
178
185
|
bodyKeys,
|
179
186
|
existingBindVarsLength,
|
180
187
|
);
|
181
|
-
// We deep freeze
|
182
|
-
|
188
|
+
// We do not deep freeze as the sql compilation intentionally mutates this object
|
189
|
+
// to clear the abstractSql tree and replace it with the compile sqlQuery to save memory
|
183
190
|
return abstractSql;
|
184
191
|
} catch (e) {
|
185
192
|
if (e instanceof PermissionError) {
|
@@ -7,7 +7,6 @@ import * as configLoader from '../config-loader/config-loader.js';
|
|
7
7
|
import * as migrator from '../migrator/sync.js';
|
8
8
|
import type * as migratorUtils from '../migrator/utils.js';
|
9
9
|
import * as tasks from '../tasks/index.js';
|
10
|
-
import * as webresource from '../webresource-handler/index.js';
|
11
10
|
|
12
11
|
import * as sbvrUtils from '../sbvr-api/sbvr-utils.js';
|
13
12
|
import { PINEJS_ADVISORY_LOCK } from '../config-loader/env.js';
|
@@ -67,23 +66,10 @@ export const init = async <T extends string>(
|
|
67
66
|
const cfgLoader = configLoader.setup(app);
|
68
67
|
await cfgLoader.loadConfig(migrator.config);
|
69
68
|
await cfgLoader.loadConfig(tasks.config);
|
70
|
-
await cfgLoader.loadConfig(webresource.config);
|
71
69
|
|
72
|
-
const promises: Array<Promise<void>> = [];
|
73
|
-
if (process.env.SBVR_SERVER_ENABLED) {
|
74
|
-
const sbvrServer = await import('../data-server/sbvr-server.js');
|
75
|
-
const transactions = await import('../http-transactions/transactions.js');
|
76
|
-
promises.push(cfgLoader.loadConfig(sbvrServer.config));
|
77
|
-
promises.push(
|
78
|
-
cfgLoader.loadConfig(transactions.config).then(() => {
|
79
|
-
transactions.addModelHooks('data');
|
80
|
-
}),
|
81
|
-
);
|
82
|
-
}
|
83
70
|
if (!process.env.CONFIG_LOADER_DISABLED) {
|
84
|
-
|
71
|
+
await cfgLoader.loadApplicationConfig(config);
|
85
72
|
}
|
86
|
-
await Promise.all(promises);
|
87
73
|
// Execute it after all other promises have resolved. Execution of promises is not neccessarily
|
88
74
|
// guaranteed to be sequentially resolving them with Promise.all
|
89
75
|
await sbvrUtils.postSetup(app, db);
|
package/src/tasks/worker.ts
CHANGED
@@ -246,6 +246,9 @@ export class Worker {
|
|
246
246
|
});
|
247
247
|
} catch (err) {
|
248
248
|
console.error('Failed polling for tasks:', err);
|
249
|
+
// Add some delay after an error to avoid retrying at max speed
|
250
|
+
// TODO: This should be configurable/adaptive
|
251
|
+
await setTimeout(100);
|
249
252
|
} finally {
|
250
253
|
if (!executed) {
|
251
254
|
await setTimeout(this.interval);
|
@@ -11,20 +11,12 @@ import {
|
|
11
11
|
odataNameToSqlName,
|
12
12
|
sqlNameToODataName,
|
13
13
|
} from '@balena/odata-to-abstract-sql';
|
14
|
-
import type { ConfigLoader } from '../server-glue/module.js';
|
15
14
|
import { errors, permissions } from '../server-glue/module.js';
|
16
15
|
import type { WebResourceType as WebResource } from '@balena/sbvr-types';
|
17
16
|
import { TypedError } from 'typed-error';
|
18
17
|
import type { Resolvable } from '../sbvr-api/common-types.js';
|
19
|
-
import type WebresourceModel from './webresource.js';
|
20
|
-
import { importSBVR } from '../server-glue/sbvr-loader.js';
|
21
|
-
import {
|
22
|
-
isMultipartUploadAvailable,
|
23
|
-
multipartUploadHooks,
|
24
|
-
} from './multipartUpload.js';
|
25
18
|
|
26
19
|
export * from './handlers/index.js';
|
27
|
-
export type { BeginUploadResponse } from './multipartUpload.js';
|
28
20
|
|
29
21
|
export interface IncomingFile {
|
30
22
|
fieldname: string;
|
@@ -39,51 +31,10 @@ export interface UploadResponse {
|
|
39
31
|
filename: string;
|
40
32
|
}
|
41
33
|
|
42
|
-
export interface BeginMultipartUploadPayload {
|
43
|
-
filename: string;
|
44
|
-
content_type: string;
|
45
|
-
size: number;
|
46
|
-
chunk_size: number;
|
47
|
-
}
|
48
|
-
|
49
|
-
export interface UploadPart {
|
50
|
-
url: string;
|
51
|
-
chunkSize: number;
|
52
|
-
partNumber: number;
|
53
|
-
}
|
54
|
-
|
55
|
-
export interface BeginMultipartUploadHandlerResponse {
|
56
|
-
uploadParts: UploadPart[];
|
57
|
-
fileKey: string;
|
58
|
-
uploadId: string;
|
59
|
-
}
|
60
|
-
|
61
|
-
export interface CommitMultipartUploadPayload {
|
62
|
-
fileKey: string;
|
63
|
-
uploadId: string;
|
64
|
-
filename: string;
|
65
|
-
providerCommitData?: Record<string, any>;
|
66
|
-
}
|
67
|
-
|
68
|
-
export interface CancelMultipartUploadPayload {
|
69
|
-
fileKey: string;
|
70
|
-
uploadId: string;
|
71
|
-
}
|
72
|
-
|
73
34
|
export interface WebResourceHandler {
|
74
35
|
handleFile: (resource: IncomingFile) => Promise<UploadResponse>;
|
75
36
|
removeFile: (fileReference: string) => Promise<void>;
|
76
37
|
onPreRespond: (webResource: WebResource) => Promise<WebResource>;
|
77
|
-
multipartUpload?: {
|
78
|
-
begin: (
|
79
|
-
fieldName: string,
|
80
|
-
payload: BeginMultipartUploadPayload,
|
81
|
-
) => Promise<BeginMultipartUploadHandlerResponse>;
|
82
|
-
commit: (commitInfo: CommitMultipartUploadPayload) => Promise<WebResource>;
|
83
|
-
cancel: (cancelInfo: CancelMultipartUploadPayload) => Promise<void>;
|
84
|
-
getMinimumPartSize: () => number;
|
85
|
-
getDefaultPartSize: () => number;
|
86
|
-
};
|
87
38
|
}
|
88
39
|
|
89
40
|
export class WebResourceError extends TypedError {}
|
@@ -337,9 +288,6 @@ const throwIfWebresourceNotInMultipart = (
|
|
337
288
|
{ req, request }: HookArgs,
|
338
289
|
) => {
|
339
290
|
if (
|
340
|
-
request.custom.isAction !== 'beginUpload' &&
|
341
|
-
request.custom.isAction !== 'commitUpload' &&
|
342
|
-
request.custom.isAction !== 'cancelUpload' &&
|
343
291
|
!req.is?.('multipart') &&
|
344
292
|
webResourceFields.some((field) => request.values[field] != null)
|
345
293
|
) {
|
@@ -536,37 +484,4 @@ export const setupUploadHooks = (
|
|
536
484
|
resourceName,
|
537
485
|
getCreateWebResourceHooks(handler),
|
538
486
|
);
|
539
|
-
|
540
|
-
if (isMultipartUploadAvailable(handler)) {
|
541
|
-
sbvrUtils.addPureHook(
|
542
|
-
'POST',
|
543
|
-
apiRoot,
|
544
|
-
resourceName,
|
545
|
-
multipartUploadHooks(handler),
|
546
|
-
);
|
547
|
-
}
|
548
|
-
};
|
549
|
-
|
550
|
-
const initSql = `
|
551
|
-
CREATE INDEX IF NOT EXISTS idx_multipart_upload_uuid ON "multipart upload" (uuid);
|
552
|
-
CREATE INDEX IF NOT EXISTS idx_multipart_upload_status ON "multipart upload" (status);
|
553
|
-
`;
|
554
|
-
|
555
|
-
const modelText = await importSBVR('./webresource.sbvr', import.meta);
|
556
|
-
|
557
|
-
declare module '../sbvr-api/sbvr-utils.js' {
|
558
|
-
export interface API {
|
559
|
-
webresource: PinejsClient<WebresourceModel>;
|
560
|
-
}
|
561
|
-
}
|
562
|
-
|
563
|
-
export const config: ConfigLoader.Config = {
|
564
|
-
models: [
|
565
|
-
{
|
566
|
-
modelName: 'webresource',
|
567
|
-
apiRoot: 'webresource',
|
568
|
-
modelText,
|
569
|
-
initSql,
|
570
|
-
},
|
571
|
-
],
|
572
487
|
};
|
@@ -1,17 +0,0 @@
|
|
1
|
-
import type { SetupFunction } from '../config-loader/config-loader.js';
|
2
|
-
import type { Tx } from '../database-layer/db.js';
|
3
|
-
export declare const setup: SetupFunction;
|
4
|
-
export declare const config: {
|
5
|
-
models: {
|
6
|
-
modelName: string;
|
7
|
-
modelText: string;
|
8
|
-
apiRoot: string;
|
9
|
-
customServerCode: {
|
10
|
-
setup: SetupFunction;
|
11
|
-
};
|
12
|
-
migrations: {
|
13
|
-
'11.0.0-modified-at': string;
|
14
|
-
'15.0.0-data-types': (tx: Tx, sbvrUtils: typeof import("../sbvr-api/sbvr-utils.js")) => Promise<void>;
|
15
|
-
};
|
16
|
-
}[];
|
17
|
-
};
|