doover-js 0.5.4 → 0.6.1
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/README.md +146 -0
- package/dist/apis/_args.d.ts +16 -0
- package/dist/apis/_args.js +26 -0
- package/dist/apis/agents-api.d.ts +4 -1
- package/dist/apis/agents-api.js +139 -1
- package/dist/apis/aggregates-api.d.ts +23 -3
- package/dist/apis/aggregates-api.js +33 -4
- package/dist/apis/alarms-api.d.ts +30 -0
- package/dist/apis/alarms-api.js +51 -6
- package/dist/apis/channels-api.d.ts +40 -3
- package/dist/apis/channels-api.js +50 -5
- package/dist/apis/connections-api.d.ts +21 -5
- package/dist/apis/connections-api.js +26 -10
- package/dist/apis/messages-api.d.ts +54 -9
- package/dist/apis/messages-api.js +94 -12
- package/dist/apis/notifications-api.d.ts +52 -0
- package/dist/apis/notifications-api.js +99 -13
- package/dist/apis/permissions-api.d.ts +8 -0
- package/dist/apis/permissions-api.js +11 -2
- package/dist/apis/processors-api.d.ts +35 -0
- package/dist/apis/processors-api.js +64 -8
- package/dist/apis/users-api.d.ts +8 -0
- package/dist/apis/users-api.js +13 -0
- package/dist/client/capabilities.d.ts +10 -0
- package/dist/client/capabilities.js +43 -0
- package/dist/client/data-client.d.ts +104 -0
- package/dist/client/data-client.js +2 -0
- package/dist/client/doover-client.d.ts +31 -31
- package/dist/client/doover-client.js +58 -37
- package/dist/client/errors.d.ts +23 -0
- package/dist/client/errors.js +50 -0
- package/dist/client/local-agent-client.d.ts +65 -0
- package/dist/client/local-agent-client.js +222 -0
- package/dist/client/multiplex-client.d.ts +151 -0
- package/dist/client/multiplex-client.js +744 -0
- package/dist/client/multiplex-gateway.d.ts +49 -0
- package/dist/client/multiplex-gateway.js +114 -0
- package/dist/client/multiplex-merge.d.ts +12 -0
- package/dist/client/multiplex-merge.js +42 -0
- package/dist/client/provenance.d.ts +60 -0
- package/dist/client/provenance.js +113 -0
- package/dist/client/stats.d.ts +24 -0
- package/dist/client/stats.js +62 -0
- package/dist/client/status-tracker.d.ts +24 -0
- package/dist/client/status-tracker.js +90 -0
- package/dist/gateway/gateway-client.d.ts +23 -1
- package/dist/gateway/gateway-client.js +75 -6
- package/dist/http/rest-client.d.ts +5 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +24 -7
- package/dist/react/context.d.ts +9 -5
- package/dist/react/context.js +6 -2
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.js +3 -1
- package/dist/react/useChannelAggregate.d.ts +8 -1
- package/dist/react/useChannelAggregate.js +24 -6
- package/dist/react/useChannelMessage.d.ts +8 -1
- package/dist/react/useChannelMessage.js +17 -6
- package/dist/react/useChannelMessages.d.ts +8 -1
- package/dist/react/useChannelMessages.js +21 -7
- package/dist/react/useChannelSubscription.d.ts +6 -0
- package/dist/react/useChannelSubscription.js +8 -18
- package/dist/react/useClientStatus.d.ts +10 -0
- package/dist/react/useClientStatus.js +22 -0
- package/dist/react/useConnectionState.d.ts +5 -0
- package/dist/react/useConnectionState.js +5 -0
- package/dist/react/useMultiAgentAggregates.d.ts +8 -1
- package/dist/react/useMultiAgentAggregates.js +25 -21
- package/dist/react/useMultiAgentChannelMessages.d.ts +19 -1
- package/dist/react/useMultiAgentChannelMessages.js +42 -19
- package/dist/react/useSendMessage.d.ts +8 -1
- package/dist/react/useSendMessage.js +15 -2
- package/dist/react/useSendRpc.js +4 -1
- package/dist/react/useUpdateAggregate.d.ts +6 -0
- package/dist/react/useUpdateAggregate.js +20 -4
- package/dist/react/useUpdateMessage.d.ts +5 -0
- package/dist/react/useUpdateMessage.js +11 -2
- package/dist/rpc/errors.d.ts +10 -0
- package/dist/rpc/errors.js +23 -0
- package/dist/rpc/rpc-dispatcher.d.ts +28 -0
- package/dist/rpc/rpc-dispatcher.js +129 -0
- package/dist/test/api-args.test.d.ts +1 -0
- package/dist/test/api-args.test.js +48 -0
- package/dist/test/api-overloads.test.d.ts +9 -0
- package/dist/test/api-overloads.test.js +276 -0
- package/dist/test/capabilities.test.d.ts +1 -0
- package/dist/test/capabilities.test.js +27 -0
- package/dist/test/data-client-errors.test.d.ts +1 -0
- package/dist/test/data-client-errors.test.js +24 -0
- package/dist/test/data-client-shape.test.d.ts +1 -0
- package/dist/test/data-client-shape.test.js +28 -0
- package/dist/test/doover-client-dataclient.test.d.ts +1 -0
- package/dist/test/doover-client-dataclient.test.js +58 -0
- package/dist/test/doover-client-provenance.test.d.ts +1 -0
- package/dist/test/doover-client-provenance.test.js +32 -0
- package/dist/test/exports.test.d.ts +1 -0
- package/dist/test/exports.test.js +76 -0
- package/dist/test/gateway-provenance.test.d.ts +1 -0
- package/dist/test/gateway-provenance.test.js +29 -0
- package/dist/test/gateway-subscriptions.test.d.ts +1 -0
- package/dist/test/gateway-subscriptions.test.js +95 -0
- package/dist/test/local-agent-client.test.d.ts +1 -0
- package/dist/test/local-agent-client.test.js +202 -0
- package/dist/test/multiplex-capabilities.test.d.ts +1 -0
- package/dist/test/multiplex-capabilities.test.js +37 -0
- package/dist/test/multiplex-conflicts.test.d.ts +1 -0
- package/dist/test/multiplex-conflicts.test.js +35 -0
- package/dist/test/multiplex-gateway.test.d.ts +1 -0
- package/dist/test/multiplex-gateway.test.js +103 -0
- package/dist/test/multiplex-merge.test.d.ts +1 -0
- package/dist/test/multiplex-merge.test.js +19 -0
- package/dist/test/multiplex-noncore.test.d.ts +1 -0
- package/dist/test/multiplex-noncore.test.js +82 -0
- package/dist/test/multiplex-passthrough.test.d.ts +1 -0
- package/dist/test/multiplex-passthrough.test.js +35 -0
- package/dist/test/multiplex-reads.test.d.ts +1 -0
- package/dist/test/multiplex-reads.test.js +87 -0
- package/dist/test/multiplex-registry.test.d.ts +1 -0
- package/dist/test/multiplex-registry.test.js +81 -0
- package/dist/test/multiplex-routing.test.d.ts +1 -0
- package/dist/test/multiplex-routing.test.js +45 -0
- package/dist/test/multiplex-status.test.d.ts +1 -0
- package/dist/test/multiplex-status.test.js +63 -0
- package/dist/test/multiplex-writes.test.d.ts +1 -0
- package/dist/test/multiplex-writes.test.js +93 -0
- package/dist/test/provenance-regression.test.d.ts +1 -0
- package/dist/test/provenance-regression.test.js +45 -0
- package/dist/test/provenance-stamper.test.d.ts +1 -0
- package/dist/test/provenance-stamper.test.js +41 -0
- package/dist/test/provenance-type.test.d.ts +1 -0
- package/dist/test/provenance-type.test.js +15 -0
- package/dist/test/react-client-status.test.d.ts +1 -0
- package/dist/test/react-client-status.test.js +35 -0
- package/dist/test/react-dataclient.test.d.ts +1 -0
- package/dist/test/react-dataclient.test.js +28 -0
- package/dist/test/react-exports.test.d.ts +1 -0
- package/dist/test/react-exports.test.js +45 -0
- package/dist/test/react-sources-option.test.d.ts +1 -0
- package/dist/test/react-sources-option.test.js +41 -0
- package/dist/test/react.test.js +2 -2
- package/dist/test/rpc-dispatcher.test.d.ts +1 -0
- package/dist/test/rpc-dispatcher.test.js +190 -0
- package/dist/test/stats-rpc.test.d.ts +1 -0
- package/dist/test/stats-rpc.test.js +69 -0
- package/dist/test/status-tracker.test.d.ts +1 -0
- package/dist/test/status-tracker.test.js +85 -0
- package/dist/test/users-api.test.d.ts +1 -0
- package/dist/test/users-api.test.js +19 -0
- package/dist/types/audit.d.ts +53 -0
- package/dist/types/audit.js +14 -0
- package/dist/types/common.d.ts +16 -0
- package/dist/types/provenance.d.ts +45 -0
- package/dist/types/provenance.js +2 -0
- package/dist/types/viewer.d.ts +3 -0
- package/dist/viewer/doover-data-provider.d.ts +30 -34
- package/dist/viewer/doover-data-provider.js +82 -316
- package/package.json +1 -1
|
@@ -2,7 +2,16 @@ import type { DooverAuth } from "../auth/doover-auth";
|
|
|
2
2
|
import type { DooverStatsCollector } from "../client/stats";
|
|
3
3
|
import type { DooverClientConfig } from "../http/rest-client";
|
|
4
4
|
import type { GatewayListenerMap, WebSocketSession } from "./types";
|
|
5
|
-
import type { ChannelRef, JSONValue } from "../types/common";
|
|
5
|
+
import type { Aggregate, ChannelRef, JSONValue, MessageStructure } from "../types/common";
|
|
6
|
+
export type GatewayProvenanceHook = <T>(value: T, ctx: {
|
|
7
|
+
event: string;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
}) => any;
|
|
10
|
+
export interface ChannelHandlers {
|
|
11
|
+
onMessage?: (msg: MessageStructure) => void;
|
|
12
|
+
onMessageUpdate?: (msg: MessageStructure, requestData?: JSONValue) => void;
|
|
13
|
+
onAggregate?: (agg: Aggregate) => void;
|
|
14
|
+
}
|
|
6
15
|
export declare class GatewayClient {
|
|
7
16
|
private readonly config;
|
|
8
17
|
private socket;
|
|
@@ -15,11 +24,18 @@ export declare class GatewayClient {
|
|
|
15
24
|
private opening;
|
|
16
25
|
private listeners;
|
|
17
26
|
private subscriptions;
|
|
27
|
+
private channelRegistry;
|
|
18
28
|
private readonly auth;
|
|
19
29
|
private stats;
|
|
30
|
+
private provenanceHook;
|
|
20
31
|
constructor(config: DooverClientConfig, auth?: DooverAuth);
|
|
21
32
|
/** Attach a stats collector. Call with `null` to detach. */
|
|
22
33
|
setStats(stats: DooverStatsCollector | null): void;
|
|
34
|
+
/** Optional hook that stamps `__source` provenance onto emitted gateway
|
|
35
|
+
* payloads. `DooverClient` / `LocalAgentClient` set this; standalone
|
|
36
|
+
* `GatewayClient` users leave it null and get raw payloads. */
|
|
37
|
+
setProvenanceHook(hook: GatewayProvenanceHook | null): void;
|
|
38
|
+
private stamp;
|
|
23
39
|
connect(): Promise<void>;
|
|
24
40
|
private openSocket;
|
|
25
41
|
disconnect(code?: number, reason?: string): void;
|
|
@@ -29,6 +45,12 @@ export declare class GatewayClient {
|
|
|
29
45
|
diff_only?: boolean;
|
|
30
46
|
}): void;
|
|
31
47
|
unsubscribe(channel: ChannelRef): void;
|
|
48
|
+
/**
|
|
49
|
+
* Attach channel-scoped handlers. Returns an idempotent unsubscribe fn.
|
|
50
|
+
* The first handler for a channel triggers a wire-level subscribe; the
|
|
51
|
+
* last detach triggers a wire-level unsubscribe.
|
|
52
|
+
*/
|
|
53
|
+
subscribeToChannel(channel: ChannelRef, handlers: ChannelHandlers): () => void;
|
|
32
54
|
syncChannel(channel: ChannelRef): void;
|
|
33
55
|
sendOneShotMessage(channel: ChannelRef, data: JSONValue): void;
|
|
34
56
|
getSession(): WebSocketSession | null;
|
|
@@ -32,7 +32,9 @@ class GatewayClient {
|
|
|
32
32
|
close: new Set(),
|
|
33
33
|
};
|
|
34
34
|
this.subscriptions = new Map();
|
|
35
|
+
this.channelRegistry = new Map();
|
|
35
36
|
this.stats = null;
|
|
37
|
+
this.provenanceHook = null;
|
|
36
38
|
this.handleVisibilityChange = () => {
|
|
37
39
|
if (typeof document === "undefined")
|
|
38
40
|
return;
|
|
@@ -50,6 +52,20 @@ class GatewayClient {
|
|
|
50
52
|
setStats(stats) {
|
|
51
53
|
this.stats = stats;
|
|
52
54
|
}
|
|
55
|
+
/** Optional hook that stamps `__source` provenance onto emitted gateway
|
|
56
|
+
* payloads. `DooverClient` / `LocalAgentClient` set this; standalone
|
|
57
|
+
* `GatewayClient` users leave it null and get raw payloads. */
|
|
58
|
+
setProvenanceHook(hook) {
|
|
59
|
+
this.provenanceHook = hook;
|
|
60
|
+
}
|
|
61
|
+
stamp(value, event) {
|
|
62
|
+
if (!this.provenanceHook)
|
|
63
|
+
return value;
|
|
64
|
+
return this.provenanceHook(value, {
|
|
65
|
+
event,
|
|
66
|
+
...(this.session?.session_id ? { sessionId: this.session.session_id } : {}),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
53
69
|
async connect() {
|
|
54
70
|
this.explicitlyDisconnected = false;
|
|
55
71
|
if (this.socket && this.socket.readyState <= WebSocket.OPEN) {
|
|
@@ -151,6 +167,59 @@ class GatewayClient {
|
|
|
151
167
|
},
|
|
152
168
|
});
|
|
153
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* Attach channel-scoped handlers. Returns an idempotent unsubscribe fn.
|
|
172
|
+
* The first handler for a channel triggers a wire-level subscribe; the
|
|
173
|
+
* last detach triggers a wire-level unsubscribe.
|
|
174
|
+
*/
|
|
175
|
+
subscribeToChannel(channel, handlers) {
|
|
176
|
+
const key = this.channelKey(channel);
|
|
177
|
+
let entry = this.channelRegistry.get(key);
|
|
178
|
+
if (!entry) {
|
|
179
|
+
entry = { handlers: new Set(), cleanup: [] };
|
|
180
|
+
this.channelRegistry.set(key, entry);
|
|
181
|
+
const matches = (c) => c.agent_id === channel.agent_id && c.name === channel.name;
|
|
182
|
+
const onMsgCreate = (msg) => {
|
|
183
|
+
if (!matches(msg.channel))
|
|
184
|
+
return;
|
|
185
|
+
entry.handlers.forEach((h) => h.onMessage?.(msg));
|
|
186
|
+
};
|
|
187
|
+
const onMsgUpdate = (msg, requestData) => {
|
|
188
|
+
if (!matches(msg.channel))
|
|
189
|
+
return;
|
|
190
|
+
entry.handlers.forEach((h) => h.onMessageUpdate?.(msg, requestData));
|
|
191
|
+
};
|
|
192
|
+
const onAggregate = (event) => {
|
|
193
|
+
if (!matches(event.channel))
|
|
194
|
+
return;
|
|
195
|
+
entry.handlers.forEach((h) => h.onAggregate?.(event.aggregate));
|
|
196
|
+
};
|
|
197
|
+
const onChannelSync = (event) => {
|
|
198
|
+
if (!matches(event.channel))
|
|
199
|
+
return;
|
|
200
|
+
entry.handlers.forEach((h) => h.onAggregate?.(event.aggregate));
|
|
201
|
+
};
|
|
202
|
+
this.on("messageCreate", onMsgCreate);
|
|
203
|
+
this.on("messageUpdate", onMsgUpdate);
|
|
204
|
+
this.on("aggregateUpdate", onAggregate);
|
|
205
|
+
this.on("channelSync", onChannelSync);
|
|
206
|
+
entry.cleanup.push(() => this.off("messageCreate", onMsgCreate), () => this.off("messageUpdate", onMsgUpdate), () => this.off("aggregateUpdate", onAggregate), () => this.off("channelSync", onChannelSync));
|
|
207
|
+
this.subscribe(channel);
|
|
208
|
+
}
|
|
209
|
+
entry.handlers.add(handlers);
|
|
210
|
+
let detached = false;
|
|
211
|
+
return () => {
|
|
212
|
+
if (detached)
|
|
213
|
+
return;
|
|
214
|
+
detached = true;
|
|
215
|
+
entry.handlers.delete(handlers);
|
|
216
|
+
if (entry.handlers.size === 0) {
|
|
217
|
+
entry.cleanup.forEach((fn) => fn());
|
|
218
|
+
this.channelRegistry.delete(key);
|
|
219
|
+
this.unsubscribe(channel);
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
154
223
|
syncChannel(channel) {
|
|
155
224
|
if (!this.isConnected()) {
|
|
156
225
|
void this.connect();
|
|
@@ -237,22 +306,22 @@ class GatewayClient {
|
|
|
237
306
|
this.resubscribeAll();
|
|
238
307
|
break;
|
|
239
308
|
case "ChannelSync":
|
|
240
|
-
this.emit("channelSync", message.d);
|
|
309
|
+
this.emit("channelSync", this.stamp(message.d, "channelSync"));
|
|
241
310
|
break;
|
|
242
311
|
case "MessageCreate":
|
|
243
|
-
this.emit("messageCreate", (0, snowflake_1.addTimestampToMessage)(message.d));
|
|
312
|
+
this.emit("messageCreate", this.stamp((0, snowflake_1.addTimestampToMessage)(message.d), "messageCreate"));
|
|
244
313
|
break;
|
|
245
314
|
case "MessageUpdate":
|
|
246
|
-
this.emit("messageUpdate", (0, snowflake_1.addTimestampToMessage)(message.d.message), message.d.request_data);
|
|
315
|
+
this.emit("messageUpdate", this.stamp((0, snowflake_1.addTimestampToMessage)(message.d.message), "messageUpdate"), message.d.request_data);
|
|
247
316
|
break;
|
|
248
317
|
case "AggregateUpdate":
|
|
249
|
-
this.emit("aggregateUpdate", message.d);
|
|
318
|
+
this.emit("aggregateUpdate", this.stamp(message.d, "aggregateUpdate"));
|
|
250
319
|
break;
|
|
251
320
|
case "AlarmTrigger":
|
|
252
|
-
this.emit("alarmTrigger", message.d);
|
|
321
|
+
this.emit("alarmTrigger", this.stamp(message.d, "alarmTrigger"));
|
|
253
322
|
break;
|
|
254
323
|
case "OneShotMessage":
|
|
255
|
-
this.emit("oneShotMessage", message.d);
|
|
324
|
+
this.emit("oneShotMessage", this.stamp(message.d, "oneShotMessage"));
|
|
256
325
|
break;
|
|
257
326
|
case "ChannelSubscription":
|
|
258
327
|
this.emit("channelSubscription", message.d);
|
|
@@ -20,6 +20,11 @@ export interface DooverClientConfig extends AuthConfig {
|
|
|
20
20
|
* in browsers and automatically skipped in non-browser environments.
|
|
21
21
|
*/
|
|
22
22
|
disableBrowserLifecycleHooks?: boolean;
|
|
23
|
+
/** Stable id for this client as a data source. Defaults to "cloud". Used in
|
|
24
|
+
* `__source` provenance and `DataClientStatus.clientId`. */
|
|
25
|
+
sourceId?: string;
|
|
26
|
+
/** Optional human label for this source (UI/debug). */
|
|
27
|
+
sourceLabel?: string;
|
|
23
28
|
}
|
|
24
29
|
export interface RequestOptions {
|
|
25
30
|
baseUrl?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export { DooverClient } from "./client/doover-client";
|
|
2
|
+
export { LocalAgentClient } from "./client/local-agent-client";
|
|
3
|
+
export type { LocalAgentClientConfig } from "./client/local-agent-client";
|
|
4
|
+
export { MultiplexClient } from "./client/multiplex-client";
|
|
5
|
+
export type { MultiplexClientOptions, SourceDescriptor, RegisteredSource, MultiplexConflict, } from "./client/multiplex-client";
|
|
2
6
|
export { getDooverClient, peekDooverClient, resetDooverClient, } from "./client/singleton";
|
|
3
7
|
export { DooverStatsCollector } from "./client/stats";
|
|
4
8
|
export type { DooverStatsSnapshot, RestStatsSnapshot, GatewayStatsSnapshot, } from "./client/stats";
|
|
@@ -12,6 +16,17 @@ export { NotificationsApi } from "./apis/notifications-api";
|
|
|
12
16
|
export { PermissionsApi } from "./apis/permissions-api";
|
|
13
17
|
export { ProcessorsApi } from "./apis/processors-api";
|
|
14
18
|
export { TurnApi } from "./apis/turn-api";
|
|
19
|
+
export { UsersApi } from "./apis/users-api";
|
|
20
|
+
export { RpcDispatcher } from "./rpc/rpc-dispatcher";
|
|
21
|
+
export type { SendRpcOptions } from "./rpc/rpc-dispatcher";
|
|
22
|
+
export { DooverRpcError } from "./rpc/errors";
|
|
23
|
+
export type { ChannelHandlers } from "./gateway/gateway-client";
|
|
24
|
+
export type { RpcStatsSnapshot } from "./client/stats";
|
|
25
|
+
export { ALL_CAPABILITIES } from "./client/capabilities";
|
|
26
|
+
export type { Capability } from "./client/capabilities";
|
|
27
|
+
export { UnsupportedCapabilityError, AmbiguousWriteError } from "./client/errors";
|
|
28
|
+
export type { DataClient, AgentScope, DataClientStatus, DataClientConnectionState, AgentsApiLike, AggregatesApiLike, AlarmsApiLike, ChannelsApiLike, ConnectionsApiLike, MessagesApiLike, NotificationsApiLike, PermissionsApiLike, ProcessorsApiLike, TurnApiLike, UsersApiLike, GatewayClientLike, RpcDispatcherLike, } from "./client/data-client";
|
|
29
|
+
export type { SourceProvenance, SourceProvenanceViaRest, SourceProvenanceViaGateway, } from "./types/provenance";
|
|
15
30
|
export { DooverAuth } from "./auth/doover-auth";
|
|
16
31
|
export { CookieAuth } from "./auth/cookie-auth";
|
|
17
32
|
export { DooverTokenAuth } from "./auth/doover-token-auth";
|
|
@@ -32,4 +47,6 @@ export type * from "./types/common";
|
|
|
32
47
|
export type * from "./types/connection";
|
|
33
48
|
export type * from "./types/openapi";
|
|
34
49
|
export type * from "./types/viewer";
|
|
50
|
+
export type * from "./types/audit";
|
|
51
|
+
export { DV_AUDIT_CHANNEL } from "./types/audit";
|
|
35
52
|
export { addTimestampToMessage, extractSnowflakeId, generateSnowflakeIdAtTime, } from "./utils/snowflake";
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateSnowflakeIdAtTime = exports.extractSnowflakeId = exports.addTimestampToMessage = exports.getIdentifierFromPath = exports.DooverDataProvider = exports.DooverValidationError = exports.DooverGatewayError = exports.DooverApiError = exports.RestClient = exports.GatewayClient = exports.buildAuth = exports.DooverAuthError = exports.AuthProfile = exports.DooverTokenAuth = exports.CookieAuth = exports.DooverAuth = exports.TurnApi = exports.ProcessorsApi = exports.PermissionsApi = exports.NotificationsApi = exports.MessagesApi = exports.ConnectionsApi = exports.ChannelsApi = exports.AlarmsApi = exports.AggregatesApi = exports.AgentsApi = exports.DooverStatsCollector = exports.resetDooverClient = exports.peekDooverClient = exports.getDooverClient = exports.DooverClient = void 0;
|
|
3
|
+
exports.generateSnowflakeIdAtTime = exports.extractSnowflakeId = exports.addTimestampToMessage = exports.DV_AUDIT_CHANNEL = exports.getIdentifierFromPath = exports.DooverDataProvider = exports.DooverValidationError = exports.DooverGatewayError = exports.DooverApiError = exports.RestClient = exports.GatewayClient = exports.buildAuth = exports.DooverAuthError = exports.AuthProfile = exports.DooverTokenAuth = exports.CookieAuth = exports.DooverAuth = exports.AmbiguousWriteError = exports.UnsupportedCapabilityError = exports.ALL_CAPABILITIES = exports.DooverRpcError = exports.RpcDispatcher = exports.UsersApi = exports.TurnApi = exports.ProcessorsApi = exports.PermissionsApi = exports.NotificationsApi = exports.MessagesApi = exports.ConnectionsApi = exports.ChannelsApi = exports.AlarmsApi = exports.AggregatesApi = exports.AgentsApi = exports.DooverStatsCollector = exports.resetDooverClient = exports.peekDooverClient = exports.getDooverClient = exports.MultiplexClient = exports.LocalAgentClient = exports.DooverClient = void 0;
|
|
4
4
|
var doover_client_1 = require("./client/doover-client");
|
|
5
5
|
Object.defineProperty(exports, "DooverClient", { enumerable: true, get: function () { return doover_client_1.DooverClient; } });
|
|
6
|
+
var local_agent_client_1 = require("./client/local-agent-client");
|
|
7
|
+
Object.defineProperty(exports, "LocalAgentClient", { enumerable: true, get: function () { return local_agent_client_1.LocalAgentClient; } });
|
|
8
|
+
var multiplex_client_1 = require("./client/multiplex-client");
|
|
9
|
+
Object.defineProperty(exports, "MultiplexClient", { enumerable: true, get: function () { return multiplex_client_1.MultiplexClient; } });
|
|
6
10
|
var singleton_1 = require("./client/singleton");
|
|
7
11
|
Object.defineProperty(exports, "getDooverClient", { enumerable: true, get: function () { return singleton_1.getDooverClient; } });
|
|
8
12
|
Object.defineProperty(exports, "peekDooverClient", { enumerable: true, get: function () { return singleton_1.peekDooverClient; } });
|
|
@@ -29,6 +33,17 @@ var processors_api_1 = require("./apis/processors-api");
|
|
|
29
33
|
Object.defineProperty(exports, "ProcessorsApi", { enumerable: true, get: function () { return processors_api_1.ProcessorsApi; } });
|
|
30
34
|
var turn_api_1 = require("./apis/turn-api");
|
|
31
35
|
Object.defineProperty(exports, "TurnApi", { enumerable: true, get: function () { return turn_api_1.TurnApi; } });
|
|
36
|
+
var users_api_1 = require("./apis/users-api");
|
|
37
|
+
Object.defineProperty(exports, "UsersApi", { enumerable: true, get: function () { return users_api_1.UsersApi; } });
|
|
38
|
+
var rpc_dispatcher_1 = require("./rpc/rpc-dispatcher");
|
|
39
|
+
Object.defineProperty(exports, "RpcDispatcher", { enumerable: true, get: function () { return rpc_dispatcher_1.RpcDispatcher; } });
|
|
40
|
+
var errors_1 = require("./rpc/errors");
|
|
41
|
+
Object.defineProperty(exports, "DooverRpcError", { enumerable: true, get: function () { return errors_1.DooverRpcError; } });
|
|
42
|
+
var capabilities_1 = require("./client/capabilities");
|
|
43
|
+
Object.defineProperty(exports, "ALL_CAPABILITIES", { enumerable: true, get: function () { return capabilities_1.ALL_CAPABILITIES; } });
|
|
44
|
+
var errors_2 = require("./client/errors");
|
|
45
|
+
Object.defineProperty(exports, "UnsupportedCapabilityError", { enumerable: true, get: function () { return errors_2.UnsupportedCapabilityError; } });
|
|
46
|
+
Object.defineProperty(exports, "AmbiguousWriteError", { enumerable: true, get: function () { return errors_2.AmbiguousWriteError; } });
|
|
32
47
|
var doover_auth_1 = require("./auth/doover-auth");
|
|
33
48
|
Object.defineProperty(exports, "DooverAuth", { enumerable: true, get: function () { return doover_auth_1.DooverAuth; } });
|
|
34
49
|
var cookie_auth_1 = require("./auth/cookie-auth");
|
|
@@ -37,22 +52,24 @@ var doover_token_auth_1 = require("./auth/doover-token-auth");
|
|
|
37
52
|
Object.defineProperty(exports, "DooverTokenAuth", { enumerable: true, get: function () { return doover_token_auth_1.DooverTokenAuth; } });
|
|
38
53
|
var auth_profile_1 = require("./auth/auth-profile");
|
|
39
54
|
Object.defineProperty(exports, "AuthProfile", { enumerable: true, get: function () { return auth_profile_1.AuthProfile; } });
|
|
40
|
-
var
|
|
41
|
-
Object.defineProperty(exports, "DooverAuthError", { enumerable: true, get: function () { return
|
|
55
|
+
var errors_3 = require("./auth/errors");
|
|
56
|
+
Object.defineProperty(exports, "DooverAuthError", { enumerable: true, get: function () { return errors_3.DooverAuthError; } });
|
|
42
57
|
var build_auth_1 = require("./auth/build-auth");
|
|
43
58
|
Object.defineProperty(exports, "buildAuth", { enumerable: true, get: function () { return build_auth_1.buildAuth; } });
|
|
44
59
|
var gateway_client_1 = require("./gateway/gateway-client");
|
|
45
60
|
Object.defineProperty(exports, "GatewayClient", { enumerable: true, get: function () { return gateway_client_1.GatewayClient; } });
|
|
46
61
|
var rest_client_1 = require("./http/rest-client");
|
|
47
62
|
Object.defineProperty(exports, "RestClient", { enumerable: true, get: function () { return rest_client_1.RestClient; } });
|
|
48
|
-
var
|
|
49
|
-
Object.defineProperty(exports, "DooverApiError", { enumerable: true, get: function () { return
|
|
50
|
-
Object.defineProperty(exports, "DooverGatewayError", { enumerable: true, get: function () { return
|
|
51
|
-
Object.defineProperty(exports, "DooverValidationError", { enumerable: true, get: function () { return
|
|
63
|
+
var errors_4 = require("./http/errors");
|
|
64
|
+
Object.defineProperty(exports, "DooverApiError", { enumerable: true, get: function () { return errors_4.DooverApiError; } });
|
|
65
|
+
Object.defineProperty(exports, "DooverGatewayError", { enumerable: true, get: function () { return errors_4.DooverGatewayError; } });
|
|
66
|
+
Object.defineProperty(exports, "DooverValidationError", { enumerable: true, get: function () { return errors_4.DooverValidationError; } });
|
|
52
67
|
var doover_data_provider_1 = require("./viewer/doover-data-provider");
|
|
53
68
|
Object.defineProperty(exports, "DooverDataProvider", { enumerable: true, get: function () { return doover_data_provider_1.DooverDataProvider; } });
|
|
54
69
|
var path_parsing_1 = require("./viewer/path-parsing");
|
|
55
70
|
Object.defineProperty(exports, "getIdentifierFromPath", { enumerable: true, get: function () { return path_parsing_1.getIdentifierFromPath; } });
|
|
71
|
+
var audit_1 = require("./types/audit");
|
|
72
|
+
Object.defineProperty(exports, "DV_AUDIT_CHANNEL", { enumerable: true, get: function () { return audit_1.DV_AUDIT_CHANNEL; } });
|
|
56
73
|
var snowflake_1 = require("./utils/snowflake");
|
|
57
74
|
Object.defineProperty(exports, "addTimestampToMessage", { enumerable: true, get: function () { return snowflake_1.addTimestampToMessage; } });
|
|
58
75
|
Object.defineProperty(exports, "extractSnowflakeId", { enumerable: true, get: function () { return snowflake_1.extractSnowflakeId; } });
|
package/dist/react/context.d.ts
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import type { DataClient } from "../client/data-client";
|
|
3
3
|
export interface DooverProviderProps {
|
|
4
|
-
client:
|
|
4
|
+
client: DataClient;
|
|
5
5
|
children: ReactNode;
|
|
6
6
|
}
|
|
7
7
|
/**
|
|
8
|
-
* Wraps a React subtree with a `
|
|
8
|
+
* Wraps a React subtree with a `DataClient` instance so downstream hooks
|
|
9
9
|
* (`useDooverClient`, `useChannelAggregate`, etc.) can read it from context.
|
|
10
10
|
*
|
|
11
11
|
* Pair with a `@tanstack/react-query` `<QueryClientProvider>` in the same tree —
|
|
12
12
|
* the hooks call `useQueryClient()` internally and will throw without one.
|
|
13
|
+
*
|
|
14
|
+
* Accepts any `DataClient` implementation — `DooverClient` (single cloud source),
|
|
15
|
+
* `LocalAgentClient` (single local device), or `MultiplexClient` (fan-out across
|
|
16
|
+
* multiple sources).
|
|
13
17
|
*/
|
|
14
18
|
export declare function DooverProvider({ client, children }: DooverProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
15
19
|
/**
|
|
16
|
-
* Read the `
|
|
20
|
+
* Read the `DataClient` from context. Throws if called outside a
|
|
17
21
|
* `<DooverProvider>`.
|
|
18
22
|
*/
|
|
19
|
-
export declare function useDooverClient():
|
|
23
|
+
export declare function useDooverClient(): DataClient;
|
package/dist/react/context.js
CHANGED
|
@@ -6,17 +6,21 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
6
6
|
const react_1 = require("react");
|
|
7
7
|
const DooverClientContext = (0, react_1.createContext)(null);
|
|
8
8
|
/**
|
|
9
|
-
* Wraps a React subtree with a `
|
|
9
|
+
* Wraps a React subtree with a `DataClient` instance so downstream hooks
|
|
10
10
|
* (`useDooverClient`, `useChannelAggregate`, etc.) can read it from context.
|
|
11
11
|
*
|
|
12
12
|
* Pair with a `@tanstack/react-query` `<QueryClientProvider>` in the same tree —
|
|
13
13
|
* the hooks call `useQueryClient()` internally and will throw without one.
|
|
14
|
+
*
|
|
15
|
+
* Accepts any `DataClient` implementation — `DooverClient` (single cloud source),
|
|
16
|
+
* `LocalAgentClient` (single local device), or `MultiplexClient` (fan-out across
|
|
17
|
+
* multiple sources).
|
|
14
18
|
*/
|
|
15
19
|
function DooverProvider({ client, children }) {
|
|
16
20
|
return ((0, jsx_runtime_1.jsx)(DooverClientContext.Provider, { value: client, children: children }));
|
|
17
21
|
}
|
|
18
22
|
/**
|
|
19
|
-
* Read the `
|
|
23
|
+
* Read the `DataClient` from context. Throws if called outside a
|
|
20
24
|
* `<DooverProvider>`.
|
|
21
25
|
*/
|
|
22
26
|
function useDooverClient() {
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { DooverProvider, useDooverClient } from "./context";
|
|
2
2
|
export type { DooverProviderProps } from "./context";
|
|
3
|
+
export type { DataClientStatus, DataClientConnectionState, AgentScope } from "../client/data-client";
|
|
4
|
+
export { useClientStatus } from "./useClientStatus";
|
|
3
5
|
export { useConnectionState } from "./useConnectionState";
|
|
4
6
|
export type { ConnectionState, ConnectionStatus } from "./useConnectionState";
|
|
5
7
|
export { useAgentConnections, agentConnectionsQueryKey, } from "./useAgentConnections";
|
|
@@ -9,6 +11,7 @@ export { useChannelAggregate, channelAggregateQueryKey, } from "./useChannelAggr
|
|
|
9
11
|
export type { UseChannelAggregateOptions, UseChannelAggregateResult, } from "./useChannelAggregate";
|
|
10
12
|
export { useAgentChannel } from "./useAgentChannel";
|
|
11
13
|
export { useSendMessage } from "./useSendMessage";
|
|
14
|
+
export type { UseSendMessageOptions } from "./useSendMessage";
|
|
12
15
|
export { useUpdateAggregate } from "./useUpdateAggregate";
|
|
13
16
|
export type { UseUpdateAggregateOptions } from "./useUpdateAggregate";
|
|
14
17
|
export { useUpdateMessage } from "./useUpdateMessage";
|
package/dist/react/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resetSharedQueryClient = exports.getSharedQueryClient = exports.useTurnCredentials = exports.useDeviceMap = exports.multiAgentChannelMessagesQueryKey = exports.useMultiAgentChannelMessages = exports.multiAgentAggregatesQueryKey = exports.useMultiAgentAggregates = exports.useSendRpc = exports.invocationLogsQueryKey = exports.useInvocationLogs = exports.channelMessageQueryKey = exports.useChannelMessage = exports.channelMessagesQueryKey = exports.useChannelMessages = exports.useUpdateMessage = exports.useUpdateAggregate = exports.useSendMessage = exports.useAgentChannel = exports.channelAggregateQueryKey = exports.useChannelAggregate = exports.useChannelSubscription = exports.agentConnectionsQueryKey = exports.useAgentConnections = exports.useConnectionState = exports.useDooverClient = exports.DooverProvider = void 0;
|
|
3
|
+
exports.resetSharedQueryClient = exports.getSharedQueryClient = exports.useTurnCredentials = exports.useDeviceMap = exports.multiAgentChannelMessagesQueryKey = exports.useMultiAgentChannelMessages = exports.multiAgentAggregatesQueryKey = exports.useMultiAgentAggregates = exports.useSendRpc = exports.invocationLogsQueryKey = exports.useInvocationLogs = exports.channelMessageQueryKey = exports.useChannelMessage = exports.channelMessagesQueryKey = exports.useChannelMessages = exports.useUpdateMessage = exports.useUpdateAggregate = exports.useSendMessage = exports.useAgentChannel = exports.channelAggregateQueryKey = exports.useChannelAggregate = exports.useChannelSubscription = exports.agentConnectionsQueryKey = exports.useAgentConnections = exports.useConnectionState = exports.useClientStatus = exports.useDooverClient = exports.DooverProvider = void 0;
|
|
4
4
|
var context_1 = require("./context");
|
|
5
5
|
Object.defineProperty(exports, "DooverProvider", { enumerable: true, get: function () { return context_1.DooverProvider; } });
|
|
6
6
|
Object.defineProperty(exports, "useDooverClient", { enumerable: true, get: function () { return context_1.useDooverClient; } });
|
|
7
|
+
var useClientStatus_1 = require("./useClientStatus");
|
|
8
|
+
Object.defineProperty(exports, "useClientStatus", { enumerable: true, get: function () { return useClientStatus_1.useClientStatus; } });
|
|
7
9
|
var useConnectionState_1 = require("./useConnectionState");
|
|
8
10
|
Object.defineProperty(exports, "useConnectionState", { enumerable: true, get: function () { return useConnectionState_1.useConnectionState; } });
|
|
9
11
|
var useAgentConnections_1 = require("./useAgentConnections");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type UseQueryResult } from "@tanstack/react-query";
|
|
2
2
|
import type { Aggregate } from "../types/common";
|
|
3
3
|
import type { ChannelIdentifier } from "../types/viewer";
|
|
4
|
-
export declare function channelAggregateQueryKey(agentId: string | undefined, channelName: string | undefined): readonly ["doover", "agent", string | undefined, "channel", string | undefined];
|
|
4
|
+
export declare function channelAggregateQueryKey(agentId: string | undefined, channelName: string | undefined, sources?: string[]): readonly ["doover", "agent", string | undefined, "channel", string | undefined, "src", string];
|
|
5
5
|
/**
|
|
6
6
|
* Shape returned by `useChannelAggregate`. Shadows the react-query
|
|
7
7
|
* `data` field with the unwrapped aggregate payload (`TData`) so the
|
|
@@ -39,6 +39,13 @@ export interface UseChannelAggregateOptions {
|
|
|
39
39
|
* `AggregateUpdate` events.
|
|
40
40
|
*/
|
|
41
41
|
fetchInitial?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Restrict to these source ids on a `MultiplexClient`. Ignored for a plain
|
|
44
|
+
* `DooverClient` or `LocalAgentClient`. When set, the query key is
|
|
45
|
+
* source-dimensioned so data from different source subsets is cached
|
|
46
|
+
* independently.
|
|
47
|
+
*/
|
|
48
|
+
sources?: string[];
|
|
42
49
|
}
|
|
43
50
|
/**
|
|
44
51
|
* Fetch a channel's aggregate and keep it live via the gateway. Incoming
|
|
@@ -7,8 +7,9 @@ const react_query_1 = require("@tanstack/react-query");
|
|
|
7
7
|
const errors_1 = require("../http/errors");
|
|
8
8
|
const context_1 = require("./context");
|
|
9
9
|
const useChannelSubscription_1 = require("./useChannelSubscription");
|
|
10
|
-
function channelAggregateQueryKey(agentId, channelName) {
|
|
11
|
-
|
|
10
|
+
function channelAggregateQueryKey(agentId, channelName, sources) {
|
|
11
|
+
const sourceDim = sources && sources.length ? [...sources].sort().join(",") : "*";
|
|
12
|
+
return ["doover", "agent", agentId, "channel", channelName, "src", sourceDim];
|
|
12
13
|
}
|
|
13
14
|
/**
|
|
14
15
|
* Fetch a channel's aggregate and keep it live via the gateway. Incoming
|
|
@@ -25,20 +26,37 @@ function useChannelAggregate(identifier, options) {
|
|
|
25
26
|
const client = (0, context_1.useDooverClient)();
|
|
26
27
|
const queryClient = (0, react_query_1.useQueryClient)();
|
|
27
28
|
const { agentId, channelName } = identifier;
|
|
28
|
-
const
|
|
29
|
+
const sources = options?.sources;
|
|
30
|
+
const key = channelAggregateQueryKey(agentId, channelName, sources);
|
|
29
31
|
const fetchInitial = options?.fetchInitial ?? true;
|
|
30
32
|
const onAggregate = (0, react_1.useCallback)((aggregate) => {
|
|
31
33
|
queryClient.setQueryData(key, aggregate);
|
|
32
34
|
},
|
|
33
|
-
// The key array is structurally stable per (agentId, channelName).
|
|
35
|
+
// The key array is structurally stable per (agentId, channelName, sourceDim).
|
|
34
36
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35
|
-
[queryClient, agentId, channelName]);
|
|
37
|
+
[queryClient, agentId, channelName, sources?.join(",")]);
|
|
36
38
|
(0, useChannelSubscription_1.useChannelSubscription)(identifier, { onAggregate });
|
|
37
39
|
const query = (0, react_query_1.useQuery)({
|
|
38
40
|
queryKey: key,
|
|
39
41
|
enabled: fetchInitial && !!agentId && !!channelName,
|
|
40
42
|
staleTime: Infinity,
|
|
41
|
-
queryFn: () =>
|
|
43
|
+
queryFn: async () => {
|
|
44
|
+
if (!agentId || !channelName)
|
|
45
|
+
return undefined;
|
|
46
|
+
const id = { agentId, channelName };
|
|
47
|
+
// Pass `{ sources }` as a trailing bag only when set. The TypeScript
|
|
48
|
+
// overloads don't declare it, so we cast through `never` — the runtime
|
|
49
|
+
// implementation reads it via `...args: unknown[]`.
|
|
50
|
+
const sourcesArg = sources ? { sources } : undefined;
|
|
51
|
+
const channel = sourcesArg
|
|
52
|
+
? await client.channels.getChannel(id, sourcesArg)
|
|
53
|
+
: await client.channels.getChannel(id);
|
|
54
|
+
if (channel.aggregate)
|
|
55
|
+
return channel.aggregate;
|
|
56
|
+
return (sourcesArg
|
|
57
|
+
? await client.aggregates.getAggregate(id, sourcesArg)
|
|
58
|
+
: await client.aggregates.getAggregate(id));
|
|
59
|
+
},
|
|
42
60
|
// A 404 means the aggregate doesn't exist — retrying won't change that,
|
|
43
61
|
// and the caller needs the error promptly to render an empty/"not
|
|
44
62
|
// installed" state. Fall back to the react-query default (3 retries) for
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
import { type UseQueryResult } from "@tanstack/react-query";
|
|
2
2
|
import type { JSONValue, MessageAttachment, MessageStructure } from "../types/common";
|
|
3
3
|
import type { ChannelIdentifier } from "../types/viewer";
|
|
4
|
-
export declare function channelMessageQueryKey(agentId: string | undefined, channelName: string | undefined, messageId: string | undefined): readonly ["doover", "agent", string | undefined, "channel", string | undefined, "message", string | undefined];
|
|
4
|
+
export declare function channelMessageQueryKey(agentId: string | undefined, channelName: string | undefined, messageId: string | undefined, sources?: string[]): readonly ["doover", "agent", string | undefined, "channel", string | undefined, "message", string | undefined, "src", string];
|
|
5
5
|
export interface UseChannelMessageOptions {
|
|
6
6
|
/** If false, skip subscribing for live message-update events. Defaults true. */
|
|
7
7
|
liveUpdates?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Restrict to these source ids on a `MultiplexClient`. Ignored for a plain
|
|
10
|
+
* `DooverClient` or `LocalAgentClient`. When set, the query key is
|
|
11
|
+
* source-dimensioned so data from different source subsets is cached
|
|
12
|
+
* independently.
|
|
13
|
+
*/
|
|
14
|
+
sources?: string[];
|
|
8
15
|
}
|
|
9
16
|
/**
|
|
10
17
|
* Shape returned by `useChannelMessage`. Mirrors `UseChannelAggregateResult`:
|
|
@@ -6,7 +6,8 @@ const react_1 = require("react");
|
|
|
6
6
|
const react_query_1 = require("@tanstack/react-query");
|
|
7
7
|
const context_1 = require("./context");
|
|
8
8
|
const useChannelSubscription_1 = require("./useChannelSubscription");
|
|
9
|
-
function channelMessageQueryKey(agentId, channelName, messageId) {
|
|
9
|
+
function channelMessageQueryKey(agentId, channelName, messageId, sources) {
|
|
10
|
+
const sourceDim = sources && sources.length ? [...sources].sort().join(",") : "*";
|
|
10
11
|
return [
|
|
11
12
|
"doover",
|
|
12
13
|
"agent",
|
|
@@ -15,6 +16,8 @@ function channelMessageQueryKey(agentId, channelName, messageId) {
|
|
|
15
16
|
channelName,
|
|
16
17
|
"message",
|
|
17
18
|
messageId,
|
|
19
|
+
"src",
|
|
20
|
+
sourceDim,
|
|
18
21
|
];
|
|
19
22
|
}
|
|
20
23
|
/**
|
|
@@ -35,15 +38,16 @@ function useChannelMessage(identifier, messageId, options) {
|
|
|
35
38
|
const queryClient = (0, react_query_1.useQueryClient)();
|
|
36
39
|
const { agentId, channelName } = identifier;
|
|
37
40
|
const liveUpdates = options?.liveUpdates ?? true;
|
|
38
|
-
const
|
|
41
|
+
const sources = options?.sources;
|
|
42
|
+
const key = channelMessageQueryKey(agentId, channelName, messageId, sources);
|
|
39
43
|
const onMessageUpdate = (0, react_1.useCallback)((message) => {
|
|
40
44
|
if (message.id !== messageId)
|
|
41
45
|
return;
|
|
42
46
|
queryClient.setQueryData(key, message);
|
|
43
47
|
},
|
|
44
|
-
// The key array is structurally stable per (agentId, channelName, messageId).
|
|
48
|
+
// The key array is structurally stable per (agentId, channelName, messageId, sourceDim).
|
|
45
49
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
46
|
-
[queryClient, agentId, channelName, messageId]);
|
|
50
|
+
[queryClient, agentId, channelName, messageId, sources?.join(",")]);
|
|
47
51
|
// Cover the case where the caller has the id before the create event has
|
|
48
52
|
// landed on this client — patch the cache when it shows up.
|
|
49
53
|
const onMessage = (0, react_1.useCallback)((message) => {
|
|
@@ -52,13 +56,20 @@ function useChannelMessage(identifier, messageId, options) {
|
|
|
52
56
|
queryClient.setQueryData(key, message);
|
|
53
57
|
},
|
|
54
58
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
55
|
-
[queryClient, agentId, channelName, messageId]);
|
|
59
|
+
[queryClient, agentId, channelName, messageId, sources?.join(",")]);
|
|
56
60
|
(0, useChannelSubscription_1.useChannelSubscription)(liveUpdates && messageId ? identifier : undefined, { onMessage, onMessageUpdate });
|
|
57
61
|
const query = (0, react_query_1.useQuery)({
|
|
58
62
|
queryKey: key,
|
|
59
63
|
enabled: !!agentId && !!channelName && !!messageId,
|
|
60
64
|
staleTime: Infinity,
|
|
61
|
-
queryFn: () =>
|
|
65
|
+
queryFn: () => {
|
|
66
|
+
// Pass `{ sources }` as a trailing bag only when set — cast through
|
|
67
|
+
// `never` since the TypeScript overloads don't declare it.
|
|
68
|
+
const sourcesArg = sources ? { sources } : undefined;
|
|
69
|
+
return (sourcesArg
|
|
70
|
+
? client.messages.getMessage(agentId, channelName, messageId, sourcesArg)
|
|
71
|
+
: client.messages.getMessage(agentId, channelName, messageId));
|
|
72
|
+
},
|
|
62
73
|
});
|
|
63
74
|
const message = query.data;
|
|
64
75
|
const { data: _ignored, ...rest } = query;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type InfiniteData, type UseInfiniteQueryResult } from "@tanstack/react-query";
|
|
2
2
|
import type { MessageStructure } from "../types/common";
|
|
3
3
|
import type { ChannelIdentifier } from "../types/viewer";
|
|
4
|
-
export declare function channelMessagesQueryKey(agentId: string | undefined, channelName: string | undefined, fields?: readonly string[]): readonly ["doover", "agent", string | undefined, "channel", string | undefined, "messages"] | readonly ["doover", "agent", string | undefined, "channel", string | undefined, "messages", {
|
|
4
|
+
export declare function channelMessagesQueryKey(agentId: string | undefined, channelName: string | undefined, fields?: readonly string[], sources?: string[]): readonly ["doover", "agent", string | undefined, "channel", string | undefined, "messages", "src", string] | readonly ["doover", "agent", string | undefined, "channel", string | undefined, "messages", "src", string, {
|
|
5
5
|
readonly fields: string[];
|
|
6
6
|
}];
|
|
7
7
|
export interface UseChannelMessagesOptions {
|
|
@@ -35,6 +35,13 @@ export interface UseChannelMessagesOptions {
|
|
|
35
35
|
* bound this will walk the channel back to its first message.
|
|
36
36
|
*/
|
|
37
37
|
autoPaginate?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Restrict to these source ids on a `MultiplexClient`. Ignored for a plain
|
|
40
|
+
* `DooverClient` or `LocalAgentClient`. When set, the query key is
|
|
41
|
+
* source-dimensioned so data from different source subsets is cached
|
|
42
|
+
* independently.
|
|
43
|
+
*/
|
|
44
|
+
sources?: string[];
|
|
38
45
|
}
|
|
39
46
|
type Page<TData> = MessageStructure<TData>[];
|
|
40
47
|
export interface UseChannelMessagesResult<TData> extends Omit<UseInfiniteQueryResult<InfiniteData<Page<TData>>>, "data"> {
|
|
@@ -6,8 +6,11 @@ const react_1 = require("react");
|
|
|
6
6
|
const react_query_1 = require("@tanstack/react-query");
|
|
7
7
|
const context_1 = require("./context");
|
|
8
8
|
const useChannelSubscription_1 = require("./useChannelSubscription");
|
|
9
|
-
function channelMessagesQueryKey(agentId, channelName, fields) {
|
|
10
|
-
|
|
9
|
+
function channelMessagesQueryKey(agentId, channelName, fields, sources) {
|
|
10
|
+
// Source-dimension the key (multiplex source subsets cache independently);
|
|
11
|
+
// "*" means "all/unspecified" for a plain DooverClient/LocalAgentClient.
|
|
12
|
+
const sourceDim = sources && sources.length ? [...sources].sort().join(",") : "*";
|
|
13
|
+
const key = ["doover", "agent", agentId, "channel", channelName, "messages", "src", sourceDim];
|
|
11
14
|
if (!fields || fields.length === 0)
|
|
12
15
|
return key;
|
|
13
16
|
// A `field_name`-filtered request returns a different message stream than
|
|
@@ -33,7 +36,8 @@ function useChannelMessages(identifier, options) {
|
|
|
33
36
|
const initialBefore = options?.initialBefore;
|
|
34
37
|
const after = options?.after;
|
|
35
38
|
const autoPaginate = options?.autoPaginate ?? false;
|
|
36
|
-
const
|
|
39
|
+
const sources = options?.sources;
|
|
40
|
+
const key = channelMessagesQueryKey(agentId, channelName, fields, sources);
|
|
37
41
|
const onMessage = (0, react_1.useCallback)((message) => {
|
|
38
42
|
// This cache entry is scoped to `fields`; the gateway delivers every
|
|
39
43
|
// message on the channel, so drop live pushes whose payload doesn't
|
|
@@ -59,7 +63,7 @@ function useChannelMessages(identifier, options) {
|
|
|
59
63
|
});
|
|
60
64
|
},
|
|
61
65
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
62
|
-
[queryClient, agentId, channelName, fields?.join(",")]);
|
|
66
|
+
[queryClient, agentId, channelName, fields?.join(","), sources?.join(",")]);
|
|
63
67
|
(0, useChannelSubscription_1.useChannelSubscription)(liveUpdates ? identifier : undefined, { onMessage });
|
|
64
68
|
const query = (0, react_query_1.useInfiniteQuery)({
|
|
65
69
|
queryKey: key,
|
|
@@ -68,13 +72,23 @@ function useChannelMessages(identifier, options) {
|
|
|
68
72
|
initialPageParam: initialBefore,
|
|
69
73
|
getNextPageParam: (lastPage) => lastPage && lastPage.length > 0 ? lastPage[0]?.id : undefined,
|
|
70
74
|
queryFn: async ({ pageParam }) => {
|
|
71
|
-
|
|
75
|
+
if (!agentId || !channelName)
|
|
76
|
+
return [];
|
|
77
|
+
const id = { agentId, channelName };
|
|
78
|
+
const params = {
|
|
72
79
|
...(typeof pageParam === "string" ? { before: pageParam } : {}),
|
|
73
80
|
...(limit !== undefined ? { limit } : {}),
|
|
74
81
|
...(fields && fields.length > 0 ? { field_name: fields } : {}),
|
|
75
82
|
...(after !== undefined ? { after } : {}),
|
|
76
|
-
|
|
77
|
-
|
|
83
|
+
order: "asc",
|
|
84
|
+
};
|
|
85
|
+
// Pass `{ sources }` as a trailing bag only when set — cast through
|
|
86
|
+
// `never` since the TypeScript overloads don't declare it.
|
|
87
|
+
const sourcesArg = sources ? { sources } : undefined;
|
|
88
|
+
const page = sourcesArg
|
|
89
|
+
? await client.messages.listMessages(id, params, sourcesArg)
|
|
90
|
+
: await client.messages.listMessages(id, params);
|
|
91
|
+
return page;
|
|
78
92
|
},
|
|
79
93
|
});
|
|
80
94
|
(0, react_1.useEffect)(() => {
|
|
@@ -9,6 +9,12 @@ export interface ChannelSubscriptionHandlers {
|
|
|
9
9
|
*/
|
|
10
10
|
onMessageUpdate?: (message: MessageStructure, request_data?: JSONValue) => void;
|
|
11
11
|
onAggregate?: (aggregate: Aggregate) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Reserved for future use. The composite gateway already routes by
|
|
14
|
+
* `channel.agent_id`, so this option is a no-op in v1. Pass it for
|
|
15
|
+
* forward-compatibility; it has no effect on the subscription.
|
|
16
|
+
*/
|
|
17
|
+
sources?: string[];
|
|
12
18
|
}
|
|
13
19
|
/**
|
|
14
20
|
* Attach live-update handlers to a channel for the lifetime of the host
|