@balena/pinejs 17.1.0-build-joshbwlng-tasks-9f3f42ef1bf62714507bacc7842e99841b116d94-1 → 17.1.0-build-model-based-typings-c276ef4fb8482a246c25940d617d76b76847eff8-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 +232 -10
- package/CHANGELOG.md +70 -3
- package/out/config-loader/env.d.ts +0 -4
- package/out/config-loader/env.js +1 -5
- package/out/config-loader/env.js.map +1 -1
- package/out/data-server/sbvr-server.js +3 -2
- package/out/data-server/sbvr-server.js.map +1 -1
- package/out/database-layer/db.d.ts +0 -3
- package/out/database-layer/db.js +0 -17
- package/out/database-layer/db.js.map +1 -1
- package/out/migrator/migrations.d.ts +58 -0
- package/out/migrator/migrations.js +3 -0
- package/out/migrator/migrations.js.map +1 -0
- package/out/migrator/sync.d.ts +17 -0
- package/out/migrator/sync.js +39 -40
- package/out/migrator/sync.js.map +1 -1
- package/out/sbvr-api/dev.d.ts +22 -0
- package/out/sbvr-api/dev.js +3 -0
- package/out/sbvr-api/dev.js.map +1 -0
- package/out/sbvr-api/hooks.d.ts +28 -28
- package/out/sbvr-api/hooks.js.map +1 -1
- package/out/sbvr-api/permissions.d.ts +26 -2
- package/out/sbvr-api/permissions.js +39 -40
- package/out/sbvr-api/permissions.js.map +1 -1
- package/out/sbvr-api/sbvr-utils.d.ts +46 -6
- package/out/sbvr-api/sbvr-utils.js +44 -44
- package/out/sbvr-api/sbvr-utils.js.map +1 -1
- package/out/sbvr-api/user.d.ts +236 -0
- package/out/sbvr-api/user.js +3 -0
- package/out/sbvr-api/user.js.map +1 -0
- package/out/server-glue/module.d.ts +0 -1
- package/out/server-glue/module.js +1 -4
- package/out/server-glue/module.js.map +1 -1
- package/package.json +19 -20
- package/src/config-loader/env.ts +1 -6
- package/src/data-server/sbvr-server.js +3 -2
- package/src/database-layer/db.ts +0 -25
- package/src/migrator/migrations.ts +64 -0
- package/src/migrator/sync.ts +46 -41
- package/src/sbvr-api/dev.ts +26 -0
- package/src/sbvr-api/hooks.ts +19 -18
- package/src/sbvr-api/permissions.ts +54 -48
- package/src/sbvr-api/sbvr-utils.ts +93 -53
- package/src/sbvr-api/user.ts +216 -0
- package/src/server-glue/module.ts +0 -3
- package/out/tasks/common.d.ts +0 -4
- package/out/tasks/common.js +0 -13
- package/out/tasks/common.js.map +0 -1
- package/out/tasks/index.d.ts +0 -8
- package/out/tasks/index.js +0 -140
- package/out/tasks/index.js.map +0 -1
- package/out/tasks/tasks.sbvr +0 -55
- package/out/tasks/types.d.ts +0 -37
- package/out/tasks/types.js +0 -10
- package/out/tasks/types.js.map +0 -1
- package/out/tasks/worker.d.ts +0 -16
- package/out/tasks/worker.js +0 -226
- package/out/tasks/worker.js.map +0 -1
- package/src/tasks/common.ts +0 -14
- package/src/tasks/index.ts +0 -155
- package/src/tasks/tasks.sbvr +0 -55
- package/src/tasks/types.ts +0 -56
- package/src/tasks/worker.ts +0 -276
@@ -2,6 +2,10 @@ import type * as Express from 'express';
|
|
2
2
|
import type * as Db from '../database-layer/db';
|
3
3
|
import type { Model } from '../config-loader/config-loader';
|
4
4
|
import type { AnyObject, RequiredField } from './common-types';
|
5
|
+
import type {
|
6
|
+
PickDeferred,
|
7
|
+
Resource,
|
8
|
+
} from '@balena/abstract-sql-to-typescript';
|
5
9
|
|
6
10
|
// Augment the Express typings
|
7
11
|
declare global {
|
@@ -32,6 +36,7 @@ import {
|
|
32
36
|
} from '@balena/odata-to-abstract-sql';
|
33
37
|
import sbvrTypes from '@balena/sbvr-types';
|
34
38
|
import deepFreeze = require('deep-freeze');
|
39
|
+
import type { AnyResource, Params } from 'pinejs-client-core';
|
35
40
|
import { PinejsClientCore, type PromiseResultTypes } from 'pinejs-client-core';
|
36
41
|
|
37
42
|
import { ExtendedSBVRParser } from '../extended-sbvr-parser/extended-sbvr-parser';
|
@@ -40,9 +45,9 @@ import * as asyncMigrator from '../migrator/async';
|
|
40
45
|
import * as syncMigrator from '../migrator/sync';
|
41
46
|
import { generateODataMetadata } from '../odata-metadata/odata-metadata-generator';
|
42
47
|
|
48
|
+
import type DevModel from './dev';
|
43
49
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
44
50
|
const devModel = require('./dev.sbvr');
|
45
|
-
import * as tasks from '../tasks';
|
46
51
|
import * as permissions from './permissions';
|
47
52
|
import {
|
48
53
|
BadRequestError,
|
@@ -78,7 +83,6 @@ export {
|
|
78
83
|
addPureHook,
|
79
84
|
addSideEffectHook,
|
80
85
|
} from './hooks';
|
81
|
-
export { addTaskHandler } from '../tasks';
|
82
86
|
|
83
87
|
import memoizeWeak = require('memoizee/weak');
|
84
88
|
import * as controlFlow from './control-flow';
|
@@ -712,7 +716,7 @@ export const executeModels = async (
|
|
712
716
|
},
|
713
717
|
});
|
714
718
|
}
|
715
|
-
const result =
|
719
|
+
const result = await api.dev.get({
|
716
720
|
resource: 'model',
|
717
721
|
passthrough: {
|
718
722
|
tx,
|
@@ -725,7 +729,7 @@ export const executeModels = async (
|
|
725
729
|
model_type: modelType,
|
726
730
|
},
|
727
731
|
},
|
728
|
-
})
|
732
|
+
});
|
729
733
|
|
730
734
|
let method: SupportedMethod = 'POST';
|
731
735
|
let uri = '/dev/model';
|
@@ -775,7 +779,7 @@ export const postExecuteModels = async (tx: Db.Tx): Promise<void> => {
|
|
775
779
|
// Hence, skipped migrations from earlier models are not set as executed as the `migration` table is missing
|
776
780
|
// Here the skipped migrations that haven't been set properly are covered
|
777
781
|
// This is mostly an edge case when running on an empty database schema and migrations model hasn't been executed, yet.
|
778
|
-
// One
|
782
|
+
// One specifc case are tests to run tests against migrated and unmigrated database states
|
779
783
|
|
780
784
|
for (const modelKey of Object.keys(models)) {
|
781
785
|
const pendingToSetExecutedMigrations =
|
@@ -785,9 +789,6 @@ export const postExecuteModels = async (tx: Db.Tx): Promise<void> => {
|
|
785
789
|
await setExecutedMigrations(tx, modelKey, pendingToSetExecutedMigrations);
|
786
790
|
}
|
787
791
|
}
|
788
|
-
|
789
|
-
// Initialize task worker and create required hooks
|
790
|
-
await tasks.setup(db);
|
791
792
|
};
|
792
793
|
|
793
794
|
const cleanupModel = (vocab: string) => {
|
@@ -1007,7 +1008,16 @@ export type Passthrough = AnyObject & {
|
|
1007
1008
|
tx?: Db.Tx;
|
1008
1009
|
};
|
1009
1010
|
|
1010
|
-
export class PinejsClient
|
1011
|
+
export class PinejsClient<
|
1012
|
+
M extends {
|
1013
|
+
[key in keyof M]: Resource;
|
1014
|
+
} = {
|
1015
|
+
[key in string]: {
|
1016
|
+
Read: AnyObject;
|
1017
|
+
Write: AnyObject;
|
1018
|
+
};
|
1019
|
+
},
|
1020
|
+
> extends PinejsClientCore<unknown, M> {
|
1011
1021
|
public async _request({
|
1012
1022
|
method,
|
1013
1023
|
url,
|
@@ -1025,11 +1035,37 @@ export class PinejsClient extends PinejsClientCore {
|
|
1025
1035
|
}) {
|
1026
1036
|
return (await runURI(method, url, body, tx, req, custom)) as object;
|
1027
1037
|
}
|
1038
|
+
|
1039
|
+
public post<TResource extends keyof M & string>(
|
1040
|
+
params: {
|
1041
|
+
resource: TResource;
|
1042
|
+
options?: Params<M[TResource]>['options'] & { returnResource?: true };
|
1043
|
+
} & Params<M[TResource]>,
|
1044
|
+
): Promise<PickDeferred<M[TResource]['Read']>>;
|
1045
|
+
public post<TResource extends keyof M & string>(
|
1046
|
+
params: {
|
1047
|
+
resource: TResource;
|
1048
|
+
options: Params<M[TResource]>['options'] & { returnResource: boolean };
|
1049
|
+
} & Params<M[TResource]>,
|
1050
|
+
): Promise<Pick<M[TResource]['Read'], 'id'>>; // TODO: This should use the primary key rather than hardcoding `id`
|
1051
|
+
/**
|
1052
|
+
* @deprecated POSTing via `url` is deprecated
|
1053
|
+
*/
|
1054
|
+
public post<T extends Resource = AnyResource>(
|
1055
|
+
params: {
|
1056
|
+
resource?: undefined;
|
1057
|
+
url: NonNullable<Params<T>['url']>;
|
1058
|
+
} & Params<T>,
|
1059
|
+
): Promise<AnyObject>;
|
1060
|
+
public post(params: Params<AnyResource>): Promise<AnyObject> {
|
1061
|
+
return super.post(params as Parameters<PinejsClient['post']>[0]);
|
1062
|
+
}
|
1028
1063
|
}
|
1029
1064
|
|
1030
|
-
export
|
1065
|
+
export interface API {
|
1031
1066
|
[vocab: string]: PinejsClient;
|
1032
|
-
}
|
1067
|
+
}
|
1068
|
+
export const api = {} as API;
|
1033
1069
|
export const logger: {
|
1034
1070
|
[vocab: string]: Console;
|
1035
1071
|
} = {};
|
@@ -1136,8 +1172,8 @@ const getIdField = (
|
|
1136
1172
|
// TODO: Should resolveSynonym also be using the finalAbstractSqlModel?
|
1137
1173
|
getFinalAbstractSqlModel(request).tables[resolveSynonym(request)].idField;
|
1138
1174
|
|
1139
|
-
export const getAffectedIds = async (
|
1140
|
-
args: HookArgs & {
|
1175
|
+
export const getAffectedIds = async <Vocab extends string>(
|
1176
|
+
args: HookArgs<Vocab> & {
|
1141
1177
|
tx: Db.Tx;
|
1142
1178
|
},
|
1143
1179
|
): Promise<number[]> => {
|
@@ -1159,11 +1195,11 @@ export const getAffectedIds = async (
|
|
1159
1195
|
return request.affectedIds;
|
1160
1196
|
};
|
1161
1197
|
|
1162
|
-
const $getAffectedIds = async ({
|
1198
|
+
const $getAffectedIds = async <Vocab extends string>({
|
1163
1199
|
req,
|
1164
1200
|
request,
|
1165
1201
|
tx,
|
1166
|
-
}: HookArgs & {
|
1202
|
+
}: HookArgs<Vocab> & {
|
1167
1203
|
tx: Db.Tx;
|
1168
1204
|
}): Promise<number[]> => {
|
1169
1205
|
if (!['PATCH', 'DELETE'].includes(request.method)) {
|
@@ -1946,47 +1982,51 @@ const runDelete = async (
|
|
1946
1982
|
}
|
1947
1983
|
};
|
1948
1984
|
|
1985
|
+
export interface API {
|
1986
|
+
[devModelConfig.apiRoot]: PinejsClient<DevModel>;
|
1987
|
+
}
|
1988
|
+
const devModelConfig = {
|
1989
|
+
apiRoot: 'dev',
|
1990
|
+
modelText: devModel,
|
1991
|
+
logging: {
|
1992
|
+
log: false,
|
1993
|
+
},
|
1994
|
+
migrations: {
|
1995
|
+
'11.0.0-modified-at': `
|
1996
|
+
ALTER TABLE "model"
|
1997
|
+
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
1998
|
+
`,
|
1999
|
+
'15.0.0-data-types': async ($tx, sbvrUtils) => {
|
2000
|
+
switch (sbvrUtils.db.engine) {
|
2001
|
+
case 'mysql':
|
2002
|
+
await $tx.executeSql(`\
|
2003
|
+
ALTER TABLE "model"
|
2004
|
+
MODIFY "model value" JSON NOT NULL;
|
2005
|
+
|
2006
|
+
UPDATE "model"
|
2007
|
+
SET "model value" = CAST('{"value":' || CAST("model value" AS CHAR) || '}' AS JSON)
|
2008
|
+
WHERE "model type" IN ('se', 'odataMetadata')
|
2009
|
+
AND CAST("model value" AS CHAR) LIKE '"%';`);
|
2010
|
+
break;
|
2011
|
+
case 'postgres':
|
2012
|
+
await $tx.executeSql(`\
|
2013
|
+
ALTER TABLE "model"
|
2014
|
+
ALTER COLUMN "model value" SET DATA TYPE JSONB USING "model value"::JSONB;
|
2015
|
+
|
2016
|
+
UPDATE "model"
|
2017
|
+
SET "model value" = CAST('{"value":' || CAST("model value" AS TEXT) || '}' AS JSON)
|
2018
|
+
WHERE "model type" IN ('se', 'odataMetadata')
|
2019
|
+
AND CAST("model value" AS TEXT) LIKE '"%';`);
|
2020
|
+
break;
|
2021
|
+
// No need to migrate for websql
|
2022
|
+
}
|
2023
|
+
},
|
2024
|
+
},
|
2025
|
+
} as const satisfies ExecutableModel;
|
1949
2026
|
export const executeStandardModels = async (tx: Db.Tx): Promise<void> => {
|
1950
2027
|
try {
|
1951
2028
|
// dev model must run first
|
1952
|
-
await executeModel(tx,
|
1953
|
-
apiRoot: 'dev',
|
1954
|
-
modelText: devModel,
|
1955
|
-
logging: {
|
1956
|
-
log: false,
|
1957
|
-
},
|
1958
|
-
migrations: {
|
1959
|
-
'11.0.0-modified-at': `
|
1960
|
-
ALTER TABLE "model"
|
1961
|
-
ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
|
1962
|
-
`,
|
1963
|
-
'15.0.0-data-types': async ($tx, sbvrUtils) => {
|
1964
|
-
switch (sbvrUtils.db.engine) {
|
1965
|
-
case 'mysql':
|
1966
|
-
await $tx.executeSql(`\
|
1967
|
-
ALTER TABLE "model"
|
1968
|
-
MODIFY "model value" JSON NOT NULL;
|
1969
|
-
|
1970
|
-
UPDATE "model"
|
1971
|
-
SET "model value" = CAST('{"value":' || CAST("model value" AS CHAR) || '}' AS JSON)
|
1972
|
-
WHERE "model type" IN ('se', 'odataMetadata')
|
1973
|
-
AND CAST("model value" AS CHAR) LIKE '"%';`);
|
1974
|
-
break;
|
1975
|
-
case 'postgres':
|
1976
|
-
await $tx.executeSql(`\
|
1977
|
-
ALTER TABLE "model"
|
1978
|
-
ALTER COLUMN "model value" SET DATA TYPE JSONB USING "model value"::JSONB;
|
1979
|
-
|
1980
|
-
UPDATE "model"
|
1981
|
-
SET "model value" = CAST('{"value":' || CAST("model value" AS TEXT) || '}' AS JSON)
|
1982
|
-
WHERE "model type" IN ('se', 'odataMetadata')
|
1983
|
-
AND CAST("model value" AS TEXT) LIKE '"%';`);
|
1984
|
-
break;
|
1985
|
-
// No need to migrate for websql
|
1986
|
-
}
|
1987
|
-
},
|
1988
|
-
},
|
1989
|
-
});
|
2029
|
+
await executeModel(tx, devModelConfig);
|
1990
2030
|
await executeModels(tx, permissions.config.models);
|
1991
2031
|
console.info('Successfully executed standard models.');
|
1992
2032
|
} catch (err: any) {
|
@@ -0,0 +1,216 @@
|
|
1
|
+
// These types were generated by @balena/abstract-sql-to-typescript v3.2.1
|
2
|
+
|
3
|
+
import type { Types } from '@balena/abstract-sql-to-typescript';
|
4
|
+
|
5
|
+
export interface Permission {
|
6
|
+
Read: {
|
7
|
+
created_at: Types['Date Time']['Read'];
|
8
|
+
modified_at: Types['Date Time']['Read'];
|
9
|
+
id: Types['Serial']['Read'];
|
10
|
+
name: Types['Text']['Read'];
|
11
|
+
is_of__role?: Array<RoleHasPermission['Read']>;
|
12
|
+
is_of__user?: Array<UserHasPermission['Read']>;
|
13
|
+
is_of__api_key?: Array<ApiKeyHasPermission['Read']>;
|
14
|
+
user__has__permission?: Array<UserHasPermission['Read']>;
|
15
|
+
user_permission?: Array<UserHasPermission['Read']>;
|
16
|
+
};
|
17
|
+
Write: {
|
18
|
+
created_at: Types['Date Time']['Write'];
|
19
|
+
modified_at: Types['Date Time']['Write'];
|
20
|
+
id: Types['Serial']['Write'];
|
21
|
+
name: Types['Text']['Write'];
|
22
|
+
};
|
23
|
+
}
|
24
|
+
|
25
|
+
export interface Role {
|
26
|
+
Read: {
|
27
|
+
created_at: Types['Date Time']['Read'];
|
28
|
+
modified_at: Types['Date Time']['Read'];
|
29
|
+
id: Types['Serial']['Read'];
|
30
|
+
name: Types['Text']['Read'];
|
31
|
+
role__has__permission?: Array<RoleHasPermission['Read']>;
|
32
|
+
user__has__role?: Array<UserHasRole['Read']>;
|
33
|
+
user_role?: Array<UserHasRole['Read']>;
|
34
|
+
is_of__user?: Array<UserHasRole['Read']>;
|
35
|
+
is_of__api_key?: Array<ApiKeyHasRole['Read']>;
|
36
|
+
};
|
37
|
+
Write: {
|
38
|
+
created_at: Types['Date Time']['Write'];
|
39
|
+
modified_at: Types['Date Time']['Write'];
|
40
|
+
id: Types['Serial']['Write'];
|
41
|
+
name: Types['Text']['Write'];
|
42
|
+
};
|
43
|
+
}
|
44
|
+
|
45
|
+
export interface RoleHasPermission {
|
46
|
+
Read: {
|
47
|
+
created_at: Types['Date Time']['Read'];
|
48
|
+
modified_at: Types['Date Time']['Read'];
|
49
|
+
role: { __id: Role['Read']['id'] } | [Role['Read']];
|
50
|
+
permission: { __id: Permission['Read']['id'] } | [Permission['Read']];
|
51
|
+
id: Types['Serial']['Read'];
|
52
|
+
is_of__role: { __id: Role['Read']['id'] } | [Role['Read']];
|
53
|
+
};
|
54
|
+
Write: {
|
55
|
+
created_at: Types['Date Time']['Write'];
|
56
|
+
modified_at: Types['Date Time']['Write'];
|
57
|
+
role: Role['Write']['id'];
|
58
|
+
permission: Permission['Write']['id'];
|
59
|
+
id: Types['Serial']['Write'];
|
60
|
+
};
|
61
|
+
}
|
62
|
+
|
63
|
+
export interface Actor {
|
64
|
+
Read: {
|
65
|
+
created_at: Types['Date Time']['Read'];
|
66
|
+
modified_at: Types['Date Time']['Read'];
|
67
|
+
id: Types['Serial']['Read'];
|
68
|
+
is_of__user?: Array<User['Read']>;
|
69
|
+
api_key?: Array<ApiKey['Read']>;
|
70
|
+
};
|
71
|
+
Write: {
|
72
|
+
created_at: Types['Date Time']['Write'];
|
73
|
+
modified_at: Types['Date Time']['Write'];
|
74
|
+
id: Types['Serial']['Write'];
|
75
|
+
};
|
76
|
+
}
|
77
|
+
|
78
|
+
export interface User {
|
79
|
+
Read: {
|
80
|
+
created_at: Types['Date Time']['Read'];
|
81
|
+
modified_at: Types['Date Time']['Read'];
|
82
|
+
id: Types['Serial']['Read'];
|
83
|
+
actor: { __id: Actor['Read']['id'] } | [Actor['Read']];
|
84
|
+
username: Types['Short Text']['Read'];
|
85
|
+
password: Types['Hashed']['Read'];
|
86
|
+
user__has__role?: Array<UserHasRole['Read']>;
|
87
|
+
user_role?: Array<UserHasRole['Read']>;
|
88
|
+
user__has__permission?: Array<UserHasPermission['Read']>;
|
89
|
+
user_permission?: Array<UserHasPermission['Read']>;
|
90
|
+
};
|
91
|
+
Write: {
|
92
|
+
created_at: Types['Date Time']['Write'];
|
93
|
+
modified_at: Types['Date Time']['Write'];
|
94
|
+
id: Types['Serial']['Write'];
|
95
|
+
actor: Actor['Write']['id'];
|
96
|
+
username: Types['Short Text']['Write'];
|
97
|
+
password: Types['Hashed']['Write'];
|
98
|
+
};
|
99
|
+
}
|
100
|
+
|
101
|
+
export interface UserHasRole {
|
102
|
+
Read: {
|
103
|
+
created_at: Types['Date Time']['Read'];
|
104
|
+
modified_at: Types['Date Time']['Read'];
|
105
|
+
user: { __id: User['Read']['id'] } | [User['Read']];
|
106
|
+
role: { __id: Role['Read']['id'] } | [Role['Read']];
|
107
|
+
id: Types['Serial']['Read'];
|
108
|
+
expiry_date: Types['Date Time']['Read'] | null;
|
109
|
+
is_of__user: { __id: User['Read']['id'] } | [User['Read']];
|
110
|
+
};
|
111
|
+
Write: {
|
112
|
+
created_at: Types['Date Time']['Write'];
|
113
|
+
modified_at: Types['Date Time']['Write'];
|
114
|
+
user: User['Write']['id'];
|
115
|
+
role: Role['Write']['id'];
|
116
|
+
id: Types['Serial']['Write'];
|
117
|
+
expiry_date: Types['Date Time']['Write'] | null;
|
118
|
+
};
|
119
|
+
}
|
120
|
+
|
121
|
+
export interface UserHasPermission {
|
122
|
+
Read: {
|
123
|
+
created_at: Types['Date Time']['Read'];
|
124
|
+
modified_at: Types['Date Time']['Read'];
|
125
|
+
user: { __id: User['Read']['id'] } | [User['Read']];
|
126
|
+
permission: { __id: Permission['Read']['id'] } | [Permission['Read']];
|
127
|
+
id: Types['Serial']['Read'];
|
128
|
+
expiry_date: Types['Date Time']['Read'] | null;
|
129
|
+
is_of__user: { __id: User['Read']['id'] } | [User['Read']];
|
130
|
+
};
|
131
|
+
Write: {
|
132
|
+
created_at: Types['Date Time']['Write'];
|
133
|
+
modified_at: Types['Date Time']['Write'];
|
134
|
+
user: User['Write']['id'];
|
135
|
+
permission: Permission['Write']['id'];
|
136
|
+
id: Types['Serial']['Write'];
|
137
|
+
expiry_date: Types['Date Time']['Write'] | null;
|
138
|
+
};
|
139
|
+
}
|
140
|
+
|
141
|
+
export interface ApiKey {
|
142
|
+
Read: {
|
143
|
+
created_at: Types['Date Time']['Read'];
|
144
|
+
modified_at: Types['Date Time']['Read'];
|
145
|
+
id: Types['Serial']['Read'];
|
146
|
+
key: Types['Short Text']['Read'];
|
147
|
+
expiry_date: Types['Date Time']['Read'] | null;
|
148
|
+
is_of__actor: { __id: Actor['Read']['id'] } | [Actor['Read']];
|
149
|
+
name: Types['Text']['Read'] | null;
|
150
|
+
description: Types['Text']['Read'] | null;
|
151
|
+
api_key__has__role?: Array<ApiKeyHasRole['Read']>;
|
152
|
+
api_key__has__permission?: Array<ApiKeyHasPermission['Read']>;
|
153
|
+
};
|
154
|
+
Write: {
|
155
|
+
created_at: Types['Date Time']['Write'];
|
156
|
+
modified_at: Types['Date Time']['Write'];
|
157
|
+
id: Types['Serial']['Write'];
|
158
|
+
key: Types['Short Text']['Write'];
|
159
|
+
expiry_date: Types['Date Time']['Write'] | null;
|
160
|
+
is_of__actor: Actor['Write']['id'];
|
161
|
+
name: Types['Text']['Write'] | null;
|
162
|
+
description: Types['Text']['Write'] | null;
|
163
|
+
};
|
164
|
+
}
|
165
|
+
|
166
|
+
export interface ApiKeyHasRole {
|
167
|
+
Read: {
|
168
|
+
created_at: Types['Date Time']['Read'];
|
169
|
+
modified_at: Types['Date Time']['Read'];
|
170
|
+
api_key: { __id: ApiKey['Read']['id'] } | [ApiKey['Read']];
|
171
|
+
role: { __id: Role['Read']['id'] } | [Role['Read']];
|
172
|
+
id: Types['Serial']['Read'];
|
173
|
+
is_of__api_key: { __id: ApiKey['Read']['id'] } | [ApiKey['Read']];
|
174
|
+
};
|
175
|
+
Write: {
|
176
|
+
created_at: Types['Date Time']['Write'];
|
177
|
+
modified_at: Types['Date Time']['Write'];
|
178
|
+
api_key: ApiKey['Write']['id'];
|
179
|
+
role: Role['Write']['id'];
|
180
|
+
id: Types['Serial']['Write'];
|
181
|
+
};
|
182
|
+
}
|
183
|
+
|
184
|
+
export interface ApiKeyHasPermission {
|
185
|
+
Read: {
|
186
|
+
created_at: Types['Date Time']['Read'];
|
187
|
+
modified_at: Types['Date Time']['Read'];
|
188
|
+
api_key: { __id: ApiKey['Read']['id'] } | [ApiKey['Read']];
|
189
|
+
permission: { __id: Permission['Read']['id'] } | [Permission['Read']];
|
190
|
+
id: Types['Serial']['Read'];
|
191
|
+
is_of__api_key: { __id: ApiKey['Read']['id'] } | [ApiKey['Read']];
|
192
|
+
};
|
193
|
+
Write: {
|
194
|
+
created_at: Types['Date Time']['Write'];
|
195
|
+
modified_at: Types['Date Time']['Write'];
|
196
|
+
api_key: ApiKey['Write']['id'];
|
197
|
+
permission: Permission['Write']['id'];
|
198
|
+
id: Types['Serial']['Write'];
|
199
|
+
};
|
200
|
+
}
|
201
|
+
|
202
|
+
export default interface $Model {
|
203
|
+
permission: Permission;
|
204
|
+
role: Role;
|
205
|
+
role__has__permission: RoleHasPermission;
|
206
|
+
actor: Actor;
|
207
|
+
user: User;
|
208
|
+
user__has__role: UserHasRole;
|
209
|
+
user__has__permission: UserHasPermission;
|
210
|
+
api_key: ApiKey;
|
211
|
+
api_key__has__role: ApiKeyHasRole;
|
212
|
+
api_key__has__permission: ApiKeyHasPermission;
|
213
|
+
// Synonyms
|
214
|
+
user_role: UserHasRole;
|
215
|
+
user_permission: UserHasPermission;
|
216
|
+
}
|
@@ -6,7 +6,6 @@ import * as dbModule from '../database-layer/db';
|
|
6
6
|
import * as configLoader from '../config-loader/config-loader';
|
7
7
|
import * as migrator from '../migrator/sync';
|
8
8
|
import type * as migratorUtils from '../migrator/utils';
|
9
|
-
import * as tasks from '../tasks';
|
10
9
|
|
11
10
|
import * as sbvrUtils from '../sbvr-api/sbvr-utils';
|
12
11
|
import { PINEJS_ADVISORY_LOCK } from '../config-loader/env';
|
@@ -20,7 +19,6 @@ export * as errors from '../sbvr-api/errors';
|
|
20
19
|
export * as env from '../config-loader/env';
|
21
20
|
export * as types from '../sbvr-api/common-types';
|
22
21
|
export * as hooks from '../sbvr-api/hooks';
|
23
|
-
export * as tasks from '../tasks';
|
24
22
|
export * as webResourceHandler from '../webresource-handler';
|
25
23
|
export type { configLoader as ConfigLoader };
|
26
24
|
export type { migratorUtils as Migrator };
|
@@ -65,7 +63,6 @@ export const init = async <T extends string>(
|
|
65
63
|
await sbvrUtils.setup(app, db);
|
66
64
|
const cfgLoader = await configLoader.setup(app);
|
67
65
|
await cfgLoader.loadConfig(migrator.config);
|
68
|
-
await cfgLoader.loadConfig(tasks.config);
|
69
66
|
|
70
67
|
const promises: Array<Promise<void>> = [];
|
71
68
|
if (process.env.SBVR_SERVER_ENABLED) {
|
package/out/tasks/common.d.ts
DELETED
package/out/tasks/common.js
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
-
};
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.ajv = exports.channel = exports.apiRoot = void 0;
|
7
|
-
const ajv_1 = __importDefault(require("ajv"));
|
8
|
-
exports.apiRoot = 'tasks';
|
9
|
-
exports.channel = 'pinejs$task_insert';
|
10
|
-
exports.ajv = new ajv_1.default({
|
11
|
-
inlineRefs: false,
|
12
|
-
});
|
13
|
-
//# sourceMappingURL=common.js.map
|
package/out/tasks/common.js.map
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/tasks/common.ts"],"names":[],"mappings":";;;;;;AAAA,8CAAsB;AAGT,QAAA,OAAO,GAAG,OAAO,CAAC;AAGlB,QAAA,OAAO,GAAG,oBAAoB,CAAC;AAK/B,QAAA,GAAG,GAAG,IAAI,aAAG,CAAC;IAC1B,UAAU,EAAE,KAAK;CACjB,CAAC,CAAC"}
|
package/out/tasks/index.d.ts
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
import type { Schema } from 'ajv';
|
2
|
-
import type * as Db from '../database-layer/db';
|
3
|
-
import type { ConfigLoader } from '../server-glue/module';
|
4
|
-
import type { TaskHandler } from './types';
|
5
|
-
export * from './types';
|
6
|
-
export declare const config: ConfigLoader.Config;
|
7
|
-
export declare function setup(db: Db.Database): Promise<void>;
|
8
|
-
export declare function addTaskHandler(name: string, fn: TaskHandler['fn'], schema?: Schema): void;
|
package/out/tasks/index.js
DELETED
@@ -1,140 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
-
if (k2 === undefined) k2 = k;
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
-
}
|
8
|
-
Object.defineProperty(o, k2, desc);
|
9
|
-
}) : (function(o, m, k, k2) {
|
10
|
-
if (k2 === undefined) k2 = k;
|
11
|
-
o[k2] = m[k];
|
12
|
-
}));
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
-
}) : function(o, v) {
|
16
|
-
o["default"] = v;
|
17
|
-
});
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
-
if (mod && mod.__esModule) return mod;
|
20
|
-
var result = {};
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
-
__setModuleDefault(result, mod);
|
23
|
-
return result;
|
24
|
-
};
|
25
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
26
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
27
|
-
};
|
28
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
29
|
-
exports.addTaskHandler = exports.setup = exports.config = void 0;
|
30
|
-
const cronParser = __importStar(require("cron-parser"));
|
31
|
-
const env_1 = require("../config-loader/env");
|
32
|
-
const errors_1 = require("../sbvr-api/errors");
|
33
|
-
const hooks_1 = require("../sbvr-api/hooks");
|
34
|
-
const sbvrUtils = __importStar(require("../sbvr-api/sbvr-utils"));
|
35
|
-
const common_1 = require("./common");
|
36
|
-
const worker_1 = require("./worker");
|
37
|
-
__exportStar(require("./types"), exports);
|
38
|
-
const modelText = require('./tasks.sbvr');
|
39
|
-
const initSql = `
|
40
|
-
CREATE OR REPLACE FUNCTION notify_task_insert()
|
41
|
-
RETURNS TRIGGER AS $$
|
42
|
-
BEGIN
|
43
|
-
PERFORM pg_notify('${common_1.channel}', NEW.id::text);
|
44
|
-
RETURN NEW;
|
45
|
-
END;
|
46
|
-
$$ LANGUAGE plpgsql;
|
47
|
-
|
48
|
-
CREATE OR REPLACE TRIGGER task_insert_trigger
|
49
|
-
AFTER INSERT ON task
|
50
|
-
FOR EACH ROW WHEN (NEW.status = 'queued' AND NEW."is scheduled to execute on-time" IS NULL)
|
51
|
-
EXECUTE FUNCTION notify_task_insert();
|
52
|
-
|
53
|
-
CREATE INDEX IF NOT EXISTS idx_task_poll ON task USING btree (
|
54
|
-
"is executed by-handler",
|
55
|
-
"is scheduled to execute on-time" ASC,
|
56
|
-
"id" ASC
|
57
|
-
) WHERE status = 'queued';
|
58
|
-
`;
|
59
|
-
exports.config = {
|
60
|
-
models: [
|
61
|
-
{
|
62
|
-
modelName: common_1.apiRoot,
|
63
|
-
apiRoot: common_1.apiRoot,
|
64
|
-
modelText,
|
65
|
-
customServerCode: exports,
|
66
|
-
initSql,
|
67
|
-
},
|
68
|
-
],
|
69
|
-
};
|
70
|
-
let worker = null;
|
71
|
-
async function setup(db) {
|
72
|
-
if (db.engine !== 'postgres') {
|
73
|
-
console.warn('Skipping task setup as database not supported');
|
74
|
-
return;
|
75
|
-
}
|
76
|
-
const client = sbvrUtils.api[common_1.apiRoot];
|
77
|
-
worker = new worker_1.Worker(client);
|
78
|
-
(0, hooks_1.addPureHook)('POST', common_1.apiRoot, 'task', {
|
79
|
-
POSTPARSE: async ({ req, request }) => {
|
80
|
-
request.values.is_created_by__actor =
|
81
|
-
req.user?.actor ?? req.apiKey?.actor;
|
82
|
-
if (request.values.is_created_by__actor == null) {
|
83
|
-
throw new errors_1.BadRequestError('Creating tasks with missing actor on req is not allowed');
|
84
|
-
}
|
85
|
-
request.values.status = 'queued';
|
86
|
-
request.values.attempt_count = 0;
|
87
|
-
request.values.attempt_limit ??= 1;
|
88
|
-
if (request.values.is_scheduled_with__cron_expression != null &&
|
89
|
-
request.values.is_scheduled_to_execute_on__time == null) {
|
90
|
-
try {
|
91
|
-
request.values.is_scheduled_to_execute_on__time = cronParser
|
92
|
-
.parseExpression(request.values.is_scheduled_with__cron_expression)
|
93
|
-
.next()
|
94
|
-
.toDate()
|
95
|
-
.toISOString();
|
96
|
-
}
|
97
|
-
catch {
|
98
|
-
throw new errors_1.BadRequestError(`Invalid cron expression: ${request.values.is_scheduled_with__cron_expression}`);
|
99
|
-
}
|
100
|
-
}
|
101
|
-
if (request.values.is_scheduled_to_execute_on__time != null) {
|
102
|
-
const now = new Date(Date.now() + env_1.tasks.queueIntervalMS);
|
103
|
-
const startTime = new Date(request.values.is_scheduled_to_execute_on__time);
|
104
|
-
if (startTime < now) {
|
105
|
-
throw new errors_1.BadRequestError(`Task scheduled start time must be greater than ${env_1.tasks.queueIntervalMS} milliseconds in the future`);
|
106
|
-
}
|
107
|
-
}
|
108
|
-
const handlerName = request.values.is_executed_by__handler;
|
109
|
-
if (handlerName == null) {
|
110
|
-
throw new errors_1.BadRequestError(`Must specify a task handler to execute`);
|
111
|
-
}
|
112
|
-
const handler = worker?.handlers[handlerName];
|
113
|
-
if (handler == null) {
|
114
|
-
throw new errors_1.BadRequestError(`No task handler with name '${handlerName}' registered`);
|
115
|
-
}
|
116
|
-
if (handler.validate != null) {
|
117
|
-
if (!handler.validate(request.values.is_executed_with__parameter_set)) {
|
118
|
-
throw new errors_1.BadRequestError(`Invalid parameter set: ${common_1.ajv.errorsText(handler.validate.errors)}`);
|
119
|
-
}
|
120
|
-
}
|
121
|
-
},
|
122
|
-
});
|
123
|
-
worker.start();
|
124
|
-
}
|
125
|
-
exports.setup = setup;
|
126
|
-
function addTaskHandler(name, fn, schema) {
|
127
|
-
if (worker == null) {
|
128
|
-
throw new Error('Database does not support tasks');
|
129
|
-
}
|
130
|
-
if (worker.handlers[name] != null) {
|
131
|
-
throw new Error(`Task handler with name '${name}' already registered`);
|
132
|
-
}
|
133
|
-
worker.handlers[name] = {
|
134
|
-
name,
|
135
|
-
fn,
|
136
|
-
validate: schema != null ? common_1.ajv.compile(schema) : undefined,
|
137
|
-
};
|
138
|
-
}
|
139
|
-
exports.addTaskHandler = addTaskHandler;
|
140
|
-
//# sourceMappingURL=index.js.map
|
package/out/tasks/index.js.map
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tasks/index.ts"],"names":[],"mappings":"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"}
|