prostgles-server 4.2.439 → 4.2.441

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 (73) hide show
  1. package/dist/DboBuilder/QueryStreamer.js +1 -1
  2. package/dist/DboBuilder/QueryStreamer.js.map +1 -1
  3. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts +6 -6
  4. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts.map +1 -1
  5. package/dist/DboBuilder/ViewHandler/ViewHandler.js +6 -8
  6. package/dist/DboBuilder/ViewHandler/ViewHandler.js.map +1 -1
  7. package/dist/DboBuilder/ViewHandler/subscribe.d.ts +4 -12
  8. package/dist/DboBuilder/ViewHandler/subscribe.d.ts.map +1 -1
  9. package/dist/DboBuilder/ViewHandler/subscribe.js +11 -25
  10. package/dist/DboBuilder/ViewHandler/subscribe.js.map +1 -1
  11. package/dist/Logging.d.ts +2 -1
  12. package/dist/Logging.d.ts.map +1 -1
  13. package/dist/PubSubManager/PubSubManager.d.ts +19 -11
  14. package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
  15. package/dist/PubSubManager/PubSubManager.js +35 -25
  16. package/dist/PubSubManager/PubSubManager.js.map +1 -1
  17. package/dist/PubSubManager/addSub.d.ts.map +1 -1
  18. package/dist/PubSubManager/addSub.js +6 -6
  19. package/dist/PubSubManager/addSub.js.map +1 -1
  20. package/dist/PubSubManager/addSync.js +1 -1
  21. package/dist/PubSubManager/addSync.js.map +1 -1
  22. package/dist/PubSubManager/init/getDataWatchFunctionQuery.d.ts.map +1 -1
  23. package/dist/PubSubManager/init/getDataWatchFunctionQuery.js +22 -1
  24. package/dist/PubSubManager/init/getDataWatchFunctionQuery.js.map +1 -1
  25. package/dist/PubSubManager/notifListener.js +3 -3
  26. package/dist/PubSubManager/notifListener.js.map +1 -1
  27. package/dist/PubSubManager/pushSubData.d.ts +1 -1
  28. package/dist/PubSubManager/pushSubData.d.ts.map +1 -1
  29. package/dist/PubSubManager/pushSubData.js +21 -42
  30. package/dist/PubSubManager/pushSubData.js.map +1 -1
  31. package/dist/PubSubManager/refreshTriggers.d.ts.map +1 -1
  32. package/dist/PubSubManager/refreshTriggers.js +6 -5
  33. package/dist/PubSubManager/refreshTriggers.js.map +1 -1
  34. package/dist/PublishParser/PublishParser.d.ts +3 -6
  35. package/dist/PublishParser/PublishParser.d.ts.map +1 -1
  36. package/dist/PublishParser/PublishParser.js +32 -42
  37. package/dist/PublishParser/PublishParser.js.map +1 -1
  38. package/dist/PublishParser/getSchemaFromPublish.js +11 -11
  39. package/dist/PublishParser/getSchemaFromPublish.js.map +1 -1
  40. package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts.map +1 -1
  41. package/dist/PublishParser/getTableRulesWithoutFileTable.js +2 -2
  42. package/dist/PublishParser/getTableRulesWithoutFileTable.js.map +1 -1
  43. package/dist/PublishParser/publishTypesAndUtils.d.ts +1 -0
  44. package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
  45. package/dist/SyncReplication.d.ts.map +1 -1
  46. package/dist/SyncReplication.js +1 -1
  47. package/dist/SyncReplication.js.map +1 -1
  48. package/dist/initProstgles.d.ts +2 -2
  49. package/dist/initProstgles.d.ts.map +1 -1
  50. package/dist/initProstgles.js +14 -1
  51. package/dist/initProstgles.js.map +1 -1
  52. package/dist/runClientRequest.d.ts.map +1 -1
  53. package/dist/runClientRequest.js +4 -3
  54. package/dist/runClientRequest.js.map +1 -1
  55. package/lib/DboBuilder/QueryStreamer.ts +1 -1
  56. package/lib/DboBuilder/ViewHandler/ViewHandler.ts +32 -30
  57. package/lib/DboBuilder/ViewHandler/subscribe.ts +22 -48
  58. package/lib/Logging.ts +3 -1
  59. package/lib/PubSubManager/PubSubManager.ts +50 -42
  60. package/lib/PubSubManager/addSub.ts +13 -8
  61. package/lib/PubSubManager/addSync.ts +1 -1
  62. package/lib/PubSubManager/init/getDataWatchFunctionQuery.ts +28 -1
  63. package/lib/PubSubManager/notifListener.ts +8 -8
  64. package/lib/PubSubManager/pushSubData.ts +20 -35
  65. package/lib/PubSubManager/refreshTriggers.ts +9 -8
  66. package/lib/PublishParser/PublishParser.ts +40 -52
  67. package/lib/PublishParser/getSchemaFromPublish.ts +21 -21
  68. package/lib/PublishParser/getTableRulesWithoutFileTable.ts +5 -6
  69. package/lib/PublishParser/publishTypesAndUtils.ts +1 -0
  70. package/lib/SyncReplication.ts +1 -0
  71. package/lib/initProstgles.ts +21 -3
  72. package/lib/runClientRequest.ts +6 -5
  73. package/package.json +3 -3
