@balena/pinejs 17.1.0-build-joshbwlng-tasks-e3dcb0e73ea9c960af553c67cbf7121650f8d1ea-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.
Files changed (64) hide show
  1. package/.pinejs-cache.json +1 -1
  2. package/.versionbot/CHANGELOG.yml +227 -13
  3. package/CHANGELOG.md +70 -4
  4. package/out/config-loader/env.d.ts +0 -4
  5. package/out/config-loader/env.js +1 -5
  6. package/out/config-loader/env.js.map +1 -1
  7. package/out/data-server/sbvr-server.js +3 -2
  8. package/out/data-server/sbvr-server.js.map +1 -1
  9. package/out/database-layer/db.d.ts +0 -3
  10. package/out/database-layer/db.js +0 -17
  11. package/out/database-layer/db.js.map +1 -1
  12. package/out/migrator/migrations.d.ts +58 -0
  13. package/out/migrator/migrations.js +3 -0
  14. package/out/migrator/migrations.js.map +1 -0
  15. package/out/migrator/sync.d.ts +17 -0
  16. package/out/migrator/sync.js +39 -40
  17. package/out/migrator/sync.js.map +1 -1
  18. package/out/sbvr-api/dev.d.ts +22 -0
  19. package/out/sbvr-api/dev.js +3 -0
  20. package/out/sbvr-api/dev.js.map +1 -0
  21. package/out/sbvr-api/hooks.d.ts +28 -28
  22. package/out/sbvr-api/hooks.js.map +1 -1
  23. package/out/sbvr-api/permissions.d.ts +26 -2
  24. package/out/sbvr-api/permissions.js +39 -40
  25. package/out/sbvr-api/permissions.js.map +1 -1
  26. package/out/sbvr-api/sbvr-utils.d.ts +46 -6
  27. package/out/sbvr-api/sbvr-utils.js +44 -44
  28. package/out/sbvr-api/sbvr-utils.js.map +1 -1
  29. package/out/sbvr-api/user.d.ts +236 -0
  30. package/out/sbvr-api/user.js +3 -0
  31. package/out/sbvr-api/user.js.map +1 -0
  32. package/out/server-glue/module.d.ts +0 -1
  33. package/out/server-glue/module.js +1 -4
  34. package/out/server-glue/module.js.map +1 -1
  35. package/package.json +20 -21
  36. package/src/config-loader/env.ts +1 -6
  37. package/src/data-server/sbvr-server.js +3 -2
  38. package/src/database-layer/db.ts +0 -25
  39. package/src/migrator/migrations.ts +64 -0
  40. package/src/migrator/sync.ts +46 -41
  41. package/src/sbvr-api/dev.ts +26 -0
  42. package/src/sbvr-api/hooks.ts +19 -18
  43. package/src/sbvr-api/permissions.ts +54 -48
  44. package/src/sbvr-api/sbvr-utils.ts +93 -53
  45. package/src/sbvr-api/user.ts +216 -0
  46. package/src/server-glue/module.ts +0 -3
  47. package/out/tasks/common.d.ts +0 -4
  48. package/out/tasks/common.js +0 -11
  49. package/out/tasks/common.js.map +0 -1
  50. package/out/tasks/index.d.ts +0 -8
  51. package/out/tasks/index.js +0 -140
  52. package/out/tasks/index.js.map +0 -1
  53. package/out/tasks/tasks.sbvr +0 -55
  54. package/out/tasks/types.d.ts +0 -37
  55. package/out/tasks/types.js +0 -10
  56. package/out/tasks/types.js.map +0 -1
  57. package/out/tasks/worker.d.ts +0 -16
  58. package/out/tasks/worker.js +0 -226
  59. package/out/tasks/worker.js.map +0 -1
  60. package/src/tasks/common.ts +0 -9
  61. package/src/tasks/index.ts +0 -155
  62. package/src/tasks/tasks.sbvr +0 -55
  63. package/src/tasks/types.ts +0 -56
  64. 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 = (await api.dev.get({
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
- })) as Array<{ id: number }>;
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 specific case are tests to run tests against migrated and unmigrated database states
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 extends PinejsClientCore {
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 const api: {
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) {
@@ -1,4 +0,0 @@
1
- import Ajv from 'ajv';
2
- export declare const apiRoot = "tasks";
3
- export declare const channel = "pinejs$task_insert";
4
- export declare const ajv: Ajv;
@@ -1,11 +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
- //# sourceMappingURL=common.js.map
@@ -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;AAE/B,QAAA,GAAG,GAAG,IAAI,aAAG,EAAE,CAAC"}
@@ -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;
@@ -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
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tasks/index.ts"],"names":[],"mappings":"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"}