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.
- package/debug/client-schema-types/DBGeneratedSchema.ts +13 -1
- package/dist/DBSchemaBuilder/constants.d.ts +6 -1
- package/dist/DBSchemaBuilder/constants.d.ts.map +1 -1
- package/dist/DBSchemaBuilder/constants.js +7 -2
- package/dist/DBSchemaBuilder/constants.js.map +1 -1
- package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.d.ts.map +1 -1
- package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.js +4 -9
- package/dist/DBSchemaBuilder/getClientDBGeneratedSchemas.js.map +1 -1
- package/dist/DBSchemaBuilder/getDBGeneratedSchema.d.ts.map +1 -1
- package/dist/DBSchemaBuilder/getDBGeneratedSchema.js +20 -8
- package/dist/DBSchemaBuilder/getDBGeneratedSchema.js.map +1 -1
- package/dist/DboBuilder/DboBuilder.js +1 -1
- package/dist/DboBuilder/DboBuilder.js.map +1 -1
- package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts +2 -2
- package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts.map +1 -1
- package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.d.ts +1 -1
- package/dist/Filtering/Filtering.d.ts +1 -1
- package/dist/Prostgles.js +1 -1
- package/dist/Prostgles.js.map +1 -1
- package/dist/PubSubManager/PubSubManager.d.ts +1 -1
- package/dist/PublishParser/PublishParser.d.ts +17 -8
- package/dist/PublishParser/PublishParser.d.ts.map +1 -1
- package/dist/PublishParser/PublishParser.js +48 -28
- package/dist/PublishParser/PublishParser.js.map +1 -1
- package/dist/PublishParser/getFileTableRules.d.ts +1 -1
- package/dist/PublishParser/getFileTableRules.d.ts.map +1 -1
- package/dist/PublishParser/getFileTableRules.js +52 -41
- package/dist/PublishParser/getFileTableRules.js.map +1 -1
- package/dist/PublishParser/getParsedPublishTable.d.ts +4 -0
- package/dist/PublishParser/getParsedPublishTable.d.ts.map +1 -0
- package/dist/PublishParser/{getTableRulesWithoutFileTable.js → getParsedPublishTable.js} +13 -7
- package/dist/PublishParser/getParsedPublishTable.js.map +1 -0
- package/dist/PublishParser/getPublishSchemas.d.ts +4 -0
- package/dist/PublishParser/getPublishSchemas.d.ts.map +1 -0
- package/dist/PublishParser/getPublishSchemas.js +42 -0
- package/dist/PublishParser/getPublishSchemas.js.map +1 -0
- package/dist/PublishParser/getPublishedObjectFromResult.d.ts +4 -0
- package/dist/PublishParser/getPublishedObjectFromResult.d.ts.map +1 -0
- package/dist/PublishParser/getPublishedObjectFromResult.js +77 -0
- package/dist/PublishParser/getPublishedObjectFromResult.js.map +1 -0
- package/dist/PublishParser/getPublishedTableNames.d.ts.map +1 -1
- package/dist/PublishParser/getPublishedTableNames.js +4 -1
- package/dist/PublishParser/getPublishedTableNames.js.map +1 -1
- package/dist/PublishParser/getSchemaFromPublish.d.ts.map +1 -1
- package/dist/PublishParser/getSchemaFromPublish.js +11 -5
- package/dist/PublishParser/getSchemaFromPublish.js.map +1 -1
- package/dist/PublishParser/publishTypesAndUtils.d.ts +28 -3
- package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
- package/dist/PublishParser/publishTypesAndUtils.js +6 -1
- package/dist/PublishParser/publishTypesAndUtils.js.map +1 -1
- package/dist/PublishParser/validatePublishProfiles.d.ts +2 -2
- package/dist/PublishParser/validatePublishProfiles.d.ts.map +1 -1
- package/dist/PublishParser/validatePublishProfiles.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runClientRequest.d.ts.map +1 -1
- package/dist/runClientRequest.js +6 -1
- package/dist/runClientRequest.js.map +1 -1
- package/lib/DBSchemaBuilder/constants.ts +6 -1
- package/lib/DBSchemaBuilder/getClientDBGeneratedSchemas.ts +7 -10
- package/lib/DBSchemaBuilder/getDBGeneratedSchema.ts +20 -8
- package/lib/DboBuilder/DboBuilder.ts +1 -1
- package/lib/Prostgles.ts +2 -2
- package/lib/PublishParser/PublishParser.ts +82 -50
- package/lib/PublishParser/getFileTableRules.ts +52 -45
- package/lib/PublishParser/{getTableRulesWithoutFileTable.ts → getParsedPublishTable.ts} +16 -12
- package/lib/PublishParser/getPublishSchemas.ts +49 -0
- package/lib/PublishParser/getPublishedObjectFromResult.ts +104 -0
- package/lib/PublishParser/getPublishedTableNames.ts +6 -1
- package/lib/PublishParser/getSchemaFromPublish.ts +9 -7
- package/lib/PublishParser/publishTypesAndUtils.ts +31 -6
- package/lib/PublishParser/validatePublishProfiles.ts +1 -1
- package/lib/index.ts +13 -1
- package/lib/runClientRequest.ts +4 -3
- package/package.json +1 -1
- package/dist/DBSchemaBuilder/getPublishSchemas.d.ts +0 -4
- package/dist/DBSchemaBuilder/getPublishSchemas.d.ts.map +0 -1
- package/dist/DBSchemaBuilder/getPublishSchemas.js +0 -34
- package/dist/DBSchemaBuilder/getPublishSchemas.js.map +0 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts +0 -6
- package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts.map +0 -1
- package/dist/PublishParser/getTableRulesWithoutFileTable.js.map +0 -1
- package/lib/DBSchemaBuilder/getPublishSchemas.ts +0 -41
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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.
|
|
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({
|
|
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
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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 " +
|
|
306
|
+
throw "INTERNAL ERROR: table handler not found for " + tableName;
|
|
291
307
|
}
|
|
292
|
-
const
|
|
293
|
-
|
|
308
|
+
const publishRulesExcludingFileTable = await this.getParsedPublishTable({
|
|
309
|
+
clientReq,
|
|
310
|
+
tableName,
|
|
294
311
|
clientInfo,
|
|
295
|
-
overriddenPublish,
|
|
296
|
-
);
|
|
297
|
-
if (this.dbo[
|
|
312
|
+
resolvedPublishObject: overriddenPublish,
|
|
313
|
+
});
|
|
314
|
+
if (this.dbo[tableName]?.is_media) {
|
|
298
315
|
const { rules: fileTableRules } = await getFileTableRules.bind(this)(
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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(
|
|
334
|
+
parsePublishTableRule(publishRulesExcludingFileTable),
|
|
318
335
|
scope,
|
|
319
336
|
);
|
|
320
337
|
}
|
|
321
338
|
|
|
322
|
-
|
|
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
|
-
|
|
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({
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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.
|
|
73
|
+
filter: tableRules.select.forcedFilter ?? {},
|
|
55
74
|
},
|
|
56
75
|
});
|
|
57
76
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
|
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 {
|
|
8
|
-
import { TABLE_RULE_NO_LIMITS
|
|
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
|
|
9
|
+
export async function getParsedPublishTable(
|
|
11
10
|
this: PublishParser,
|
|
12
|
-
{ tableName, clientReq }:
|
|
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
|
-
|
|
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 =
|
|
57
|
-
|
|
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
|
-
|
|
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
|
|
30
|
+
let resolvedPublishObject: PublishObject | undefined;
|
|
31
31
|
try {
|
|
32
|
-
|
|
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 (!
|
|
38
|
+
if (!resolvedPublishObject || !Object.keys(resolvedPublishObject).length) {
|
|
39
39
|
return { tables, tableSchemaErrors };
|
|
40
40
|
}
|
|
41
|
-
const tableNames = getPublishedTableNames(this,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
571
|
-
|
|
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
|
+
};
|