prostgles-server 2.0.144 → 2.0.147
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/AuthHandler.d.ts +15 -13
- package/dist/AuthHandler.d.ts.map +1 -1
- package/dist/AuthHandler.js +41 -43
- package/dist/AuthHandler.js.map +1 -1
- package/dist/DBEventsManager.d.ts +6 -5
- package/dist/DBEventsManager.d.ts.map +1 -1
- package/dist/DBEventsManager.js +8 -2
- package/dist/DBEventsManager.js.map +1 -1
- package/dist/DboBuilder.d.ts +62 -50
- package/dist/DboBuilder.d.ts.map +1 -1
- package/dist/DboBuilder.js +229 -170
- package/dist/DboBuilder.js.map +1 -1
- package/dist/FileManager.d.ts +5 -5
- package/dist/FileManager.d.ts.map +1 -1
- package/dist/FileManager.js +48 -21
- package/dist/FileManager.js.map +1 -1
- package/dist/Filtering.d.ts.map +1 -1
- package/dist/Filtering.js +11 -9
- package/dist/Filtering.js.map +1 -1
- package/dist/PostgresNotifListenManager.d.ts +3 -3
- package/dist/PostgresNotifListenManager.d.ts.map +1 -1
- package/dist/PostgresNotifListenManager.js +7 -5
- package/dist/PostgresNotifListenManager.js.map +1 -1
- package/dist/Prostgles.d.ts +6 -9
- package/dist/Prostgles.d.ts.map +1 -1
- package/dist/Prostgles.js +122 -83
- package/dist/Prostgles.js.map +1 -1
- package/dist/PubSubManager.d.ts +9 -9
- package/dist/PubSubManager.d.ts.map +1 -1
- package/dist/PubSubManager.js +10 -9
- package/dist/PubSubManager.js.map +1 -1
- package/dist/QueryBuilder.d.ts +26 -8
- package/dist/QueryBuilder.d.ts.map +1 -1
- package/dist/QueryBuilder.js +114 -46
- package/dist/QueryBuilder.js.map +1 -1
- package/dist/SyncReplication.d.ts +1 -1
- package/dist/SyncReplication.d.ts.map +1 -1
- package/dist/SyncReplication.js +31 -29
- package/dist/SyncReplication.js.map +1 -1
- package/dist/TableConfig.d.ts +0 -1
- package/dist/TableConfig.d.ts.map +1 -1
- package/dist/TableConfig.js +25 -17
- package/dist/TableConfig.js.map +1 -1
- package/dist/shortestPath.d.ts.map +1 -1
- package/dist/shortestPath.js.map +1 -1
- package/dist/utils.d.ts +2 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +6 -0
- package/dist/utils.js.map +1 -1
- package/lib/AuthHandler.ts +50 -40
- package/lib/DBEventsManager.ts +14 -7
- package/lib/DboBuilder.ts +265 -199
- package/lib/FileManager.ts +30 -21
- package/lib/Filtering.ts +19 -16
- package/lib/PostgresNotifListenManager.ts +11 -10
- package/lib/Prostgles.ts +89 -73
- package/lib/PubSubManager.ts +13 -11
- package/lib/QueryBuilder.ts +135 -54
- package/lib/SyncReplication.ts +10 -10
- package/lib/TableConfig.ts +23 -15
- package/lib/shortestPath.ts +6 -4
- package/lib/utils.ts +7 -1
- package/package.json +7 -8
- package/tests/client/PID.txt +1 -1
- package/tests/client/index.js +10 -7
- package/tests/client/index.ts +12 -8
- package/tests/client/package-lock.json +14 -14
- package/tests/client/package.json +2 -2
- package/tests/client/tsconfig.json +2 -2
- package/tests/client_only_queries.js +127 -104
- package/tests/client_only_queries.ts +43 -17
- package/tests/isomorphic_queries.js +44 -6
- package/tests/isomorphic_queries.ts +42 -6
- package/tests/server/package-lock.json +27 -29
- package/tests/server/package.json +2 -2
- package/tests/server/tsconfig.json +2 -2
- package/tsconfig.json +3 -2
package/lib/Prostgles.ts
CHANGED
|
@@ -16,7 +16,7 @@ console.log("Add a basic auth mode where user and sessions table are created");
|
|
|
16
16
|
import TableConfigurator, { TableConfig } from "./TableConfig";
|
|
17
17
|
|
|
18
18
|
import { get } from "./utils";
|
|
19
|
-
import { DboBuilder, DbHandler, TableHandler, ViewHandler, isPlainObject, LocalParams, CommonTableRules, TableSchema, PRGLIOSocket } from "./DboBuilder";
|
|
19
|
+
import { DboBuilder, DbHandler, TableHandler, ViewHandler, isPlainObject, LocalParams, CommonTableRules, TableSchema, PRGLIOSocket, getKeys } from "./DboBuilder";
|
|
20
20
|
import { PubSubManager, DEFAULT_SYNC_BATCH_SIZE, asValue } from "./PubSubManager";
|
|
21
21
|
export { DbHandler }
|
|
22
22
|
export type PGP = pgPromise.IMain<{}, pg.IClient>;
|
|
@@ -28,8 +28,7 @@ import { DBEventsManager } from "./DBEventsManager";
|
|
|
28
28
|
export type DB = pgPromise.IDatabase<{}, pg.IClient>;
|
|
29
29
|
type DbConnection = string | pg.IConnectionParameters<pg.IClient>;
|
|
30
30
|
type DbConnectionOpts = pg.IDefaults;
|
|
31
|
-
|
|
32
|
-
let currConnection: { db: DB, pgp: PGP };
|
|
31
|
+
const TABLE_METHODS = ["update", "find", "findOne", "insert", "delete", "upsert"];
|
|
33
32
|
function getDbConnection(dbConnection: DbConnection, options: DbConnectionOpts | undefined, debugQueries = false, onNotice: ProstglesInitOptions["onNotice"]): { db: DB, pgp: PGP } {
|
|
34
33
|
let pgp: PGP = pgPromise({
|
|
35
34
|
|
|
@@ -398,8 +397,8 @@ export type ProstglesInitOptions<DBO = DbHandler> = {
|
|
|
398
397
|
onReady(dbo: DBO, db: DB): void;
|
|
399
398
|
transactions?: string | boolean;
|
|
400
399
|
wsChannelNamePrefix?: string;
|
|
401
|
-
onSocketConnect?(socket:
|
|
402
|
-
onSocketDisconnect?(socket:
|
|
400
|
+
onSocketConnect?(socket: PRGLIOSocket, dbo: DBO, db?: DB): any;
|
|
401
|
+
onSocketDisconnect?(socket: PRGLIOSocket, dbo: DBO, db?: DB): any;
|
|
403
402
|
auth?: Auth<DBO>;
|
|
404
403
|
DEBUG_MODE?: boolean;
|
|
405
404
|
watchSchemaType?:
|
|
@@ -673,7 +672,8 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
673
672
|
this.isSuperUser = await isSuperUser(db);
|
|
674
673
|
}
|
|
675
674
|
this.checkDb();
|
|
676
|
-
const
|
|
675
|
+
const db = this.db!;
|
|
676
|
+
const pgp = this.pgp!;
|
|
677
677
|
|
|
678
678
|
/* 2. Execute any SQL file if provided */
|
|
679
679
|
if(this.opts.sqlFilePath){
|
|
@@ -722,7 +722,7 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
722
722
|
this.authHandler = new AuthHandler(this as any);
|
|
723
723
|
await this.authHandler.init();
|
|
724
724
|
|
|
725
|
-
this.publishParser = new PublishParser(this.opts.publish, this.opts.publishMethods, this.opts.publishRawSQL, this.dbo
|
|
725
|
+
this.publishParser = new PublishParser(this.opts.publish, this.opts.publishMethods, this.opts.publishRawSQL, this.dbo!, this.db, this as any);
|
|
726
726
|
this.dboBuilder.publishParser = this.publishParser;
|
|
727
727
|
|
|
728
728
|
/* 4. Set publish and auth listeners */
|
|
@@ -751,7 +751,7 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
751
751
|
|
|
752
752
|
this.loaded = true;
|
|
753
753
|
return {
|
|
754
|
-
db: this.dbo
|
|
754
|
+
db: this.dbo!,
|
|
755
755
|
_db: db,
|
|
756
756
|
pgp,
|
|
757
757
|
io: this.opts.io,
|
|
@@ -778,6 +778,7 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
778
778
|
};
|
|
779
779
|
} catch (e) {
|
|
780
780
|
console.trace(e)
|
|
781
|
+
// @ts-ignore
|
|
781
782
|
throw "init issues: " + e.toString();
|
|
782
783
|
}
|
|
783
784
|
}
|
|
@@ -786,7 +787,7 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
786
787
|
|
|
787
788
|
const fileContent = await this.getFileText(filePath);//.then(console.log);
|
|
788
789
|
|
|
789
|
-
return this.db
|
|
790
|
+
return this.db?.multi(fileContent).then((data)=>{
|
|
790
791
|
console.log("Prostgles: SQL file executed successfuly \n -> " + filePath);
|
|
791
792
|
return data
|
|
792
793
|
}).catch((err) => {
|
|
@@ -814,7 +815,7 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
814
815
|
|
|
815
816
|
if(!this.dbo) throw "dbo missing";
|
|
816
817
|
|
|
817
|
-
let publishParser = new PublishParser(this.opts.publish, this.opts.publishMethods, this.opts.publishRawSQL, this.dbo, this.db
|
|
818
|
+
let publishParser = new PublishParser(this.opts.publish, this.opts.publishMethods, this.opts.publishRawSQL, this.dbo, this.db!, this as any);
|
|
818
819
|
this.publishParser = publishParser;
|
|
819
820
|
|
|
820
821
|
if(!this.opts.io) return;
|
|
@@ -829,7 +830,7 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
829
830
|
}
|
|
830
831
|
|
|
831
832
|
/* Initialise */
|
|
832
|
-
this.opts.io.on('connection', async (socket) => {
|
|
833
|
+
this.opts.io.on('connection', async (socket: PRGLIOSocket) => {
|
|
833
834
|
if(this.destroyed){
|
|
834
835
|
console.log("Socket connected to destroyed instance");
|
|
835
836
|
socket.disconnect();
|
|
@@ -848,18 +849,19 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
848
849
|
Checks request against publish and if OK run it with relevant publish functions. Local (server) requests do not check the policy
|
|
849
850
|
*/
|
|
850
851
|
socket.removeAllListeners(CHANNELS.DEFAULT)
|
|
851
|
-
socket.on(CHANNELS.DEFAULT, async ({ tableName, command, param1, param2, param3 }: SocketRequestParams, cb = (...callback) => {} ) => {
|
|
852
|
+
socket.on(CHANNELS.DEFAULT, async ({ tableName, command, param1, param2, param3 }: SocketRequestParams, cb = (...callback: any[]) => {} ) => {
|
|
852
853
|
|
|
853
854
|
try { /* Channel name will only include client-sent params so we ignore table_rules enforced params */
|
|
854
|
-
if(!socket) {
|
|
855
|
-
console.error("socket missing??!!")
|
|
856
|
-
throw "socket missing??!!";
|
|
855
|
+
if(!socket || !this.authHandler || !this.publishParser || !this.dbo) {
|
|
856
|
+
console.error("socket or authhandler missing??!!")
|
|
857
|
+
throw "socket or authhandler missing??!!";
|
|
857
858
|
}
|
|
858
859
|
|
|
859
860
|
const clientInfo = await this.authHandler.getClientInfo({ socket });
|
|
860
861
|
let valid_table_command_rules = await this.publishParser.getValidatedRequestRule({ tableName, command, localParams: { socket } }, clientInfo);
|
|
861
862
|
if(valid_table_command_rules){
|
|
862
|
-
|
|
863
|
+
//@ts-ignore
|
|
864
|
+
let res = await this.dbo[tableName][command]!(param1, param2, param3, valid_table_command_rules, { socket, has_rules: true });
|
|
863
865
|
cb(null, res);
|
|
864
866
|
} else throw `Invalid OR disallowed request: ${tableName}.${command} `;
|
|
865
867
|
|
|
@@ -873,8 +875,8 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
873
875
|
});
|
|
874
876
|
|
|
875
877
|
socket.on("disconnect", () => {
|
|
876
|
-
this.dbEventsManager
|
|
877
|
-
this.dbEventsManager
|
|
878
|
+
this.dbEventsManager?.removeNotice(socket);
|
|
879
|
+
this.dbEventsManager?.removeNotify(undefined, socket);
|
|
878
880
|
this.connectedSockets = this.connectedSockets.filter(s => s.id !== socket.id);
|
|
879
881
|
// subscriptions = subscriptions.filter(sub => sub.socket.id !== socket.id);
|
|
880
882
|
if(this.opts.onSocketDisconnect){
|
|
@@ -883,9 +885,9 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
883
885
|
});
|
|
884
886
|
|
|
885
887
|
socket.removeAllListeners(CHANNELS.METHOD)
|
|
886
|
-
socket.on(CHANNELS.METHOD, async ({ method, params }: SocketMethodRequest, cb = (...callback) => {} ) => {
|
|
888
|
+
socket.on(CHANNELS.METHOD, async ({ method, params }: SocketMethodRequest, cb = (...callback: any) => {} ) => {
|
|
887
889
|
try {
|
|
888
|
-
const methods = await this.publishParser
|
|
890
|
+
const methods = await this.publishParser?.getMethods(socket) as any;
|
|
889
891
|
|
|
890
892
|
if(!methods || !methods[method]){
|
|
891
893
|
cb("Disallowed/missing method " + JSON.stringify(method));
|
|
@@ -924,7 +926,7 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
924
926
|
|
|
925
927
|
const { dbo, db, pgp, publishParser } = this;
|
|
926
928
|
try {
|
|
927
|
-
schema = await publishParser
|
|
929
|
+
schema = await publishParser?.getSchemaFromPublish(socket);
|
|
928
930
|
} catch(e){
|
|
929
931
|
publishValidationError = "Server Error: PUBLISH VALIDATION ERROR";
|
|
930
932
|
console.error(`\nProstgles PUBLISH VALIDATION ERROR (after socket connected):\n ->`, e);
|
|
@@ -934,19 +936,19 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
934
936
|
/* RUN Raw sql from client IF PUBLISHED
|
|
935
937
|
*/
|
|
936
938
|
let fullSchema: TableSchema[] = [];
|
|
937
|
-
let allTablesViews = this.dboBuilder.tablesOrViews;
|
|
939
|
+
let allTablesViews = this.dboBuilder.tablesOrViews ?? [];
|
|
938
940
|
if(this.opts.publishRawSQL && typeof this.opts.publishRawSQL === "function"){
|
|
939
941
|
const canRunSQL = async () => {
|
|
940
|
-
const publishParams = await this.publishParser
|
|
941
|
-
let res = await this.opts.publishRawSQL(publishParams as any);
|
|
942
|
+
const publishParams = await this.publishParser?.getPublishParams({ socket })
|
|
943
|
+
let res = await this.opts.publishRawSQL?.(publishParams as any);
|
|
942
944
|
return Boolean(res && typeof res === "boolean" || res === "*");
|
|
943
945
|
}
|
|
944
946
|
|
|
945
947
|
if(await canRunSQL()){
|
|
946
948
|
socket.removeAllListeners(CHANNELS.SQL)
|
|
947
|
-
socket.on(CHANNELS.SQL, async ({ query, params, options }: SQLRequest, cb = (...callback) => {}) => {
|
|
949
|
+
socket.on(CHANNELS.SQL, async ({ query, params, options }: SQLRequest, cb = (...callback: any) => {}) => {
|
|
948
950
|
|
|
949
|
-
if(!this.dbo
|
|
951
|
+
if(!this.dbo?.sql) throw "Internal error: sql handler missing";
|
|
950
952
|
|
|
951
953
|
this.dbo.sql(query, params, options, { socket }).then(res => {
|
|
952
954
|
cb(null, res)
|
|
@@ -963,7 +965,7 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
963
965
|
}
|
|
964
966
|
|
|
965
967
|
// let joinTables = [];
|
|
966
|
-
let joinTables2 = [];
|
|
968
|
+
let joinTables2: string[][] = [];
|
|
967
969
|
if(this.opts.joins){
|
|
968
970
|
// joinTables = Array.from(new Set(flat(this.dboBuilder.getJoins().map(j => j.tables)).filter(t => schema[t])));
|
|
969
971
|
let _joinTables2 = this.dboBuilder.getJoinPaths()
|
|
@@ -977,11 +979,11 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
977
979
|
});
|
|
978
980
|
}
|
|
979
981
|
|
|
980
|
-
const methods = await publishParser
|
|
982
|
+
const methods = await publishParser?.getMethods(socket);
|
|
981
983
|
|
|
982
984
|
socket.emit(CHANNELS.SCHEMA, {
|
|
983
985
|
schema,
|
|
984
|
-
methods:
|
|
986
|
+
methods: getKeys(methods),
|
|
985
987
|
...(fullSchema? { fullSchema } : {}),
|
|
986
988
|
rawSQL,
|
|
987
989
|
joinTables: joinTables2,
|
|
@@ -991,19 +993,19 @@ export class Prostgles<DBO = DbHandler> {
|
|
|
991
993
|
});
|
|
992
994
|
}
|
|
993
995
|
}
|
|
994
|
-
function makeSocketError(cb, err){
|
|
996
|
+
function makeSocketError(cb: Function, err: any){
|
|
995
997
|
const err_msg = (err instanceof Error)?
|
|
996
998
|
err.toString() :
|
|
997
999
|
isPlainObject(err)?
|
|
998
1000
|
JSON.stringify(err, null, 2) :
|
|
999
|
-
err.toString(),
|
|
1001
|
+
(err as any).toString(),
|
|
1000
1002
|
e = { err_msg, err };
|
|
1001
1003
|
cb(e);
|
|
1002
1004
|
}
|
|
1003
1005
|
|
|
1004
1006
|
type SocketRequestParams = {
|
|
1005
1007
|
tableName: string;
|
|
1006
|
-
command:
|
|
1008
|
+
command: typeof TABLE_METHODS[number];
|
|
1007
1009
|
param1: any;
|
|
1008
1010
|
param2: any;
|
|
1009
1011
|
param3: any;
|
|
@@ -1014,11 +1016,6 @@ type SocketMethodRequest = {
|
|
|
1014
1016
|
}
|
|
1015
1017
|
|
|
1016
1018
|
|
|
1017
|
-
type callback = {
|
|
1018
|
-
(err: { err: any, err_msg: string }, res: any)
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
1019
|
type Request = {
|
|
1023
1020
|
socket?: any;
|
|
1024
1021
|
httpReq?: any;
|
|
@@ -1112,14 +1109,14 @@ const RULE_TO_METHODS = [
|
|
|
1112
1109
|
// const ALL_PUBLISH_METHODS = ["update", "upsert", "delete", "insert", "find", "findOne", "subscribe", "unsubscribe", "sync", "unsync", "remove"];
|
|
1113
1110
|
// const ALL_PUBLISH_METHODS = RULE_TO_METHODS.map(r => r.methods).flat();
|
|
1114
1111
|
|
|
1115
|
-
export function flat(arr){
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1112
|
+
// export function flat(arr){
|
|
1113
|
+
// // let res = arr.reduce((acc, val) => [ ...acc, ...val ], []);
|
|
1114
|
+
// let res = arr.reduce(function (farr, toFlatten) {
|
|
1115
|
+
// return farr.concat(Array.isArray(toFlatten) ? flat(toFlatten) : toFlatten);
|
|
1116
|
+
// }, []);
|
|
1120
1117
|
|
|
1121
|
-
|
|
1122
|
-
}
|
|
1118
|
+
// return res;
|
|
1119
|
+
// }
|
|
1123
1120
|
|
|
1124
1121
|
export class PublishParser {
|
|
1125
1122
|
publish: any;
|
|
@@ -1142,10 +1139,10 @@ export class PublishParser {
|
|
|
1142
1139
|
|
|
1143
1140
|
async getPublishParams(localParams: LocalParams, clientInfo?: ClientInfo): Promise<PublishParams> {
|
|
1144
1141
|
return {
|
|
1145
|
-
...(clientInfo || await this.prostgles.authHandler
|
|
1142
|
+
...(clientInfo || await this.prostgles.authHandler?.getClientInfo(localParams)),
|
|
1146
1143
|
dbo: this.dbo,
|
|
1147
1144
|
db: this.db,
|
|
1148
|
-
socket: localParams.socket
|
|
1145
|
+
socket: localParams.socket!
|
|
1149
1146
|
}
|
|
1150
1147
|
}
|
|
1151
1148
|
|
|
@@ -1156,8 +1153,9 @@ export class PublishParser {
|
|
|
1156
1153
|
const _methods = await applyParamsIfFunc(this.publishMethods, publishParams);
|
|
1157
1154
|
|
|
1158
1155
|
if(_methods && Object.keys(_methods).length){
|
|
1159
|
-
|
|
1156
|
+
getKeys(_methods).map(key => {
|
|
1160
1157
|
if(_methods[key] && (typeof _methods[key] === "function" || typeof _methods[key].then === "function")){
|
|
1158
|
+
//@ts-ignore
|
|
1161
1159
|
methods[key] = _methods[key];
|
|
1162
1160
|
} else {
|
|
1163
1161
|
throw `invalid publishMethods item -> ${key} \n Expecting a function or promise`
|
|
@@ -1178,8 +1176,8 @@ export class PublishParser {
|
|
|
1178
1176
|
let _publish = await applyParamsIfFunc(this.publish, publishParams );
|
|
1179
1177
|
|
|
1180
1178
|
if(_publish === "*"){
|
|
1181
|
-
let publish = {}
|
|
1182
|
-
this.prostgles.dboBuilder.tablesOrViews
|
|
1179
|
+
let publish = {} as any;
|
|
1180
|
+
this.prostgles.dboBuilder.tablesOrViews?.map(tov => {
|
|
1183
1181
|
publish[tov.name] = "*";
|
|
1184
1182
|
});
|
|
1185
1183
|
return publish;
|
|
@@ -1188,11 +1186,11 @@ export class PublishParser {
|
|
|
1188
1186
|
return _publish;
|
|
1189
1187
|
}
|
|
1190
1188
|
async getValidatedRequestRuleWusr({ tableName, command, localParams }: DboTableCommand): Promise<TableRule>{
|
|
1191
|
-
const clientInfo = await this.prostgles.authHandler
|
|
1189
|
+
const clientInfo = await this.prostgles.authHandler!.getClientInfo(localParams);
|
|
1192
1190
|
return await this.getValidatedRequestRule({ tableName, command, localParams }, clientInfo);
|
|
1193
1191
|
}
|
|
1194
1192
|
|
|
1195
|
-
async getValidatedRequestRule({ tableName, command, localParams }: DboTableCommand, clientInfo
|
|
1193
|
+
async getValidatedRequestRule({ tableName, command, localParams }: DboTableCommand, clientInfo?: ClientInfo): Promise<TableRule>{
|
|
1196
1194
|
if(!this.dbo) throw "INTERNAL ERROR: dbo is missing";
|
|
1197
1195
|
|
|
1198
1196
|
if(!command || !tableName) throw "command OR tableName are missing";
|
|
@@ -1233,7 +1231,7 @@ export class PublishParser {
|
|
|
1233
1231
|
} else throw `Invalid or disallowed command: ${tableName}.${command}`;
|
|
1234
1232
|
}
|
|
1235
1233
|
|
|
1236
|
-
async getTableRules({ tableName, localParams }: DboTable, clientInfo
|
|
1234
|
+
async getTableRules({ tableName, localParams }: DboTable, clientInfo?: ClientInfo): Promise<PublishTable> {
|
|
1237
1235
|
|
|
1238
1236
|
try {
|
|
1239
1237
|
if(!localParams || !tableName) throw "publish OR socket OR dbo OR tableName are missing";
|
|
@@ -1259,7 +1257,8 @@ export class PublishParser {
|
|
|
1259
1257
|
if(
|
|
1260
1258
|
tHandler.tableOrViewInfo.privileges[r.sqlRule]
|
|
1261
1259
|
){
|
|
1262
|
-
|
|
1260
|
+
// @ts-ignore
|
|
1261
|
+
table_rules[r.rule] = { ...(r as any).no_limits } as any;
|
|
1263
1262
|
}
|
|
1264
1263
|
|
|
1265
1264
|
|
|
@@ -1270,19 +1269,25 @@ export class PublishParser {
|
|
|
1270
1269
|
/* Add missing implied rules */
|
|
1271
1270
|
MY_RULES.map(r => {
|
|
1272
1271
|
|
|
1273
|
-
if(["getInfo", "getColumns"].includes(r.rule) && ![null, false, 0].includes(table_rules[r.rule])){
|
|
1272
|
+
if(["getInfo", "getColumns"].includes(r.rule) && ![null, false, 0].includes((table_rules as any)[r.rule])){
|
|
1273
|
+
// @ts-ignore
|
|
1274
1274
|
table_rules[r.rule] = r.no_limits;
|
|
1275
1275
|
return ;
|
|
1276
1276
|
}
|
|
1277
1277
|
|
|
1278
1278
|
/* Add nested properties for fully allowed rules */
|
|
1279
|
+
// @ts-ignore
|
|
1279
1280
|
if ([true, "*"].includes(table_rules[r.rule]) && r.no_limits) {
|
|
1281
|
+
// @ts-ignore
|
|
1280
1282
|
table_rules[r.rule] = Object.assign({}, r.no_limits);
|
|
1281
1283
|
}
|
|
1282
1284
|
|
|
1285
|
+
// @ts-ignore
|
|
1283
1286
|
if(table_rules[r.rule]){
|
|
1284
1287
|
/* Add implied methods if not falsy */
|
|
1285
|
-
|
|
1288
|
+
// @ts-ignore
|
|
1289
|
+
r.methods.forEach(method => {
|
|
1290
|
+
// @ts-ignore
|
|
1286
1291
|
if(table_rules[method] === undefined){
|
|
1287
1292
|
const publishedTable = (table_rules as PublishTable);
|
|
1288
1293
|
if(method === "updateBatch" && !publishedTable.update){
|
|
@@ -1290,6 +1295,7 @@ export class PublishParser {
|
|
|
1290
1295
|
} else if(method === "upsert" && (!publishedTable.update || !publishedTable.insert)){
|
|
1291
1296
|
// return;
|
|
1292
1297
|
} else {
|
|
1298
|
+
// @ts-ignore
|
|
1293
1299
|
table_rules[method] = {};
|
|
1294
1300
|
}
|
|
1295
1301
|
}
|
|
@@ -1302,51 +1308,61 @@ export class PublishParser {
|
|
|
1302
1308
|
Add defaults
|
|
1303
1309
|
Check for invalid params
|
|
1304
1310
|
*/
|
|
1305
|
-
if(
|
|
1306
|
-
const ruleKeys =
|
|
1311
|
+
if(table_rules && getKeys(table_rules).length && table_rules !== "*"){
|
|
1312
|
+
const ruleKeys = getKeys(table_rules as PublishTableRule | PublishViewRule)
|
|
1307
1313
|
|
|
1314
|
+
// @ts-ignore
|
|
1308
1315
|
ruleKeys.filter(m => table_rules[m])
|
|
1309
1316
|
.find(method => {
|
|
1310
1317
|
let rm = MY_RULES.find(r => r.rule === method || (r.methods as any).includes(method));
|
|
1311
1318
|
if(!rm){
|
|
1312
|
-
throw `Invalid rule in publish.${tableName} -> ${method} \nExpecting any of: ${
|
|
1319
|
+
throw `Invalid rule in publish.${tableName} -> ${method} \nExpecting any of: ${MY_RULES.flatMap(r => [r.rule, ...r.methods]).join(", ")}`;
|
|
1313
1320
|
}
|
|
1314
1321
|
|
|
1315
1322
|
/** Check user privileges */
|
|
1316
1323
|
if(!tHandler.tableOrViewInfo.privileges[rm.sqlRule]){
|
|
1317
|
-
|
|
1324
|
+
// @ts-ignore
|
|
1325
|
+
delete table_rules![method];
|
|
1318
1326
|
return;
|
|
1319
1327
|
}
|
|
1320
1328
|
|
|
1321
1329
|
/* Check RULES for invalid params */
|
|
1322
1330
|
/* Methods do not have params -> They use them from rules */
|
|
1323
1331
|
if(method === rm.rule){
|
|
1324
|
-
|
|
1325
|
-
let
|
|
1332
|
+
// @ts-ignore
|
|
1333
|
+
let method_params = getKeys(table_rules![method]);
|
|
1334
|
+
let iparam = method_params.find(p => !rm?.allowed_params.includes(<never>p));
|
|
1326
1335
|
if(iparam){
|
|
1327
1336
|
throw `Invalid setting in publish.${tableName}.${method} -> ${iparam}. \n Expecting any of: ${rm.allowed_params.join(", ")}`;
|
|
1328
1337
|
}
|
|
1329
1338
|
}
|
|
1330
1339
|
|
|
1331
1340
|
/* Add default params (if missing) */
|
|
1341
|
+
// @ts-ignore
|
|
1332
1342
|
if(method === "sync"){
|
|
1333
1343
|
|
|
1334
|
-
|
|
1344
|
+
// @ts-ignore
|
|
1345
|
+
if([true, "*"].includes(table_rules![method])){
|
|
1335
1346
|
throw "Invalid sync rule. Expecting { id_fields: string[], synced_field: string } ";
|
|
1336
1347
|
}
|
|
1337
1348
|
if(typeof get(table_rules, [method, "throttle"]) !== "number"){
|
|
1338
|
-
|
|
1349
|
+
// @ts-ignore
|
|
1350
|
+
table_rules![method].throttle = 100;
|
|
1339
1351
|
}
|
|
1340
1352
|
if(typeof get(table_rules, [method, "batch_size"]) !== "number"){
|
|
1341
|
-
|
|
1353
|
+
// @ts-ignore
|
|
1354
|
+
table_rules![method].batch_size = DEFAULT_SYNC_BATCH_SIZE;
|
|
1342
1355
|
}
|
|
1343
1356
|
}
|
|
1344
1357
|
|
|
1345
1358
|
/* Enable subscribe if not explicitly disabled */
|
|
1359
|
+
// @ts-ignore
|
|
1346
1360
|
if(method === "select" && !ruleKeys.includes("subscribe")){
|
|
1347
1361
|
const sr = MY_RULES.find(r => r.rule === "subscribe");
|
|
1348
1362
|
if(sr){
|
|
1363
|
+
// @ts-ignore
|
|
1349
1364
|
table_rules[sr.rule] = { ...sr.no_limits };
|
|
1365
|
+
// @ts-ignore
|
|
1350
1366
|
(table_rules as PublishTable).subscribeOne = { ...sr.no_limits };
|
|
1351
1367
|
}
|
|
1352
1368
|
}
|
|
@@ -1364,11 +1380,11 @@ export class PublishParser {
|
|
|
1364
1380
|
|
|
1365
1381
|
/* Prepares schema for client. Only allowed views and commands will be present */
|
|
1366
1382
|
async getSchemaFromPublish(socket: any): Promise<AnyObject> {
|
|
1367
|
-
let schema = {};
|
|
1383
|
+
let schema: AnyObject = {};
|
|
1368
1384
|
|
|
1369
1385
|
try {
|
|
1370
1386
|
/* Publish tables and views based on socket */
|
|
1371
|
-
const clientInfo = await this.prostgles.authHandler
|
|
1387
|
+
const clientInfo = await this.prostgles.authHandler?.getClientInfo({ socket });
|
|
1372
1388
|
let _publish = await this.getPublish(socket, clientInfo);
|
|
1373
1389
|
|
|
1374
1390
|
|
|
@@ -1383,7 +1399,7 @@ export class PublishParser {
|
|
|
1383
1399
|
.map(async tableName => {
|
|
1384
1400
|
if(!this.dbo[tableName]) {
|
|
1385
1401
|
throw `Table ${tableName} does not exist
|
|
1386
|
-
Expecting one of: ${this.prostgles.dboBuilder.tablesOrViews
|
|
1402
|
+
Expecting one of: ${this.prostgles.dboBuilder.tablesOrViews?.map(tov => tov.name).join(", ")}
|
|
1387
1403
|
DBO tables: ${Object.keys(this.dbo).filter(k => (this.dbo[k] as any).find).join(", ")}
|
|
1388
1404
|
`;
|
|
1389
1405
|
}
|
|
@@ -1393,13 +1409,13 @@ export class PublishParser {
|
|
|
1393
1409
|
// if(tableName === "insert_rule") throw {table_rules}
|
|
1394
1410
|
if(table_rules && Object.keys(table_rules).length){
|
|
1395
1411
|
schema[tableName] = {};
|
|
1396
|
-
let methods = [];
|
|
1412
|
+
let methods: Array<typeof TABLE_METHODS[number]> = [];
|
|
1397
1413
|
|
|
1398
1414
|
if(typeof table_rules === "object"){
|
|
1399
|
-
methods =
|
|
1415
|
+
methods = getKeys(table_rules) as any;
|
|
1400
1416
|
}
|
|
1401
1417
|
|
|
1402
|
-
await Promise.all(methods.filter(m => m !== "select").map(async method => {
|
|
1418
|
+
await Promise.all(methods.filter(m => m !== "select" as any).map(async method => {
|
|
1403
1419
|
if(method === "sync" && table_rules[method]){
|
|
1404
1420
|
|
|
1405
1421
|
/* Pass sync info */
|
|
@@ -1409,12 +1425,12 @@ export class PublishParser {
|
|
|
1409
1425
|
schema[tableName][method] = {};
|
|
1410
1426
|
|
|
1411
1427
|
/* Test for issues with the publish rules */
|
|
1412
|
-
if(
|
|
1428
|
+
if(TABLE_METHODS.includes(method)){
|
|
1413
1429
|
|
|
1414
1430
|
let err = null;
|
|
1415
1431
|
try {
|
|
1416
1432
|
let valid_table_command_rules = await this.getValidatedRequestRule({ tableName, command: method, localParams: {socket} }, clientInfo);
|
|
1417
|
-
await this.dbo[tableName][method]({}, {}, {}, valid_table_command_rules, { socket, has_rules: true, testRule: true });
|
|
1433
|
+
await (this.dbo[tableName] as any)[method]({}, {}, {}, valid_table_command_rules, { socket, has_rules: true, testRule: true });
|
|
1418
1434
|
|
|
1419
1435
|
} catch(e) {
|
|
1420
1436
|
err = "INTERNAL PUBLISH ERROR";
|
|
@@ -1461,7 +1477,7 @@ export async function isSuperUser(db: DB): Promise<boolean>{
|
|
|
1461
1477
|
}
|
|
1462
1478
|
|
|
1463
1479
|
|
|
1464
|
-
function sleep(ms) {
|
|
1480
|
+
function sleep(ms: number) {
|
|
1465
1481
|
return new Promise((resolve) => {
|
|
1466
1482
|
setTimeout(resolve, ms);
|
|
1467
1483
|
});
|
package/lib/PubSubManager.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { PostgresNotifListenManager } from "./PostgresNotifListenManager";
|
|
7
7
|
import { get } from "./utils";
|
|
8
|
-
import { TableOrViewInfo, TableInfo, DbHandler, TableHandler, DboBuilder } from "./DboBuilder";
|
|
8
|
+
import { TableOrViewInfo, TableInfo, DbHandler, TableHandler, DboBuilder, PRGLIOSocket } from "./DboBuilder";
|
|
9
9
|
import { TableRule, DB, isSuperUser } from "./Prostgles";
|
|
10
10
|
|
|
11
11
|
import * as Bluebird from "bluebird";
|
|
@@ -57,7 +57,7 @@ type AddSyncParams = {
|
|
|
57
57
|
table_info: TableInfo;
|
|
58
58
|
table_rules: TableRule;
|
|
59
59
|
synced_field: string;
|
|
60
|
-
allow_delete
|
|
60
|
+
allow_delete?: boolean;
|
|
61
61
|
id_fields: string[];
|
|
62
62
|
filter: object;
|
|
63
63
|
params: {
|
|
@@ -68,12 +68,12 @@ type AddSyncParams = {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
type SubscriptionParams = {
|
|
71
|
-
socket_id
|
|
71
|
+
socket_id?: string;
|
|
72
72
|
channel_name: string;
|
|
73
73
|
table_name: string;
|
|
74
|
-
socket:
|
|
74
|
+
socket: PRGLIOSocket | undefined;
|
|
75
75
|
table_info: TableOrViewInfo;
|
|
76
|
-
table_rules
|
|
76
|
+
table_rules?: TableRule;
|
|
77
77
|
filter: object;
|
|
78
78
|
params: SelectParams;
|
|
79
79
|
func?: (data: any) => any;
|
|
@@ -1106,7 +1106,9 @@ export class PubSubManager {
|
|
|
1106
1106
|
sub.last_throttled = Date.now();
|
|
1107
1107
|
|
|
1108
1108
|
if(err){
|
|
1109
|
-
|
|
1109
|
+
if(socket_id){
|
|
1110
|
+
this.sockets[socket_id].emit(channel_name, { err });
|
|
1111
|
+
}
|
|
1110
1112
|
return true;
|
|
1111
1113
|
}
|
|
1112
1114
|
|
|
@@ -1115,7 +1117,7 @@ export class PubSubManager {
|
|
|
1115
1117
|
// this.dbo[table_name][subOne? "findOne" : "find"](filter, params, null, table_rules)
|
|
1116
1118
|
if(!this.dbo?.[table_name]?.find) throw "1107 this.dbo[table_name].find";
|
|
1117
1119
|
|
|
1118
|
-
this.dbo?.[table_name]?.find?.(filter, params,
|
|
1120
|
+
this.dbo?.[table_name]?.find?.(filter, params, undefined, table_rules)
|
|
1119
1121
|
.then(data => {
|
|
1120
1122
|
|
|
1121
1123
|
if(socket_id && this.sockets[socket_id]){
|
|
@@ -1276,9 +1278,9 @@ export class PubSubManager {
|
|
|
1276
1278
|
|
|
1277
1279
|
/* Must return a channel for socket */
|
|
1278
1280
|
/* The distinct list of channel names must have a corresponding trigger in the database */
|
|
1279
|
-
async addSub(subscriptionParams: AddSubscriptionParams){
|
|
1281
|
+
async addSub(subscriptionParams: Omit<AddSubscriptionParams, "channel_name">){
|
|
1280
1282
|
const {
|
|
1281
|
-
socket
|
|
1283
|
+
socket, func = null, table_info = null, table_rules, filter = {},
|
|
1282
1284
|
params = {}, condition = "", throttle = 0 //subOne = false,
|
|
1283
1285
|
} = subscriptionParams || {};
|
|
1284
1286
|
|
|
@@ -1300,7 +1302,7 @@ export class PubSubManager {
|
|
|
1300
1302
|
const upsertSub = (newSubData: { table_name: string, condition: string, is_ready: boolean }) => {
|
|
1301
1303
|
const { table_name, condition: _cond, is_ready = false } = newSubData,
|
|
1302
1304
|
condition = this.parseCondition(_cond),
|
|
1303
|
-
newSub = {
|
|
1305
|
+
newSub: SubscriptionParams = {
|
|
1304
1306
|
socket,
|
|
1305
1307
|
table_name: table_info.name,
|
|
1306
1308
|
table_info,
|
|
@@ -1309,7 +1311,7 @@ export class PubSubManager {
|
|
|
1309
1311
|
table_rules,
|
|
1310
1312
|
channel_name,
|
|
1311
1313
|
func: func? func : undefined,
|
|
1312
|
-
socket_id: socket
|
|
1314
|
+
socket_id: socket?.id,
|
|
1313
1315
|
throttle: validated_throttle,
|
|
1314
1316
|
is_throttling: null,
|
|
1315
1317
|
last_throttled: 0,
|