prostgles-server 4.2.598 → 4.2.600

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 (80) hide show
  1. package/README.md +26 -0
  2. package/dist/DBSchemaBuilder/getServerFunctionReturnTypes.external.fixture.d.ts +2 -2
  3. package/dist/DBSchemaBuilder/getServerFunctionReturnTypes.fixture.d.ts +8 -8
  4. package/dist/DboBuilder/TableHandler/TableHandler.d.ts +8 -5
  5. package/dist/DboBuilder/TableHandler/TableHandler.d.ts.map +1 -1
  6. package/dist/DboBuilder/TableHandler/TableHandler.js +1 -0
  7. package/dist/DboBuilder/TableHandler/TableHandler.js.map +1 -1
  8. package/dist/DboBuilder/TableHandler/delete.d.ts.map +1 -1
  9. package/dist/DboBuilder/TableHandler/delete.js +1 -0
  10. package/dist/DboBuilder/TableHandler/delete.js.map +1 -1
  11. package/dist/DboBuilder/TableHandler/executeAfterHooksCheckAndPostValidation.d.ts.map +1 -1
  12. package/dist/DboBuilder/TableHandler/executeAfterHooksCheckAndPostValidation.js +2 -0
  13. package/dist/DboBuilder/TableHandler/executeAfterHooksCheckAndPostValidation.js.map +1 -1
  14. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts +2 -2
  15. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts.map +1 -1
  16. package/dist/DboBuilder/ViewHandler/ViewHandler.js.map +1 -1
  17. package/dist/Prostgles.d.ts +13 -8
  18. package/dist/Prostgles.d.ts.map +1 -1
  19. package/dist/Prostgles.js +57 -4
  20. package/dist/Prostgles.js.map +1 -1
  21. package/dist/ProstglesContext.spec.d.ts +2 -0
  22. package/dist/ProstglesContext.spec.d.ts.map +1 -0
  23. package/dist/ProstglesContext.spec.js +73 -0
  24. package/dist/ProstglesContext.spec.js.map +1 -0
  25. package/dist/ProstglesTypes.d.ts +11 -5
  26. package/dist/ProstglesTypes.d.ts.map +1 -1
  27. package/dist/PublishParser/PublishParser.d.ts +2 -2
  28. package/dist/PublishParser/PublishParser.d.ts.map +1 -1
  29. package/dist/PublishParser/PublishParser.js +2 -0
  30. package/dist/PublishParser/PublishParser.js.map +1 -1
  31. package/dist/PublishParser/defineServerFunction.d.ts +21 -16
  32. package/dist/PublishParser/defineServerFunction.d.ts.map +1 -1
  33. package/dist/PublishParser/defineServerFunction.js +7 -1
  34. package/dist/PublishParser/defineServerFunction.js.map +1 -1
  35. package/dist/PublishParser/defineServerFunction.spec.js +38 -0
  36. package/dist/PublishParser/defineServerFunction.spec.js.map +1 -1
  37. package/dist/PublishParser/publishTypesAndUtils.d.ts +6 -3
  38. package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
  39. package/dist/PublishParser/publishTypesAndUtils.js.map +1 -1
  40. package/dist/StorageClient/getFileTableConfig.d.ts +1 -1
  41. package/dist/StorageClient/getFileTableConfig.d.ts.map +1 -1
  42. package/dist/StorageClient/getFileTableConfig.js.map +1 -1
  43. package/dist/TableConfig/TableConfigTypes.d.ts.map +1 -1
  44. package/dist/TableConfig/initTableConfig.js +3 -3
  45. package/dist/TableHooks/TableHooks.d.ts +26 -20
  46. package/dist/TableHooks/TableHooks.d.ts.map +1 -1
  47. package/dist/index.d.ts +5 -2
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +6 -0
  50. package/dist/index.js.map +1 -1
  51. package/dist/initProstgles.d.ts +22 -13
  52. package/dist/initProstgles.d.ts.map +1 -1
  53. package/dist/initProstgles.js +11 -2
  54. package/dist/initProstgles.js.map +1 -1
  55. package/dist/runClientRequest.d.ts.map +1 -1
  56. package/dist/runClientRequest.js.map +1 -1
  57. package/dist/updateConfiguration.d.ts +1 -1
  58. package/dist/updateConfiguration.d.ts.map +1 -1
  59. package/dist/updateConfiguration.js.map +1 -1
  60. package/lib/DboBuilder/TableHandler/TableHandler.ts +2 -1
  61. package/lib/DboBuilder/TableHandler/delete.ts +1 -0
  62. package/lib/DboBuilder/TableHandler/executeAfterHooksCheckAndPostValidation.ts +2 -0
  63. package/lib/DboBuilder/ViewHandler/ViewHandler.ts +2 -2
  64. package/lib/Prostgles.ts +63 -8
  65. package/lib/ProstglesContext.spec.ts +76 -0
  66. package/lib/ProstglesTypes.ts +16 -5
  67. package/lib/PublishParser/PublishParser.ts +6 -4
  68. package/lib/PublishParser/defineServerFunction.spec.ts +48 -0
  69. package/lib/PublishParser/defineServerFunction.ts +61 -21
  70. package/lib/PublishParser/publishTypesAndUtils.ts +6 -3
  71. package/lib/StorageClient/getFileTableConfig.ts +2 -2
  72. package/lib/TableConfig/TableConfigTypes.ts +2 -13
  73. package/lib/TableConfig/initTableConfig.ts +3 -3
  74. package/lib/TableHooks/TableHooks.ts +33 -20
  75. package/lib/index.ts +25 -5
  76. package/lib/initProstgles.ts +57 -19
  77. package/lib/runClientRequest.ts +6 -2
  78. package/lib/updateConfiguration.ts +1 -1
  79. package/package.json +2 -2
  80. package/tsconfig.json +2 -1
