@gonvex/client 0.1.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.
@@ -0,0 +1,67 @@
1
+ import { cacheFailureAction } from "./cache.js";
2
+ import { CacheCoordinatorModel } from "./cache-coordinator.js";
3
+ export class FakeTabWorker {
4
+ tabId;
5
+ state = new Map();
6
+ openCount = 0;
7
+ writeCount = 0;
8
+ constructor(tabId) {
9
+ this.tabId = tabId;
10
+ }
11
+ async boot() {
12
+ this.openCount += 1;
13
+ }
14
+ async execute(request) {
15
+ if (request.operation === "write") {
16
+ this.writeCount += 1;
17
+ }
18
+ return request.execute(this.state);
19
+ }
20
+ }
21
+ export class BrowserCacheCoordinatorHarness {
22
+ coordinator = new CacheCoordinatorModel();
23
+ workers = new Map();
24
+ requestLog = [];
25
+ registerTab(tab) {
26
+ this.coordinator.registerTab(tab);
27
+ this.workers.set(tab.id, new FakeTabWorker(tab.id));
28
+ }
29
+ async bootActiveOwner() {
30
+ const activeTabId = this.coordinator.snapshot().activeTabId;
31
+ if (!activeTabId) {
32
+ return;
33
+ }
34
+ const worker = this.workers.get(activeTabId);
35
+ if (!worker) {
36
+ return;
37
+ }
38
+ await worker.boot();
39
+ this.coordinator.markActiveOwnerReady();
40
+ }
41
+ closeTab(tabId) {
42
+ this.coordinator.closeTab(tabId);
43
+ }
44
+ async request(requestingTabId, request) {
45
+ const route = this.coordinator.routeRequest();
46
+ if (route.route === "server") {
47
+ this.requestLog.push({ requestingTabId, operation: request.operation });
48
+ return { ok: false, route: "server", reason: route.reason };
49
+ }
50
+ const owner = this.workers.get(route.activeTabId);
51
+ if (!owner) {
52
+ return { ok: false, route: "server", reason: "active-worker-missing" };
53
+ }
54
+ this.requestLog.push({ requestingTabId, ownerTabId: route.activeTabId, operation: request.operation });
55
+ try {
56
+ const value = await owner.execute(request);
57
+ return { ok: true, ownerTabId: route.activeTabId, value };
58
+ }
59
+ catch (error) {
60
+ return { ok: false, route: "server", reason: "local-db-error", failure: cacheFailureAction(error) };
61
+ }
62
+ }
63
+ activeWriters() {
64
+ return [...this.workers.values()].filter((worker) => worker.writeCount > 0).map((worker) => worker.tabId);
65
+ }
66
+ }
67
+ //# sourceMappingURL=browser-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-cache.js","sourceRoot":"","sources":["../src/browser-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export type BrowserCacheDisableReason = "shared-worker-unavailable" | "web-locks-unavailable" | "dedicated-worker-unavailable" | "persistent-storage-unavailable";
2
+ export type BrowserCacheCapabilities = {
3
+ sharedWorker: boolean;
4
+ webLocks: boolean;
5
+ dedicatedWorker: boolean;
6
+ opfs: boolean;
7
+ supported: boolean;
8
+ disableReason?: BrowserCacheDisableReason;
9
+ };
10
+ type CapabilityGlobal = {
11
+ SharedWorker?: unknown;
12
+ Worker?: unknown;
13
+ navigator?: {
14
+ locks?: unknown;
15
+ storage?: {
16
+ getDirectory?: unknown;
17
+ };
18
+ };
19
+ };
20
+ export declare function detectBrowserCacheCapabilities(globalValue?: CapabilityGlobal): BrowserCacheCapabilities;
21
+ export {};
@@ -0,0 +1,31 @@
1
+ export function detectBrowserCacheCapabilities(globalValue = globalThis) {
2
+ const sharedWorker = typeof globalValue.SharedWorker === "function";
3
+ const webLocks = typeof globalValue.navigator?.locks === "object" && globalValue.navigator?.locks !== null;
4
+ const dedicatedWorker = typeof globalValue.Worker === "function";
5
+ const opfs = typeof globalValue.navigator?.storage?.getDirectory === "function";
6
+ const disableReason = firstDisableReason({ sharedWorker, webLocks, dedicatedWorker, opfs });
7
+ return {
8
+ sharedWorker,
9
+ webLocks,
10
+ dedicatedWorker,
11
+ opfs,
12
+ supported: disableReason === undefined,
13
+ disableReason,
14
+ };
15
+ }
16
+ function firstDisableReason(capabilities) {
17
+ if (!capabilities.sharedWorker) {
18
+ return "shared-worker-unavailable";
19
+ }
20
+ if (!capabilities.webLocks) {
21
+ return "web-locks-unavailable";
22
+ }
23
+ if (!capabilities.dedicatedWorker) {
24
+ return "dedicated-worker-unavailable";
25
+ }
26
+ if (!capabilities.opfs) {
27
+ return "persistent-storage-unavailable";
28
+ }
29
+ return undefined;
30
+ }
31
+ //# sourceMappingURL=browser-capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-capabilities.js","sourceRoot":"","sources":["../src/browser-capabilities.ts"],"names":[],"mappings":"AA0BA,MAAM,UAAU,8BAA8B,CAAC,cAAgC,UAAU;IACvF,MAAM,YAAY,GAAG,OAAO,WAAW,CAAC,YAAY,KAAK,UAAU,CAAC;IACpE,MAAM,QAAQ,GAAG,OAAO,WAAW,CAAC,SAAS,EAAE,KAAK,KAAK,QAAQ,IAAI,WAAW,CAAC,SAAS,EAAE,KAAK,KAAK,IAAI,CAAC;IAC3G,MAAM,eAAe,GAAG,OAAO,WAAW,CAAC,MAAM,KAAK,UAAU,CAAC;IACjE,MAAM,IAAI,GAAG,OAAO,WAAW,CAAC,SAAS,EAAE,OAAO,EAAE,YAAY,KAAK,UAAU,CAAC;IAChF,MAAM,aAAa,GAAG,kBAAkB,CAAC,EAAE,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;IAE5F,OAAO;QACL,YAAY;QACZ,QAAQ;QACR,eAAe;QACf,IAAI;QACJ,SAAS,EAAE,aAAa,KAAK,SAAS;QACtC,aAAa;KACd,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CACzB,YAAsG;IAEtG,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,CAAC;QAC/B,OAAO,2BAA2B,CAAC;IACrC,CAAC;IACD,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC;QAC3B,OAAO,uBAAuB,CAAC;IACjC,CAAC;IACD,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,CAAC;QAClC,OAAO,8BAA8B,CAAC;IACxC,CAAC;IACD,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC;QACvB,OAAO,gCAAgC,CAAC;IAC1C,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,37 @@
1
+ export type CacheOwnerStatus = "no_owner" | "electing" | "active_owner_ready" | "owner_lost" | "unsafe_fallback_disabled";
2
+ export type CacheTab = {
3
+ id: string;
4
+ hasLivenessLock: boolean;
5
+ dedicatedWorkerReady: boolean;
6
+ storageReady?: boolean;
7
+ integrityVerified?: boolean;
8
+ };
9
+ export type CacheCoordinatorSnapshot = {
10
+ status: CacheOwnerStatus;
11
+ activeTabId?: string;
12
+ tabs: CacheTab[];
13
+ };
14
+ export type DBRequestRoute = {
15
+ route: "active-worker";
16
+ activeTabId: string;
17
+ } | {
18
+ route: "server";
19
+ reason: "no-active-owner" | "owner-not-ready" | "unsafe-fallback-disabled";
20
+ };
21
+ export declare class CacheCoordinatorModel {
22
+ private tabs;
23
+ private activeTabId;
24
+ private status;
25
+ registerTab(tab: CacheTab): void;
26
+ updateTab(tabId: string, patch: Partial<Omit<CacheTab, "id">>): void;
27
+ closeTab(tabId: string): void;
28
+ disableUnsafeFallback(): void;
29
+ verifyActiveOwnerIntegrity(): void;
30
+ markActiveOwnerStorageReady(): void;
31
+ markActiveOwnerReady(): void;
32
+ routeRequest(): DBRequestRoute;
33
+ snapshot(): CacheCoordinatorSnapshot;
34
+ private electIfNeeded;
35
+ private canOwn;
36
+ private ownerReady;
37
+ }
@@ -0,0 +1,109 @@
1
+ export class CacheCoordinatorModel {
2
+ tabs = new Map();
3
+ activeTabId;
4
+ status = "no_owner";
5
+ registerTab(tab) {
6
+ this.tabs.set(tab.id, normalizeTab(tab));
7
+ this.electIfNeeded();
8
+ }
9
+ updateTab(tabId, patch) {
10
+ const current = this.tabs.get(tabId);
11
+ if (!current) {
12
+ return;
13
+ }
14
+ this.tabs.set(tabId, normalizeTab({ ...current, ...patch }));
15
+ if (tabId === this.activeTabId && !this.canOwn(this.tabs.get(tabId))) {
16
+ this.activeTabId = undefined;
17
+ this.status = "owner_lost";
18
+ }
19
+ this.electIfNeeded();
20
+ }
21
+ closeTab(tabId) {
22
+ this.tabs.delete(tabId);
23
+ if (this.activeTabId === tabId) {
24
+ this.activeTabId = undefined;
25
+ this.status = "owner_lost";
26
+ }
27
+ this.electIfNeeded();
28
+ }
29
+ disableUnsafeFallback() {
30
+ this.activeTabId = undefined;
31
+ this.status = "unsafe_fallback_disabled";
32
+ }
33
+ verifyActiveOwnerIntegrity() {
34
+ if (!this.activeTabId || this.status === "unsafe_fallback_disabled") {
35
+ return;
36
+ }
37
+ this.updateTab(this.activeTabId, { integrityVerified: true });
38
+ }
39
+ markActiveOwnerStorageReady() {
40
+ if (!this.activeTabId || this.status === "unsafe_fallback_disabled") {
41
+ return;
42
+ }
43
+ this.updateTab(this.activeTabId, { storageReady: true });
44
+ }
45
+ markActiveOwnerReady() {
46
+ if (!this.activeTabId || this.status === "unsafe_fallback_disabled") {
47
+ return;
48
+ }
49
+ this.updateTab(this.activeTabId, {
50
+ dedicatedWorkerReady: true,
51
+ storageReady: true,
52
+ integrityVerified: true,
53
+ });
54
+ this.electIfNeeded();
55
+ }
56
+ routeRequest() {
57
+ if (this.status === "unsafe_fallback_disabled") {
58
+ return { route: "server", reason: "unsafe-fallback-disabled" };
59
+ }
60
+ if (!this.activeTabId) {
61
+ return { route: "server", reason: "no-active-owner" };
62
+ }
63
+ const active = this.tabs.get(this.activeTabId);
64
+ if (!this.canOwn(active) || !this.ownerReady(active) || this.status !== "active_owner_ready") {
65
+ return { route: "server", reason: "owner-not-ready" };
66
+ }
67
+ return { route: "active-worker", activeTabId: this.activeTabId };
68
+ }
69
+ snapshot() {
70
+ return {
71
+ status: this.status,
72
+ activeTabId: this.activeTabId,
73
+ tabs: [...this.tabs.values()].map((tab) => ({ ...tab })),
74
+ };
75
+ }
76
+ electIfNeeded() {
77
+ if (this.status === "unsafe_fallback_disabled") {
78
+ return;
79
+ }
80
+ if (this.activeTabId && this.canOwn(this.tabs.get(this.activeTabId))) {
81
+ this.status = this.ownerReady(this.tabs.get(this.activeTabId)) ? "active_owner_ready" : "electing";
82
+ return;
83
+ }
84
+ const nextOwner = [...this.tabs.values()]
85
+ .filter((tab) => this.canOwn(tab))
86
+ .sort((left, right) => left.id.localeCompare(right.id))[0];
87
+ if (!nextOwner) {
88
+ this.activeTabId = undefined;
89
+ this.status = this.tabs.size > 0 ? "electing" : "no_owner";
90
+ return;
91
+ }
92
+ this.activeTabId = nextOwner.id;
93
+ this.status = this.ownerReady(nextOwner) ? "active_owner_ready" : "electing";
94
+ }
95
+ canOwn(tab) {
96
+ return Boolean(tab?.hasLivenessLock);
97
+ }
98
+ ownerReady(tab) {
99
+ return Boolean(tab?.dedicatedWorkerReady && tab.storageReady && tab.integrityVerified);
100
+ }
101
+ }
102
+ function normalizeTab(tab) {
103
+ return {
104
+ ...tab,
105
+ storageReady: tab.storageReady ?? false,
106
+ integrityVerified: tab.integrityVerified ?? false,
107
+ };
108
+ }
109
+ //# sourceMappingURL=cache-coordinator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-coordinator.js","sourceRoot":"","sources":["../src/cache-coordinator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ export type ShapeSyncStatus = "not_started" | "syncing" | "ready" | "stale" | "too_large" | "error";
2
+ export type CacheDBHealth = "healthy" | "initializing" | "unavailable" | "corrupt";
3
+ export type CacheRoutingSource = "local" | "server";
4
+ export type CacheRoutingReason = "local-ready" | "query-has-no-local-plan" | "query-has-no-shape" | "shape-missing" | "shape-does-not-cover-query" | "shape-not-ready" | "shape-too-large" | "query-row-limit-unsafe" | "shape-auth-scope-mismatch" | "shape-epoch-mismatch" | "db-not-healthy" | "db-owner-unsafe";
5
+ export type CacheShapeVisibilityScope = "project" | "tenant" | "user" | "auth";
6
+ export type CacheShapeDefinition = {
7
+ id: string;
8
+ tables: string[];
9
+ visibilityScope: CacheShapeVisibilityScope;
10
+ maxRows?: number;
11
+ maxBytes?: number;
12
+ schemaVersion: string;
13
+ permissionVersion: string;
14
+ };
15
+ export type CacheShapeState = {
16
+ id: string;
17
+ projectId: string;
18
+ tenantId: string;
19
+ userId: string;
20
+ authScope: string;
21
+ status: ShapeSyncStatus;
22
+ schemaVersion: string;
23
+ permissionVersion: string;
24
+ checkpoint?: string;
25
+ rowCount?: number;
26
+ maxRows?: number;
27
+ };
28
+ export type CacheQueryPlan = {
29
+ queryKey: string;
30
+ queryPath?: string;
31
+ projectId: string;
32
+ tenantId: string;
33
+ userId: string;
34
+ authScope: string;
35
+ requiredShapeId?: string;
36
+ hasLocalPlan: boolean;
37
+ schemaVersion: string;
38
+ permissionVersion: string;
39
+ coveredByShapeIds?: string[];
40
+ estimatedRows?: number;
41
+ limit?: number;
42
+ };
43
+ export type CacheEnvironment = {
44
+ dbHealth: CacheDBHealth;
45
+ singleWriter: boolean;
46
+ shapes: Record<string, CacheShapeState | undefined>;
47
+ definitions?: Record<string, CacheShapeDefinition | undefined>;
48
+ };
49
+ export type CacheRoutingDecision = {
50
+ source: CacheRoutingSource;
51
+ reason: CacheRoutingReason;
52
+ shape?: CacheShapeState;
53
+ };
54
+ export type CacheFailureAction = {
55
+ action: "reset-and-server-fallback";
56
+ reason: "cache-corruption-suspected";
57
+ } | {
58
+ action: "server-fallback";
59
+ reason: "ordinary-failure";
60
+ };
61
+ export declare function chooseQuerySource(query: CacheQueryPlan, environment: CacheEnvironment): CacheRoutingDecision;
62
+ export declare function defineVisibleShape(definition: CacheShapeDefinition): CacheShapeDefinition;
63
+ export declare function cacheKey(parts: {
64
+ projectId: string;
65
+ tenantId: string;
66
+ userId: string;
67
+ authScope: string;
68
+ queryPath: string;
69
+ argsHash: string;
70
+ schemaVersion: string;
71
+ permissionVersion: string;
72
+ }): string;
73
+ export declare function shouldResetLocalCache(error: unknown): boolean;
74
+ export declare function cacheFailureAction(error: unknown): CacheFailureAction;
package/dist/cache.js ADDED
@@ -0,0 +1,120 @@
1
+ export function chooseQuerySource(query, environment) {
2
+ if (!query.hasLocalPlan) {
3
+ return server("query-has-no-local-plan");
4
+ }
5
+ if (!query.requiredShapeId) {
6
+ return server("query-has-no-shape");
7
+ }
8
+ if (environment.dbHealth !== "healthy") {
9
+ return server("db-not-healthy");
10
+ }
11
+ if (!environment.singleWriter) {
12
+ return server("db-owner-unsafe");
13
+ }
14
+ const shape = environment.shapes[query.requiredShapeId];
15
+ if (!shape) {
16
+ return server("shape-missing");
17
+ }
18
+ const definition = environment.definitions?.[query.requiredShapeId];
19
+ if (!shapeCoversQuery(query, definition)) {
20
+ return server("shape-does-not-cover-query", shape);
21
+ }
22
+ if (shape.status === "too_large") {
23
+ return server("shape-too-large", shape);
24
+ }
25
+ if (shape.status !== "ready") {
26
+ return server("shape-not-ready", shape);
27
+ }
28
+ if (!sameScope(query, shape)) {
29
+ return server("shape-auth-scope-mismatch", shape);
30
+ }
31
+ if (shape.schemaVersion !== query.schemaVersion || shape.permissionVersion !== query.permissionVersion) {
32
+ return server("shape-epoch-mismatch", shape);
33
+ }
34
+ if (shape.maxRows !== undefined && shape.rowCount !== undefined && shape.rowCount > shape.maxRows) {
35
+ return server("shape-too-large", shape);
36
+ }
37
+ if (!queryLimitIsSafe(query, shape, definition)) {
38
+ return server("query-row-limit-unsafe", shape);
39
+ }
40
+ return { source: "local", reason: "local-ready", shape };
41
+ }
42
+ export function defineVisibleShape(definition) {
43
+ if (!definition.id.trim()) {
44
+ throw new Error("cache shape id is required");
45
+ }
46
+ if (definition.tables.length === 0 || definition.tables.some((table) => !table.trim())) {
47
+ throw new Error(`cache shape ${definition.id} must include at least one table`);
48
+ }
49
+ if (definition.maxRows !== undefined && definition.maxRows <= 0) {
50
+ throw new Error(`cache shape ${definition.id} maxRows must be positive`);
51
+ }
52
+ if (definition.maxBytes !== undefined && definition.maxBytes <= 0) {
53
+ throw new Error(`cache shape ${definition.id} maxBytes must be positive`);
54
+ }
55
+ return {
56
+ ...definition,
57
+ tables: [...definition.tables],
58
+ };
59
+ }
60
+ export function cacheKey(parts) {
61
+ return [
62
+ "gonvex",
63
+ parts.projectId,
64
+ parts.tenantId,
65
+ parts.userId,
66
+ parts.authScope,
67
+ parts.queryPath,
68
+ parts.argsHash,
69
+ parts.schemaVersion,
70
+ parts.permissionVersion,
71
+ ].map(escapeKeyPart).join(":");
72
+ }
73
+ export function shouldResetLocalCache(error) {
74
+ if (!(error instanceof Error)) {
75
+ return false;
76
+ }
77
+ const message = error.message.toLowerCase();
78
+ return message.includes("corrupt")
79
+ || message.includes("integrity")
80
+ || message.includes("checkpoint")
81
+ || message.includes("schema mismatch");
82
+ }
83
+ export function cacheFailureAction(error) {
84
+ if (shouldResetLocalCache(error)) {
85
+ return { action: "reset-and-server-fallback", reason: "cache-corruption-suspected" };
86
+ }
87
+ return { action: "server-fallback", reason: "ordinary-failure" };
88
+ }
89
+ function sameScope(query, shape) {
90
+ return shape.projectId === query.projectId
91
+ && shape.tenantId === query.tenantId
92
+ && shape.userId === query.userId
93
+ && shape.authScope === query.authScope;
94
+ }
95
+ function shapeCoversQuery(query, definition) {
96
+ if (query.coveredByShapeIds) {
97
+ return query.coveredByShapeIds.includes(query.requiredShapeId ?? "");
98
+ }
99
+ return definition !== undefined;
100
+ }
101
+ function queryLimitIsSafe(query, shape, definition) {
102
+ const maxRows = shape.maxRows ?? definition?.maxRows;
103
+ if (maxRows === undefined) {
104
+ return true;
105
+ }
106
+ if (query.limit !== undefined) {
107
+ return query.limit <= maxRows;
108
+ }
109
+ if (query.estimatedRows !== undefined) {
110
+ return query.estimatedRows <= maxRows;
111
+ }
112
+ return shape.rowCount === undefined || shape.rowCount <= maxRows;
113
+ }
114
+ function server(reason, shape) {
115
+ return { source: "server", reason, shape };
116
+ }
117
+ function escapeKeyPart(part) {
118
+ return encodeURIComponent(part);
119
+ }
120
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import type { BrowserTelemetryInfo, JsonValue, MessageTrace, ServerMessage } from "@gonvex/protocol";
2
+ export * from "./cache.js";
3
+ export * from "./cache-coordinator.js";
4
+ export * from "./browser-cache.js";
5
+ export * from "./browser-cache-client.js";
6
+ export * from "./browser-cache-shared-worker.js";
7
+ export * from "./browser-capabilities.js";
8
+ export * from "./persistent-cache.js";
9
+ type SubscriptionHandler = (message: ServerMessage) => void;
10
+ type WatchUpdateHandler = () => void;
11
+ type TelemetryHandler = (event: GonvexTelemetryEvent) => void;
12
+ export type FunctionReference = {
13
+ kind: string;
14
+ path: string;
15
+ };
16
+ export type GonvexClientAuth = {
17
+ project?: string;
18
+ token?: string;
19
+ tenant?: string;
20
+ telemetry?: boolean;
21
+ };
22
+ export type GonvexTelemetryEvent = {
23
+ type: "mutation" | "action" | "query";
24
+ id: string;
25
+ path: string;
26
+ reason?: "initial" | "invalidate";
27
+ outcome: "ok" | "error";
28
+ error?: string;
29
+ clientSentAtMs?: number;
30
+ clientReceivedAtMs: number;
31
+ clientDurationMs?: number;
32
+ serverTrace?: MessageTrace;
33
+ device?: BrowserTelemetryInfo;
34
+ };
35
+ export declare class GonvexClient {
36
+ private readonly url;
37
+ private socket;
38
+ private readonly handlers;
39
+ private readonly querySubscriptions;
40
+ private readonly telemetryHandlers;
41
+ private readonly pendingMessages;
42
+ private auth;
43
+ private authInFlight;
44
+ private telemetryEnabled;
45
+ constructor(url: string, auth?: GonvexClientAuth);
46
+ setAuth(auth: GonvexClientAuth): void;
47
+ connect(): void;
48
+ close(): void;
49
+ onTelemetry(handler: TelemetryHandler): () => boolean;
50
+ subscribeQuery(ref: FunctionReference, args: JsonValue | undefined, onMessage: SubscriptionHandler): () => void;
51
+ watchQuery<T = JsonValue>(ref: FunctionReference, args?: JsonValue): {
52
+ localQueryResult(): T | undefined;
53
+ onUpdate(handler: WatchUpdateHandler): () => void;
54
+ };
55
+ mutation<T = JsonValue>(ref: FunctionReference, args?: JsonValue): Promise<T>;
56
+ action<T = JsonValue>(ref: FunctionReference, args?: JsonValue): Promise<T>;
57
+ query<T = JsonValue>(ref: FunctionReference, args?: JsonValue): Promise<T>;
58
+ private call;
59
+ private unsubscribeQueryListener;
60
+ private emitTelemetryFromCall;
61
+ private recordTelemetry;
62
+ private emitTelemetry;
63
+ private reportTelemetry;
64
+ private sendAuth;
65
+ private send;
66
+ private sendNow;
67
+ private flushPendingMessages;
68
+ }
69
+ export declare class ConvexReactClient extends GonvexClient {
70
+ constructor(url: string, auth?: GonvexClientAuth);
71
+ }