prostgles-server 4.2.622 → 4.2.624

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 (84) hide show
  1. package/debug/client-schema-types/DBGeneratedSchema.ts +13 -1
  2. package/dist/DBSchemaBuilder/constants.d.ts +6 -1
  3. package/dist/DBSchemaBuilder/constants.d.ts.map +1 -1
  4. package/dist/DBSchemaBuilder/constants.js +7 -2
  5. package/dist/DBSchemaBuilder/constants.js.map +1 -1
  6. package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.d.ts.map +1 -1
  7. package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.js +4 -9
  8. package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.js.map +1 -1
  9. package/dist/DBSchemaBuilder/getDBGeneratedSchema.d.ts.map +1 -1
  10. package/dist/DBSchemaBuilder/getDBGeneratedSchema.js +20 -8
  11. package/dist/DBSchemaBuilder/getDBGeneratedSchema.js.map +1 -1
  12. package/dist/DboBuilder/DboBuilder.js +1 -1
  13. package/dist/DboBuilder/DboBuilder.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/schema/getTablesForSchemaPostgresSQL.d.ts +1 -1
  17. package/dist/Filtering/Filtering.d.ts +1 -1
  18. package/dist/Prostgles.js +1 -1
  19. package/dist/Prostgles.js.map +1 -1
  20. package/dist/PubSubManager/PubSubManager.d.ts +1 -1
  21. package/dist/PublishParser/PublishParser.d.ts +17 -8
  22. package/dist/PublishParser/PublishParser.d.ts.map +1 -1
  23. package/dist/PublishParser/PublishParser.js +48 -28
  24. package/dist/PublishParser/PublishParser.js.map +1 -1
  25. package/dist/PublishParser/getFileTableRules.d.ts +1 -1
  26. package/dist/PublishParser/getFileTableRules.d.ts.map +1 -1
  27. package/dist/PublishParser/getFileTableRules.js +52 -41
  28. package/dist/PublishParser/getFileTableRules.js.map +1 -1
  29. package/dist/PublishParser/getParsedPublishTable.d.ts +4 -0
  30. package/dist/PublishParser/getParsedPublishTable.d.ts.map +1 -0
  31. package/dist/PublishParser/{getTableRulesWithoutFileTable.js → getParsedPublishTable.js} +13 -7
  32. package/dist/PublishParser/getParsedPublishTable.js.map +1 -0
  33. package/dist/PublishParser/getPublishSchemas.d.ts +4 -0
  34. package/dist/PublishParser/getPublishSchemas.d.ts.map +1 -0
  35. package/dist/PublishParser/getPublishSchemas.js +42 -0
  36. package/dist/PublishParser/getPublishSchemas.js.map +1 -0
  37. package/dist/PublishParser/getPublishedObjectFromResult.d.ts +4 -0
  38. package/dist/PublishParser/getPublishedObjectFromResult.d.ts.map +1 -0
  39. package/dist/PublishParser/getPublishedObjectFromResult.js +77 -0
  40. package/dist/PublishParser/getPublishedObjectFromResult.js.map +1 -0
  41. package/dist/PublishParser/getPublishedTableNames.d.ts.map +1 -1
  42. package/dist/PublishParser/getPublishedTableNames.js +4 -1
  43. package/dist/PublishParser/getPublishedTableNames.js.map +1 -1
  44. package/dist/PublishParser/getSchemaFromPublish.d.ts.map +1 -1
  45. package/dist/PublishParser/getSchemaFromPublish.js +11 -5
  46. package/dist/PublishParser/getSchemaFromPublish.js.map +1 -1
  47. package/dist/PublishParser/publishTypesAndUtils.d.ts +28 -3
  48. package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
  49. package/dist/PublishParser/publishTypesAndUtils.js +6 -1
  50. package/dist/PublishParser/publishTypesAndUtils.js.map +1 -1
  51. package/dist/PublishParser/validatePublishProfiles.d.ts +2 -2
  52. package/dist/PublishParser/validatePublishProfiles.d.ts.map +1 -1
  53. package/dist/PublishParser/validatePublishProfiles.js.map +1 -1
  54. package/dist/index.d.ts +1 -1
  55. package/dist/index.d.ts.map +1 -1
  56. package/dist/index.js.map +1 -1
  57. package/dist/runClientRequest.d.ts.map +1 -1
  58. package/dist/runClientRequest.js +6 -1
  59. package/dist/runClientRequest.js.map +1 -1
  60. package/lib/DBSchemaBuilder/constants.ts +6 -1
  61. package/lib/DBSchemaBuilder/getClientDBGeneratedSchemas.ts +7 -10
  62. package/lib/DBSchemaBuilder/getDBGeneratedSchema.ts +20 -8
  63. package/lib/DboBuilder/DboBuilder.ts +1 -1
  64. package/lib/Prostgles.ts +2 -2
  65. package/lib/PublishParser/PublishParser.ts +82 -50
  66. package/lib/PublishParser/getFileTableRules.ts +52 -45
  67. package/lib/PublishParser/{getTableRulesWithoutFileTable.ts → getParsedPublishTable.ts} +16 -12
  68. package/lib/PublishParser/getPublishSchemas.ts +49 -0
  69. package/lib/PublishParser/getPublishedObjectFromResult.ts +104 -0
  70. package/lib/PublishParser/getPublishedTableNames.ts +6 -1
  71. package/lib/PublishParser/getSchemaFromPublish.ts +9 -7
  72. package/lib/PublishParser/publishTypesAndUtils.ts +31 -6
  73. package/lib/PublishParser/validatePublishProfiles.ts +1 -1
  74. package/lib/index.ts +13 -1
  75. package/lib/runClientRequest.ts +4 -3
  76. package/package.json +1 -1
  77. package/dist/DBSchemaBuilder/getPublishSchemas.d.ts +0 -4
  78. package/dist/DBSchemaBuilder/getPublishSchemas.d.ts.map +0 -1
  79. package/dist/DBSchemaBuilder/getPublishSchemas.js +0 -34
  80. package/dist/DBSchemaBuilder/getPublishSchemas.js.map +0 -1
  81. package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts +0 -6
  82. package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts.map +0 -1
  83. package/dist/PublishParser/getTableRulesWithoutFileTable.js.map +0 -1
  84. package/lib/DBSchemaBuilder/getPublishSchemas.ts +0 -41