@@ -0,0 +1,76 @@
1
+ import assert from "node:assert";
2
+ import { describe, test } from "node:test";
3
+ import type { DboBuilder } from "./DboBuilder/DboBuilder";
4
+ import { Prostgles } from "./Prostgles";
5
+
6
+ void describe("Prostgles context", async () => {
7
+ await test("recreates context and runs cleanups in reverse order", async () => {
8
+ const events: string[] = [];
9
+ let contextId = 0;
10
+ const prostgles = new Prostgles({
11
+ dbConnection: "postgres://unused",
12
+ onReady: () => {},
13
+ createContext: ({ onCleanup }) => {
14
+ const id = ++contextId;
15
+ events.push(`create:${id}`);
16
+ onCleanup(() => {
17
+ events.push(`cleanup:first:${id}`);
18
+ });
19
+ onCleanup(() => {
20
+ events.push(`cleanup:second:${id}`);
21
+ });
22
+ return { id };
23
+ },
24
+ });
25
+ prostgles.db = {} as typeof prostgles.db;
26
+ prostgles.dboBuilder = {
27
+ build: async () => {},
28
+ dbo: {},
29
+ sql: {},
30
+ tables: [],
31
+ } as unknown as DboBuilder;
32
+
33
+ await prostgles.refreshDBO();
34
+ assert.deepEqual(prostgles.context, { id: 1 });
35
+ await prostgles.refreshDBO();
36
+ assert.deepEqual(prostgles.context, { id: 2 });
37
+ await prostgles.cleanupContext();
38
+
39
+ assert.deepEqual(events, [
40
+ "create:1",
41
+ "cleanup:second:1",
42
+ "cleanup:first:1",
43
+ "create:2",
44
+ "cleanup:second:2",
45
+ "cleanup:first:2",
46
+ ]);
47
+ assert.equal(prostgles.context, undefined);
48
+ });
49
+
50
+ await test("cleans partially-created context after an error", async () => {
51
+ const events: string[] = [];
52
+ const prostgles = new Prostgles({
53
+ dbConnection: "postgres://unused",
54
+ onReady: () => {},
55
+ createContext: ({ onCleanup }) => {
56
+ onCleanup(() => {
57
+ events.push("cleanup");
58
+ });
59
+ throw new Error("create failed");
60
+ },
61
+ });
62
+ prostgles.db = {} as typeof prostgles.db;
63
+ prostgles.dbo = {};
64
+ prostgles.dboBuilder = {
65
+ sql: {},
66
+ tables: [],
67
+ } as unknown as DboBuilder;
68
+
69
+ await assert.rejects(
70
+ prostgles.createContext({ type: "init" }),
71
+ /create failed/,
72
+ );
73
+ assert.deepEqual(events, ["cleanup"]);
74
+ assert.equal(prostgles.context, undefined);
75
+ });
76
+ });
@@ -6,7 +6,7 @@ import type {
6
6
  SessionUser,
7
7
  } from "./Auth/AuthTypes";
8
8
  import type { EventTriggerTagFilter } from "./Event_Trigger_Tags";
9
- import type { DbConnection, OnReadyCallback } from "./initProstgles";
9
+ import type { CreateContext, DbConnection, OnReadyCallback } from "./initProstgles";
10
10
  import type { EventInfo } from "./Logging";
