prostgles-client 4.0.164 → 4.0.166
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/index.js +1 -1
- package/dist/index.no-sync.js +1 -1
- package/dist/prostgles.d.ts +15 -0
- package/dist/prostgles.d.ts.map +1 -1
- package/dist/prostgles.js +23 -158
- package/dist/subscriptionHandler.d.ts +22 -0
- package/dist/subscriptionHandler.d.ts.map +1 -0
- package/dist/subscriptionHandler.js +182 -0
- package/lib/prostgles.ts +42 -181
- package/lib/subscriptionHandler.ts +207 -0
- package/package.json +1 -1
- package/tests/package-lock.json +1 -1
package/lib/prostgles.ts
CHANGED
|
@@ -41,6 +41,7 @@ import { FunctionQueuer } from "./FunctionQueuer";
|
|
|
41
41
|
import { isEqual, useFetch, useSubscribe, useSync } from "./react-hooks";
|
|
42
42
|
import { SQL } from "./SQL";
|
|
43
43
|
import type { DbTableSync, Sync, SyncDataItem, SyncOne, SyncOneOptions, SyncOptions, SyncedTable } from "./SyncedTable/SyncedTable";
|
|
44
|
+
import { getSubscriptionHandler } from "./subscriptionHandler";
|
|
44
45
|
|
|
45
46
|
const DEBUG_KEY = "DEBUG_SYNCEDTABLE";
|
|
46
47
|
export const hasWnd = typeof window !== "undefined";
|
|
@@ -52,8 +53,8 @@ export const debug: any = function (...args: any[]) {
|
|
|
52
53
|
|
|
53
54
|
export { MethodHandler, SQLResult, asName };
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
export * from "./react-hooks";
|
|
57
|
+
export * from "./useProstglesClient";
|
|
57
58
|
|
|
58
59
|
|
|
59
60
|
export type ViewHandlerClient<T extends AnyObject = AnyObject, S extends DBSchema | void = void> = ViewHandler<T, S> & {
|
|
@@ -133,7 +134,17 @@ type SyncDebugEvent = {
|
|
|
133
134
|
command: keyof ClientSyncHandles;
|
|
134
135
|
data: AnyObject;
|
|
135
136
|
};
|
|
136
|
-
type DebugEvent =
|
|
137
|
+
type DebugEvent =
|
|
138
|
+
| {
|
|
139
|
+
type: "table";
|
|
140
|
+
command: "unsubscribe";
|
|
141
|
+
tableName: string;
|
|
142
|
+
/**
|
|
143
|
+
* If defined then the server will be asked to unsubscribe
|
|
144
|
+
*/
|
|
145
|
+
unsubChannel?: string;
|
|
146
|
+
}
|
|
147
|
+
| {
|
|
137
148
|
type: "table";
|
|
138
149
|
command: keyof TableHandlerClient;
|
|
139
150
|
tableName: string;
|
|
@@ -168,28 +179,15 @@ export type InitOptions<DBSchema = void> = {
|
|
|
168
179
|
onDebug?: (event: DebugEvent) => any;
|
|
169
180
|
}
|
|
170
181
|
|
|
171
|
-
type AnyFunction = (...args: any[]) => any;
|
|
182
|
+
export type AnyFunction = (...args: any[]) => any;
|
|
172
183
|
|
|
173
|
-
type CoreParams = {
|
|
184
|
+
export type CoreParams = {
|
|
174
185
|
tableName: string;
|
|
175
186
|
command: string;
|
|
176
187
|
param1?: AnyObject;
|
|
177
188
|
param2?: AnyObject;
|
|
178
189
|
};
|
|
179
190
|
|
|
180
|
-
type Subscription = CoreParams & {
|
|
181
|
-
lastData: any;
|
|
182
|
-
onCall: AnyFunction,
|
|
183
|
-
handlers: AnyFunction[];
|
|
184
|
-
errorHandlers: (AnyFunction | undefined)[];
|
|
185
|
-
unsubChannel: string;
|
|
186
|
-
destroy: () => any;
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
type Subscriptions = {
|
|
190
|
-
[key: string]: Subscription
|
|
191
|
-
};
|
|
192
|
-
|
|
193
191
|
export type onUpdatesParams = { data: object[]; isSynced: boolean }
|
|
194
192
|
|
|
195
193
|
export type SyncInfo = {
|
|
@@ -224,17 +222,19 @@ export function prostgles<DBSchema>(initOpts: InitOptions<DBSchema>, syncedTable
|
|
|
224
222
|
}
|
|
225
223
|
|
|
226
224
|
const preffix = CHANNELS._preffix;
|
|
227
|
-
const subscriptions: Subscriptions = {};
|
|
228
225
|
|
|
229
226
|
let syncedTables: Record<string, any> = {};
|
|
230
227
|
|
|
228
|
+
//@ts-ignore
|
|
229
|
+
const subscriptionHandler = getSubscriptionHandler(initOpts);
|
|
230
|
+
|
|
231
231
|
let syncs: Syncs = {};
|
|
232
232
|
let state: undefined | "connected" | "disconnected" | "reconnected";
|
|
233
|
-
const sql = new SQL()
|
|
233
|
+
const sql = new SQL();
|
|
234
234
|
|
|
235
235
|
const destroySyncs = async () => {
|
|
236
|
-
debug("destroySyncs", {
|
|
237
|
-
await
|
|
236
|
+
debug("destroySyncs", { syncedTables });
|
|
237
|
+
// await subscriptionHandler.destroy();
|
|
238
238
|
syncs = {};
|
|
239
239
|
Object.values(syncedTables).map((s: any) => {
|
|
240
240
|
if (s && s.destroy) s.destroy();
|
|
@@ -242,32 +242,6 @@ export function prostgles<DBSchema>(initOpts: InitOptions<DBSchema>, syncedTable
|
|
|
242
242
|
syncedTables = {};
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
function _unsubscribe(channelName: string, unsubChannel: string, handler: AnyFunction) {
|
|
246
|
-
debug("_unsubscribe", { channelName, handler });
|
|
247
|
-
|
|
248
|
-
return new Promise((resolve, reject) => {
|
|
249
|
-
const sub = subscriptions[channelName];
|
|
250
|
-
if (sub) {
|
|
251
|
-
sub.handlers = sub.handlers.filter(h => h !== handler);
|
|
252
|
-
if (!sub.handlers.length) {
|
|
253
|
-
socket.emit(unsubChannel, {}, (err: any, _res: any) => {
|
|
254
|
-
if (err) console.error(err);
|
|
255
|
-
else reject(err);
|
|
256
|
-
});
|
|
257
|
-
socket.removeListener(channelName, sub.onCall);
|
|
258
|
-
delete subscriptions[channelName];
|
|
259
|
-
|
|
260
|
-
/* Not waiting for server confirmation to speed things up */
|
|
261
|
-
resolve(true)
|
|
262
|
-
} else {
|
|
263
|
-
resolve(true)
|
|
264
|
-
}
|
|
265
|
-
} else {
|
|
266
|
-
resolve(true)
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
|
|
271
245
|
function _unsync(channelName: string, triggers: ClientSyncHandles) {
|
|
272
246
|
debug("_unsync", { channelName, triggers })
|
|
273
247
|
return new Promise((resolve, reject) => {
|
|
@@ -306,21 +280,21 @@ export function prostgles<DBSchema>(initOpts: InitOptions<DBSchema>, syncedTable
|
|
|
306
280
|
});
|
|
307
281
|
});
|
|
308
282
|
}
|
|
309
|
-
/**
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
function addServerSub({ tableName, command, param1, param2 }: CoreParams): Promise<SubscriptionChannels> {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
283
|
+
// /**
|
|
284
|
+
// * Obtaines subscribe channel from server
|
|
285
|
+
// */
|
|
286
|
+
// function addServerSub({ tableName, command, param1, param2 }: CoreParams): Promise<SubscriptionChannels> {
|
|
287
|
+
// return new Promise((resolve, reject) => {
|
|
288
|
+
// socket.emit(preffix, { tableName, command, param1, param2 }, (err?: any, res?: SubscriptionChannels) => {
|
|
289
|
+
// if (err) {
|
|
290
|
+
// console.error(err);
|
|
291
|
+
// reject(err);
|
|
292
|
+
// } else if (res) {
|
|
293
|
+
// resolve(res);
|
|
294
|
+
// }
|
|
295
|
+
// });
|
|
296
|
+
// });
|
|
297
|
+
// }
|
|
324
298
|
|
|
325
299
|
const addSyncQueuer = new FunctionQueuer(_addSync, ([{ tableName }]) => tableName);
|
|
326
300
|
async function addSync(params: CoreParams, triggers: ClientSyncHandles): Promise<any> {
|
|
@@ -428,112 +402,6 @@ export function prostgles<DBSchema>(initOpts: InitOptions<DBSchema>, syncedTable
|
|
|
428
402
|
|
|
429
403
|
}
|
|
430
404
|
|
|
431
|
-
/**
|
|
432
|
-
* Can be used concurrently
|
|
433
|
-
*/
|
|
434
|
-
const addSubQueuer = new FunctionQueuer(_addSub, ([_, { tableName }]) => tableName);
|
|
435
|
-
async function addSub(dbo: any, params: CoreParams, onChange: AnyFunction, _onError?: AnyFunction): Promise<SubscriptionHandler> {
|
|
436
|
-
return addSubQueuer.run([dbo, params, onChange, _onError]);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Do NOT use concurrently
|
|
441
|
-
*/
|
|
442
|
-
async function _addSub(dbo: any, { tableName, command, param1, param2 }: CoreParams, onChange: AnyFunction, _onError?: AnyFunction): Promise<SubscriptionHandler> {
|
|
443
|
-
|
|
444
|
-
function makeHandler(channelName: string, unsubChannel: string) {
|
|
445
|
-
|
|
446
|
-
const unsubscribe = function () {
|
|
447
|
-
return _unsubscribe(channelName, unsubChannel, onChange);
|
|
448
|
-
}
|
|
449
|
-
let res: any = { unsubscribe, filter: { ...param1 } }
|
|
450
|
-
/* Some dbo sorting was done to make sure this will work */
|
|
451
|
-
if (dbo[tableName].update) {
|
|
452
|
-
res = {
|
|
453
|
-
...res,
|
|
454
|
-
update: function (newData: AnyObject, updateParams: UpdateParams) {
|
|
455
|
-
return dbo[tableName].update(param1, newData, updateParams);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
if (dbo[tableName].delete) {
|
|
460
|
-
res = {
|
|
461
|
-
...res,
|
|
462
|
-
delete: function (deleteParams: DeleteParams) {
|
|
463
|
-
return dbo[tableName].delete(param1, deleteParams);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
return Object.freeze(res);
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
const existing = Object.entries(subscriptions).find(([ch, s]) => {
|
|
471
|
-
return (
|
|
472
|
-
s.tableName === tableName &&
|
|
473
|
-
s.command === command &&
|
|
474
|
-
JSON.stringify(s.param1 || {}) === JSON.stringify(param1 || {}) &&
|
|
475
|
-
JSON.stringify(s.param2 || {}) === JSON.stringify(param2 || {})
|
|
476
|
-
);
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
if (existing) {
|
|
480
|
-
const existingCh = existing[0];
|
|
481
|
-
existing[1].handlers.push(onChange);
|
|
482
|
-
existing[1].errorHandlers.push(_onError);
|
|
483
|
-
setTimeout(() => {
|
|
484
|
-
if (subscriptions[existingCh]?.lastData) {
|
|
485
|
-
onChange(subscriptions[existingCh]?.lastData)
|
|
486
|
-
}
|
|
487
|
-
}, 10)
|
|
488
|
-
return makeHandler(existingCh, existing[1].unsubChannel);
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
const { channelName, channelNameReady, channelNameUnsubscribe } = await addServerSub({ tableName, command, param1, param2 })
|
|
492
|
-
|
|
493
|
-
const onCall = function (data: any) {
|
|
494
|
-
/* TO DO: confirm receiving data or server will unsubscribe */
|
|
495
|
-
// if(cb) cb(true);
|
|
496
|
-
const sub = subscriptions[channelName];
|
|
497
|
-
if (sub) {
|
|
498
|
-
if (data.data) {
|
|
499
|
-
sub.lastData = data.data;
|
|
500
|
-
sub.handlers.forEach(h => {
|
|
501
|
-
h(data.data);
|
|
502
|
-
});
|
|
503
|
-
} else if (data.err) {
|
|
504
|
-
sub.errorHandlers.forEach(h => {
|
|
505
|
-
h?.(data.err);
|
|
506
|
-
});
|
|
507
|
-
} else {
|
|
508
|
-
console.error("INTERNAL ERROR: Unexpected data format from subscription: ", data)
|
|
509
|
-
}
|
|
510
|
-
} else {
|
|
511
|
-
console.warn("Orphaned subscription: ", channelName)
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
const onError = _onError || function (err: any) { console.error(`Uncaught error within running subscription \n ${channelName}`, err) }
|
|
515
|
-
|
|
516
|
-
socket.on(channelName, onCall);
|
|
517
|
-
subscriptions[channelName] = {
|
|
518
|
-
lastData: undefined,
|
|
519
|
-
tableName,
|
|
520
|
-
command,
|
|
521
|
-
param1,
|
|
522
|
-
param2,
|
|
523
|
-
onCall,
|
|
524
|
-
unsubChannel: channelNameUnsubscribe,
|
|
525
|
-
handlers: [onChange],
|
|
526
|
-
errorHandlers: [onError],
|
|
527
|
-
destroy: async () => {
|
|
528
|
-
for await(const h of subscriptions[channelName]?.handlers ?? []){
|
|
529
|
-
await _unsubscribe(channelName, channelNameUnsubscribe, h);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
socket.emit(channelNameReady, { now: Date.now() });
|
|
534
|
-
return makeHandler(channelName, channelNameUnsubscribe);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
405
|
return new Promise((resolve, reject) => {
|
|
538
406
|
|
|
539
407
|
socket.removeAllListeners(CHANNELS.CONNECTION)
|
|
@@ -560,11 +428,13 @@ export function prostgles<DBSchema>(initOpts: InitOptions<DBSchema>, syncedTable
|
|
|
560
428
|
/* Schema = published schema */
|
|
561
429
|
socket.on(CHANNELS.SCHEMA, async ({ joinTables = [], ...clientSchema }: ClientSchema) => {
|
|
562
430
|
const { schema, methods, tableSchema, auth: authConfig, rawSQL, err } = clientSchema;
|
|
431
|
+
|
|
563
432
|
/** Only destroy existing syncs if schema changed */
|
|
564
433
|
const schemaDidNotChange = schemaAge?.clientSchema && isEqual(schemaAge.clientSchema, clientSchema)
|
|
565
434
|
if(!schemaDidNotChange){
|
|
566
435
|
await destroySyncs();
|
|
567
436
|
}
|
|
437
|
+
|
|
568
438
|
if ((state === "connected" || state === "reconnected") && onReconnect) {
|
|
569
439
|
onReconnect(socket, err);
|
|
570
440
|
if (err) {
|
|
@@ -684,7 +554,7 @@ export function prostgles<DBSchema>(initOpts: InitOptions<DBSchema>, syncedTable
|
|
|
684
554
|
const subFunc = async function (param1 = {}, param2 = {}, onChange, onError) {
|
|
685
555
|
await onDebug?.({ type: "table", command: command as typeof sub_commands[number], tableName, data: { param1, param2, onChange, onError } });
|
|
686
556
|
checkSubscriptionArgs(param1, param2, onChange, onError);
|
|
687
|
-
return addSub(dbo, { tableName, command, param1, param2 }, onChange, onError);
|
|
557
|
+
return subscriptionHandler.addSub(dbo, { tableName, command, param1, param2 }, onChange, onError);
|
|
688
558
|
};
|
|
689
559
|
dboTable[command] = subFunc;
|
|
690
560
|
const SUBONE = "subscribeOne";
|
|
@@ -704,7 +574,7 @@ export function prostgles<DBSchema>(initOpts: InitOptions<DBSchema>, syncedTable
|
|
|
704
574
|
checkSubscriptionArgs(param1, param2, onChange, onError);
|
|
705
575
|
|
|
706
576
|
const onChangeOne = (rows) => { onChange(rows[0]) };
|
|
707
|
-
return addSub(dbo, { tableName, command, param1, param2 }, onChangeOne, onError);
|
|
577
|
+
return subscriptionHandler.addSub(dbo, { tableName, command, param1, param2 }, onChangeOne, onError);
|
|
708
578
|
};
|
|
709
579
|
}
|
|
710
580
|
} else {
|
|
@@ -741,16 +611,7 @@ export function prostgles<DBSchema>(initOpts: InitOptions<DBSchema>, syncedTable
|
|
|
741
611
|
})
|
|
742
612
|
});
|
|
743
613
|
|
|
744
|
-
|
|
745
|
-
// Re-attach listeners
|
|
746
|
-
Object.entries(subscriptions).forEach(async ([ch, s]) => {
|
|
747
|
-
try {
|
|
748
|
-
await addServerSub(s);
|
|
749
|
-
socket.on(ch, s.onCall);
|
|
750
|
-
} catch (err) {
|
|
751
|
-
console.error("There was an issue reconnecting old subscriptions", err)
|
|
752
|
-
}
|
|
753
|
-
});
|
|
614
|
+
await subscriptionHandler.reAttachAll();
|
|
754
615
|
Object.entries(syncs).forEach(async ([ch, s]) => {
|
|
755
616
|
const firstTrigger = s.triggers[0];
|
|
756
617
|
if(firstTrigger){
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { CHANNELS, type AnyObject, type DeleteParams, type SubscriptionChannels, type SubscriptionHandler, type UpdateParams } from "prostgles-types";
|
|
2
|
+
import { debug, isEqual, type AnyFunction, type CoreParams, type InitOptions } from "./prostgles";
|
|
3
|
+
import { FunctionQueuer } from "./FunctionQueuer";
|
|
4
|
+
|
|
5
|
+
type Subscription = CoreParams & {
|
|
6
|
+
lastData: any;
|
|
7
|
+
onCall: AnyFunction,
|
|
8
|
+
handlers: AnyFunction[];
|
|
9
|
+
errorHandlers: (AnyFunction | undefined)[];
|
|
10
|
+
unsubChannel: string;
|
|
11
|
+
reAttach: () => Promise<void>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type Subscriptions = {
|
|
15
|
+
[key: string]: Subscription
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const preffix = CHANNELS._preffix;
|
|
19
|
+
|
|
20
|
+
export const getSubscriptionHandler = <DBSchema>(initOpts: InitOptions<DBSchema>) => {
|
|
21
|
+
const { socket, onDebug, } = initOpts;
|
|
22
|
+
|
|
23
|
+
const subscriptions: Subscriptions = {};
|
|
24
|
+
|
|
25
|
+
const removeServerSub = (unsubChannel: string) => {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
socket.emit(unsubChannel, {}, (err: any, _res: any) => {
|
|
28
|
+
if (err) {
|
|
29
|
+
console.error(err);
|
|
30
|
+
reject(err);
|
|
31
|
+
} else {
|
|
32
|
+
resolve(_res);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function _unsubscribe(channelName: string, unsubChannel: string, handler: AnyFunction, onDebug: InitOptions["onDebug"]): Promise<true> {
|
|
39
|
+
debug("_unsubscribe", { channelName, handler });
|
|
40
|
+
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
const sub = subscriptions[channelName];
|
|
43
|
+
if (sub) {
|
|
44
|
+
sub.handlers = sub.handlers.filter(h => h !== handler);
|
|
45
|
+
if (!sub.handlers.length) {
|
|
46
|
+
onDebug?.({ type: "table", command: "unsubscribe", tableName: sub.tableName });
|
|
47
|
+
removeServerSub(unsubChannel);
|
|
48
|
+
socket.removeListener(channelName, sub.onCall);
|
|
49
|
+
delete subscriptions[channelName];
|
|
50
|
+
|
|
51
|
+
/* Not waiting for server confirmation to speed things up */
|
|
52
|
+
resolve(true)
|
|
53
|
+
} else {
|
|
54
|
+
onDebug?.({ type: "table", command: "unsubscribe", tableName: sub.tableName, unsubChannel });
|
|
55
|
+
resolve(true)
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
resolve(true)
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Obtaines subscribe channel from server
|
|
66
|
+
*/
|
|
67
|
+
function addServerSub({ tableName, command, param1, param2 }: CoreParams): Promise<SubscriptionChannels> {
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
socket.emit(preffix, { tableName, command, param1, param2 }, (err?: any, res?: SubscriptionChannels) => {
|
|
70
|
+
if (err) {
|
|
71
|
+
console.error(err);
|
|
72
|
+
reject(err);
|
|
73
|
+
} else if (res) {
|
|
74
|
+
resolve(res);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Can be used concurrently
|
|
83
|
+
*/
|
|
84
|
+
const addSubQueuer = new FunctionQueuer(_addSub, ([_, { tableName }]) => tableName);
|
|
85
|
+
const addSub = async (dbo: any, params: CoreParams, onChange: AnyFunction, _onError?: AnyFunction): Promise<SubscriptionHandler> => {
|
|
86
|
+
return addSubQueuer.run([dbo, params, onChange, _onError]);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Do NOT use concurrently
|
|
91
|
+
*/
|
|
92
|
+
async function _addSub(dbo: any, { tableName, command, param1, param2 }: CoreParams, onChange: AnyFunction, _onError?: AnyFunction): Promise<SubscriptionHandler> {
|
|
93
|
+
|
|
94
|
+
const makeHandler = (channelName: string, unsubChannel: string) => {
|
|
95
|
+
|
|
96
|
+
const unsubscribe = function () {
|
|
97
|
+
return _unsubscribe(channelName, unsubChannel, onChange, onDebug);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let subHandlers: any = { unsubscribe, filter: { ...param1 } }
|
|
101
|
+
|
|
102
|
+
/* Some dbo sorting was done to make sure this will work */
|
|
103
|
+
if (dbo[tableName].update) {
|
|
104
|
+
subHandlers = {
|
|
105
|
+
...subHandlers,
|
|
106
|
+
update: function (newData: AnyObject, updateParams: UpdateParams) {
|
|
107
|
+
return dbo[tableName].update(param1, newData, updateParams);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (dbo[tableName].delete) {
|
|
112
|
+
subHandlers = {
|
|
113
|
+
...subHandlers,
|
|
114
|
+
delete: function (deleteParams: DeleteParams) {
|
|
115
|
+
return dbo[tableName].delete(param1, deleteParams);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return Object.freeze(subHandlers);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const existing = Object.entries(subscriptions).find(([ch, s]) => {
|
|
123
|
+
return (
|
|
124
|
+
s.tableName === tableName &&
|
|
125
|
+
s.command === command &&
|
|
126
|
+
isEqual(s.param1 || {}, param1 || {}) &&
|
|
127
|
+
isEqual(s.param2 || {}, param2 || {})
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (existing) {
|
|
132
|
+
const existingCh = existing[0];
|
|
133
|
+
existing[1].handlers.push(onChange);
|
|
134
|
+
existing[1].errorHandlers.push(_onError);
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
if (subscriptions[existingCh]?.lastData) {
|
|
137
|
+
onChange(subscriptions[existingCh]?.lastData)
|
|
138
|
+
}
|
|
139
|
+
}, 10)
|
|
140
|
+
return makeHandler(existingCh, existing[1].unsubChannel);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const { channelName, channelNameReady, channelNameUnsubscribe } = await addServerSub({ tableName, command, param1, param2 })
|
|
144
|
+
|
|
145
|
+
const onCall = function (data: any) {
|
|
146
|
+
/* TO DO: confirm receiving data or server will unsubscribe */
|
|
147
|
+
// if(cb) cb(true);
|
|
148
|
+
const sub = subscriptions[channelName];
|
|
149
|
+
if (sub) {
|
|
150
|
+
if (data.data) {
|
|
151
|
+
sub.lastData = data.data;
|
|
152
|
+
sub.handlers.forEach(h => {
|
|
153
|
+
h(data.data);
|
|
154
|
+
});
|
|
155
|
+
} else if (data.err) {
|
|
156
|
+
sub.errorHandlers.forEach(h => {
|
|
157
|
+
h?.(data.err);
|
|
158
|
+
});
|
|
159
|
+
} else {
|
|
160
|
+
console.error("INTERNAL ERROR: Unexpected data format from subscription: ", data)
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
console.warn("Orphaned subscription: ", channelName)
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const onError = _onError || function (err: any) { console.error(`Uncaught error within running subscription \n ${channelName}`, err) }
|
|
167
|
+
|
|
168
|
+
socket.on(channelName, onCall);
|
|
169
|
+
subscriptions[channelName] = {
|
|
170
|
+
lastData: undefined,
|
|
171
|
+
tableName,
|
|
172
|
+
command,
|
|
173
|
+
param1,
|
|
174
|
+
param2,
|
|
175
|
+
onCall,
|
|
176
|
+
unsubChannel: channelNameUnsubscribe,
|
|
177
|
+
handlers: [onChange],
|
|
178
|
+
errorHandlers: [onError],
|
|
179
|
+
reAttach: async () => {
|
|
180
|
+
await removeServerSub(channelNameUnsubscribe).catch(console.error);
|
|
181
|
+
await addServerSub({ tableName, command, param1, param2 });
|
|
182
|
+
socket.emit(channelNameReady, { now: Date.now() });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
socket.emit(channelNameReady, { now: Date.now() });
|
|
186
|
+
return makeHandler(channelName, channelNameUnsubscribe);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const reAttachAll = async () => {
|
|
190
|
+
for await (const s of Object.values(subscriptions)) {
|
|
191
|
+
try {
|
|
192
|
+
await s.reAttach();
|
|
193
|
+
} catch (err) {
|
|
194
|
+
console.error("There was an issue reconnecting old subscriptions", err, s)
|
|
195
|
+
Object.values(s.errorHandlers).forEach(h => h?.(err));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
addSub,
|
|
202
|
+
subscriptions,
|
|
203
|
+
addServerSub,
|
|
204
|
+
_unsubscribe,
|
|
205
|
+
reAttachAll,
|
|
206
|
+
}
|
|
207
|
+
}
|
package/package.json
CHANGED