@balena/pinejs 17.1.0-build-joshbwlng-tasks-e3dcb0e73ea9c960af553c67cbf7121650f8d1ea-1 → 17.1.0-build-model-based-typings-c276ef4fb8482a246c25940d617d76b76847eff8-1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -49,7 +49,7 @@ export const cache = {
49
49
  apiKeyActorId: false as CacheOpts,
50
50
  };
51
51
 
52
- import { boolVar, intVar } from '@balena/env-parsing';
52
+ import { boolVar } from '@balena/env-parsing';
53
53
  import memoize from 'memoizee';
54
54
  import memoizeWeak = require('memoizee/weak');
55
55
  export const createCache = <T extends (...args: any[]) => any>(
@@ -146,8 +146,3 @@ export const migrator = {
146
146
  */
147
147
  asyncMigrationIsEnabled: boolVar('PINEJS_ASYNC_MIGRATION_ENABLED', true),
148
148
  };
149
-
150
- export const tasks = {
151
- queueConcurrency: intVar('PINEJS_QUEUE_CONCURRENCY', 0),
152
- queueIntervalMS: intVar('PINEJS_QUEUE_INTERVAL_MS', 1000),
153
- };
@@ -133,14 +133,15 @@ export async function setup(app, sbvrUtils, db) {
133
133
  },
134
134
  },
135
135
  })