@@ -101,21 +101,21 @@ export async function notifListener(this: PubSubManager, data: { payload: string
101
101
  } else if (conditionIds?.every((id) => Number.isInteger(id))) {
102
102
  state = "ok";
103
103
  const firedTableConditions = tableTriggerConditions.filter(({ idx }) =>
104
- conditionIds.includes(idx)
104
+ conditionIds.includes(idx),
105
105
  );
106
106
  const orphanedTableConditions = conditionIds.filter((condId) => {
107
107
  const tc = tableTriggerConditions.at(condId);
108
108
  return !tc || (tc.subs.length === 0 && tc.syncs.length === 0);
109
109
  });
110
110
  if (orphanedTableConditions.length) {
111
- void this.deleteOrphanedTriggers.bind(this)(table_name);
111
+ void this.deleteOrphanedTriggers(new Set(table_name));
112
112
  }
113
113
 
114
114
  firedTableConditions.map(({ subs, syncs }) => {
115
115
  log(
116
116
  "notifListener",
117
117
  subs.map((s) => s.channel_name),
118
- syncs.map((s) => s.channel_name)
118
+ syncs.map((s) => s.channel_name),
119
119
  );
120
120
 
121
121
  syncs.map((s) => {
@@ -128,8 +128,8 @@ export async function notifListener(this: PubSubManager, data: { payload: string
128
128
  (trg) =>
129
129
  this.dbo[trg.table_name] &&
130
130
  sub.is_ready &&
131
- ((sub.socket_id && this.sockets[sub.socket_id]) || sub.localFuncs)
132
- )
131
+ ((sub.socket_id && this.sockets[sub.socket_id]) || sub.onData),
132
+ ),
133
133
  );
134
134
 
135
135
  activeAndReadySubs.forEach((sub) => {
@@ -143,7 +143,7 @@ export async function notifListener(this: PubSubManager, data: { payload: string
143
143
  tracked_columns
144
144
  ) {
145
145
  const subFieldsHaveChanged = changedColumns.some((changedColumn) =>
146
- tracked_columns.includes(changedColumn)
146
+ tracked_columns.includes(changedColumn),
147
147
  );
148
148
  if (!subFieldsHaveChanged) return;
149
149
  }
@@ -181,11 +181,11 @@ export async function notifListener(this: PubSubManager, data: { payload: string
181
181
  state,
182
182
  op_name,
183
183
  condition_ids_str,
184
- tableTriggers: this._triggers[table_name],
184
+ tableTriggers: this._triggers.get(table_name),
185
185
  tableSyncs: JSON.stringify(
186
186
  this.syncs
187
187
  .filter((s) => s.table_name === table_name)
188
- .map((s) => pickKeys(s, ["condition", "socket_id"]))
188
+ .map((s) => pickKeys(s, ["condition", "socket_id"])),
189
189
  ),
190
190
  connectedSocketIds: this.connectedSocketIds,
191
191
  });
@@ -1,12 +1,10 @@
1
- import { getSerialisableError } from "prostgles-types";
2
- import { parseLocalFuncs } from "../DboBuilder/ViewHandler/subscribe";
3
1
  import type { EventTypes } from "../Logging";
4
2
  import type { Subscription } from "./PubSubManager";
5
3
  import { type PubSubManager } from "./PubSubManager";
6
4
  import { log } from "./PubSubManagerUtils";
7
5
 
8
6
  export async function pushSubData(this: PubSubManager, sub: Subscription, err?: any) {
9
- const { socket_id, channel_name } = sub;
7
+ const { socket_id, channel_name, onData } = sub;
10
8
 
11
9
  const onLog = (
12
10
  state: Extract<EventTypes.SyncOrSub, { type: "syncOrSub"; command: "pushSubData" }>["state"],
@@ -28,7 +26,6 @@ export async function pushSubData(this: PubSubManager, sub: Subscription, err?:
28
26
  onLog("sub_not_found");
29
27
  return;
30
28
  }
31
- const localFuncs = parseLocalFuncs(sub.localFuncs);
32
29
 
33
30
  if (err) {
34
31
  onLog("error");
@@ -39,40 +36,28 @@ export async function pushSubData(this: PubSubManager, sub: Subscription, err?:
39
36
  }
40
37
 
41
38
  sub.lastPushed = Date.now();
42
- return new Promise(async (resolve, reject) => {
43
- /* TODO: Retire subOne -> it's redundant */
44
39
 
45
- const { data, err } = await this.getSubData(sub);
40
+ const { data, err: subDataError } = await this.getSubData(sub);
46
41
 
47
- if (data) {
48
- if (socket_id && this.sockets[socket_id]) {
49
- log("Pushed " + data.length + " records to sub");
50
- onLog("Emiting to socket");
51
- this.sockets[socket_id].emit(channel_name, { data }, () => {
52
- resolve(data);
53
- });
42
+ if (subDataError !== undefined) {
43
+ onLog("fetch data error");
44
+ }
45
+ if (socket_id && this.sockets[socket_id]) {
46
+ log(`Pushing ${data?.length ?? 0} rows to socket`);
47
+ onLog("Emiting to socket");
48
+ this.sockets[socket_id].emit(
49
+ channel_name,
50
+ subDataError !== undefined ? { err: subDataError } : { data },
51
+ () => {
54
52
  /* TO DO: confirm receiving data or server will unsubscribe
55
53
  { data }, (cb)=> { console.log(cb) });
56
54
  */
57
- } else if (localFuncs) {
58
- onLog("pushed to local client");
59
- localFuncs.onData(data);
60
- resolve(data);
61
- } else {
62
- onLog("no client to push data to");
63
- }
64
- } else {
65
- onLog("fetch data error");
66
- const errObj = getSerialisableError(err) || "Unknown error fetching subscription data";
67
- if (socket_id && this.sockets[socket_id]) {
68
- this.sockets[socket_id].emit(channel_name, { err: errObj });
69
- } else if (localFuncs) {
70
- if (!localFuncs.onError) {
71
- console.error("Uncaught subscription error", err);
72
- }
73
- localFuncs.onError?.(errObj);
74
- }
75
- reject(errObj);
76
- }
77
- });
55
+ },
56
+ );
57
+ } else if (onData) {
58
+ onLog("pushed to local client");
59
+ onData(data ?? [], subDataError);
60
+ } else {
61
+ onLog("no client to push data to");
62
+ }
78
63
  }
@@ -2,27 +2,28 @@ import type { PubSubManager } from "./PubSubManager";
2
2
 
3
3
  export async function refreshTriggers(this: PubSubManager) {
4
4
  const start = Date.now();
5
- const triggers: {
5
+ const triggers = await this.db.any<{
6
6
  table_name: string;
7
7
  condition: string;
8
8
  condition_hash: string;
9
- }[] = await this.db.any(
9
+ }>(
10
10
  `
11
11
  SELECT *
12
12
  FROM prostgles.v_triggers
13
13
  WHERE app_id = $1
14
14
  ORDER BY table_name, condition
15
15
  `,
16
- [this.dboBuilder.prostgles.appId]
16
+ [this.dboBuilder.prostgles.appId],
17
17
  );
18
18
 
19
- const oldTriggers = { ...this._triggers };
19
+ const oldTriggers = new Map(this._triggers);
20
20
 
21
- this._triggers = {};
21
+ this._triggers = new Map();
22
22
  triggers.map((t) => {
23
- this._triggers[t.table_name] ??= [];
24
- if (!this._triggers[t.table_name]?.map((t) => t.condition).includes(t.condition)) {
25
- this._triggers[t.table_name]?.push({ condition: t.condition, hash: t.condition_hash });
23
+ this._triggers.set(t.table_name, this._triggers.get(t.table_name) ?? []);
24
+ const tableTriggers = this._triggers.get(t.table_name)!;
25
+ if (!tableTriggers.map((t) => t.condition).includes(t.condition)) {
26
+ tableTriggers.push({ condition: t.condition, hash: t.condition_hash });
26
27
  }
27
28
  });
28
29
 
@@ -1,10 +1,10 @@
1
- import { isObject } from "prostgles-types";
2
1
  import { getClientRequestIPsInfo } from "../Auth/AuthHandler";
3
2
  import type { AuthClientRequest, AuthResultWithSID } from "../Auth/AuthTypes";
4
3
  import type { DBOFullyTyped } from "../DBSchemaBuilder/DBSchemaBuilder";
5
4
  import type { DB, DBHandlerServer, Prostgles } from "../Prostgles";
6
5
  import type { ProstglesInitOptions } from "../ProstglesTypes";
7
6
  import { getClientHandlers } from "../WebsocketAPI/getClientHandlers";
7
+ import type { ServerFunctionDefinition } from "./defineServerFunction";
8
8
  import { getFileTableRules } from "./getFileTableRules";
9
9
  import { getSchemaFromPublish } from "./getSchemaFromPublish";
10
10
  import { getTableRulesWithoutFileTable } from "./getTableRulesWithoutFileTable";
@@ -20,7 +20,6 @@ import {
20
20
  type PermissionScope,
21
21
  type PublishObject,
22
22
  } from "./publishTypesAndUtils";
23
- import type { ServerFunctionDefinition } from "./defineServerFunction";
24
23
 
25
24
  export class PublishParser {
26
25
  publish: ProstglesInitOptions["publish"];
@@ -63,31 +62,20 @@ export class PublishParser {
63
62
  };
64
63
  }
65
64
 
66
- getFunctionHandler = async (
67
- params: PublishParams,
68
- ): Promise<{ [key: string]: ServerFunctionDefinition } | undefined> => {
69
- try {
70
- const prostgles = this.prostgles;
71
- return await prostgles.opts.functions?.(params);
72
- } catch (e) {
73
- console.error("Invalid functions:", e);
74
- throw e;
75
- }
76
- };
77
65
  async getAllowedFunctions(clientReq: AuthClientRequest, userData: AuthResultWithSID | undefined) {
78
66
  const publishParams = await this.getPublishParams(clientReq, userData);
79
- const functionHandler = await this.getFunctionHandler(publishParams);
80
- if (!functionHandler) {
67
+ const allowedFunctions = await this.prostgles.opts.functions?.(publishParams);
68
+ if (!allowedFunctions) {
81
69
  return;
82
70
  }
83
- const methods: Map<string, ServerFunctionDefinition> = new Map();
71
+ const allowedFunctionsMap: Map<string, ServerFunctionDefinition> = new Map();
84
72
 
85
- for (const [name, method] of Object.entries(functionHandler)) {
73
+ for (const [name, method] of Object.entries(allowedFunctions)) {
86
74
  if (method.run !== undefined) {
87
- methods.set(name, method);
75
+ allowedFunctionsMap.set(name, method);
88
76
  }
89
77
  }
90
- return methods;
78
+ return allowedFunctionsMap;
91
79
  }
92
80
 
93
81
  /**
@@ -116,37 +104,21 @@ export class PublishParser {
116
104
  command,
117
105
  clientReq,
118
106
  }: DboTableCommand): Promise<ParsedTableRule> {
107
+ const rules = await this.getParsedTableRule({ tableName, clientReq }, undefined);
119
108
  const clientInfo =
120
109
  clientReq && (await this.prostgles.authHandler.getSidAndUserFromRequest(clientReq));
121
110
  if (clientInfo === "new-session-redirect") {
122
111
  throw "new-session-redirect";
123
112
  }
124
- const rules = await this.getValidatedRequestRule(
125
- { tableName, command, clientReq },
126
- clientInfo,
127
- undefined,
128
- );
113
+ this.validateRequestRule({ tableName, command, clientReq }, rules, undefined);
129
114
  return rules;
130
115
  }
131
116
 
132
- async getValidatedRequestRule(
133
- { tableName, command, clientReq }: DboTableCommand,
117
+ async getParsedTableRule(
118
+ { tableName, clientReq }: Pick<DboTableCommand, "tableName" | "clientReq">,
134
119
  clientInfo: AuthResultWithSID | undefined,
135
- scope: PermissionScope | undefined,
136
120
  ): Promise<ParsedTableRule> {
137
- if (!command || !tableName) throw "command OR tableName are missing";
138
-
139
- const rule = RULE_TO_METHODS.find((rtms) => rtms.methods.some((v) => v === command));
140
- if (!rule) {
141
- throw "Invalid command: " + command;
142
- }
143
-
144
- if (scope) {
145
- const tableScope = scope.tables;
146
- if (!tableScope?.[tableName] || !tableScope[tableName][rule.sqlRule]) {
147
- throw `Invalid or disallowed command: ${tableName}.${command}. The PermissionsScope does not allow this command.`;
148
- }
149
- }
121
+ if (!tableName) throw "tableName missing";
150
122
 
151
123
  /* Must be local request -> allow everything */
152
124
  if (!clientReq) {
@@ -162,17 +134,41 @@ export class PublishParser {
162
134
  /* Must be from socket. Must have a publish */
163
135
  if (!this.publish) throw "publish is missing";
164
136
 
137
+ const tableErrors = clientReq.socket?.prostgles?.tableSchemaErrors[tableName];
165
138
  /* Get any publish errors for socket */
166
- const errorInfo = clientReq.socket?.prostgles?.tableSchemaErrors[tableName]?.[command];
167
-
168
- if (errorInfo) throw errorInfo.error;
139
+ Object.values(tableErrors ?? {}).forEach((errorInfo) => {
140
+ throw errorInfo.error;
141
+ });
169
142
 
170
143
  const tableRule = await this.getTableRules({ tableName, clientReq }, clientInfo);
171
- if (!tableRule)
144
+
145
+ if (!tableRule) {
172
146
  throw {
173
147
  stack: ["getValidatedRequestRule()"],
174
148
  message: "Invalid or disallowed table: " + tableName,
175
149
  };
150
+ }
151
+ return tableRule;
152
+ }
153
+
154
+ validateRequestRule(
155
+ { tableName, command }: DboTableCommand,
156
+ tableRule: ParsedTableRule,
157
+ scope: PermissionScope | undefined,
158
+ ) {
159
+ if (!command || !tableName) throw "command OR tableName are missing";
160
+
161
+ const rule = RULE_TO_METHODS.find((rtms) => rtms.methods.some((v) => v === command));
162
+ if (!rule) {
163
+ throw "Invalid command: " + command;
164
+ }
165
+
166
+ if (scope) {
167
+ const tableScope = scope.tables;
168
+ if (!tableScope?.[tableName] || !tableScope[tableName][rule.sqlRule]) {
169
+ throw `Invalid or disallowed command: ${tableName}.${command}. The PermissionsScope does not allow this command.`;
170
+ }
171
+ }
176
172
 
177
173
  if (command === "upsert") {
178
174
  if (!tableRule.update || !tableRule.insert) {
@@ -189,8 +185,6 @@ export class PublishParser {
189
185
  message: `Invalid or disallowed command: ${tableName}.${command}`,
190
186
  };
191
187
  }
192
-
193
- return tableRule;
194
188
  }
195
189
 
196
190
  async getTableRules(
@@ -236,9 +230,3 @@ function applyParamsIfFunc<T>(
236
230
  //@ts-ignore
237
231
  return maybeFunc;
238
232
  }
239
-
240
- export const getV2Methods = (functions: ProstglesInitOptions["functions"]) => {
241
- if (typeof functions !== "function" && isObject(functions)) {
242
- return functions;
243
- }
244
- };
@@ -20,7 +20,7 @@ const SUBSCRIBE_METHODS = ["subscribe", "subscribeOne", "sync", "unsubscribe", "
20
20
  export async function getSchemaFromPublish(
21
21
  this: PublishParser,
22
22
  { userData, ...clientReq }: Args,
23
- scope: PermissionScope | undefined
23
+ scope: PermissionScope | undefined,
24
24
  ): Promise<{
25
25
  schema: TableSchemaForClient;
26
26
  tables: DBSchemaTable[];
@@ -60,7 +60,7 @@ export async function getSchemaFromPublish(
60
60
  !tableNames.includes(fileTableName)
61
61
  ) {
62
62
  const isReferenced = this.prostgles.dboBuilder.tablesOrViews?.some((t) =>
63
- t.columns.some((c) => c.references?.some((r) => r.ftable === fileTableName))
63
+ t.columns.some((c) => c.references?.some((r) => r.ftable === fileTableName)),
64
64
  );
65
65
  if (isReferenced) {
66
66
  tableNames.unshift(fileTableName);
@@ -77,17 +77,17 @@ export async function getSchemaFromPublish(
77
77
  throw errMsg;
78
78
  }
79
79
 
80
- const tableRules = await this.getTableRules({ clientReq, tableName }, clientInfo);
80
+ const parsedTableRule = await this.getTableRules({ clientReq, tableName }, clientInfo);
81
81
 
82
- if (!tableRules || isEmpty(tableRules)) return;
83
- if (!isObject(tableRules)) {
82
+ if (!parsedTableRule || isEmpty(parsedTableRule)) return;
83
+ if (!isObject(parsedTableRule)) {
84
84
  throw `Invalid tableRules for table ${tableName}. Expecting an object`;
85
85
  }
86
86
 
87
87
  schema[tableName] = {};
88
88
  const tableSchema = schema[tableName];
89
- const methods = getKeys(tableRules).filter(
90
- (m) => canSubscribe || !includes(SUBSCRIBE_METHODS, m)
89
+ const methods = getKeys(parsedTableRule).filter(
90
+ (m) => canSubscribe || !includes(SUBSCRIBE_METHODS, m),
91
91
  );
92
92
  let tableInfo: TableInfo | undefined;
93
93
  let tableColumns: DBSchemaTable["columns"] | undefined;
@@ -98,25 +98,25 @@ export async function getSchemaFromPublish(
98
98
  .map(async (method) => {
99
99
  if (method === "sync") {
100
100
  /* Pass sync info */
101
- tableSchema[method] = tableRules[method];
102
- } else if (includes(getKeys(tableRules), method) && tableRules[method]) {
101
+ tableSchema[method] = parsedTableRule[method];
102
+ } else if (includes(getKeys(parsedTableRule), method) && parsedTableRule[method]) {
103
103
  //@ts-ignore
104
104
  tableSchema[method] =
105
105
  method === "insert" ?
106
- pickKeys(tableRules[method], ["allowedNestedInserts"])
106
+ pickKeys(parsedTableRule[method], ["allowedNestedInserts"])
107
107
  : ({} as AnyObject);
108
108
 
109
109
  /* Test for issues with the common table CRUD methods () */
110
110
  if (includes(TABLE_METHODS, method)) {
111
111
  try {
112
- const parsedTableRule = await this.getValidatedRequestRule(
112
+ this.validateRequestRule(
113
113
  {
114
114
  tableName,
115
115
  command: method,
116
116
  clientReq,
117
117
  },
118
- clientInfo,
119
- scope
118
+ parsedTableRule,
119
+ scope,
120
120
  );
121
121
  if (this.prostgles.opts.testRulesOnConnect) {
122
122
  await (this.dbo[tableName] as TableHandler)[method](
@@ -128,7 +128,7 @@ export async function getSchemaFromPublish(
128
128
  ...clientReq,
129
129
  isRemoteRequest: {},
130
130
  testRule: true,
131
- }
131
+ },
132
132
  );
133
133
  }
134
134
  } catch (e) {
@@ -146,17 +146,17 @@ export async function getSchemaFromPublish(
146
146
  }
147
147
 
148
148
  if (method === "getInfo" || method === "getColumns") {
149
- const tableRules = await this.getValidatedRequestRule(
149
+ this.validateRequestRule(
150
150
  { tableName, command: method, clientReq },
151
- clientInfo,
152
- scope
151
+ parsedTableRule,
152
+ scope,
153
153
  );
154
154
  const res = await (this.dbo[tableName] as TableHandler)[method](
155
155
  undefined,
156
156
  undefined,
157
157
  undefined,
158
- tableRules,
159
- { ...clientReq, isRemoteRequest: {} }
158
+ parsedTableRule,
159
+ { ...clientReq, isRemoteRequest: {} },
160
160
  );
161
161
  if (method === "getInfo") {
162
162
  tableInfo = res as TableInfo;
@@ -165,7 +165,7 @@ export async function getSchemaFromPublish(
165
165
  }
166
166
  }
167
167
  }
168
- })
168
+ }),
169
169
  );
170
170
 
171
171
  if (tableInfo && tableColumns) {
@@ -175,7 +175,7 @@ export async function getSchemaFromPublish(
175
175
  columns: tableColumns,
176
176
  });
177
177
  }
178
- })
178
+ }),
179
179
  );
180
180
  }
181
181
  } catch (error) {
@@ -9,7 +9,6 @@ import type {
9
9
  ParsedPublishTable,
10
10
  PublishTableRule,
11
11
  PublishViewRule,
12
- SubscribeRule,
13
12
  } from "./publishTypesAndUtils";
14
13
  import { type PublishObject, RULE_TO_METHODS } from "./publishTypesAndUtils";
15
14
 
@@ -17,7 +16,7 @@ export async function getTableRulesWithoutFileTable(
17
16
  this: PublishParser,
18
17
  { tableName, clientReq }: DboTable,
19
18
  clientInfo: AuthResultWithSID | undefined,
20
- overridenPublish?: PublishObject
19
+ overridenPublish?: PublishObject,
21
20
  ): Promise<ParsedPublishTable | undefined> {
22
21
  if (!tableName) throw new Error("tableName is missing in getTableRules");
23
22
 
@@ -111,7 +110,7 @@ export async function getTableRulesWithoutFileTable(
111
110
  const rule = parsedTableRule[method];
112
111
 
113
112
  const ruleInfo = MY_RULES.find(
114
- (r) => r.rule === method || (r.methods as readonly string[]).includes(method)
113
+ (r) => r.rule === method || (r.methods as readonly string[]).includes(method),
115
114
  );
116
115
  if (!ruleInfo) {
117
116
  let extraInfo = "";
@@ -120,7 +119,7 @@ export async function getTableRulesWithoutFileTable(
120
119
  RULE_TO_METHODS.find(
121
120
  (r) =>
122
121
  r.table_only &&
123
- (r.rule === method || (r.methods as readonly string[]).includes(method))
122
+ (r.rule === method || (r.methods as readonly string[]).includes(method)),
124
123
  )
125
124
  ) {
126
125
  extraInfo = "You've specified table rules to a view\n";
@@ -159,8 +158,8 @@ export async function getTableRulesWithoutFileTable(
159
158
  if (method === "select" && !dissallowedRuleKeys.includes(subKey)) {
160
159
  const sr = MY_RULES.find((r) => r.rule === subKey);
161
160
  if (sr && canSubscribe) {
162
- parsedTableRule[subKey] = { ...(sr.no_limits) };
163
- parsedTableRule.subscribeOne = { ...(sr.no_limits) };
161
+ parsedTableRule[subKey] = { ...sr.no_limits };
162
+ parsedTableRule.subscribeOne = { ...sr.no_limits };
164
163
  }
165
164
  }
166
165
  });
@@ -505,6 +505,7 @@ export type DbTableInfo = {
505
505
  };
506
506
  export type PermissionScope = {
507
507
  sql?: "commited" | "rolledback";
508
+ /** TODO: this should match publish types */
508
509
  tables?: Record<string, Partial<Record<"select" | "update" | "delete" | "insert", boolean>>>;
509
510
  methods?: Record<string, boolean>;
510
511
  };
@@ -115,6 +115,7 @@ export async function syncData(
115
115
  { orderBy: orderByAsc, select: sync_fields, limit, offset },
116
116
  undefined,
117
117
  table_rules,
118
+ { clientReq: { socket } },
118
119
  );
119
120
  const last_rows = first_rows.slice(-1); // Why not logic below?
120
121
  // const last_rows = await _this?.dbo[table_name]?.find?.(_filter, { orderBy: (orderByDesc as OrderBy), select: sync_fields, limit: 1, offset: -offset || 0 }, null, table_rules);
@@ -74,11 +74,11 @@ export type OnReadyParams<S> = OnReadyParamsCommon & {
74
74
  export type OnReadyCallback<S, SUser extends SessionUser> = (
75
75
  params: OnReadyParams<S>,
76
76
  update: (newOpts: UpdateableOptions<S, SUser>, force?: true) => Promise<void>,
77
- ) => any;
77
+ ) => void | Promise<void>;
78
78
  export type OnReadyCallbackBasic = (
79
79
  params: OnReadyParamsBasic,
80
80
  update: (newOpts: UpdateableOptions<void, SessionUser>, force?: true) => Promise<void>,
81
- ) => any;
81
+ ) => void | Promise<void>;
82
82
 
83
83
  export type InitResult<S = void, SUser extends SessionUser = SessionUser> = {
84
84
  db: DBOFullyTyped<S>;
@@ -155,6 +155,24 @@ export const initProstgles = async function (
155
155
  }
156
156
  },
157
157
  });
158
+
159
+ /** Drop stale triggers */
160
+ await db
161
+ .any(
162
+ `
163
+ WITH active_app_ids AS (
164
+ SELECT DISTINCT (string_to_array(application_name, ' '))[2] AS app_id
165
+ FROM pg_stat_activity
166
+ WHERE application_name LIKE 'prostgles %'
167
+ )
168
+ DELETE FROM prostgles.app_triggers
169
+ WHERE app_id NOT IN (SELECT app_id FROM active_app_ids)
170
+ AND app_id != $1
171
+ `,
172
+ [this.appId],
173
+ )
174
+ .catch(() => {});
175
+
158
176
  this.db = db;
159
177
  this.pgp = pgp;
160
178
  this.isSuperUser = await getIsSuperUser(db);
@@ -200,7 +218,7 @@ export const initProstgles = async function (
200
218
  if (this.destroyed) {
201
219
  console.trace("Prostgles: Instance is destroyed");
202
220
  }
203
- onReady(
221
+ void onReady(
204
222
  {
205
223
  sql: this.dboBuilder.sql,
206
224
  dbo: this.dbo!,
@@ -101,14 +101,15 @@ export const runClientRequest = async function (
101
101
  if (clientInfo === "new-session-redirect") {
102
102
  throw clientInfo;
103
103
  }
104
- const validRules = await this.publishParser.getValidatedRequestRule(
105
- { tableName, command, clientReq },
104
+
105
+ const parsedTableRule = await this.publishParser.getParsedTableRule(
106
+ { tableName, clientReq },
106
107
  clientInfo,
107
- scope,
108
108
  );
109
+ this.publishParser.validateRequestRule({ tableName, command, clientReq }, parsedTableRule, scope);
109
110
 
110
111
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
111
- if (!validRules) {
112
+ if (!parsedTableRule) {
112
113
  throw `Invalid OR disallowed request: ${tableName}.${command} `;
113
114
  }
114
115
 
@@ -150,7 +151,7 @@ export const runClientRequest = async function (
150
151
  param1,
151
152
  param2,
152
153
  param3,
153
- validRules,
154
+ parsedTableRule,
154
155
  localParams,
155
156
  ) as AnyObject | undefined;
156
157
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prostgles-server",
3
- "version": "4.2.439",
3
+ "version": "4.2.441",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,7 +38,7 @@
38
38
  ],
39
39
  "homepage": "https://prostgles.com",
40
40
  "dependencies": {
41
- "@aws-sdk/client-ses": "^3.980.0",
41
+ "@aws-sdk/client-ses": "^3.985.0",
42
42
  "@aws-sdk/credential-provider-node": "^3.972.4",
43
43
  "@types/passport": "^1.0.17",
44
44
  "@types/passport-facebook": "^3.0.3",
@@ -57,7 +57,7 @@
57
57
  "pg": "^8.15.6",
58
58
  "pg-cursor": "^2.17.0",
59
59
  "pg-promise": "^12.6.0",
60
- "prostgles-types": "^4.0.207"
60
+ "prostgles-types": "^4.0.209"
61
61
  },
62
62
  "devDependencies": {
63
63
  "@eslint/js": "^9.22.0",