@rpcbase/client 0.329.0 → 0.330.0
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/rts/pouchStore.d.ts +6 -0
- package/dist/rts/pouchStore.d.ts.map +1 -1
- package/dist/rts/wsClient.d.ts +2 -0
- package/dist/rts/wsClient.d.ts.map +1 -1
- package/dist/rts/wsClient.sync.test.d.ts +2 -0
- package/dist/rts/wsClient.sync.test.d.ts.map +1 -0
- package/dist/rts.d.ts +2 -23
- package/dist/rts.d.ts.map +1 -1
- package/dist/rts.js +273 -19
- package/package.json +1 -1
package/dist/rts/pouchStore.d.ts
CHANGED
|
@@ -34,6 +34,12 @@ export declare const runQuery: <T extends Record<string, unknown>>({ modelName,
|
|
|
34
34
|
export declare const updateDocs: (modelName: string, data: Array<Record<string, unknown> & {
|
|
35
35
|
_id: string;
|
|
36
36
|
}>, uid: string) => Promise<void>;
|
|
37
|
+
export declare const deleteDocs: (modelName: string, ids: string[], uid: string) => Promise<void>;
|
|
38
|
+
export declare const destroyCollection: (modelName: string, uid: string) => Promise<void>;
|
|
39
|
+
export declare const resetRtsPouchStore: ({ tenantId, appName }: {
|
|
40
|
+
tenantId: string;
|
|
41
|
+
appName?: string;
|
|
42
|
+
}) => string;
|
|
37
43
|
export declare const destroyAllCollections: () => Promise<void>;
|
|
38
44
|
export {};
|
|
39
45
|
//# sourceMappingURL=pouchStore.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pouchStore.d.ts","sourceRoot":"","sources":["../../src/rts/pouchStore.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pouchStore.d.ts","sourceRoot":"","sources":["../../src/rts/pouchStore.ts"],"names":[],"mappings":"AAOA,KAAK,eAAe,GAAG;IACrB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAA;KAAE,CAAC,CAAA;IACxF,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/D,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CAChC,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,OAAO,CAAA;CAChB,CAAA;AA8ID,eAAO,MAAM,sBAAsB,GAAI,QAAQ,mBAAmB,GAAG,IAAI,SAIxE,CAAA;AAED,eAAO,MAAM,aAAa,GAAU,WAAW,MAAM,EAAE,SAAS;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,eAAe,CAexG,CAAA;AAqED,eAAO,MAAM,QAAQ,GAAU,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,gCAI/D;IACD,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,OAAO,EAAE,oBAAoB,CAAA;CAC9B,KAAG,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,CA8CvD,CAAA;AAED,eAAO,MAAM,UAAU,GACrB,WAAW,MAAM,EACjB,MAAM,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,EACtD,KAAK,MAAM,KACV,OAAO,CAAC,IAAI,CAqCd,CAAA;AAED,eAAO,MAAM,UAAU,GAAU,WAAW,MAAM,EAAE,KAAK,MAAM,EAAE,EAAE,KAAK,MAAM,KAAG,OAAO,CAAC,IAAI,CAsB5F,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAU,WAAW,MAAM,EAAE,KAAK,MAAM,KAAG,OAAO,CAAC,IAAI,CAOpF,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,uBAAuB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,KAAG,MA4ClG,CAAA;AAED,eAAO,MAAM,qBAAqB,QAAa,OAAO,CAAC,IAAI,CAI1D,CAAA"}
|
package/dist/rts/wsClient.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export type RtsConnectOptions = {
|
|
|
19
19
|
path?: string;
|
|
20
20
|
appName?: string;
|
|
21
21
|
configureStore?: boolean;
|
|
22
|
+
syncChanges?: boolean;
|
|
22
23
|
reconnect?: {
|
|
23
24
|
attempts?: number;
|
|
24
25
|
delayMs?: number;
|
|
@@ -27,6 +28,7 @@ export type RtsConnectOptions = {
|
|
|
27
28
|
};
|
|
28
29
|
type QueryCallback = (error: unknown | null, data: unknown, context: RtsQueryContext) => void;
|
|
29
30
|
export declare const addLocalTxn: (txnId: string) => void;
|
|
31
|
+
export declare const syncRtsChanges: (tenantId: string, uid: string, options?: Pick<RtsConnectOptions, "appName">) => Promise<void>;
|
|
30
32
|
export declare const connect: (tenantId: string, uid: string, options?: RtsConnectOptions) => Promise<void>;
|
|
31
33
|
export declare const disconnect: () => void;
|
|
32
34
|
export declare const reconnect: (tenantId: string, uid: string, options?: RtsConnectOptions) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wsClient.d.ts","sourceRoot":"","sources":["../../src/rts/wsClient.ts"],"names":[],"mappings":"AAGA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEzC,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,SAAS,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,sBAAsB,GAAG,oBAAoB,CAAA;AAE3E,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,SAAS,CAAC,EAAE;QACV,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;CACF,CAAA;AAED,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"wsClient.d.ts","sourceRoot":"","sources":["../../src/rts/wsClient.ts"],"names":[],"mappings":"AAGA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEzC,MAAM,MAAM,sBAAsB,GAAG;IACnC,MAAM,EAAE,SAAS,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,sBAAsB,GAAG,oBAAoB,CAAA;AAE3E,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,SAAS,CAAC,EAAE;QACV,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;CACF,CAAA;AAED,KAAK,aAAa,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,KAAK,IAAI,CAAA;AAuL7F,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,KAAG,IAM3C,CAAA;AA8DD,eAAO,MAAM,cAAc,GAAU,UAAU,MAAM,EAAE,KAAK,MAAM,EAAE,UAAS,IAAI,CAAC,iBAAiB,EAAE,SAAS,CAAM,KAAG,OAAO,CAAC,IAAI,CAkElI,CAAA;AAoFD,eAAO,MAAM,OAAO,GAAI,UAAU,MAAM,EAAE,KAAK,MAAM,EAAE,UAAS,iBAAsB,KAAG,OAAO,CAAC,IAAI,CAEpG,CAAA;AAED,eAAO,MAAM,UAAU,QAAO,IAY7B,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,UAAU,MAAM,EAAE,KAAK,MAAM,EAAE,UAAS,iBAAsB,KAAG,OAAO,CAAC,IAAI,CAGtG,CAAA;AAED,eAAO,MAAM,aAAa,GACxB,WAAW,MAAM,EACjB,OAAO,UAAU,EACjB,oBAAoB,eAAe,GAAG,aAAa,EACnD,gBAAgB,aAAa,KAC5B,CAAC,MAAM,IAAI,CAAC,GAAG,SAsDjB,CAAA;AAED,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,EAAE,UAAU,OAAO,KAAG,IAE9D,CAAA;AAED,eAAO,MAAM,SAAS,GAAI,OAAO,MAAM,EAAE,UAAU,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAU1F,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wsClient.sync.test.d.ts","sourceRoot":"","sources":["../../src/rts/wsClient.sync.test.ts"],"names":[],"mappings":""}
|
package/dist/rts.d.ts
CHANGED
|
@@ -1,25 +1,4 @@
|
|
|
1
|
-
export { configureRtsPouchStore, destroyAllCollections, getCollection, runQuery, updateDocs, type RtsPouchQueryContext, type RtsPouchQueryOptions, type RtsPouchStoreConfig, } from './rts/pouchStore';
|
|
2
|
-
export { addLocalTxn, connect, disconnect, onMessage, reconnect, registerQuery, sendMessage, type RtsConnectOptions, type RtsQueryContext, type RtsQueryOptions, } from './rts/wsClient';
|
|
1
|
+
export { configureRtsPouchStore, destroyAllCollections, destroyCollection, deleteDocs, getCollection, resetRtsPouchStore, runQuery, updateDocs, type RtsPouchQueryContext, type RtsPouchQueryOptions, type RtsPouchStoreConfig, } from './rts/pouchStore';
|
|
2
|
+
export { addLocalTxn, connect, disconnect, onMessage, reconnect, registerQuery, sendMessage, syncRtsChanges, type RtsConnectOptions, type RtsQueryContext, type RtsQueryOptions, } from './rts/wsClient';
|
|
3
3
|
export { useQuery, type UseRtsQueryOptions, type UseRtsQueryResult, } from './rts/useQuery';
|
|
4
|
-
export declare const get_collection: (modelName: string, options: {
|
|
5
|
-
uid: string;
|
|
6
|
-
}) => Promise<{
|
|
7
|
-
find: (options: Record<string, unknown>) => Promise<{
|
|
8
|
-
docs: Record<string, unknown>[];
|
|
9
|
-
}>;
|
|
10
|
-
bulkDocs: (docs: Record<string, unknown>[]) => Promise<unknown>;
|
|
11
|
-
destroy: () => Promise<unknown>;
|
|
12
|
-
}>;
|
|
13
|
-
export declare const run_query: <T extends Record<string, unknown>>({ modelName, query, options, }: {
|
|
14
|
-
modelName: string;
|
|
15
|
-
query?: Record<string, unknown>;
|
|
16
|
-
options: import('./rts/pouchStore').RtsPouchQueryOptions;
|
|
17
|
-
}) => Promise<{
|
|
18
|
-
data: T[];
|
|
19
|
-
context: import('./rts/pouchStore').RtsPouchQueryContext;
|
|
20
|
-
}>;
|
|
21
|
-
export declare const update_docs: (modelName: string, data: Array<Record<string, unknown> & {
|
|
22
|
-
_id: string;
|
|
23
|
-
}>, uid: string) => Promise<void>;
|
|
24
|
-
export declare const destroy_all: () => Promise<void>;
|
|
25
4
|
//# sourceMappingURL=rts.d.ts.map
|
package/dist/rts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rts.d.ts","sourceRoot":"","sources":["../src/rts.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,aAAa,EACb,QAAQ,EACR,UAAU,EACV,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EACL,WAAW,EACX,OAAO,EACP,UAAU,EACV,SAAS,EACT,SAAS,EACT,aAAa,EACb,WAAW,EACX,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,QAAQ,EACR,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACvB,MAAM,gBAAgB,CAAA
|
|
1
|
+
{"version":3,"file":"rts.d.ts","sourceRoot":"","sources":["../src/rts.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,QAAQ,EACR,UAAU,EACV,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EACL,WAAW,EACX,OAAO,EACP,UAAU,EACV,SAAS,EACT,SAAS,EACT,aAAa,EACb,WAAW,EACX,cAAc,EACd,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EACL,QAAQ,EACR,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACvB,MAAM,gBAAgB,CAAA"}
|
package/dist/rts.js
CHANGED
|
@@ -5,21 +5,89 @@ let storeConfig = null;
|
|
|
5
5
|
let pouchDbPromise = null;
|
|
6
6
|
let lastAppliedPrefix = null;
|
|
7
7
|
const collections = /* @__PURE__ */ new Map();
|
|
8
|
-
const
|
|
8
|
+
const dbNamesByPrefix = /* @__PURE__ */ new Map();
|
|
9
|
+
const unwrapDefault = (mod) => {
|
|
10
|
+
if (!mod || typeof mod !== "object") return mod;
|
|
11
|
+
const maybe = mod;
|
|
12
|
+
return maybe.default ?? mod;
|
|
13
|
+
};
|
|
9
14
|
const ensureBrowser$1 = () => {
|
|
10
15
|
if (typeof window === "undefined") {
|
|
11
16
|
throw new Error("RTS PouchDB store can only be used in the browser");
|
|
12
17
|
}
|
|
13
18
|
};
|
|
19
|
+
const computeBasePrefix = ({ tenantId, appName }) => {
|
|
20
|
+
let prefix = "rb/";
|
|
21
|
+
if (appName) prefix += `${appName}/`;
|
|
22
|
+
prefix += `${tenantId}/`;
|
|
23
|
+
return prefix;
|
|
24
|
+
};
|
|
25
|
+
const getDbNamesKey = (prefix) => `rb:rts:pouchDbs:${prefix}`;
|
|
26
|
+
const getPrefixOverrideKey = ({ tenantId, appName }) => `rb:rts:pouchPrefix:${appName ?? ""}:${tenantId}`;
|
|
27
|
+
const readPrefixOverride = ({ tenantId, appName }) => {
|
|
28
|
+
try {
|
|
29
|
+
const value = window.localStorage.getItem(getPrefixOverrideKey({ tenantId, appName }));
|
|
30
|
+
if (!value) return null;
|
|
31
|
+
if (!value.endsWith("/")) return `${value}/`;
|
|
32
|
+
return value;
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
14
37
|
const getPrefix = () => {
|
|
15
38
|
if (!storeConfig) {
|
|
16
39
|
throw new Error("RTS PouchDB store is not configured");
|
|
17
40
|
}
|
|
18
41
|
if (storeConfig.prefix) return storeConfig.prefix;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
42
|
+
const basePrefix = computeBasePrefix({ tenantId: storeConfig.tenantId, appName: storeConfig.appName });
|
|
43
|
+
const override = readPrefixOverride({ tenantId: storeConfig.tenantId, appName: storeConfig.appName });
|
|
44
|
+
return override ?? basePrefix;
|
|
45
|
+
};
|
|
46
|
+
const loadDbNames = (prefix) => {
|
|
47
|
+
const existing = dbNamesByPrefix.get(prefix);
|
|
48
|
+
if (existing) return existing;
|
|
49
|
+
const names = /* @__PURE__ */ new Set();
|
|
50
|
+
try {
|
|
51
|
+
const raw = window.localStorage.getItem(getDbNamesKey(prefix));
|
|
52
|
+
if (raw) {
|
|
53
|
+
const parsed = JSON.parse(raw);
|
|
54
|
+
if (Array.isArray(parsed)) {
|
|
55
|
+
for (const value of parsed) {
|
|
56
|
+
if (typeof value === "string" && value) names.add(value);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
return names;
|
|
62
|
+
}
|
|
63
|
+
dbNamesByPrefix.set(prefix, names);
|
|
64
|
+
return names;
|
|
65
|
+
};
|
|
66
|
+
const persistDbNames = (prefix, names) => {
|
|
67
|
+
try {
|
|
68
|
+
if (!names.size) {
|
|
69
|
+
window.localStorage.removeItem(getDbNamesKey(prefix));
|
|
70
|
+
dbNamesByPrefix.delete(prefix);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
window.localStorage.setItem(getDbNamesKey(prefix), JSON.stringify(Array.from(names)));
|
|
74
|
+
dbNamesByPrefix.set(prefix, names);
|
|
75
|
+
} catch {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const registerDbName = (prefix, dbName) => {
|
|
80
|
+
if (!prefix || !dbName) return;
|
|
81
|
+
const names = loadDbNames(prefix);
|
|
82
|
+
if (names.has(dbName)) return;
|
|
83
|
+
names.add(dbName);
|
|
84
|
+
persistDbNames(prefix, names);
|
|
85
|
+
};
|
|
86
|
+
const unregisterDbName = (prefix, dbName) => {
|
|
87
|
+
if (!prefix || !dbName) return;
|
|
88
|
+
const names = loadDbNames(prefix);
|
|
89
|
+
if (!names.delete(dbName)) return;
|
|
90
|
+
persistDbNames(prefix, names);
|
|
23
91
|
};
|
|
24
92
|
const getPouchDb = async () => {
|
|
25
93
|
ensureBrowser$1();
|
|
@@ -47,15 +115,18 @@ const applyPrefix = (PouchDB) => {
|
|
|
47
115
|
const configureRtsPouchStore = (config) => {
|
|
48
116
|
storeConfig = config;
|
|
49
117
|
lastAppliedPrefix = null;
|
|
118
|
+
collections.clear();
|
|
50
119
|
};
|
|
51
120
|
const getCollection = async (modelName, options) => {
|
|
52
121
|
const PouchDB = await getPouchDb();
|
|
53
122
|
applyPrefix(PouchDB);
|
|
54
123
|
const prefix = getPrefix();
|
|
55
|
-
const
|
|
124
|
+
const dbName = `${options.uid}/${modelName}`;
|
|
125
|
+
const dbKey = `${prefix}${dbName}`;
|
|
56
126
|
const existing = collections.get(dbKey);
|
|
57
127
|
if (existing) return existing;
|
|
58
|
-
|
|
128
|
+
registerDbName(prefix, dbName);
|
|
129
|
+
const db = new PouchDB(dbName, { adapter: "indexeddb", revs_limit: 1 });
|
|
59
130
|
collections.set(dbKey, db);
|
|
60
131
|
return db;
|
|
61
132
|
};
|
|
@@ -136,8 +207,16 @@ const runQuery = async ({
|
|
|
136
207
|
const dir = options.sort[key];
|
|
137
208
|
const aVal = a[key];
|
|
138
209
|
const bVal = b[key];
|
|
139
|
-
if (aVal
|
|
140
|
-
|
|
210
|
+
if (typeof aVal === "number" && typeof bVal === "number") {
|
|
211
|
+
if (aVal < bVal) return -1 * dir;
|
|
212
|
+
if (aVal > bVal) return 1 * dir;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (typeof aVal === "string" && typeof bVal === "string") {
|
|
216
|
+
if (aVal < bVal) return -1 * dir;
|
|
217
|
+
if (aVal > bVal) return 1 * dir;
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
141
220
|
}
|
|
142
221
|
return 0;
|
|
143
222
|
});
|
|
@@ -175,12 +254,76 @@ const updateDocs = async (modelName, data, uid) => {
|
|
|
175
254
|
});
|
|
176
255
|
await collection.bulkDocs(newDocs);
|
|
177
256
|
};
|
|
257
|
+
const deleteDocs = async (modelName, ids, uid) => {
|
|
258
|
+
const collection = await getCollection(modelName, { uid });
|
|
259
|
+
const allIds = ids.map((id) => String(id ?? "")).filter(Boolean);
|
|
260
|
+
if (!allIds.length) return;
|
|
261
|
+
const { docs: currentDocs } = await collection.find({
|
|
262
|
+
selector: { _id: { $in: allIds } },
|
|
263
|
+
fields: ["_id", "_rev"],
|
|
264
|
+
limit: allIds.length
|
|
265
|
+
});
|
|
266
|
+
const deletions = currentDocs.map((doc) => ({
|
|
267
|
+
_id: String(doc?._id ?? ""),
|
|
268
|
+
_rev: doc?._rev,
|
|
269
|
+
_deleted: true
|
|
270
|
+
})).filter((doc) => doc._id && typeof doc._rev === "string" && doc._rev);
|
|
271
|
+
if (!deletions.length) return;
|
|
272
|
+
await collection.bulkDocs(deletions);
|
|
273
|
+
};
|
|
274
|
+
const destroyCollection = async (modelName, uid) => {
|
|
275
|
+
const collection = await getCollection(modelName, { uid });
|
|
276
|
+
const prefix = getPrefix();
|
|
277
|
+
const dbName = `${uid}/${modelName}`;
|
|
278
|
+
collections.delete(`${prefix}${dbName}`);
|
|
279
|
+
unregisterDbName(prefix, dbName);
|
|
280
|
+
await collection.destroy();
|
|
281
|
+
};
|
|
282
|
+
const resetRtsPouchStore = ({ tenantId, appName }) => {
|
|
283
|
+
ensureBrowser$1();
|
|
284
|
+
const basePrefix = computeBasePrefix({ tenantId, appName });
|
|
285
|
+
const oldPrefix = readPrefixOverride({ tenantId, appName }) ?? basePrefix;
|
|
286
|
+
const dbNames = Array.from(loadDbNames(oldPrefix));
|
|
287
|
+
const openDbs = Array.from(collections.entries()).filter(([key]) => key.startsWith(oldPrefix)).map(([, db]) => db);
|
|
288
|
+
void (async () => {
|
|
289
|
+
const remaining = new Set(dbNames);
|
|
290
|
+
await Promise.all(openDbs.map((db) => db.destroy().catch(() => {
|
|
291
|
+
})));
|
|
292
|
+
if (remaining.size) {
|
|
293
|
+
const PouchDB = await getPouchDb();
|
|
294
|
+
const PouchDBForPrefix = PouchDB.defaults?.({}) ?? PouchDB;
|
|
295
|
+
PouchDBForPrefix.prefix = oldPrefix;
|
|
296
|
+
await Promise.all(Array.from(remaining).map(async (name) => {
|
|
297
|
+
const db = new PouchDBForPrefix(name, { adapter: "indexeddb", revs_limit: 1 });
|
|
298
|
+
await db.destroy().then(() => {
|
|
299
|
+
remaining.delete(name);
|
|
300
|
+
}).catch(() => {
|
|
301
|
+
});
|
|
302
|
+
}));
|
|
303
|
+
}
|
|
304
|
+
if (remaining.size) {
|
|
305
|
+
persistDbNames(oldPrefix, remaining);
|
|
306
|
+
} else {
|
|
307
|
+
persistDbNames(oldPrefix, /* @__PURE__ */ new Set());
|
|
308
|
+
}
|
|
309
|
+
})();
|
|
310
|
+
const newPrefix = `${basePrefix}reset-${Date.now().toString(16)}/`;
|
|
311
|
+
try {
|
|
312
|
+
window.localStorage.setItem(getPrefixOverrideKey({ tenantId, appName }), newPrefix);
|
|
313
|
+
} catch {
|
|
314
|
+
return newPrefix;
|
|
315
|
+
}
|
|
316
|
+
lastAppliedPrefix = null;
|
|
317
|
+
collections.clear();
|
|
318
|
+
return newPrefix;
|
|
319
|
+
};
|
|
178
320
|
const destroyAllCollections = async () => {
|
|
179
321
|
const dbs = Array.from(collections.values());
|
|
180
322
|
await Promise.all(dbs.map((db) => db.destroy()));
|
|
181
323
|
collections.clear();
|
|
182
324
|
};
|
|
183
325
|
const TENANT_ID_QUERY_PARAM = "rb-tenant-id";
|
|
326
|
+
const RTS_CHANGES_ROUTE = "/api/rb/rts/changes";
|
|
184
327
|
const MAX_TXN_BUF = 2048;
|
|
185
328
|
let socket = null;
|
|
186
329
|
let connectPromise = null;
|
|
@@ -194,6 +337,8 @@ const subscriptions = /* @__PURE__ */ new Map();
|
|
|
194
337
|
const messageCallbacks = /* @__PURE__ */ new Map();
|
|
195
338
|
let reconnectTimer = null;
|
|
196
339
|
let reconnectAttempts = 0;
|
|
340
|
+
let syncPromise = null;
|
|
341
|
+
let syncKey = null;
|
|
197
342
|
const ensureBrowser = () => {
|
|
198
343
|
if (typeof window === "undefined") {
|
|
199
344
|
throw new Error("RTS websocket client can only be used in the browser");
|
|
@@ -278,8 +423,12 @@ const handleQueryPayload = (payload) => {
|
|
|
278
423
|
}
|
|
279
424
|
for (const cb of callbacks) cb(null, data, context);
|
|
280
425
|
if (!currentUid) return;
|
|
281
|
-
|
|
282
|
-
|
|
426
|
+
const docs = Array.isArray(data) ? data.filter((doc) => {
|
|
427
|
+
if (!doc || typeof doc !== "object") return false;
|
|
428
|
+
return typeof doc._id === "string";
|
|
429
|
+
}) : [];
|
|
430
|
+
if (!docs.length) return;
|
|
431
|
+
void updateDocs(modelName, docs, currentUid).catch(() => {
|
|
283
432
|
});
|
|
284
433
|
};
|
|
285
434
|
const handleEvent = (payload) => {
|
|
@@ -311,6 +460,114 @@ const addLocalTxn = (txnId) => {
|
|
|
311
460
|
localTxnBuf.shift();
|
|
312
461
|
}
|
|
313
462
|
};
|
|
463
|
+
const getSyncStorageKey = ({ tenantId, uid, appName }) => `rb:rts:changesSeq:${appName ?? ""}:${tenantId}:${uid}`;
|
|
464
|
+
const readStoredSeq = (key) => {
|
|
465
|
+
try {
|
|
466
|
+
const raw = window.localStorage.getItem(key);
|
|
467
|
+
const num = raw ? Number(raw) : 0;
|
|
468
|
+
return Number.isFinite(num) && num >= 0 ? Math.floor(num) : 0;
|
|
469
|
+
} catch {
|
|
470
|
+
return 0;
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
const writeStoredSeq = (key, value) => {
|
|
474
|
+
try {
|
|
475
|
+
window.localStorage.setItem(key, String(Math.max(0, Math.floor(value))));
|
|
476
|
+
} catch {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
const applyChangeBatch = async (changes, uid) => {
|
|
481
|
+
const resetModels = /* @__PURE__ */ new Set();
|
|
482
|
+
const deletesByModel = /* @__PURE__ */ new Map();
|
|
483
|
+
for (const change of changes) {
|
|
484
|
+
const modelName = typeof change.modelName === "string" ? change.modelName : "";
|
|
485
|
+
if (!modelName) continue;
|
|
486
|
+
if (change.op === "reset_model") {
|
|
487
|
+
resetModels.add(modelName);
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
if (change.op === "delete") {
|
|
491
|
+
const docId = typeof change.docId === "string" ? change.docId : "";
|
|
492
|
+
if (!docId) continue;
|
|
493
|
+
const existing = deletesByModel.get(modelName) ?? [];
|
|
494
|
+
existing.push(docId);
|
|
495
|
+
deletesByModel.set(modelName, existing);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
for (const modelName of resetModels) {
|
|
499
|
+
await destroyCollection(modelName, uid).catch(() => {
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
for (const [modelName, ids] of deletesByModel.entries()) {
|
|
503
|
+
if (resetModels.has(modelName)) continue;
|
|
504
|
+
await deleteDocs(modelName, ids, uid).catch(() => {
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
const syncRtsChanges = async (tenantId, uid, options = {}) => {
|
|
509
|
+
ensureBrowser();
|
|
510
|
+
if (!tenantId || !uid) return;
|
|
511
|
+
const storageKey = getSyncStorageKey({ tenantId, uid, appName: options.appName });
|
|
512
|
+
let sinceSeq = readStoredSeq(storageKey);
|
|
513
|
+
for (let i = 0; i < 32; i += 1) {
|
|
514
|
+
const url = `${RTS_CHANGES_ROUTE}?${TENANT_ID_QUERY_PARAM}=${encodeURIComponent(tenantId)}`;
|
|
515
|
+
const response = await fetch(url, {
|
|
516
|
+
method: "POST",
|
|
517
|
+
credentials: "include",
|
|
518
|
+
headers: { "Content-Type": "application/json" },
|
|
519
|
+
body: JSON.stringify({ sinceSeq, limit: 2e3 })
|
|
520
|
+
});
|
|
521
|
+
if (!response.ok) return;
|
|
522
|
+
const payload = await response.json().catch(() => null);
|
|
523
|
+
if (!payload || typeof payload !== "object") return;
|
|
524
|
+
const ok = payload.ok;
|
|
525
|
+
if (ok !== true) return;
|
|
526
|
+
const latestSeq = Number(payload.latestSeq ?? 0);
|
|
527
|
+
const needsFullResync = Boolean(payload.needsFullResync);
|
|
528
|
+
if (needsFullResync) {
|
|
529
|
+
resetRtsPouchStore({ tenantId, appName: options.appName });
|
|
530
|
+
writeStoredSeq(storageKey, latestSeq);
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
const changesRaw = payload.changes;
|
|
534
|
+
const changes = Array.isArray(changesRaw) ? changesRaw : [];
|
|
535
|
+
const normalized = changes.map((c) => {
|
|
536
|
+
if (!c || typeof c !== "object") return null;
|
|
537
|
+
const obj = c;
|
|
538
|
+
const seq = Number(obj.seq ?? 0);
|
|
539
|
+
const modelName = typeof obj.modelName === "string" ? obj.modelName : String(obj.modelName ?? "");
|
|
540
|
+
const op = obj.op === "reset_model" ? "reset_model" : "delete";
|
|
541
|
+
const docId = typeof obj.docId === "string" && obj.docId ? obj.docId : obj.docId ? String(obj.docId) : void 0;
|
|
542
|
+
return { seq, modelName, op, ...docId ? { docId } : {} };
|
|
543
|
+
}).filter((c) => c !== null).filter(
|
|
544
|
+
(c) => Number.isFinite(c.seq) && c.seq > 0 && c.modelName && (c.op === "reset_model" || !!c.docId)
|
|
545
|
+
);
|
|
546
|
+
if (!normalized.length) {
|
|
547
|
+
writeStoredSeq(storageKey, latestSeq);
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
await applyChangeBatch(normalized, uid);
|
|
551
|
+
const lastSeq = normalized.reduce((max, c) => c.seq > max ? c.seq : max, sinceSeq);
|
|
552
|
+
sinceSeq = lastSeq;
|
|
553
|
+
writeStoredSeq(storageKey, sinceSeq);
|
|
554
|
+
if (latestSeq > 0 && sinceSeq >= latestSeq) {
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
const ensureSynced = (tenantId, uid, options) => {
|
|
560
|
+
if (options.syncChanges === false) return;
|
|
561
|
+
const key = `${options.appName ?? ""}:${tenantId}:${uid}`;
|
|
562
|
+
if (syncPromise && syncKey === key) return;
|
|
563
|
+
syncKey = key;
|
|
564
|
+
syncPromise = syncRtsChanges(tenantId, uid, { appName: options.appName }).catch(() => {
|
|
565
|
+
}).finally(() => {
|
|
566
|
+
if (syncKey === key) {
|
|
567
|
+
syncPromise = null;
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
};
|
|
314
571
|
const connectInternal = (tenantId, uid, options, { resetReconnectAttempts }) => {
|
|
315
572
|
ensureBrowser();
|
|
316
573
|
if (!tenantId) return Promise.resolve();
|
|
@@ -321,6 +578,7 @@ const connectInternal = (tenantId, uid, options, { resetReconnectAttempts }) =>
|
|
|
321
578
|
if (options.configureStore !== false) {
|
|
322
579
|
configureRtsPouchStore({ tenantId, appName: options.appName });
|
|
323
580
|
}
|
|
581
|
+
ensureSynced(tenantId, uid, options);
|
|
324
582
|
if (socket && (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING)) {
|
|
325
583
|
return connectPromise ?? Promise.resolve();
|
|
326
584
|
}
|
|
@@ -509,26 +767,22 @@ const useQuery = (modelName, query = {}, options = {}) => {
|
|
|
509
767
|
[data, source, error, loading]
|
|
510
768
|
);
|
|
511
769
|
};
|
|
512
|
-
const get_collection = getCollection;
|
|
513
|
-
const run_query = runQuery;
|
|
514
|
-
const update_docs = updateDocs;
|
|
515
|
-
const destroy_all = destroyAllCollections;
|
|
516
770
|
export {
|
|
517
771
|
addLocalTxn,
|
|
518
772
|
configureRtsPouchStore,
|
|
519
773
|
connect,
|
|
774
|
+
deleteDocs,
|
|
520
775
|
destroyAllCollections,
|
|
521
|
-
|
|
776
|
+
destroyCollection,
|
|
522
777
|
disconnect,
|
|
523
778
|
getCollection,
|
|
524
|
-
get_collection,
|
|
525
779
|
onMessage,
|
|
526
780
|
reconnect,
|
|
527
781
|
registerQuery,
|
|
782
|
+
resetRtsPouchStore,
|
|
528
783
|
runQuery,
|
|
529
|
-
run_query,
|
|
530
784
|
sendMessage,
|
|
785
|
+
syncRtsChanges,
|
|
531
786
|
updateDocs,
|
|
532
|
-
update_docs,
|
|
533
787
|
useQuery
|
|
534
788
|
};
|