@@ -1,9 +1,13 @@
1
- import { getObjectEntries, includes, SQL_COMMAND_TABLE_METHODS } from "prostgles-types";
1
+ import {
2
+ getObjectEntries,
3
+ includes,
4
+ SQL_COMMAND_TABLE_METHODS,
5
+ type TableSchema,
6
+ } from "prostgles-types";
2
7
  import { getClientRequestIPsInfo } from "../Auth/AuthHandler";
3
8
  import type { AuthClientRequest, AuthResultWithSID, SessionUser } from "../Auth/AuthTypes";
4
9
  import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder";
5
10
  import type { DB, DBHandlerServer, Prostgles } from "../Prostgles";
6
- import type { ProstglesInitOptions } from "../ProstglesTypes";
7
11
  import { getClientHandlers } from "../WebsocketAPI/getClientHandlers";
8
12
  import { applyScopeToTableRules } from "./applyScopeToTableRules";
9
13
  import type {
@@ -12,15 +16,18 @@ import type {
12
16
  UnrestrictedFunctionContext,
13
17
  } from "./defineServerFunction";
14
18
  import { getFileTableRules } from "./getFileTableRules";
19
+ import { getPublishedObjectFromResult } from "./getPublishedObjectFromResult";
15
20
  import { getSchemaFromPublish } from "./getSchemaFromPublish";
16
- import { getTableRulesWithoutFileTable } from "./getTableRulesWithoutFileTable";
21
+ import { getParsedPublishTable } from "./getParsedPublishTable";
17
22
  import type {
18
23
  DboTable,
19
24
  DboTableCommand,
20
25
  ParsedTableRule,
26
+ Publish,
21
27
  PublishParams,
22
28
  } from "./publishTypesAndUtils";
23
29
  import {
30
+ isPublishProfiles,
24
31
  parsePublishTableRule,
25
32
  type PermissionScope,
26
33
  type PublishObject,
@@ -28,9 +35,7 @@ import {
28
35
  import { validatePublishProfiles } from "./validatePublishProfiles";
29
36
 
30
37
  export class PublishParser {
31
- publish:
32
- | Exclude<ProstglesInitOptions<void, SessionUser, any>["publish"], unknown[]>
33
- | ReturnType<typeof validatePublishProfiles>;
38
+ parsedPublish: ReturnType<typeof getParsedPublish>;
34
39
  publishRawSQL?: any;
35
40
  dbo: DBHandlerServer;
36
41
  db: DB;
@@ -39,7 +44,8 @@ export class PublishParser {
39
44
  constructor(prostgles: Prostgles) {
40
45
  this.prostgles = prostgles;
41
46
  const { publish } = prostgles.opts;
42
- this.publish = Array.isArray(publish) ? validatePublishProfiles(publish) : publish;
47
+
48
+ this.parsedPublish = getParsedPublish(publish, prostgles.dboBuilder.tablesOrViews ?? []);
43
49
 
44
50
  // eslint-disable-next-line @typescript-eslint/unbound-method
45
51
  this.publishRawSQL = prostgles.opts.publishRawSQL;
@@ -145,50 +151,54 @@ export class PublishParser {
145
151
  /**
146
152
  * Parses the first level of publish. (If false then nothing if * then all tables and views)
147
153
  */
148
- async getPublishObject(
154
+ async getPublishObjectForUser(
149
155
  clientReq: AuthClientRequest,
150
156
  clientInfo: AuthResultWithSID | undefined,
151
157
  ): Promise<PublishObject | undefined> {
152
158
  const publishParams = await this.getPublishParams(clientReq, clientInfo);
153
159
 
154
- const result = await applyParamsIfFunc(this.publish, publishParams);
155
- const publish =
156
- Array.isArray(result) ?
157
- validatePublishProfiles(result).find((profile) =>
158
- publishParams.user ? profile.userTypes.includes(publishParams.user.type) : false,
159
- )?.publish
160
- : result;
161
-
162
- if (publish === "*") {
163
- const publish: PublishObject = {};
164
- this.prostgles.dboBuilder.tablesOrViews?.map((tov) => {
165
- publish[tov.name] = "*";
166
- });
167
- return publish;
168
- }
160
+ const parsedPublish = await applyParamsIfFunc(this.parsedPublish, publishParams);
161
+
162
+ const publishResult = (() => {
163
+ if (!isPublishProfiles(parsedPublish)) {
164
+ return parsedPublish;
165
+ }
166
+
167
+ const { user } = publishParams;
168
+ if (!user) return;
169
+ return parsedPublish.find(({ userTypes }) => userTypes.includes(user.type))?.publish;
170
+ })();
169
171
 
170
- return publish || undefined;
172
+ if (!publishResult) return;
173
+
174
+ const publishedObject = getPublishedObjectFromResult(
175
+ publishResult,
176
+ this.prostgles.dboBuilder.tablesOrViews ?? [],
177
+ publishParams,
178
+ );
179
+ return publishedObject;
171
180
  }
172
181
 
173
182
  async getValidatedRequestRuleWusr(
174
183
  { tableName, command, clientReq }: DboTableCommand,
175
184
  scope: PermissionScope | undefined,
176
185
  ): Promise<ParsedTableRule> {
177
- const rules = await this.getParsedTableRule({ tableName, clientReq }, undefined, scope);
178
186
  const clientInfo =
179
187
  clientReq && (await this.prostgles.authHandler.getSidAndUserFromRequest(clientReq));
180
188
  if (clientInfo === "new-session-redirect") {
181
189
  throw "new-session-redirect";
182
190
  }
191
+ const rules = await this.getParsedTableRule({ tableName, clientReq, scope, clientInfo });
183
192
  this.validateRequestRule({ tableName, command, clientReq }, rules, scope);
184
193
  return rules;
185
194
  }
186
195
 
187
- async getParsedTableRule(
188
- { tableName, clientReq }: Pick<DboTableCommand, "tableName" | "clientReq">,
189
- clientInfo: AuthResultWithSID | undefined,
190
- scope: PermissionScope | undefined,
191
- ): Promise<ParsedTableRule> {
196
+ async getParsedTableRule({
197
+ tableName,
198
+ clientReq,
199
+ clientInfo,
200
+ scope,
201
+ }: Omit<TableRequest, "resolvedPublishObject">): Promise<ParsedTableRule> {
192
202
  if (!tableName) throw "tableName missing";
193
203
 
194
204
  /* Must be local request -> allow everything */
@@ -202,7 +212,7 @@ export class PublishParser {
202
212
  }
203
213
 
204
214
  /* Must be from socket. Must have a publish */
205
- if (!this.publish) throw "publish is missing";
215
+ if (!this.parsedPublish) throw "publish is missing";
206
216
 
207
217
  const tableErrors = clientReq.socket?.prostgles?.get(this.prostgles.appId)?.tableSchemaErrors[
208
218
  tableName
@@ -212,7 +222,13 @@ export class PublishParser {
212
222
  throw errorInfo.error;
213
223
  });
214
224
 
215
- const tableRule = await this.getTableRules({ tableName, clientReq }, clientInfo, scope);
225
+ const tableRule = await this.getTableRules({
226
+ tableName,
227
+ clientReq,
228
+ clientInfo,
229
+ scope,
230
+ resolvedPublishObject: undefined,
231
+ });
216
232
 
217
233
  if (!tableRule) {
218
234
  throw {
@@ -278,27 +294,28 @@ export class PublishParser {
278
294
  }
279
295
  }
280
296
 
281
- async getTableRules(
282
- args: DboTable,
283
- clientInfo: AuthResultWithSID | undefined,
284
- scope: PermissionScope | undefined,
285
- overriddenPublish?: PublishObject,
286
- ): Promise<ParsedTableRule | undefined> {
287
- const { tableName } = args;
297
+ async getTableRules({
298
+ resolvedPublishObject: overriddenPublish,
299
+ scope,
300
+ clientInfo,
301
+ clientReq,
302
+ tableName,
303
+ }: TableRequest): Promise<ParsedTableRule | undefined> {
288
304
  const tableHandler = this.dbo[tableName];
289
305
  if (!tableHandler) {
290
- throw "INTERNAL ERROR: table handler not found for " + args.tableName;
306
+ throw "INTERNAL ERROR: table handler not found for " + tableName;
291
307
  }
292
- const fileTablePublishRules = await this.getTableRulesWithoutFileTable(
293
- args,
308
+ const publishRulesExcludingFileTable = await this.getParsedPublishTable({
309
+ clientReq,
310
+ tableName,
294
311
  clientInfo,
295
- overriddenPublish,
296
- );
297
- if (this.dbo[args.tableName]?.is_media) {
312
+ resolvedPublishObject: overriddenPublish,
313
+ });
314
+ if (this.dbo[tableName]?.is_media) {
298
315
  const { rules: fileTableRules } = await getFileTableRules.bind(this)(
299
- args.tableName,
300
- fileTablePublishRules,
301
- args.clientReq,
316
+ tableName,
317
+ publishRulesExcludingFileTable,
318
+ clientReq,
302
319
  clientInfo,
303
320
  scope,
304
321
  overriddenPublish,
@@ -314,17 +331,32 @@ export class PublishParser {
314
331
  return applyScopeToTableRules(
315
332
  tableName,
316
333
  tableHandler,
317
- parsePublishTableRule(fileTablePublishRules),
334
+ parsePublishTableRule(publishRulesExcludingFileTable),
318
335
  scope,
319
336
  );
320
337
  }
321
338
 
322
- getTableRulesWithoutFileTable = getTableRulesWithoutFileTable.bind(this);
339
+ getParsedPublishTable = getParsedPublishTable.bind(this);
323
340
 
324
341
  /* Prepares schema for client. Only allowed views and commands will be present */
325
342
  getSchemaFromPublish = getSchemaFromPublish.bind(this);
326
343
  }
327
344
 
345
+ const getParsedPublish = (publish: Publish | undefined, tablesOrViews: TableSchema[]) => {
346
+ if (!publish) return;
347
+ return (
348
+ isPublishProfiles(publish) ? validatePublishProfiles(publish)
349
+ : typeof publish === "function" ? publish
350
+ : getPublishedObjectFromResult(publish, tablesOrViews, undefined)
351
+ );
352
+ };
353
+
354
+ export type TableRequest = DboTable & {
355
+ clientInfo: AuthResultWithSID | undefined;
356
+ scope: PermissionScope | undefined;
357
+ resolvedPublishObject: PublishObject | undefined;
358
+ };
359
+
328
360
  export * from "./publishTypesAndUtils";
329
361
 
330
362
  type FunctionWithArguments = (...args: any) => any;
@@ -20,8 +20,8 @@ export async function getFileTableRules(
20
20
  fileTablePublishRules: ParsedPublishTable | undefined,
21
21
  clientReq: AuthClientRequest | undefined,
22
22
  clientInfo: AuthResultWithSID | undefined,
23
- scope: LocalParams["scope"],
24
- overriddenPublish?: PublishObject,
23
+ scope: LocalParams["scope"] | undefined,
24
+ resolvedPublishObject: PublishObject | undefined,
25
25
  ) {
26
26
  const forcedDeleteFilters: FullFilter<AnyObject, void>[] = [];
27
27
  const forcedSelectFilters: FullFilter<AnyObject, void>[] = [];
@@ -43,51 +43,58 @@ export async function getFileTableRules(
43
43
  .filter(isDefined);
44
44
  if (referencedColumns?.length) {
45
45
  for (const { tableName, fileColumns, allColumns } of referencedColumns) {
46
- const tableRules = await this.getTableRules({ clientReq, tableName }, clientInfo, scope, overriddenPublish);
47
- if (tableRules) {
48
- fileColumns.map((column) => {
49
- const path = [{ table: tableName, on: [{ id: column }] }];
50
- if (tableRules.delete) {
51
- forcedDeleteFilters.push({
46
+ const tableRules = await this.getTableRules({
47
+ clientReq,
48
+ tableName,
49
+ clientInfo,
50
+ scope,
51
+ resolvedPublishObject,
52
+ });
53
+ if (!tableRules) {
54
+ continue;
55
+ }
56
+ fileColumns.map((column) => {
57
+ const path = [{ table: tableName, on: [{ id: column }] }];
58
+ if (tableRules.delete) {
59
+ forcedDeleteFilters.push({
60
+ $existsJoined: {
61
+ path,
62
+ filter: tableRules.delete.forcedFilter ?? {},
63
+ },
64
+ });
65
+ }
66
+ if (tableRules.select) {
67
+ const parsedFields = parseFieldFilter(tableRules.select.fields, false, allColumns);
68
+ /** Must be allowed to view this column */
69
+ if (includes(parsedFields, column)) {
70
+ forcedSelectFilters.push({
52
71
  $existsJoined: {
53
72
  path,
54
- filter: tableRules.delete.forcedFilter ?? {},
73
+ filter: tableRules.select.forcedFilter ?? {},
55
74
  },
56
75
  });
57
76
  }
58
- if (tableRules.select) {
59
- const parsedFields = parseFieldFilter(tableRules.select.fields, false, allColumns);
60
- /** Must be allowed to view this column */
61
- if (includes(parsedFields, column)) {
62
- forcedSelectFilters.push({
63
- $existsJoined: {
64
- path,
65
- filter: tableRules.select.forcedFilter ?? {},
66
- },
67
- });
68
- }
69
- }
70
- if (tableRules.insert) {
71
- const parsedFields = parseFieldFilter(tableRules.insert.fields, false, allColumns);
72
- /** Must be allowed to view this column */
73
- if (includes(parsedFields, column)) {
74
- allowedNestedInserts.push({ table: tableName, column });
75
- }
77
+ }
78
+ if (tableRules.insert) {
79
+ const parsedFields = parseFieldFilter(tableRules.insert.fields, false, allColumns);
80
+ /** Must be allowed to view this column */
81
+ if (includes(parsedFields, column)) {
82
+ allowedNestedInserts.push({ table: tableName, column });
76
83
  }
77
- if (tableRules.update) {
78
- const parsedFields = parseFieldFilter(tableRules.update.fields, false, allColumns);
79
- /** Must be allowed to view this column */
80
- if (includes(parsedFields, column)) {
81
- forcedUpdateFilters.push({
82
- $existsJoined: {
83
- path,
84
- filter: tableRules.update.forcedFilter ?? {},
85
- },
86
- });
87
- }
84
+ }
85
+ if (tableRules.update) {
86
+ const parsedFields = parseFieldFilter(tableRules.update.fields, false, allColumns);
87
+ /** Must be allowed to view this column */
88
+ if (includes(parsedFields, column)) {
89
+ forcedUpdateFilters.push({
90
+ $existsJoined: {
91
+ path,
92
+ filter: tableRules.update.forcedFilter ?? {},
93
+ },
94
+ });
88
95
  }
89
- });
90
- }
96
+ }
97
+ });
91
98
  }
92
99
  }
93
100
 
@@ -137,11 +144,11 @@ export async function getFileTableRules(
137
144
  };
138
145
  }
139
146
 
140
- /** Add missing implied methods (getColumns, getInfo) */
141
- const rules = await this.getTableRulesWithoutFileTable.bind(this)(
142
- { clientReq, tableName: fileTableName },
147
+ const rules = await this.getParsedPublishTable.bind(this)({
148
+ clientReq,
149
+ tableName: fileTableName,
143
150
  clientInfo,
144
- { [fileTableName]: fileTableRule },
145
- );
151
+ resolvedPublishObject: { [fileTableName]: fileTableRule },
152
+ });
146
153
  return { rules, allowedInserts: allowedNestedInserts };
147
154
  }
@@ -1,24 +1,22 @@
1
- import { isAuditTable } from "../Audit/getAuditTableConfig";
2
1
  import { getObjectEntries, isObject } from "prostgles-types";
3
- import type { AuthResultWithSID } from "../Auth/AuthTypes";
2
+ import { isAuditTable } from "../Audit/getAuditTableConfig";
4
3
  import type { TableHandler } from "../DboBuilder/TableHandler/TableHandler";
5
4
  import type { ViewHandler } from "../DboBuilder/ViewHandler/ViewHandler";
6
- import type { PublishParser } from "./PublishParser";
7
- import type { DboTable, ParsedPublishTable } from "./publishTypesAndUtils";
8
- import { TABLE_RULE_NO_LIMITS, type PublishObject } from "./publishTypesAndUtils";
5
+ import type { PublishParser, TableRequest } from "./PublishParser";
6
+ import type { ParsedPublishTable } from "./publishTypesAndUtils";
7
+ import { TABLE_RULE_NO_LIMITS } from "./publishTypesAndUtils";
9
8
 
10
- export async function getTableRulesWithoutFileTable(
9
+ export async function getParsedPublishTable(
11
10
  this: PublishParser,
12
- { tableName, clientReq }: DboTable,
13
- clientInfo: AuthResultWithSID | undefined,
14
- overridenPublish?: PublishObject,
11
+ { tableName, clientReq, clientInfo, resolvedPublishObject }: Omit<TableRequest, "scope">,
15
12
  ): Promise<ParsedPublishTable | undefined> {
16
13
  if (!tableName) {
17
14
  throw new Error("tableName is missing in getTableRules");
18
15
  }
19
16
 
20
17
  const publish =
21
- overridenPublish ?? (clientReq && (await this.getPublishObject(clientReq, clientInfo)));
18
+ resolvedPublishObject ??
19
+ (clientReq && (await this.getPublishObjectForUser(clientReq, clientInfo)));
22
20
 
23
21
  const rawTableRule = publish?.[tableName];
24
22
  if (!rawTableRule || (isObject(rawTableRule) && Object.values(rawTableRule).every((v) => !v))) {
@@ -53,8 +51,14 @@ export async function getTableRulesWithoutFileTable(
53
51
  }
54
52
  : rawTableRule;
55
53
 
56
- const tableRulesObject = isAuditTable(this.prostgles, tableName)
57
- ? { select: rawTableRulesObject.select, insert: undefined, update: undefined, delete: undefined }
54
+ const tableRulesObject =
55
+ isAuditTable(this.prostgles, tableName) ?
56
+ {
57
+ select: rawTableRulesObject.select,
58
+ insert: undefined,
59
+ update: undefined,
60
+ delete: undefined,
61
+ }
58
62
  : rawTableRulesObject;
59
63
 
60
64
  const selectRule =
@@ -0,0 +1,49 @@
1
+ import { fromEntries, type DBSchemaTable } from "prostgles-types";
2
+ import { getRawColumns } from "../DboBuilder/getColumns";
3
+ import { getRawInfo } from "../DboBuilder/ViewHandler/getRawInfo";
4
+ import type { ClientSchemaProfiles } from "../DBSchemaBuilder/getClientDBGeneratedSchemas";
5
+ import { isArray } from "../utils/utils";
6
+ import { getPublishedObjectFromResult } from "./getPublishedObjectFromResult";
7
+ import { getPublishedTableNames } from "./getPublishedTableNames";
8
+ import type { PublishParser } from "./PublishParser";
9
+
10
+ export const getPublishSchemas = async (
11
+ publishParser: PublishParser,
12
+ ): Promise<ClientSchemaProfiles | undefined> => {
13
+ if (!isArray(publishParser.parsedPublish)) {
14
+ return;
15
+ }
16
+ const entries = publishParser.parsedPublish;
17
+ const { tablesOrViews = [] } = publishParser.prostgles.dboBuilder;
18
+ const profiles: ClientSchemaProfiles = fromEntries(
19
+ await Promise.all(
20
+ entries.map(async ({ name, publish }) => {
21
+ const resolvedPublishObject = getPublishedObjectFromResult(
22
+ publish,
23
+ tablesOrViews,
24
+ undefined,
25
+ );
26
+ const tableNames = getPublishedTableNames(publishParser, resolvedPublishObject);
27
+ const tableSchema: DBSchemaTable[] = [];
28
+ for (const tableName of tableNames) {
29
+ const rules = await publishParser.getTableRules({
30
+ tableName,
31
+ resolvedPublishObject,
32
+ clientReq: undefined,
33
+ clientInfo: undefined,
34
+ scope: undefined,
35
+ });
36
+ if (!rules || !Object.values(rules).some(Boolean)) continue;
37
+ const table = publishParser.dbo[tableName]!;
38
+ tableSchema.push({
39
+ ...getRawInfo.call(table, undefined, rules),
40
+ name: tableName,
41
+ columns: await getRawColumns.call(table, undefined, undefined, rules),
42
+ });
43
+ }
44
+ return [name, { tableSchema }];
45
+ }),
46
+ ),
47
+ );
48
+ return profiles;
49
+ };
@@ -0,0 +1,104 @@
1
+ import {
2
+ fromEntries,
3
+ getJSONBSchemaValidationError,
4
+ getProperty,
5
+ isObject,
6
+ pickKeys,
7
+ type TableSchema,
8
+ } from "prostgles-types";
9
+ import { isArray } from "../utils/utils";
10
+ import type {
11
+ PublishContextValue,
12
+ PublishedResult,
13
+ PublishObject,
14
+ PublishParams,
15
+ } from "./publishTypesAndUtils";
16
+
17
+ export const getPublishedObjectFromResult = (
18
+ publish: PublishedResult | undefined,
19
+ tablesOrViews: TableSchema[],
20
+ publishParams: PublishParams | undefined,
21
+ ): PublishObject => {
22
+ if (!publish) return {};
23
+ if (publish === "*") {
24
+ return Object.fromEntries(tablesOrViews.map((table) => [table.name, "*"]));
25
+ }
26
+
27
+ if (isArray(publish)) {
28
+ const validation = getJSONBSchemaValidationError(
29
+ {
30
+ tuple: [
31
+ { enum: ["*"] },
32
+ {
33
+ record: {
34
+ keysEnum: ["select", "update", "insert", "delete"] as const,
35
+ values: { enum: ["*", false, true] },
36
+ partial: true,
37
+ },
38
+ },
39
+ ],
40
+ } as const,
41
+ publish,
42
+ );
43
+ if (validation.error !== undefined) {
44
+ throw new Error(`Invalid publish all tables: ${validation.error}`);
45
+ }
46
+
47
+ const [_, allTableRules] = validation.data;
48
+ return fromEntries(
49
+ tablesOrViews.map((table) => {
50
+ return [table.name, table.is_view ? pickKeys(allTableRules, ["select"]) : allTableRules];
51
+ }),
52
+ );
53
+ }
54
+
55
+ return replaceContextPlaceholders(publish, publishParams);
56
+ };
57
+
58
+ const replaceContextPlaceholders = <T>(publish: T, publishParams: PublishParams | undefined): T => {
59
+ const context = { user: publishParams?.user };
60
+ if (!publishParams) return publish;
61
+ if (isArray(publish)) {
62
+ return publish.map((item) => replaceContextPlaceholders(item, publishParams)) as T;
63
+ }
64
+ if (isObject(publish) && isPlainObject(publish)) {
65
+ const { data } = getJSONBSchemaValidationError(
66
+ {
67
+ type: {
68
+ $prostglesContext: {
69
+ type: { objectName: { enum: ["user"] as const }, objectPropertyName: "string" },
70
+ },
71
+ },
72
+ },
73
+ publish,
74
+ { allowExtraProperties: false },
75
+ );
76
+ if (data) {
77
+ data satisfies PublishContextValue;
78
+ const { objectName, objectPropertyName } = data["$prostglesContext"];
79
+ const contextObject = getProperty(context, objectName);
80
+ if (!contextObject) {
81
+ throw new Error(`Context object "${objectName}" not found`);
82
+ }
83
+ const contextProperty = getProperty(contextObject, objectPropertyName);
84
+ if (contextProperty === undefined) {
85
+ throw new Error(
86
+ `Context property "${objectPropertyName}" not found/undefined in context object "${objectName}"`,
87
+ );
88
+ }
89
+ return contextProperty as T;
90
+ }
91
+ return Object.fromEntries(
92
+ Object.entries(publish).map(([key, value]) => [
93
+ key,
94
+ replaceContextPlaceholders(value, publishParams),
95
+ ]),
96
+ ) as T;
97
+ }
98
+ return publish;
99
+ };
100
+ const isPlainObject = (value: unknown): value is Record<string, unknown> => {
101
+ if (!value || typeof value !== "object") return false;
102
+ const prototype = Object.getPrototypeOf(value);
103
+ return prototype === Object.prototype || prototype === null;
104
+ };
@@ -6,7 +6,12 @@ export const getPublishedTableNames = (
6
6
  publishObject: PublishObject,
7
7
  ) => {
8
8
  const txKey = !publishParserInstance.prostgles.opts.transactions ? "" : "tx";
9
- const tableNames = Object.keys(publishObject).filter((k) => !txKey || txKey !== k);
9
+ if (txKey && txKey in publishObject) {
10
+ throw new Error(
11
+ `Transactions key ${JSON.stringify(txKey)} collides with a published table name`,
12
+ );
13
+ }
14
+ const tableNames = Object.keys(publishObject);
10
15
 
11
16
  /**
12
17
  * Add file table to the list of published tables if it's referenced by other published tables.
@@ -27,18 +27,18 @@ export async function getSchemaFromPublish(
27
27
  if (clientInfo === "new-session-redirect") {
28
28
  throw "new-session-redirect";
29
29
  }
30
- let publish: PublishObject | undefined;
30
+ let resolvedPublishObject: PublishObject | undefined;
31
31
  try {
32
- publish = await this.getPublishObject(clientReq, clientInfo);
32
+ resolvedPublishObject = await this.getPublishObjectForUser(clientReq, clientInfo);
33
33
  } catch (err) {
34
34
  console.error("Error within then Publish function ", err);
35
35
  throw err;
36
36
  }
37
37
 
38
- if (!publish || !Object.keys(publish).length) {
38
+ if (!resolvedPublishObject || !Object.keys(resolvedPublishObject).length) {
39
39
  return { tables, tableSchemaErrors };
40
40
  }
41
- const tableNames = getPublishedTableNames(this, publish);
41
+ const tableNames = getPublishedTableNames(this, resolvedPublishObject);
42
42
 
43
43
  await Promise.all(
44
44
  tableNames.map(async (tableName) => {
@@ -52,11 +52,13 @@ export async function getSchemaFromPublish(
52
52
  throw errMsg;
53
53
  }
54
54
 
55
- const parsedTableRule = await this.getTableRules(
56
- { clientReq, tableName },
55
+ const parsedTableRule = await this.getTableRules({
56
+ clientReq,
57
+ tableName,
57
58
  clientInfo,
58
59
  scope,
59
- );
60
+ resolvedPublishObject,
61
+ });
60
62
 
61
63
  if (!parsedTableRule || isEmpty(parsedTableRule)) return;
62
64
  if (!isObject(parsedTableRule)) {
@@ -27,6 +27,7 @@ import type {
27
27
  import type { AuthClientRequest, LoginClientInfo, SessionUser } from "../Auth/AuthTypes";
28
28
  import type { TableSchemaColumn } from "../DboBuilder/DboBuilderTypes";
29
29
  import type { ClientHandlers } from "../WebsocketAPI/getClientHandlers";
30
+ import { isArray } from "../utils/utils";
30
31
 
31
32
  export type InsertRequestData = {
32
33
  data: object | object[];
@@ -556,16 +557,40 @@ export type ParsedPublishTables = {
556
557
  };
557
558
 
558
559
  type PublishAllOrNothingRoot = Exclude<PublishAllOrNothing, boolean>;
559
- export type PublishedResult<Schema = void> = PublishAllOrNothingRoot | PublishFullyTyped<Schema>;
560
+ export type PublishAllTables = [
561
+ "*",
562
+ Partial<{ select: boolean; update: boolean; insert: boolean; delete: boolean }>,
563
+ ];
564
+ export type PublishedResult<Schema = void> =
565
+ PublishAllOrNothingRoot | PublishAllTables | PublishFullyTyped<Schema>;
566
+
560
567
  export type PublishProfile<Schema = void> = {
561
568
  /** Exported schema type name; defaults to Publish1Schema, Publish2Schema, etc. */
562
569
  name?: string;
563
- userTypes: string[];
570
+ userTypes: readonly string[] | string[];
564
571
  publish: PublishedResult<Schema>;
565
572
  };
573
+
574
+ /**
575
+ * Used in PublishProfile to provide user data
576
+ */
577
+ export type PublishContextValue<C extends { user: AnyObject } = { user: AnyObject }> = {
578
+ $prostglesContext: {
579
+ [K in keyof C]: {
580
+ objectName: K;
581
+ objectPropertyName: keyof C[K];
582
+ };
583
+ }[keyof C];
584
+ };
585
+
566
586
  export type Publish<Schema = void, SUser extends SessionUser = SessionUser> =
567
- | PublishProfile<Schema>[]
568
587
  | PublishedResult<Schema>
569
- | ((
570
- params: PublishParams<Schema, SUser>,
571
- ) => Awaitable<PublishedResult<Schema> | PublishProfile<Schema>[]>);
588
+ | PublishProfile<Schema>[]
589
+ | readonly PublishProfile<Schema>[]
590
+ | ((params: PublishParams<Schema, SUser>) => Awaitable<PublishedResult<Schema>>);
591
+
592
+ export const isPublishProfiles = <const P extends Publish | undefined>(
593
+ publish: P,
594
+ ): publish is Extract<P, PublishProfile[] | readonly PublishProfile[]> => {
595
+ return isArray(publish) && publish[0] !== "*";
596
+ };