@rpcbase/client 0.326.0 → 0.328.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 +39 -0
- package/dist/rts/pouchStore.d.ts.map +1 -0
- package/dist/rts/useQuery.d.ts +14 -0
- package/dist/rts/useQuery.d.ts.map +1 -0
- package/dist/rts/wsClient.d.ts +37 -0
- package/dist/rts/wsClient.d.ts.map +1 -0
- package/dist/rts.d.ts +25 -0
- package/dist/rts.d.ts.map +1 -0
- package/dist/rts.js +534 -0
- package/package.json +12 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
type PouchDbDatabase = {
|
|
2
|
+
find: (options: Record<string, unknown>) => Promise<{
|
|
3
|
+
docs: Record<string, unknown>[];
|
|
4
|
+
}>;
|
|
5
|
+
bulkDocs: (docs: Record<string, unknown>[]) => Promise<unknown>;
|
|
6
|
+
destroy: () => Promise<unknown>;
|
|
7
|
+
};
|
|
8
|
+
export type RtsPouchStoreConfig = {
|
|
9
|
+
tenantId: string;
|
|
10
|
+
appName?: string;
|
|
11
|
+
prefix?: string;
|
|
12
|
+
};
|
|
13
|
+
export type RtsPouchQueryOptions = {
|
|
14
|
+
uid: string;
|
|
15
|
+
projection?: Record<string, 0 | 1>;
|
|
16
|
+
sort?: Record<string, 1 | -1>;
|
|
17
|
+
limit?: number;
|
|
18
|
+
};
|
|
19
|
+
export type RtsPouchQueryContext = {
|
|
20
|
+
source: "cache";
|
|
21
|
+
};
|
|
22
|
+
export declare const configureRtsPouchStore: (config: RtsPouchStoreConfig | null) => void;
|
|
23
|
+
export declare const getCollection: (modelName: string, options: {
|
|
24
|
+
uid: string;
|
|
25
|
+
}) => Promise<PouchDbDatabase>;
|
|
26
|
+
export declare const runQuery: <T extends Record<string, unknown>>({ modelName, query, options, }: {
|
|
27
|
+
modelName: string;
|
|
28
|
+
query?: Record<string, unknown>;
|
|
29
|
+
options: RtsPouchQueryOptions;
|
|
30
|
+
}) => Promise<{
|
|
31
|
+
data: T[];
|
|
32
|
+
context: RtsPouchQueryContext;
|
|
33
|
+
}>;
|
|
34
|
+
export declare const updateDocs: (modelName: string, data: Array<Record<string, unknown> & {
|
|
35
|
+
_id: string;
|
|
36
|
+
}>, uid: string) => Promise<void>;
|
|
37
|
+
export declare const destroyAllCollections: () => Promise<void>;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=pouchStore.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RtsQueryContext, RtsQueryOptions } from './wsClient';
|
|
2
|
+
type JsonObject = Record<string, unknown>;
|
|
3
|
+
export type UseRtsQueryOptions = RtsQueryOptions & {
|
|
4
|
+
skipLocal?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export type UseRtsQueryResult<T> = {
|
|
7
|
+
data: T[] | undefined;
|
|
8
|
+
source: RtsQueryContext["source"] | undefined;
|
|
9
|
+
error: unknown | undefined;
|
|
10
|
+
loading: boolean;
|
|
11
|
+
};
|
|
12
|
+
export declare const useQuery: <T extends Record<string, unknown> = Record<string, unknown>>(modelName: string, query?: JsonObject, options?: UseRtsQueryOptions) => UseRtsQueryResult<T>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=useQuery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useQuery.d.ts","sourceRoot":"","sources":["../../src/rts/useQuery.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAIlE,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEzC,MAAM,MAAM,kBAAkB,GAAG,eAAe,GAAG;IACjD,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAAI;IACjC,IAAI,EAAE,CAAC,EAAE,GAAG,SAAS,CAAA;IACrB,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAA;IAC7C,KAAK,EAAE,OAAO,GAAG,SAAS,CAAA;IAC1B,OAAO,EAAE,OAAO,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClF,WAAW,MAAM,EACjB,QAAO,UAAe,EACtB,UAAS,kBAAuB,KAC/B,iBAAiB,CAAC,CAAC,CA2FrB,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
type JsonObject = Record<string, unknown>;
|
|
2
|
+
export type RtsNetworkQueryContext = {
|
|
3
|
+
source: "network";
|
|
4
|
+
isLocal: boolean;
|
|
5
|
+
txnId?: string;
|
|
6
|
+
};
|
|
7
|
+
export type RtsCacheQueryContext = {
|
|
8
|
+
source: "cache";
|
|
9
|
+
};
|
|
10
|
+
export type RtsQueryContext = RtsNetworkQueryContext | RtsCacheQueryContext;
|
|
11
|
+
export type RtsQueryOptions = {
|
|
12
|
+
key?: string;
|
|
13
|
+
projection?: Record<string, 0 | 1>;
|
|
14
|
+
sort?: Record<string, 1 | -1>;
|
|
15
|
+
limit?: number;
|
|
16
|
+
};
|
|
17
|
+
export type RtsConnectOptions = {
|
|
18
|
+
url?: string;
|
|
19
|
+
path?: string;
|
|
20
|
+
appName?: string;
|
|
21
|
+
configureStore?: boolean;
|
|
22
|
+
reconnect?: {
|
|
23
|
+
attempts?: number;
|
|
24
|
+
delayMs?: number;
|
|
25
|
+
delayMaxMs?: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
type QueryCallback = (error: unknown | null, data: unknown, context: RtsQueryContext) => void;
|
|
29
|
+
export declare const addLocalTxn: (txnId: string) => void;
|
|
30
|
+
export declare const connect: (tenantId: string, uid: string, options?: RtsConnectOptions) => Promise<void>;
|
|
31
|
+
export declare const disconnect: () => void;
|
|
32
|
+
export declare const reconnect: (tenantId: string, uid: string, options?: RtsConnectOptions) => Promise<void>;
|
|
33
|
+
export declare const registerQuery: (modelName: string, query: JsonObject, optionsOrCallback?: RtsQueryOptions | QueryCallback, callbackMaybe?: QueryCallback) => (() => void) | undefined;
|
|
34
|
+
export declare const sendMessage: (event: string, payload?: unknown) => void;
|
|
35
|
+
export declare const onMessage: (event: string, callback: (payload: unknown) => void) => (() => void);
|
|
36
|
+
export {};
|
|
37
|
+
//# sourceMappingURL=wsClient.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/rts.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
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';
|
|
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
|
+
//# sourceMappingURL=rts.d.ts.map
|
|
@@ -0,0 +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"}
|
package/dist/rts.js
ADDED
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import { useId, useState, useRef, useEffect, useMemo } from "react";
|
|
2
|
+
const UNDERSCORE_PREFIX = "$_";
|
|
3
|
+
const DEFAULT_FIND_LIMIT = 4096;
|
|
4
|
+
let storeConfig = null;
|
|
5
|
+
let pouchDbPromise = null;
|
|
6
|
+
let lastAppliedPrefix = null;
|
|
7
|
+
const collections = /* @__PURE__ */ new Map();
|
|
8
|
+
const unwrapDefault = (mod) => mod?.default ?? mod;
|
|
9
|
+
const ensureBrowser$1 = () => {
|
|
10
|
+
if (typeof window === "undefined") {
|
|
11
|
+
throw new Error("RTS PouchDB store can only be used in the browser");
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const getPrefix = () => {
|
|
15
|
+
if (!storeConfig) {
|
|
16
|
+
throw new Error("RTS PouchDB store is not configured");
|
|
17
|
+
}
|
|
18
|
+
if (storeConfig.prefix) return storeConfig.prefix;
|
|
19
|
+
let prefix = "rb/";
|
|
20
|
+
if (storeConfig.appName) prefix += `${storeConfig.appName}/`;
|
|
21
|
+
prefix += `${storeConfig.tenantId}/`;
|
|
22
|
+
return prefix;
|
|
23
|
+
};
|
|
24
|
+
const getPouchDb = async () => {
|
|
25
|
+
ensureBrowser$1();
|
|
26
|
+
if (!pouchDbPromise) {
|
|
27
|
+
pouchDbPromise = (async () => {
|
|
28
|
+
const [core, indexedDbAdapter, findPlugin] = await Promise.all([
|
|
29
|
+
import("pouchdb-core"),
|
|
30
|
+
import("pouchdb-adapter-indexeddb"),
|
|
31
|
+
import("pouchdb-find")
|
|
32
|
+
]);
|
|
33
|
+
const PouchDB = unwrapDefault(core);
|
|
34
|
+
PouchDB.plugin(unwrapDefault(indexedDbAdapter));
|
|
35
|
+
PouchDB.plugin(unwrapDefault(findPlugin));
|
|
36
|
+
return PouchDB;
|
|
37
|
+
})();
|
|
38
|
+
}
|
|
39
|
+
return pouchDbPromise;
|
|
40
|
+
};
|
|
41
|
+
const applyPrefix = (PouchDB) => {
|
|
42
|
+
const prefix = getPrefix();
|
|
43
|
+
if (prefix === lastAppliedPrefix) return;
|
|
44
|
+
PouchDB.prefix = prefix;
|
|
45
|
+
lastAppliedPrefix = prefix;
|
|
46
|
+
};
|
|
47
|
+
const configureRtsPouchStore = (config) => {
|
|
48
|
+
storeConfig = config;
|
|
49
|
+
lastAppliedPrefix = null;
|
|
50
|
+
};
|
|
51
|
+
const getCollection = async (modelName, options) => {
|
|
52
|
+
const PouchDB = await getPouchDb();
|
|
53
|
+
applyPrefix(PouchDB);
|
|
54
|
+
const prefix = getPrefix();
|
|
55
|
+
const dbKey = `${prefix}${options.uid}/${modelName}`;
|
|
56
|
+
const existing = collections.get(dbKey);
|
|
57
|
+
if (existing) return existing;
|
|
58
|
+
const db = new PouchDB(`${options.uid}/${modelName}`, { adapter: "indexeddb", revs_limit: 1 });
|
|
59
|
+
collections.set(dbKey, db);
|
|
60
|
+
return db;
|
|
61
|
+
};
|
|
62
|
+
const replaceQueryKeys = (value, replaceKey) => {
|
|
63
|
+
if (typeof value !== "object" || value === null) {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
if (Array.isArray(value)) {
|
|
67
|
+
return value.map((item) => replaceQueryKeys(item, replaceKey));
|
|
68
|
+
}
|
|
69
|
+
const obj = value;
|
|
70
|
+
const next = Object.create(Object.getPrototypeOf(obj));
|
|
71
|
+
for (const key of Object.keys(obj)) {
|
|
72
|
+
if (/^\$/.test(key) || /\.\d+$/.test(key)) {
|
|
73
|
+
throw new Error(`replaceQueryKeys: Unexpected key format: ${key}`);
|
|
74
|
+
}
|
|
75
|
+
const newKey = replaceKey(key);
|
|
76
|
+
next[newKey] = replaceQueryKeys(obj[key], replaceKey);
|
|
77
|
+
}
|
|
78
|
+
return next;
|
|
79
|
+
};
|
|
80
|
+
const getKeys = (obj, parentKey = "") => {
|
|
81
|
+
const keys = [];
|
|
82
|
+
for (const key of Object.keys(obj)) {
|
|
83
|
+
const nextKey = parentKey ? `${parentKey}.${key}` : key;
|
|
84
|
+
const value = obj[key];
|
|
85
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
86
|
+
keys.push(...getKeys(value, nextKey));
|
|
87
|
+
} else {
|
|
88
|
+
keys.push(nextKey);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return keys;
|
|
92
|
+
};
|
|
93
|
+
const satisfiesProjection = (doc, projection) => {
|
|
94
|
+
const docKeys = new Set(getKeys(doc));
|
|
95
|
+
const projectionKeys = new Set(Object.keys(projection).filter((key) => projection[key] === 1));
|
|
96
|
+
if (!projectionKeys.has("_id")) {
|
|
97
|
+
docKeys.delete("_id");
|
|
98
|
+
}
|
|
99
|
+
if (projectionKeys.size > docKeys.size) return false;
|
|
100
|
+
for (const key of projectionKeys) {
|
|
101
|
+
if (!docKeys.has(key)) return false;
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
104
|
+
};
|
|
105
|
+
const remapDocFromStorage = (doc) => {
|
|
106
|
+
const next = {};
|
|
107
|
+
for (const [key, value] of Object.entries(doc)) {
|
|
108
|
+
const newKey = key.startsWith(UNDERSCORE_PREFIX) ? key.replace(/^\$_/, "") : key;
|
|
109
|
+
next[newKey] = value;
|
|
110
|
+
}
|
|
111
|
+
return next;
|
|
112
|
+
};
|
|
113
|
+
const runQuery = async ({
|
|
114
|
+
modelName,
|
|
115
|
+
query = {},
|
|
116
|
+
options
|
|
117
|
+
}) => {
|
|
118
|
+
const collection = await getCollection(modelName, { uid: options.uid });
|
|
119
|
+
const replacedQuery = replaceQueryKeys(
|
|
120
|
+
query,
|
|
121
|
+
(key) => key.startsWith("_") && key !== "_id" ? `${UNDERSCORE_PREFIX}${key}` : key
|
|
122
|
+
);
|
|
123
|
+
const limit = typeof options.limit === "number" ? Math.abs(options.limit) : DEFAULT_FIND_LIMIT;
|
|
124
|
+
const { docs } = await collection.find({
|
|
125
|
+
selector: replacedQuery,
|
|
126
|
+
limit
|
|
127
|
+
});
|
|
128
|
+
let mappedDocs = docs.map(({ _rev: _revIgnored, ...rest }) => remapDocFromStorage(rest));
|
|
129
|
+
if (options.projection) {
|
|
130
|
+
mappedDocs = mappedDocs.filter((doc) => satisfiesProjection(doc, options.projection));
|
|
131
|
+
}
|
|
132
|
+
if (options.sort) {
|
|
133
|
+
mappedDocs = mappedDocs.sort((a, b) => {
|
|
134
|
+
for (const key of Object.keys(options.sort)) {
|
|
135
|
+
if (!Object.hasOwn(a, key) || !Object.hasOwn(b, key)) continue;
|
|
136
|
+
const dir = options.sort[key];
|
|
137
|
+
const aVal = a[key];
|
|
138
|
+
const bVal = b[key];
|
|
139
|
+
if (aVal < bVal) return -1 * dir;
|
|
140
|
+
if (aVal > bVal) return 1 * dir;
|
|
141
|
+
}
|
|
142
|
+
return 0;
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return { data: mappedDocs, context: { source: "cache" } };
|
|
146
|
+
};
|
|
147
|
+
const updateDocs = async (modelName, data, uid) => {
|
|
148
|
+
const collection = await getCollection(modelName, { uid });
|
|
149
|
+
const allIds = data.map((doc) => doc._id).filter(Boolean);
|
|
150
|
+
if (!allIds.length) return;
|
|
151
|
+
const { docs: currentDocs } = await collection.find({
|
|
152
|
+
selector: { _id: { $in: allIds } },
|
|
153
|
+
fields: ["_id", "_rev"],
|
|
154
|
+
limit: allIds.length
|
|
155
|
+
});
|
|
156
|
+
const currentDocsById = currentDocs.reduce((acc, doc) => {
|
|
157
|
+
const id = String(doc._id ?? "");
|
|
158
|
+
if (id) acc[id] = doc;
|
|
159
|
+
return acc;
|
|
160
|
+
}, {});
|
|
161
|
+
const newDocs = data.map((mongoDoc) => {
|
|
162
|
+
const currentDoc = currentDocsById[mongoDoc._id] ?? { _id: mongoDoc._id };
|
|
163
|
+
const nextDoc = Object.entries(mongoDoc).reduce((acc, [key, value]) => {
|
|
164
|
+
const newKey = key !== "_id" && key.startsWith("_") ? `${UNDERSCORE_PREFIX}${key}` : key;
|
|
165
|
+
acc[newKey] = value;
|
|
166
|
+
return acc;
|
|
167
|
+
}, { ...currentDoc });
|
|
168
|
+
const rev = currentDoc._rev;
|
|
169
|
+
if (typeof rev === "string" && rev) {
|
|
170
|
+
nextDoc._rev = rev;
|
|
171
|
+
} else {
|
|
172
|
+
delete nextDoc._rev;
|
|
173
|
+
}
|
|
174
|
+
return nextDoc;
|
|
175
|
+
});
|
|
176
|
+
await collection.bulkDocs(newDocs);
|
|
177
|
+
};
|
|
178
|
+
const destroyAllCollections = async () => {
|
|
179
|
+
const dbs = Array.from(collections.values());
|
|
180
|
+
await Promise.all(dbs.map((db) => db.destroy()));
|
|
181
|
+
collections.clear();
|
|
182
|
+
};
|
|
183
|
+
const TENANT_ID_QUERY_PARAM = "rb-tenant-id";
|
|
184
|
+
const MAX_TXN_BUF = 2048;
|
|
185
|
+
let socket = null;
|
|
186
|
+
let connectPromise = null;
|
|
187
|
+
let explicitDisconnect = false;
|
|
188
|
+
let currentTenantId = null;
|
|
189
|
+
let currentUid = null;
|
|
190
|
+
let connectOptions = {};
|
|
191
|
+
const localTxnBuf = [];
|
|
192
|
+
const queryCallbacks = /* @__PURE__ */ new Map();
|
|
193
|
+
const subscriptions = /* @__PURE__ */ new Map();
|
|
194
|
+
const messageCallbacks = /* @__PURE__ */ new Map();
|
|
195
|
+
let reconnectTimer = null;
|
|
196
|
+
let reconnectAttempts = 0;
|
|
197
|
+
const ensureBrowser = () => {
|
|
198
|
+
if (typeof window === "undefined") {
|
|
199
|
+
throw new Error("RTS websocket client can only be used in the browser");
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
const buildSocketUrl = (tenantId, _uid, options) => {
|
|
203
|
+
if (options.url) {
|
|
204
|
+
const url = new URL(options.url);
|
|
205
|
+
url.searchParams.set(TENANT_ID_QUERY_PARAM, tenantId);
|
|
206
|
+
return url.toString();
|
|
207
|
+
}
|
|
208
|
+
const base = new URL(window.location.href);
|
|
209
|
+
base.protocol = base.protocol === "https:" ? "wss:" : "ws:";
|
|
210
|
+
base.pathname = options.path ?? "/rts";
|
|
211
|
+
base.search = "";
|
|
212
|
+
base.hash = "";
|
|
213
|
+
base.searchParams.set(TENANT_ID_QUERY_PARAM, tenantId);
|
|
214
|
+
return base.toString();
|
|
215
|
+
};
|
|
216
|
+
const computeQueryKey = (query, options) => {
|
|
217
|
+
const key = options.key ?? "";
|
|
218
|
+
const projection = options.projection ? JSON.stringify(options.projection) : "";
|
|
219
|
+
const sort = options.sort ? JSON.stringify(options.sort) : "";
|
|
220
|
+
const limit = typeof options.limit === "number" ? String(options.limit) : "";
|
|
221
|
+
return `${key}${JSON.stringify(query)}${projection}${sort}${limit}`;
|
|
222
|
+
};
|
|
223
|
+
const sendToServer = (message) => {
|
|
224
|
+
if (!socket) return;
|
|
225
|
+
if (socket.readyState !== WebSocket.OPEN) return;
|
|
226
|
+
socket.send(JSON.stringify(message));
|
|
227
|
+
};
|
|
228
|
+
const resubscribeAll = () => {
|
|
229
|
+
for (const sub of subscriptions.values()) {
|
|
230
|
+
sendToServer({
|
|
231
|
+
type: "registerQuery",
|
|
232
|
+
modelName: sub.modelName,
|
|
233
|
+
queryKey: sub.queryKey,
|
|
234
|
+
query: sub.query,
|
|
235
|
+
options: sub.options
|
|
236
|
+
});
|
|
237
|
+
sendToServer({
|
|
238
|
+
type: "run_query",
|
|
239
|
+
modelName: sub.modelName,
|
|
240
|
+
queryKey: sub.queryKey,
|
|
241
|
+
query: sub.query,
|
|
242
|
+
options: sub.options
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
const clearReconnectTimer = () => {
|
|
247
|
+
if (reconnectTimer === null) return;
|
|
248
|
+
if (typeof window !== "undefined") {
|
|
249
|
+
window.clearTimeout(reconnectTimer);
|
|
250
|
+
}
|
|
251
|
+
reconnectTimer = null;
|
|
252
|
+
};
|
|
253
|
+
const scheduleReconnect = () => {
|
|
254
|
+
clearReconnectTimer();
|
|
255
|
+
if (explicitDisconnect) return;
|
|
256
|
+
if (!currentTenantId || !currentUid) return;
|
|
257
|
+
const cfg = connectOptions.reconnect ?? {};
|
|
258
|
+
const maxAttempts = cfg.attempts ?? 128;
|
|
259
|
+
const delayMs = cfg.delayMs ?? 400;
|
|
260
|
+
const delayMaxMs = cfg.delayMaxMs ?? 1e4;
|
|
261
|
+
if (reconnectAttempts >= maxAttempts) return;
|
|
262
|
+
const delay = Math.min(delayMaxMs, delayMs * Math.pow(2, reconnectAttempts));
|
|
263
|
+
reconnectAttempts += 1;
|
|
264
|
+
reconnectTimer = window.setTimeout(() => {
|
|
265
|
+
void connectInternal(currentTenantId, currentUid, connectOptions, { resetReconnectAttempts: false });
|
|
266
|
+
}, delay);
|
|
267
|
+
};
|
|
268
|
+
const handleQueryPayload = (payload) => {
|
|
269
|
+
const { modelName, queryKey, data, error, txnId } = payload;
|
|
270
|
+
const cbKey = `${modelName}.${queryKey}`;
|
|
271
|
+
const callbacks = queryCallbacks.get(cbKey);
|
|
272
|
+
if (!callbacks || !callbacks.size) return;
|
|
273
|
+
const isLocal = !!(txnId && localTxnBuf.includes(txnId));
|
|
274
|
+
const context = { source: "network", isLocal, txnId };
|
|
275
|
+
if (error) {
|
|
276
|
+
for (const cb of callbacks) cb(error, void 0, context);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
for (const cb of callbacks) cb(null, data, context);
|
|
280
|
+
if (!currentUid) return;
|
|
281
|
+
if (!Array.isArray(data)) return;
|
|
282
|
+
void updateDocs(modelName, data, currentUid).catch(() => {
|
|
283
|
+
});
|
|
284
|
+
};
|
|
285
|
+
const handleEvent = (payload) => {
|
|
286
|
+
const callbacks = messageCallbacks.get(payload.event);
|
|
287
|
+
if (!callbacks || !callbacks.size) return;
|
|
288
|
+
for (const cb of callbacks) cb(payload.payload);
|
|
289
|
+
};
|
|
290
|
+
const handleMessage = (event) => {
|
|
291
|
+
let parsed;
|
|
292
|
+
try {
|
|
293
|
+
parsed = JSON.parse(typeof event.data === "string" ? event.data : String(event.data));
|
|
294
|
+
} catch {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (!parsed || typeof parsed !== "object") return;
|
|
298
|
+
const message = parsed;
|
|
299
|
+
if (message.type === "query_payload") {
|
|
300
|
+
handleQueryPayload(message);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (message.type === "event") {
|
|
304
|
+
handleEvent(message);
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
const addLocalTxn = (txnId) => {
|
|
308
|
+
if (!txnId) return;
|
|
309
|
+
localTxnBuf.push(txnId);
|
|
310
|
+
if (localTxnBuf.length > MAX_TXN_BUF) {
|
|
311
|
+
localTxnBuf.shift();
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
const connectInternal = (tenantId, uid, options, { resetReconnectAttempts }) => {
|
|
315
|
+
ensureBrowser();
|
|
316
|
+
if (!tenantId) return Promise.resolve();
|
|
317
|
+
if (!uid) throw new Error("Missing uid");
|
|
318
|
+
currentTenantId = tenantId;
|
|
319
|
+
currentUid = uid;
|
|
320
|
+
connectOptions = options;
|
|
321
|
+
if (options.configureStore !== false) {
|
|
322
|
+
configureRtsPouchStore({ tenantId, appName: options.appName });
|
|
323
|
+
}
|
|
324
|
+
if (socket && (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING)) {
|
|
325
|
+
return connectPromise ?? Promise.resolve();
|
|
326
|
+
}
|
|
327
|
+
explicitDisconnect = false;
|
|
328
|
+
clearReconnectTimer();
|
|
329
|
+
const url = buildSocketUrl(tenantId, uid, options);
|
|
330
|
+
connectPromise = new Promise((resolve, reject) => {
|
|
331
|
+
if (resetReconnectAttempts) reconnectAttempts = 0;
|
|
332
|
+
let opened = false;
|
|
333
|
+
let settled = false;
|
|
334
|
+
socket = new WebSocket(url);
|
|
335
|
+
socket.addEventListener("open", () => {
|
|
336
|
+
opened = true;
|
|
337
|
+
settled = true;
|
|
338
|
+
reconnectAttempts = 0;
|
|
339
|
+
resubscribeAll();
|
|
340
|
+
resolve();
|
|
341
|
+
});
|
|
342
|
+
socket.addEventListener("message", handleMessage);
|
|
343
|
+
socket.addEventListener("close", (event) => {
|
|
344
|
+
if (!opened && !settled) {
|
|
345
|
+
settled = true;
|
|
346
|
+
reject(new Error(`RTS WebSocket closed before opening (code=${event.code})`));
|
|
347
|
+
}
|
|
348
|
+
socket = null;
|
|
349
|
+
connectPromise = null;
|
|
350
|
+
scheduleReconnect();
|
|
351
|
+
});
|
|
352
|
+
socket.addEventListener("error", (err) => {
|
|
353
|
+
if (settled) return;
|
|
354
|
+
settled = true;
|
|
355
|
+
reject(err instanceof Error ? err : new Error("RTS WebSocket error"));
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
return connectPromise;
|
|
359
|
+
};
|
|
360
|
+
const connect = (tenantId, uid, options = {}) => {
|
|
361
|
+
return connectInternal(tenantId, uid, options, { resetReconnectAttempts: true });
|
|
362
|
+
};
|
|
363
|
+
const disconnect = () => {
|
|
364
|
+
explicitDisconnect = true;
|
|
365
|
+
clearReconnectTimer();
|
|
366
|
+
if (socket) {
|
|
367
|
+
try {
|
|
368
|
+
socket.close();
|
|
369
|
+
} catch {
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
socket = null;
|
|
373
|
+
connectPromise = null;
|
|
374
|
+
};
|
|
375
|
+
const reconnect = (tenantId, uid, options = {}) => {
|
|
376
|
+
disconnect();
|
|
377
|
+
return connect(tenantId, uid, options);
|
|
378
|
+
};
|
|
379
|
+
const registerQuery = (modelName, query, optionsOrCallback, callbackMaybe) => {
|
|
380
|
+
let options;
|
|
381
|
+
let callback;
|
|
382
|
+
if (typeof optionsOrCallback === "function") {
|
|
383
|
+
options = {};
|
|
384
|
+
callback = optionsOrCallback;
|
|
385
|
+
} else {
|
|
386
|
+
options = optionsOrCallback ?? {};
|
|
387
|
+
callback = callbackMaybe;
|
|
388
|
+
}
|
|
389
|
+
if (!callback) return void 0;
|
|
390
|
+
if (!modelName) return void 0;
|
|
391
|
+
const queryKey = computeQueryKey(query, options);
|
|
392
|
+
const cbKey = `${modelName}.${queryKey}`;
|
|
393
|
+
const set = queryCallbacks.get(cbKey) ?? /* @__PURE__ */ new Set();
|
|
394
|
+
set.add(callback);
|
|
395
|
+
queryCallbacks.set(cbKey, set);
|
|
396
|
+
subscriptions.set(cbKey, { modelName, query, options, queryKey });
|
|
397
|
+
if (currentUid) {
|
|
398
|
+
void runQuery({
|
|
399
|
+
modelName,
|
|
400
|
+
query,
|
|
401
|
+
options: {
|
|
402
|
+
uid: currentUid,
|
|
403
|
+
projection: options.projection,
|
|
404
|
+
sort: options.sort,
|
|
405
|
+
limit: options.limit
|
|
406
|
+
}
|
|
407
|
+
}).then(({ data, context }) => {
|
|
408
|
+
callback?.(null, data, context);
|
|
409
|
+
}).catch(() => {
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
sendToServer({ type: "run_query", modelName, queryKey, query, options });
|
|
413
|
+
sendToServer({ type: "registerQuery", modelName, queryKey, query, options });
|
|
414
|
+
return () => {
|
|
415
|
+
sendToServer({ type: "remove_query", modelName, queryKey });
|
|
416
|
+
const callbacks = queryCallbacks.get(cbKey);
|
|
417
|
+
callbacks?.delete(callback);
|
|
418
|
+
if (callbacks && callbacks.size === 0) {
|
|
419
|
+
queryCallbacks.delete(cbKey);
|
|
420
|
+
subscriptions.delete(cbKey);
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
};
|
|
424
|
+
const sendMessage = (event, payload) => {
|
|
425
|
+
sendToServer({ type: "event", event, payload });
|
|
426
|
+
};
|
|
427
|
+
const onMessage = (event, callback) => {
|
|
428
|
+
const set = messageCallbacks.get(event) ?? /* @__PURE__ */ new Set();
|
|
429
|
+
set.add(callback);
|
|
430
|
+
messageCallbacks.set(event, set);
|
|
431
|
+
return () => {
|
|
432
|
+
const callbacks = messageCallbacks.get(event);
|
|
433
|
+
callbacks?.delete(callback);
|
|
434
|
+
if (callbacks && callbacks.size === 0) messageCallbacks.delete(event);
|
|
435
|
+
};
|
|
436
|
+
};
|
|
437
|
+
const useQuery = (modelName, query = {}, options = {}) => {
|
|
438
|
+
const id = useId();
|
|
439
|
+
const key = options.key ?? id;
|
|
440
|
+
const projectionJson = options.projection ? JSON.stringify(options.projection) : "";
|
|
441
|
+
const sortJson = options.sort ? JSON.stringify(options.sort) : "";
|
|
442
|
+
const limitStr = typeof options.limit === "number" ? String(options.limit) : "";
|
|
443
|
+
const [data, setData] = useState(void 0);
|
|
444
|
+
const [source, setSource] = useState(void 0);
|
|
445
|
+
const [error, setError] = useState(void 0);
|
|
446
|
+
const [loading, setLoading] = useState(true);
|
|
447
|
+
const hasFirstReply = useRef(false);
|
|
448
|
+
const hasNetworkReply = useRef(false);
|
|
449
|
+
const lastDataJsonRef = useRef("");
|
|
450
|
+
useEffect(() => {
|
|
451
|
+
hasFirstReply.current = false;
|
|
452
|
+
hasNetworkReply.current = false;
|
|
453
|
+
lastDataJsonRef.current = "";
|
|
454
|
+
setLoading(true);
|
|
455
|
+
setError(void 0);
|
|
456
|
+
}, [modelName, key, JSON.stringify(query), projectionJson, sortJson, limitStr]);
|
|
457
|
+
useEffect(() => {
|
|
458
|
+
if (!modelName) return;
|
|
459
|
+
const unsubscribe = registerQuery(
|
|
460
|
+
modelName,
|
|
461
|
+
query,
|
|
462
|
+
{
|
|
463
|
+
key,
|
|
464
|
+
projection: options.projection,
|
|
465
|
+
sort: options.sort,
|
|
466
|
+
limit: options.limit
|
|
467
|
+
},
|
|
468
|
+
(err, result, context) => {
|
|
469
|
+
if (context.source === "cache" && hasNetworkReply.current) return;
|
|
470
|
+
if (context.source === "network") {
|
|
471
|
+
hasNetworkReply.current = true;
|
|
472
|
+
}
|
|
473
|
+
setLoading(false);
|
|
474
|
+
if (err) {
|
|
475
|
+
setError(err);
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
if (!Array.isArray(result)) return;
|
|
479
|
+
if (context.source === "network" && context.isLocal && options.skipLocal && hasFirstReply.current) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
hasFirstReply.current = true;
|
|
483
|
+
let nextJson = "";
|
|
484
|
+
try {
|
|
485
|
+
nextJson = JSON.stringify(result);
|
|
486
|
+
} catch {
|
|
487
|
+
nextJson = "";
|
|
488
|
+
}
|
|
489
|
+
if (nextJson && nextJson === lastDataJsonRef.current) {
|
|
490
|
+
setSource(context.source);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
lastDataJsonRef.current = nextJson;
|
|
494
|
+
setSource(context.source);
|
|
495
|
+
setData(result);
|
|
496
|
+
}
|
|
497
|
+
);
|
|
498
|
+
return () => {
|
|
499
|
+
unsubscribe?.();
|
|
500
|
+
};
|
|
501
|
+
}, [modelName, key, JSON.stringify(query), projectionJson, sortJson, limitStr]);
|
|
502
|
+
return useMemo(
|
|
503
|
+
() => ({
|
|
504
|
+
data,
|
|
505
|
+
source,
|
|
506
|
+
error,
|
|
507
|
+
loading
|
|
508
|
+
}),
|
|
509
|
+
[data, source, error, loading]
|
|
510
|
+
);
|
|
511
|
+
};
|
|
512
|
+
const get_collection = getCollection;
|
|
513
|
+
const run_query = runQuery;
|
|
514
|
+
const update_docs = updateDocs;
|
|
515
|
+
const destroy_all = destroyAllCollections;
|
|
516
|
+
export {
|
|
517
|
+
addLocalTxn,
|
|
518
|
+
configureRtsPouchStore,
|
|
519
|
+
connect,
|
|
520
|
+
destroyAllCollections,
|
|
521
|
+
destroy_all,
|
|
522
|
+
disconnect,
|
|
523
|
+
getCollection,
|
|
524
|
+
get_collection,
|
|
525
|
+
onMessage,
|
|
526
|
+
reconnect,
|
|
527
|
+
registerQuery,
|
|
528
|
+
runQuery,
|
|
529
|
+
run_query,
|
|
530
|
+
sendMessage,
|
|
531
|
+
updateDocs,
|
|
532
|
+
update_docs,
|
|
533
|
+
useQuery
|
|
534
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpcbase/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.328.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
"import": "./dist/index.js",
|
|
14
14
|
"default": "./dist/index.js"
|
|
15
15
|
},
|
|
16
|
+
"./rts": {
|
|
17
|
+
"types": "./dist/rts.d.ts",
|
|
18
|
+
"import": "./dist/rts.js",
|
|
19
|
+
"default": "./dist/rts.js"
|
|
20
|
+
},
|
|
16
21
|
"./instrument": {
|
|
17
22
|
"types": "./dist/instrument.d.ts",
|
|
18
23
|
"import": "./dist/instrument.js",
|
|
@@ -60,6 +65,12 @@
|
|
|
60
65
|
}
|
|
61
66
|
}
|
|
62
67
|
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"events": "3.3.0",
|
|
70
|
+
"pouchdb-adapter-indexeddb": "9.0.0",
|
|
71
|
+
"pouchdb-core": "9.0.0",
|
|
72
|
+
"pouchdb-find": "9.0.0"
|
|
73
|
+
},
|
|
63
74
|
"peerDependencies": {
|
|
64
75
|
"axios": "^1.13"
|
|
65
76
|
},
|