@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.
@@ -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":"AAMA,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;AA8DD,eAAO,MAAM,sBAAsB,GAAI,QAAQ,mBAAmB,GAAG,IAAI,SAGxE,CAAA;AAED,eAAO,MAAM,aAAa,GAAU,WAAW,MAAM,EAAE,SAAS;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,eAAe,CAaxG,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,CAqCvD,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,qBAAqB,QAAa,OAAO,CAAC,IAAI,CAI1D,CAAA"}
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"}
@@ -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;AA2K7F,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,KAAG,IAM3C,CAAA;AAoED,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"}
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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=wsClient.sync.test.d.ts.map
@@ -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;AAKvB,eAAO,MAAM,cAAc;;;;;;;;EAAgB,CAAA;AAC3C,eAAO,MAAM,SAAS;;SAGigI,CAAC;;;;;EAHv/H,CAAA;AACjC,eAAO,MAAM,WAAW;;iCAAa,CAAA;AACrC,eAAO,MAAM,WAAW,qBAAwB,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 unwrapDefault = (mod) => mod?.default ?? mod;
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
- let prefix = "rb/";
20
- if (storeConfig.appName) prefix += `${storeConfig.appName}/`;
21
- prefix += `${storeConfig.tenantId}/`;
22
- return prefix;
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 dbKey = `${prefix}${options.uid}/${modelName}`;
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
- const db = new PouchDB(`${options.uid}/${modelName}`, { adapter: "indexeddb", revs_limit: 1 });
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 < bVal) return -1 * dir;
140
- if (aVal > bVal) return 1 * dir;
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
- if (!Array.isArray(data)) return;
282
- void updateDocs(modelName, data, currentUid).catch(() => {
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
- destroy_all,
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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/client",
3
- "version": "0.329.0",
3
+ "version": "0.330.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"