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.
- package/dist/DboBuilder/QueryStreamer.js +1 -1
- package/dist/DboBuilder/QueryStreamer.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts +6 -6
- package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/ViewHandler.js +6 -8
- package/dist/DboBuilder/ViewHandler/ViewHandler.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/subscribe.d.ts +4 -12
- package/dist/DboBuilder/ViewHandler/subscribe.d.ts.map +1 -1
- package/dist/DboBuilder/ViewHandler/subscribe.js +11 -25
- package/dist/DboBuilder/ViewHandler/subscribe.js.map +1 -1
- package/dist/Logging.d.ts +2 -1
- package/dist/Logging.d.ts.map +1 -1
- package/dist/PubSubManager/PubSubManager.d.ts +19 -11
- package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager/PubSubManager.js +35 -25
- package/dist/PubSubManager/PubSubManager.js.map +1 -1
- package/dist/PubSubManager/addSub.d.ts.map +1 -1
- package/dist/PubSubManager/addSub.js +6 -6
- package/dist/PubSubManager/addSub.js.map +1 -1
- package/dist/PubSubManager/addSync.js +1 -1
- package/dist/PubSubManager/addSync.js.map +1 -1
- package/dist/PubSubManager/init/getDataWatchFunctionQuery.d.ts.map +1 -1
- package/dist/PubSubManager/init/getDataWatchFunctionQuery.js +22 -1
- package/dist/PubSubManager/init/getDataWatchFunctionQuery.js.map +1 -1
- package/dist/PubSubManager/notifListener.js +3 -3
- package/dist/PubSubManager/notifListener.js.map +1 -1
- package/dist/PubSubManager/pushSubData.d.ts +1 -1
- package/dist/PubSubManager/pushSubData.d.ts.map +1 -1
- package/dist/PubSubManager/pushSubData.js +21 -42
- package/dist/PubSubManager/pushSubData.js.map +1 -1
- package/dist/PubSubManager/refreshTriggers.d.ts.map +1 -1
- package/dist/PubSubManager/refreshTriggers.js +6 -5
- package/dist/PubSubManager/refreshTriggers.js.map +1 -1
- package/dist/PublishParser/PublishParser.d.ts +3 -6
- package/dist/PublishParser/PublishParser.d.ts.map +1 -1
- package/dist/PublishParser/PublishParser.js +32 -42
- package/dist/PublishParser/PublishParser.js.map +1 -1
- package/dist/PublishParser/getSchemaFromPublish.js +11 -11
- package/dist/PublishParser/getSchemaFromPublish.js.map +1 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts.map +1 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.js +2 -2
- package/dist/PublishParser/getTableRulesWithoutFileTable.js.map +1 -1
- package/dist/PublishParser/publishTypesAndUtils.d.ts +1 -0
- package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
- package/dist/SyncReplication.d.ts.map +1 -1
- package/dist/SyncReplication.js +1 -1
- package/dist/SyncReplication.js.map +1 -1
- package/dist/initProstgles.d.ts +2 -2
- package/dist/initProstgles.d.ts.map +1 -1
- package/dist/initProstgles.js +14 -1
- package/dist/initProstgles.js.map +1 -1
- package/dist/runClientRequest.d.ts.map +1 -1
- package/dist/runClientRequest.js +4 -3
- package/dist/runClientRequest.js.map +1 -1
- package/lib/DboBuilder/QueryStreamer.ts +1 -1
- package/lib/DboBuilder/ViewHandler/ViewHandler.ts +32 -30
- package/lib/DboBuilder/ViewHandler/subscribe.ts +22 -48
- package/lib/Logging.ts +3 -1
- package/lib/PubSubManager/PubSubManager.ts +50 -42
- package/lib/PubSubManager/addSub.ts +13 -8
- package/lib/PubSubManager/addSync.ts +1 -1
- package/lib/PubSubManager/init/getDataWatchFunctionQuery.ts +28 -1
- package/lib/PubSubManager/notifListener.ts +8 -8
- package/lib/PubSubManager/pushSubData.ts +20 -35
- package/lib/PubSubManager/refreshTriggers.ts +9 -8
- package/lib/PublishParser/PublishParser.ts +40 -52
- package/lib/PublishParser/getSchemaFromPublish.ts +21 -21
- package/lib/PublishParser/getTableRulesWithoutFileTable.ts +5 -6
- package/lib/PublishParser/publishTypesAndUtils.ts +1 -0
- package/lib/SyncReplication.ts +1 -0
- package/lib/initProstgles.ts +21 -3
- package/lib/runClientRequest.ts +6 -5
- 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
|
|
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.
|
|
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
|
|
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
|
-
|
|
40
|
+
const { data, err: subDataError } = await this.getSubData(sub);
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
}
|
|
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 =
|
|
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
|
|
24
|
-
|
|
25
|
-
|
|
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
|
|
80
|
-
if (!
|
|
67
|
+
const allowedFunctions = await this.prostgles.opts.functions?.(publishParams);
|
|
68
|
+
if (!allowedFunctions) {
|
|
81
69
|
return;
|
|
82
70
|
}
|
|
83
|
-
const
|
|
71
|
+
const allowedFunctionsMap: Map<string, ServerFunctionDefinition> = new Map();
|
|
84
72
|
|
|
85
|
-
for (const [name, method] of Object.entries(
|
|
73
|
+
for (const [name, method] of Object.entries(allowedFunctions)) {
|
|
86
74
|
if (method.run !== undefined) {
|
|
87
|
-
|
|
75
|
+
allowedFunctionsMap.set(name, method);
|
|
88
76
|
}
|
|
89
77
|
}
|
|
90
|
-
return
|
|
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
|
-
|
|
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
|
|
133
|
-
{ tableName,
|
|
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 (!
|
|
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
|
-
|
|
167
|
-
|
|
168
|
-
|
|
139
|
+
Object.values(tableErrors ?? {}).forEach((errorInfo) => {
|
|
140
|
+
throw errorInfo.error;
|
|
141
|
+
});
|
|
169
142
|
|
|
170
143
|
const tableRule = await this.getTableRules({ tableName, clientReq }, clientInfo);
|
|
171
|
-
|
|
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
|
|
80
|
+
const parsedTableRule = await this.getTableRules({ clientReq, tableName }, clientInfo);
|
|
81
81
|
|
|
82
|
-
if (!
|
|
83
|
-
if (!isObject(
|
|
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(
|
|
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] =
|
|
102
|
-
} else if (includes(getKeys(
|
|
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(
|
|
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
|
-
|
|
112
|
+
this.validateRequestRule(
|
|
113
113
|
{
|
|
114
114
|
tableName,
|
|
115
115
|
command: method,
|
|
116
116
|
clientReq,
|
|
117
117
|
},
|
|
118
|
-
|
|
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
|
-
|
|
149
|
+
this.validateRequestRule(
|
|
150
150
|
{ tableName, command: method, clientReq },
|
|
151
|
-
|
|
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
|
-
|
|
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] = { ...
|
|
163
|
-
parsedTableRule.subscribeOne = { ...
|
|
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
|
};
|
package/lib/SyncReplication.ts
CHANGED
|
@@ -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);
|
package/lib/initProstgles.ts
CHANGED
|
@@ -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
|
-
) =>
|
|
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
|
-
) =>
|
|
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!,
|
package/lib/runClientRequest.ts
CHANGED
|
@@ -101,14 +101,15 @@ export const runClientRequest = async function (
|
|
|
101
101
|
if (clientInfo === "new-session-redirect") {
|
|
102
102
|
throw clientInfo;
|
|
103
103
|
}
|
|
104
|
-
|
|
105
|
-
|
|
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 (!
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
60
|
+
"prostgles-types": "^4.0.209"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@eslint/js": "^9.22.0",
|