136
- .then(async (/** @type { Array<{ [key: string]: any }> } */ result) => {
136
+ .then(async (result) => {
137
137
  if (result.length === 0) {
138
138
  throw new Error('No SE data model found');
139
139
  }
140
140
  const instance = result[0];
141
141
  await sbvrUtils.executeModel(tx, {
142
142
  apiRoot: instance.is_of__vocabulary,
143
- modelText: instance.model_value.value,
143
+ // prettier-ignore
144
+ modelText: /** @type { string } */ (instance.model_value.value),
144
145
  });
145
146
  });
146
147
  await isServerOnAir(true);
@@ -98,13 +98,6 @@ export interface Database extends BaseDatabase {
98
98
  ) => Promise<Result>;
99
99
  transaction: TransactionFn;
100
100
  readTransaction: TransactionFn;
101
- on?: (
102
- name: 'notification',
103
- fn: (...args: any[]) => Promise<void>,
104
- options?: {
105
- channel?: string;
106
- },
107
- ) => void;
108
101
  }
109
102
 
110
103
  interface EngineParams {
@@ -696,24 +689,6 @@ if (maybePg != null) {
696
689
  return {
697
690
  engine: Engines.postgres,
698
691
  executeSql: atomicExecuteSql,
699
- on: async (name, fn, options) => {
700
- if (name === 'notification' && options?.channel === undefined) {
701
- throw new Error('Missing channel option for notification listener');
702
- }
703
-
704
- const client = await pool.connect();
705
- client.on(name, async (msg) => {
706
- try {
707
- await fn(msg);
708
- } catch (error) {
709
- console.error('Error handling message:', error);
710
- }
711
- });
712
-
713
- if (name === 'notification' && options?.channel !== undefined) {
714
- await client.query(`LISTEN "${options.channel}";`);
715
- }
716
- },
717
692
  transaction: createTransaction(async (stackTraceErr) => {
718
693
  const client = await pool.connect();
719
694
  const tx = new PostgresTx(client, false, stackTraceErr);
@@ -0,0 +1,64 @@
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 Migration {
6
+ Read: {
7
+ created_at: Types['Date Time']['Read'];
8
+ modified_at: Types['Date Time']['Read'];
9
+ model_name: Types['Short Text']['Read'];
10
+ executed_migrations: Types['JSON']['Read'];
11
+ };
12
+ Write: {
13
+ created_at: Types['Date Time']['Write'];
14
+ modified_at: Types['Date Time']['Write'];
15
+ model_name: Types['Short Text']['Write'];
16
+ executed_migrations: Types['JSON']['Write'];
17
+ };
18
+ }
19
+
20
+ export interface MigrationLock {
21
+ Read: {
22
+ created_at: Types['Date Time']['Read'];
23
+ modified_at: Types['Date Time']['Read'];
24
+ model_name: Types['Short Text']['Read'];
25
+ };
26
+ Write: {
27
+ created_at: Types['Date Time']['Write'];
28
+ modified_at: Types['Date Time']['Write'];
29
+ model_name: Types['Short Text']['Write'];
30
+ };
31
+ }
32
+
33
+ export interface MigrationStatus {
34
+ Read: {
35
+ created_at: Types['Date Time']['Read'];
36
+ modified_at: Types['Date Time']['Read'];
37
+ migration_key: Types['Short Text']['Read'];
38
+ start_time: Types['Date Time']['Read'] | null;
39
+ last_run_time: Types['Date Time']['Read'] | null;
40
+ run_count: Types['Integer']['Read'];
41
+ migrated_row_count: Types['Integer']['Read'] | null;
42
+ error_count: Types['Integer']['Read'] | null;
43
+ is_backing_off: Types['Boolean']['Read'];
44
+ converged_time: Types['Date Time']['Read'] | null;
45
+ };
46
+ Write: {
47
+ created_at: Types['Date Time']['Write'];
48
+ modified_at: Types['Date Time']['Write'];
49
+ migration_key: Types['Short Text']['Write'];
50
+ start_time: Types['Date Time']['Write'] | null;
51
+ last_run_time: Types['Date Time']['Write'] | null;
52
+ run_count: Types['Integer']['Write'];
53
+ migrated_row_count: Types['Integer']['Write'] | null;
54
+ error_count: Types['Integer']['Write'] | null;
55
+ is_backing_off: Types['Boolean']['Write'];
56
+ converged_time: Types['Date Time']['Write'] | null;
57
+ };
58
+ }
59
+
60
+ export default interface $Model {
61
+ migration: Migration;
62
+ migration_lock: MigrationLock;
63
+ migration_status: MigrationStatus;
64
+ }
@@ -1,3 +1,4 @@
1
+ import type MigrationsModel from './migrations';
1
2
  import {
2
3
  type MigrationTuple,
3
4
  MigrationError,
@@ -16,7 +17,7 @@ import _ from 'lodash';
16
17
  import * as sbvrUtils from '../sbvr-api/sbvr-utils';
17
18
 
18
19
  // eslint-disable-next-line @typescript-eslint/no-var-requires
19
- const modelText = require('./migrations.sbvr');
20
+ const migrationsModel = require('./migrations.sbvr');
20
21
 
21
22
  type ApiRootModel = Model & { apiRoot: string };
22
23
 
@@ -136,45 +137,49 @@ const executeMigration = async (
136
137
  }
137
138
  };
138
139
 
139
- export const config: Config = {
140
- models: [
141
- {
142
- modelName: 'migrations',
143
- apiRoot: 'migrations',
144
- modelText,
145
- migrations: {
146
- '11.0.0-modified-at': `
147
- ALTER TABLE "migration"
148
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
149
- `,
150
- '11.0.1-modified-at': `
151
- ALTER TABLE "migration lock"
152
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
153
- `,
154
- '15.0.0-data-types': async (tx, { db }) => {
155
- switch (db.engine) {
156
- case 'mysql':
157
- await tx.executeSql(`\
158
- ALTER TABLE "migration"
159
- MODIFY "executed migrations" JSON NOT NULL;`);
160
- await tx.executeSql(`\
161
- ALTER TABLE "migration status"
162
- MODIFY "is backing off" BOOLEAN NOT NULL;`);
163
- break;
164
- case 'postgres':
165
- await tx.executeSql(`\
166
- ALTER TABLE "migration"
167
- ALTER COLUMN "executed migrations" SET DATA TYPE JSONB USING "executed migrations"::JSONB;`);
168
- await tx.executeSql(`\
169
- ALTER TABLE "migration status"
170
- ALTER COLUMN "is backing off" DROP DEFAULT,
171
- ALTER COLUMN "is backing off" SET DATA TYPE BOOLEAN USING "is backing off"::BOOLEAN,
172
- ALTER COLUMN "is backing off" SET DEFAULT FALSE;`);
173
- break;
174
- // No need to migrate for websql
175
- }
176
- },
177
- },
140
+ declare module '../sbvr-api/sbvr-utils' {
141
+ export interface API {
142
+ [migrationModelConfig.apiRoot]: PinejsClient<MigrationsModel>;
143
+ }
144
+ }
145
+ const migrationModelConfig = {
146
+ modelName: 'migrations',
147
+ apiRoot: 'migrations',
148
+ modelText: migrationsModel,
149
+ migrations: {
150
+ '11.0.0-modified-at': `
151
+ ALTER TABLE "migration"
152
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
153
+ `,
154
+ '11.0.1-modified-at': `
155
+ ALTER TABLE "migration lock"
156
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
157
+ `,
158
+ '15.0.0-data-types': async (tx, { db }) => {
159
+ switch (db.engine) {
160
+ case 'mysql':
161
+ await tx.executeSql(`\
162
+ ALTER TABLE "migration"
163
+ MODIFY "executed migrations" JSON NOT NULL;`);
164
+ await tx.executeSql(`\
165
+ ALTER TABLE "migration status"
166
+ MODIFY "is backing off" BOOLEAN NOT NULL;`);
167
+ break;
168
+ case 'postgres':
169
+ await tx.executeSql(`\
170
+ ALTER TABLE "migration"
171
+ ALTER COLUMN "executed migrations" SET DATA TYPE JSONB USING "executed migrations"::JSONB;`);
172
+ await tx.executeSql(`\
173
+ ALTER TABLE "migration status"
174
+ ALTER COLUMN "is backing off" DROP DEFAULT,
175
+ ALTER COLUMN "is backing off" SET DATA TYPE BOOLEAN USING "is backing off"::BOOLEAN,
176
+ ALTER COLUMN "is backing off" SET DEFAULT FALSE;`);
177
+ break;
178
+ // No need to migrate for websql
179
+ }
178
180
  },
179
- ],
181
+ },
182
+ } as const satisfies sbvrUtils.ExecutableModel;
183
+ export const config: Config = {
184
+ models: [migrationModelConfig],
180
185
  };
@@ -0,0 +1,26 @@
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 Model {
6
+ Read: {
7
+ created_at: Types['Date Time']['Read'];
8
+ modified_at: Types['Date Time']['Read'];
9
+ id: Types['Serial']['Read'];
10
+ is_of__vocabulary: Types['Short Text']['Read'];
11
+ model_type: Types['Short Text']['Read'];
12
+ model_value: Types['JSON']['Read'];
13
+ };
14
+ Write: {
15
+ created_at: Types['Date Time']['Write'];
16
+ modified_at: Types['Date Time']['Write'];
17
+ id: Types['Serial']['Write'];
18
+ is_of__vocabulary: Types['Short Text']['Write'];
19
+ model_type: Types['Short Text']['Write'];
20
+ model_value: Types['JSON']['Write'];
21
+ };
22
+ }
23
+
24
+ export default interface $Model {
25
+ model: Model;
26
+ }
@@ -9,7 +9,6 @@ import _ from 'lodash';
9
9
  import { settleMapSeries } from './control-flow';
10
10
  import memoize from 'memoizee';
11
11
  import {
12
- type PinejsClient,
13
12
  type User,
14
13
  type ApiKey,
15
14
  resolveSynonym,
@@ -31,25 +30,27 @@ export interface HookReq {
31
30
  hooks?: InstantiatedHooks;
32
31
  is?: (type: string | string[]) => string | false | null;
33
32
  }
34
- export interface HookArgs {
33
+ export interface HookArgs<Vocab extends string = string> {
35
34
  req: HookReq;
36
35
  request: ODataRequest;
37
- api: PinejsClient;
36
+ api: (typeof api)[Vocab];
38
37
  tx?: Tx | undefined;
39
38
  }
40
39
  export type HookResponse = PromiseLike<any> | null | void;
41
40
 
42
- export interface Hooks {
43
- PREPARSE?: (options: Omit<HookArgs, 'request' | 'api'>) => HookResponse;
44
- POSTPARSE?: (options: HookArgs) => HookResponse;
45
- PRERUN?: (options: HookArgs & { tx: Tx }) => HookResponse;
41
+ export interface Hooks<Vocab extends string = string> {
42
+ PREPARSE?: (
43
+ options: Omit<HookArgs<Vocab>, 'request' | 'api'>,
44
+ ) => HookResponse;
45
+ POSTPARSE?: (options: HookArgs<Vocab>) => HookResponse;
46
+ PRERUN?: (options: HookArgs<Vocab> & { tx: Tx }) => HookResponse;
46
47
  /** These are run in reverse translation order from newest to oldest */
47
48
  POSTRUN?: (
48
- options: HookArgs & { tx: Tx; result: Result | number | undefined },
49
+ options: HookArgs<Vocab> & { tx: Tx; result: Result | number | undefined },
49
50
  ) => HookResponse;
50
51
  /** These are run in reverse translation order from newest to oldest */
51
52
  PRERESPOND?: (
52
- options: HookArgs & {
53
+ options: HookArgs<Vocab> & {
53
54
  tx: Tx;
54
55
  result?: Result | number | AnyObject;
55
56
  /** This can be mutated to modify the response sent to the client */
@@ -58,7 +59,7 @@ export interface Hooks {
58
59
  ) => HookResponse;
59
60
  /** These are run in reverse translation order from newest to oldest */
60
61
  'POSTRUN-ERROR'?: (
61
- options: HookArgs & { tx: Tx; error: TypedError | any },
62
+ options: HookArgs<Vocab> & { tx: Tx; error: TypedError | any },
62
63
  ) => HookResponse;
63
64
  }
64
65
  export type HookBlueprints = {
@@ -264,9 +265,9 @@ const apiHooks = {
264
265
  // Share hooks between merge and patch since they are the same operation,
265
266
  // just MERGE was the OData intermediary until the HTTP spec added PATCH.
266
267
  apiHooks.MERGE = apiHooks.PATCH;
267
- export const addHook = (
268
+ export const addHook = <Vocab extends string>(
268
269
  method: keyof typeof apiHooks,
269
- vocabulary: string,
270
+ vocabulary: Vocab,
270
271
  resourceName: string,
271
272
  hooks:
272
273
  | { [key in keyof Hooks]: HookBlueprint<NonNullable<Hooks[key]>> }
@@ -345,11 +346,11 @@ export const addHook = (
345
346
  getHooks.clear();
346
347
  };
347
348
 
348
- export const addSideEffectHook = (
349
+ export const addSideEffectHook = <Vocab extends string>(
349
350
  method: HookMethod,
350
- apiRoot: string,
351
+ apiRoot: Vocab,
351
352
  resourceName: string,
352
- hooks: Hooks,
353
+ hooks: Hooks<NoInfer<Vocab>>,
353
354
  ): void => {
354
355
  addHook(method, apiRoot, resourceName, {
355
356
  ...hooks,
@@ -358,11 +359,11 @@ export const addSideEffectHook = (
358
359
  });
359
360
  };
360
361
 
361
- export const addPureHook = (
362
+ export const addPureHook = <Vocab extends string>(
362
363
  method: HookMethod,
363
- apiRoot: string,
364
+ apiRoot: Vocab,
364
365
  resourceName: string,
365
- hooks: Hooks,
366
+ hooks: Hooks<NoInfer<Vocab>>,
366
367
  ): void => {
367
368
  addHook(method, apiRoot, resourceName, {
368
369
  ...hooks,
@@ -1,3 +1,4 @@
1
+ import type AuthModel from './user';
1
2
  import type {
2
3
  AbstractSqlModel,
3
4
  AbstractSqlQuery,
@@ -51,6 +52,7 @@ import {
51
52
  type ODataRequest,
52
53
  } from './uri-parser';
53
54
  import memoizeWeak = require('memoizee/weak');
55
+ import type { Config } from '../config-loader/config-loader';
54
56
 
55
57
  // eslint-disable-next-line @typescript-eslint/no-var-requires
56
58
  const userModel: string = require('./user.sbvr');
@@ -1118,7 +1120,7 @@ const memoizedGetConstrainedModel = (
1118
1120
  getBoundConstrainedMemoizer(abstractSqlModel)(permissionsLookup, vocabulary);
1119
1121
 
1120
1122
  const getCheckPasswordQuery = _.once(() =>
1121
- sbvrUtils.api.Auth.prepare<{ username: string }>({
1123
+ sbvrUtils.api.Auth.prepare<{ username: string }, 'user'>({
1122
1124
  resource: 'user',
1123
1125
  passthrough: {
1124
1126
  req: rootRead,
@@ -1164,7 +1166,7 @@ export const checkPassword = async (
1164
1166
 
1165
1167
  const $getUserPermissions = (() => {
1166
1168
  const getUserPermissionsQuery = _.once(() =>
1167
- sbvrUtils.api.Auth.prepare<{ userId: number }>({
1169
+ sbvrUtils.api.Auth.prepare<{ userId: number }, 'permission'>({
1168
1170
  resource: 'permission',
1169
1171
  passthrough: {
1170
1172
  req: rootRead,
@@ -1275,7 +1277,7 @@ export const getUserPermissions = async (
1275
1277
 
1276
1278
  const $getApiKeyPermissions = (() => {
1277
1279
  const getApiKeyPermissionsQuery = _.once(() =>
1278
- sbvrUtils.api.Auth.prepare<{ apiKey: string }>({
1280
+ sbvrUtils.api.Auth.prepare<{ apiKey: string }, 'permission'>({
1279
1281
  resource: 'permission',
1280
1282
  passthrough: {
1281
1283
  req: rootRead,
@@ -1403,7 +1405,7 @@ export const getApiKeyPermissions = async (
1403
1405
 
1404
1406
  const getApiKeyActorId = (() => {
1405
1407
  const getApiKeyActorIdQuery = _.once(() =>
1406
- sbvrUtils.api.Auth.prepare<{ apiKey: string }>({
1408
+ sbvrUtils.api.Auth.prepare<{ apiKey: string }, 'api_key'>({
1407
1409
  resource: 'api_key',
1408
1410
  passthrough: {
1409
1411
  req: rootRead,
@@ -1586,7 +1588,7 @@ let guestPermissionsInitialized = false;
1586
1588
  const getGuestPermissions = memoize(
1587
1589
  async () => {
1588
1590
  // Get guest user
1589
- const result = (await sbvrUtils.api.Auth.get({
1591
+ const result = await sbvrUtils.api.Auth.get({
1590
1592
  resource: 'user',
1591
1593
  passthrough: {
1592
1594
  req: rootRead,
@@ -1597,7 +1599,7 @@ const getGuestPermissions = memoize(
1597
1599
  options: {
1598
1600
  $select: 'id',
1599
1601
  },
1600
- })) as { id: number } | undefined;
1602
+ });
1601
1603
  if (result == null) {
1602
1604
  throw new Error('No guest user');
1603
1605
  }
@@ -1686,49 +1688,53 @@ export const addPermissions = async (
1686
1688
  }
1687
1689
  };
1688
1690
 
1691
+ declare module './sbvr-utils' {
1692
+ export interface API {
1693
+ [authModelConfig.apiRoot]: PinejsClient<AuthModel>;
1694
+ }
1695
+ }
1696
+ const authModelConfig = {
1697
+ apiRoot: 'Auth',
1698
+ modelText: userModel,
1699
+ customServerCode: exports,
1700
+ migrations: {
1701
+ '11.0.0-modified-at': `
1702
+ ALTER TABLE "actor"
1703
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1704
+
1705
+ ALTER TABLE "api key"
1706
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1707
+ ALTER TABLE "api key-has-permission"
1708
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1709
+ ALTER TABLE "api key-has-role"
1710
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1711
+
1712
+ ALTER TABLE "permission"
1713
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1714
+
1715
+ ALTER TABLE "role"
1716
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1717
+
1718
+ ALTER TABLE "user"
1719
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1720
+ ALTER TABLE "user-has-role"
1721
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1722
+ ALTER TABLE "user-has-permission"
1723
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1724
+ `,
1725
+ '11.0.1-modified-at': `
1726
+ ALTER TABLE "role-has-permission"
1727
+ ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1728
+ `,
1729
+ '14.42.0-api-key-expiry-date': `
1730
+ ALTER TABLE "api key"
1731
+ ADD COLUMN IF NOT EXISTS "expiry date" TIMESTAMP NULL;
1732
+ `,
1733
+ },
1734
+ } as const satisfies sbvrUtils.ExecutableModel;
1689
1735
  export const config = {
1690
- models: [
1691
- {
1692
- apiRoot: 'Auth',
1693
- modelText: userModel,
1694
- customServerCode: exports,
1695
- migrations: {
1696
- '11.0.0-modified-at': `
1697
- ALTER TABLE "actor"
1698
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1699
-
1700
- ALTER TABLE "api key"
1701
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1702
- ALTER TABLE "api key-has-permission"
1703
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1704
- ALTER TABLE "api key-has-role"
1705
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1706
-
1707
- ALTER TABLE "permission"
1708
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1709
-
1710
- ALTER TABLE "role"
1711
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1712
-
1713
- ALTER TABLE "user"
1714
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1715
- ALTER TABLE "user-has-role"
1716
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1717
- ALTER TABLE "user-has-permission"
1718
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1719
- `,
1720
- '11.0.1-modified-at': `
1721
- ALTER TABLE "role-has-permission"
1722
- ADD COLUMN IF NOT EXISTS "modified at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL;
1723
- `,
1724
- '14.42.0-api-key-expiry-date': `
1725
- ALTER TABLE "api key"
1726
- ADD COLUMN IF NOT EXISTS "expiry date" TIMESTAMP NULL;
1727
- `,
1728
- },
1729
- },
1730
- ] as sbvrUtils.ExecutableModel[],
1731
- };
1736
+ models: [authModelConfig],
1737
+ } satisfies Config;
1732
1738
  export const setup = () => {
1733
1739
  addHook('all', 'all', 'all', {
1734
1740
  sideEffects: false,