11
11
  import type { RestApiConfig } from "./RestApi";
12
12
  import type { OnSchemaChangeCallback } from "./SchemaWatch/SchemaWatch";
@@ -102,7 +102,11 @@ type ModifyClientSchema<SUser extends SessionUser = SessionUser> = (
102
102
  userData: AuthResultWithSID<SUser> | undefined,
103
103
  ) => MaybePromise<DBSchemaTable>;
104
104
 
105
- export type ProstglesInitOptions<S = void, SUser extends SessionUser = SessionUser> = {
105
+ export type ProstglesInitOptions<
106
+ S = void,
107
+ SUser extends SessionUser = SessionUser,
108
+ Context = undefined,
109
+ > = {
106
110
  /**
107
111
  * Database connection details and options
108
112
  */
@@ -112,7 +116,14 @@ export type ProstglesInitOptions<S = void, SUser extends SessionUser = SessionUs
112
116
  * Called when the prostgles server is ready to accept connections.
113
117
  * It waits for auth, tableConfig and other async configurations to complete before executing
114
118
  */
115
- onReady: OnReadyCallback<S, SUser>;
119
+ onReady: OnReadyCallback<S, SUser, Context>;
120
+
121
+ /**
122
+ * Creates instance-scoped dependencies after the database object is ready.
123
+ * The returned context is available to onReady, server functions, and table hooks.
124
+ * Registered cleanups run in reverse order before context replacement and destruction.
125
+ */
126
+ createContext?: CreateContext<S, Context>;
116
127
 
117
128
  /**
118
129
  * Path to the directory where the generated types (`DBGeneratedSchema.d.ts`) will be saved.
@@ -181,7 +192,7 @@ export type ProstglesInitOptions<S = void, SUser extends SessionUser = SessionUs
181
192
  /**
182
193
  * Server-side functions that can be invoked by the client
183
194
  */
184
- functions?: ServerFunctionDefinitions<S, SUser>;
195
+ functions?: ServerFunctionDefinitions<S, SUser, Context>;
185
196
 
186
197
  /**
187
198
  * If true then will test all table methods on each socket connect.
@@ -311,7 +322,7 @@ export type ProstglesInitOptions<S = void, SUser extends SessionUser = SessionUs
311
322
  /**
312
323
  * Allows defining hooks for table events such as insert, update, delete and select.
313
324
  */
314
- tableHooks?: TableHooks<S>;
325
+ tableHooks?: TableHooks<S, Context>;
315
326
 
316
327
  /**
317
328
  * Useful for logging or debugging
@@ -1,6 +1,6 @@
1
1
  import { getObjectEntries, includes, SQL_COMMAND_TABLE_METHODS } from "prostgles-types";
2
2
  import { getClientRequestIPsInfo } from "../Auth/AuthHandler";
3
- import type { AuthClientRequest, AuthResultWithSID } from "../Auth/AuthTypes";
3
+ import type { AuthClientRequest, AuthResultWithSID, SessionUser } from "../Auth/AuthTypes";
4
4
  import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder";
5
5
  import type { DB, DBHandlerServer, Prostgles } from "../Prostgles";
6
6
  import type { ProstglesInitOptions } from "../ProstglesTypes";
@@ -27,7 +27,7 @@ import {
27
27
  } from "./publishTypesAndUtils";
28
28
 
29
29
  export class PublishParser {
30
- publish: ProstglesInitOptions["publish"];
30
+ publish: ProstglesInitOptions<void, SessionUser, any>["publish"];
31
31
  publishRawSQL?: any;
32
32
  dbo: DBHandlerServer;
33
33
  db: DB;
@@ -106,20 +106,22 @@ export class PublishParser {
106
106
  const runWithContext = async (args: Record<string, unknown> | undefined) => {
107
107
  const ctx = await (async () => {
108
108
  if (method.unrestrictedDbAccess) {
109
- const unrestrictedCtx: UnrestrictedFunctionContext = {
109
+ const unrestrictedCtx: UnrestrictedFunctionContext<void, SessionUser, unknown> = {
110
110
  ...publishParams,
111
111
  user,
112
+ context: this.prostgles.context,
112
113
  };
113
114
  return unrestrictedCtx;
114
115
  }
115
116
  const { clientDb } = await publishParams.getClientDBHandlers(undefined);
116
117
  const { clientInfo, clientReq, tables } = publishParams;
117
- const restrictedCtx: RestrictedFunctionContext = {
118
+ const restrictedCtx: RestrictedFunctionContext<void, SessionUser, unknown> = {
118
119
  dbo: clientDb as unknown as DBOFullyTyped<void>,
119
120
  user,
120
121
  clientInfo,
121
122
  clientReq,
122
123
  tables,
124
+ context: this.prostgles.context,
123
125
  };
124
126
  return restrictedCtx;
125
127
  })();
@@ -2,8 +2,11 @@ import { describe, test } from "node:test";
2
2
  import {
3
3
  defineFunction,
4
4
  createFunctionGroupDefiner,
5
+ createFunctionGroupDefinerWithContext,
5
6
  createFunctionsDefiner,
6
7
  } from "./defineServerFunction";
8
+ import type { TableHooks } from "../TableHooks/TableHooks";
9
+ import { createProstgles } from "../index";
7
10
 
8
11
  type TestSchema = {
9
12
  items: {
@@ -58,5 +61,50 @@ void describe("defineFunction type test", async () => {
58
61
 
59
62
  // @ts-expect-error A group must have a user filter.
60
63
  defineTestFunctionGroup({ functions });
64
+
65
+ type AppContext = {
66
+ serviceManager: { getService: (name: string) => string };
67
+ };
68
+ const defineContextFunctions =
69
+ createFunctionGroupDefinerWithContext<TestSchema, AppContext>();
70
+ defineContextFunctions({
71
+ userFilter: { type: "public" },
72
+ functions: {
73
+ getContextItem: defineFunction({
74
+ run: (_args, { context, dbo }) => {
75
+ void dbo.items.find();
76
+ return context.serviceManager.getService("documents");
77
+ },
78
+ }),
79
+ },
80
+ });
81
+
82
+ const contextualHooks: TableHooks<TestSchema, AppContext> = {
83
+ items: {
84
+ afterEach: [
85
+ {
86
+ commands: { insert: 1 },
87
+ validate: ({ context }) => {
88
+ context.serviceManager.getService("documents");
89
+ return Promise.resolve();
90
+ },
91
+ },
92
+ ],
93
+ },
94
+ };
95
+ contextualHooks satisfies TableHooks<TestSchema, AppContext>;
96
+
97
+ const startTestProstgles = createProstgles<TestSchema>();
98
+ const inferredContextTypeTest = () =>
99
+ startTestProstgles({
100
+ dbConnection: "postgres://unused",
101
+ createContext: () => ({
102
+ serviceManager: { getService: (name: string) => name },
103
+ }),
104
+ onReady: ({ context }) => {
105
+ context.serviceManager.getService("documents");
106
+ },
107
+ });
108
+ void inferredContextTypeTest;
61
109
  });
62
110
  });
@@ -12,10 +12,11 @@ import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder";
12
12
  import type { DB } from "../initProstgles";
13
13
  import type { PublishParams } from "./publishTypesAndUtils";
14
14
 
15
- type FunctionContextBase<S, SUser extends SessionUser> = Pick<
15
+ type FunctionContextBase<S, SUser extends SessionUser, Context> = Pick<
16
16
  PublishParams<S, SUser>,
17
17
  "tables" | "clientReq" | "clientInfo"
18
18
  > & {
19
+ context: Context;
19
20
  dbo: DBOFullyTyped<S>;
20
21
  user: S extends DBSchema ?
21
22
  S["users"]["columns"] extends AnyObject ?
@@ -27,18 +28,22 @@ type FunctionContextBase<S, SUser extends SessionUser> = Pick<
27
28
  export type RestrictedFunctionContext<
28
29
  S = void,
29
30
  SUser extends SessionUser = SessionUser,
30
- > = FunctionContextBase<S, SUser>;
31
+ Context = undefined,
32
+ > = FunctionContextBase<S, SUser, Context>;
31
33
 
32
34
  export type UnrestrictedFunctionContext<
33
35
  S = void,
34
36
  SUser extends SessionUser = SessionUser,
35
- > = FunctionContextBase<S, SUser> & {
37
+ Context = undefined,
38
+ > = FunctionContextBase<S, SUser, Context> & {
36
39
  db: DB;
37
40
  sql: SQLHandler;
38
41
  getClientDBHandlers: PublishParams<S, SUser>["getClientDBHandlers"];
39
42
  };
40
43
 
41
- export type ServerFunctionContext = RestrictedFunctionContext | UnrestrictedFunctionContext;
44
+ export type ServerFunctionContext =
45
+ | RestrictedFunctionContext<void, SessionUser, unknown>
46
+ | UnrestrictedFunctionContext<void, SessionUser, unknown>;
42
47
 
43
48
  export type ServerFunctionDefinition = {
44
49
  input?: Record<string, JSONB.FieldType>;
@@ -48,8 +53,12 @@ export type ServerFunctionDefinition = {
48
53
  };
49
54
 
50
55
  declare const serverFunctionContext: unique symbol;
51
- export type ServerFunctionContextMarker<S, SUser extends SessionUser> = {
52
- [serverFunctionContext]?: [S, SUser];
56
+ export type ServerFunctionContextMarker<
57
+ S,
58
+ SUser extends SessionUser,
59
+ Context = undefined,
60
+ > = {
61
+ [serverFunctionContext]?: [S, SUser, Context];
53
62
  };
54
63
 
55
64
  type DefineFunctionArgs<
@@ -67,22 +76,24 @@ export function defineFunction<
67
76
  S = void,
68
77
  SUser extends SessionUser = SessionUser,
69
78
  Return = unknown,
79
+ Context = undefined,
70
80
  >(
71
- args: DefineFunctionArgs<TInput, UnrestrictedFunctionContext<S, SUser>, Return> & {
81
+ args: DefineFunctionArgs<TInput, UnrestrictedFunctionContext<S, SUser, Context>, Return> & {
72
82
  unrestrictedDbAccess: true;
73
83
  },
74
- ): typeof args & ServerFunctionContextMarker<S, SUser>;
84
+ ): typeof args & ServerFunctionContextMarker<S, SUser, Context>;
75
85
 
76
86
  export function defineFunction<
77
87
  TInput extends Record<string, JSONB.FieldType> | undefined = undefined,
78
88
  S = void,
79
89
  SUser extends SessionUser = SessionUser,
80
90
  Return = unknown,
91
+ Context = undefined,
81
92
  >(
82
- args: DefineFunctionArgs<TInput, RestrictedFunctionContext<S, SUser>, Return> & {
93
+ args: DefineFunctionArgs<TInput, RestrictedFunctionContext<S, SUser, Context>, Return> & {
83
94
  unrestrictedDbAccess?: undefined;
84
95
  },
85
- ): typeof args & ServerFunctionContextMarker<S, SUser>;
96
+ ): typeof args & ServerFunctionContextMarker<S, SUser, Context>;
86
97
  export function defineFunction(args: unknown) {
87
98
  return args;
88
99
  }
@@ -99,30 +110,59 @@ type ValidDbSchema<S> = S extends DBSchema ? S : void;
99
110
  export type ServerFunctionGroupFunctions<
100
111
  S = void,
101
112
  SUser extends SessionUser = SessionUser,
102
- > = Record<string, ServerFunctionDefinition & ServerFunctionContextMarker<S, SUser>>;
113
+ Context = undefined,
114
+ > = Record<string, ServerFunctionDefinition & ServerFunctionContextMarker<S, SUser, Context>>;
103
115
 
104
- export type ServerFunctionGroup<S = void, SUser extends SessionUser = SessionUser> = {
116
+ export type ServerFunctionGroup<
117
+ S = void,
118
+ SUser extends SessionUser = SessionUser,
119
+ Context = undefined,
120
+ > = {
105
121
  userFilter: FullFilter<UsersTableRow<S>, ValidDbSchema<S>>;
106
- functions: ServerFunctionGroupFunctions<S, SUser>;
122
+ functions: ServerFunctionGroupFunctions<S, SUser, Context>;
107
123
  };
108
124
 
109
- export type ServerFunctionDefinitions<S = void, SUser extends SessionUser = SessionUser> = Record<
110
- string,
111
- ServerFunctionGroup<S, SUser>
112
- >;
125
+ export type ServerFunctionDefinitions<
126
+ S = void,
127
+ SUser extends SessionUser = SessionUser,
128
+ Context = undefined,
129
+ > = Record<string, ServerFunctionGroup<S, SUser, Context>>;
113
130
 
114
131
  /**
115
132
  * Creates a schema-aware identity helper for defining a server function group
116
133
  * while preserving its inferred function names and return types.
117
134
  */
118
- export const createFunctionGroupDefiner = <S = void, SUser extends SessionUser = SessionUser>() => {
119
- return <const T extends ServerFunctionGroup<S, SUser>>(group: T): T => group;
135
+ export const createFunctionGroupDefiner = <
136
+ S = void,
137
+ SUser extends SessionUser = SessionUser,
138
+ Context = undefined,
139
+ >() => {
140
+ return <const T extends ServerFunctionGroup<S, SUser, Context>>(group: T): T => group;
120
141
  };
121
142
 
143
+ /** Creates a schema-aware function group definer with application context. */
144
+ export const createFunctionGroupDefinerWithContext = <
145
+ S,
146
+ Context,
147
+ SUser extends SessionUser = SessionUser,
148
+ >() => createFunctionGroupDefiner<S, SUser, Context>();
149
+
122
150
  /**
123
151
  * Creates a schema-aware identity helper for function maps that are composed
124
152
  * into a server function group elsewhere.
125
153
  */
126
- export const createFunctionsDefiner = <S = void, SUser extends SessionUser = SessionUser>() => {
127
- return <const T extends ServerFunctionGroupFunctions<S, SUser>>(functions: T): T => functions;
154
+ export const createFunctionsDefiner = <
155
+ S = void,
156
+ SUser extends SessionUser = SessionUser,
157
+ Context = undefined,
158
+ >() => {
159
+ return <const T extends ServerFunctionGroupFunctions<S, SUser, Context>>(functions: T): T =>
160
+ functions;
128
161
  };
162
+
163
+ /** Creates a schema-aware function-map definer with application context. */
164
+ export const createFunctionsDefinerWithContext = <
165
+ S,
166
+ Context,
167
+ SUser extends SessionUser = SessionUser,
168
+ >() => createFunctionsDefiner<S, SUser, Context>();
@@ -81,7 +81,7 @@ export type ValidateRowArgsCommon<R = AnyObject, DBX = DBHandlerServer> = {
81
81
  }
82
82
  );
83
83
 
84
- export type BeforeEachTsTrigger<R, DBX> = {
84
+ export type BeforeEachTsTrigger<R, DBX, Context = undefined> = {
85
85
  commands: Partial<Record<"insert" | "update", 1>>;
86
86
  /**
87
87
  * Will only run this trigger if the insert/update provides non null values for these fields.
@@ -91,11 +91,12 @@ export type BeforeEachTsTrigger<R, DBX> = {
91
91
  params: ValidateBeforeRowArgsCommon<R, DBX> & {
92
92
  localParams: undefined | LocalParams;
93
93
  hookContext: AnyObject | undefined;
94
+ context: Context;
94
95
  },
95
96
  ) => MaybePromise<void | { row: Partial<R>; hookContext?: AnyObject; onInserted?: () => void }>;
96
97
  };
97
98
 
98
- export type AfterEachTsTrigger<R, DBX> = {
99
+ export type AfterEachTsTrigger<R, DBX, Context = undefined> = {
99
100
  commands: Partial<Record<"insert" | "update" | "delete", 1>>;
100
101
  /**
101
102
  * Will only run this trigger if the insert/update provides non null values for these fields.
@@ -104,6 +105,7 @@ export type AfterEachTsTrigger<R, DBX> = {
104
105
  validate: (
105
106
  params: ValidateRowArgsCommon<R, DBX> & {
106
107
  localParams: undefined | LocalParams;
108
+ context: Context;
107
109
  },
108
110
  ) => Promise<void>;
109
111
  };
@@ -139,12 +141,13 @@ export type ValidateRowsArgsCommon<R = AnyObject, DBX = DBHandlerServer> = {
139
141
  }
140
142
  );
141
143
 
142
- export type AfterAllTsTrigger<R, DBX> = {
144
+ export type AfterAllTsTrigger<R, DBX, Context = undefined> = {
143
145
  commands: Partial<Record<"insert" | "update" | "delete", 1>>;
144
146
  changedFields?: string[];
145
147
  validate: (
146
148
  params: ValidateRowsArgsCommon<R, DBX> & {
147
149
  localParams: undefined | LocalParams;
150
+ context: Context;
148
151
  },
149
152
  ) => Promise<void>;
150
153
  };
@@ -44,7 +44,7 @@ export type FileTableRow = {
44
44
 
45
45
  export const getFileTableConfig = (
46
46
  prg: Prostgles,
47
- ): { tableConfig: TableConfig | undefined; tableHooks: TableHooks | undefined } => {
47
+ ): { tableConfig: TableConfig | undefined; tableHooks: TableHooks<void, any> | undefined } => {
48
48
  const { fileTable, tableConfig, tableHooks } = prg.opts;
49
49
  if (!fileTable) {
50
50
  return { tableConfig, tableHooks };
@@ -102,7 +102,7 @@ export const getFileTableConfig = (
102
102
  };
103
103
 
104
104
  const userFileTableHooks = tableHooks?.[fileTableName];
105
- const mergedTableHooks: TableHooks = {
105
+ const mergedTableHooks: TableHooks<void, any> = {
106
106
  [fileTableName]: {
107
107
  ...userFileTableHooks,
108
108
  beforeEach: [
@@ -1,24 +1,13 @@
1
- import type pgPromise from "pg-promise";
2
1
  import type {
3
2
  ALLOWED_CONTENT_TYPE,
4
3
  ALLOWED_EXTENSION,
5
- AnyObject,
6
- DBSchema,
7
4
  JSONB,
8
5
  MaybePromise,
9
6
  StrictUnion,
10
7
  } from "prostgles-types";
11
- import type { JoinInfo, LocalParams } from "../DboBuilder/DboBuilder";
12
- import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder";
8
+ import type { JoinInfo } from "../DboBuilder/DboBuilder";
13
9
  import type { DB, DBHandlerServer } from "../Prostgles";
14
- import type {
15
- AfterAllTsTrigger,
16
- AfterEachTsTrigger,
17
- BeforeEachTsTrigger,
18
- InsertRule,
19
- SyncConfig,
20
- ValidateRowArgsCommon,
21
- } from "../PublishParser/PublishParser";
10
+ import type { SyncConfig } from "../PublishParser/PublishParser";
22
11
 
23
12
  export type ColExtraInfo = {
24
13
  min?: string | number;
@@ -153,7 +153,7 @@ export const initTableConfig = async function (this: TableConfigurator) {
153
153
 
154
154
  if (queries.length) {
155
155
  await runQueries(queries);
156
- await this.prostgles.refreshDBO();
156
+ await this.prostgles.rebuildDBO();
157
157
  }
158
158
 
159
159
  /* Create/Alter columns */
@@ -348,8 +348,8 @@ export const initTableConfig = async function (this: TableConfigurator) {
348
348
  console.error("Table config failed queries: ", failedQueries);
349
349
  }
350
350
 
351
- await this.prostgles.refreshDBO();
351
+ await this.prostgles.rebuildDBO();
352
352
  await this.setTableOnMounts();
353
353
  /** Needed in case some onMounts change schema */
354
- await this.prostgles.refreshDBO();
354
+ await this.prostgles.rebuildDBO();
355
355
  };
@@ -1,38 +1,56 @@
1
1
  import type pgPromise from "pg-promise";
2
2
  import type { AnyObject, DBSchema } from "prostgles-types";
3
3
 
4
- import type { DbTxTableHandlers, LocalParams } from "../DboBuilder/DboBuilderTypes";
4
+ import type { DbTxTableHandlers } from "../DboBuilder/DboBuilderTypes";
5
5
  import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder";
6
6
  import type {
7
7
  AfterAllTsTrigger,
8
8
  AfterEachTsTrigger,
9
9
  BeforeEachTsTrigger,
10
- InsertRule,
11
- ValidateRowArgsCommon,
12
10
  } from "../PublishParser/PublishParser";
13
11
 
14
- export type TableHooks<S = void> =
12
+ export type TableHooks<S = void, Context = undefined> =
15
13
  S extends DBSchema ?
16
14
  Partial<{
17
15
  [tableName in keyof S]: TableHooksDefinition<
18
16
  Required<S[tableName]["columns"]>,
19
- DBOFullyTyped<S>
17
+ DBOFullyTyped<S>,
18
+ Context
20
19
  >;
21
20
  }>
22
- : Record<string, TableHooksDefinition>;
21
+ : Record<string, TableHooksDefinition<AnyObject, DbTxTableHandlers, Context>>;
23
22
 
24
- export type TableHooksDefinition<R = AnyObject, DBX = DbTxTableHandlers> = {
23
+ export type TableHooksDefinition<
24
+ RowDataType = AnyObject,
25
+ DBX = DbTxTableHandlers,
26
+ Context = undefined,
27
+ > = {
25
28
  /**
26
- * Hook used to run custom logic before inserting a row.
27
- * The returned row must satisfy the table schema.
29
+ * Runs sequentially before validation and SQL for each insert row, or once per update request.
30
+ * May replace the pending data and pass `hookContext` to the next hook.
31
+ * `onInserted` also runs for updates, is not awaited, and runs before the transaction commits.
32
+ */
33
+ beforeEach?: BeforeEachTsTrigger<RowDataType, DBX, Context>[];
34
+
35
+ /**
36
+ * Runs once per affected row after SQL, inside the same transaction.
37
+ * `row` is the inserted/updated row or the deleted row's pre-delete state. Throwing rolls back.
38
+ */
39
+ afterEach?: AfterEachTsTrigger<RowDataType, DBX, Context>[];
40
+
41
+ /**
42
+ * Runs once after all applicable `afterEach` hooks, inside the same transaction.
43
+ * Receives all affected `rows`; throwing rolls back the operation.
44
+ * Same-table, same-command writes from after-hooks do not retrigger after-hooks.
45
+ */
46
+ afterAll?: AfterAllTsTrigger<RowDataType, DBX, Context>[];
47
+
48
+ /**
49
+ * Replaces the generated DELETE. Must perform the mutation and shape its return value using
50
+ * the prepared filter and returning arguments. Delete `afterEach`/`afterAll` hooks do not run.
28
51
  */
29
- getPreInsertRow?: (
30
- args: PreInsertRowArgs,
31
- ) => Promise<{ row: AnyObject; onInserted: Promise<void> }>;
32
- beforeEach?: BeforeEachTsTrigger<R, DBX>[];
33
- afterEach?: AfterEachTsTrigger<R, DBX>[];
34
- afterAll?: AfterAllTsTrigger<R, DBX>[];
35
52
  onInsteadOfDelete?: (args: {
53
+ context: Context;
36
54
  dbx: DBX;
37
55
  tx: pgPromise.ITask<{}>;
38
56
  returningQuery: string;
@@ -44,8 +62,3 @@ export type TableHooksDefinition<R = AnyObject, DBX = DbTxTableHandlers> = {
44
62
  };
45
63
  }) => Promise<AnyObject[] | undefined>;
46
64
  };
47
-
48
- type PreInsertRowArgs = Omit<ValidateRowArgsCommon, "localParams"> & {
49
- validate: InsertRule["validate"];
50
- localParams: LocalParams | undefined;
51
- };
package/lib/index.ts CHANGED
@@ -3,14 +3,26 @@ import type { InitResult, OnReadyCallbackBasic } from "./initProstgles";
3
3
  import { Prostgles } from "./Prostgles";
4
4
  import type { ProstglesInitOptions } from "./ProstglesTypes";
5
5
 
6
- function prostgles<S = void, SUser extends SessionUser = SessionUser>(
7
- params: ProstglesInitOptions<S, SUser>,
6
+ function prostgles<
7
+ S = void,
8
+ SUser extends SessionUser = SessionUser,
9
+ Context = undefined,
10
+ >(
11
+ params: ProstglesInitOptions<S, SUser, Context>,
8
12
  ) {
9
- const prgl = new Prostgles(params as ProstglesInitOptions);
13
+ const prgl = new Prostgles(
14
+ params as unknown as ProstglesInitOptions<void, SessionUser, any>,
15
+ );
10
16
  return prgl.init(params.onReady as unknown as OnReadyCallbackBasic, {
11
17
  type: "init",
12
- }) as unknown as Promise<InitResult<S, SUser>>;
18
+ }) as unknown as Promise<InitResult<S, SUser, Context>>;
13
19
  }
20
+
21
+ /** Creates a schema-bound Prostgles initializer while allowing context inference. */
22
+ export const createProstgles = <S = void, SUser extends SessionUser = SessionUser>() => {
23
+ return <Context = undefined>(params: ProstglesInitOptions<S, SUser, Context>) =>
24
+ prostgles<S, SUser, Context>(params);
25
+ };
14
26
  export * from "./PublishParser/defineServerFunction";
15
27
  export * from "./Auth/AuthTypes";
16
28
  export type { PublishParams } from "./PublishParser/publishTypesAndUtils";
@@ -18,7 +30,15 @@ export type { DBOFullyTyped } from "./DBSchemaBuilder/DBSchemaBuilder";
18
30
  export type { DBHandlerServer } from "./Prostgles";
19
31
  export type { StorageClient as CloudClient } from "./StorageClient/StorageClientTypes";
20
32
  export * from "./StorageClient/getLocalStorageClient";
21
- export type { DB } from "./initProstgles";
33
+ export type {
34
+ ContextCleanup,
35
+ CreateContext,
36
+ CreateContextParams,
37
+ DB,
38
+ InitResult,
39
+ OnReadyParams,
40
+ } from "./initProstgles";
41
+ export type { ProstglesInitOptions } from "./ProstglesTypes";
22
42
  export type * from "./TableConfig/TableConfigTypes";
23
43
  export type * from "./TableHooks/TableHooks";
24
44
  export * from "./Auth/utils/upsertNamedExpressMiddleware";