doover-js 0.11.0 → 0.13.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/README.md +106 -0
- package/dist/apis/_args.js +5 -5
- package/dist/apis/agents-api.d.ts +4 -4
- package/dist/apis/agents-api.js +2 -2
- package/dist/apis/aggregates-api.d.ts +4 -4
- package/dist/apis/aggregates-api.js +5 -5
- package/dist/apis/alarms-api.d.ts +2 -2
- package/dist/apis/alarms-api.js +3 -3
- package/dist/apis/channels-api.d.ts +3 -3
- package/dist/apis/channels-api.js +6 -6
- package/dist/apis/connections-api.d.ts +2 -2
- package/dist/apis/connections-api.js +6 -6
- package/dist/apis/messages-api.d.ts +4 -4
- package/dist/apis/messages-api.js +11 -11
- package/dist/apis/notifications-api.d.ts +2 -2
- package/dist/apis/notifications-api.js +4 -4
- package/dist/apis/organisations-api.d.ts +2 -2
- package/dist/apis/permissions-api.d.ts +2 -2
- package/dist/apis/permissions-api.js +3 -3
- package/dist/apis/processors-api.d.ts +2 -2
- package/dist/apis/turn-api.d.ts +2 -2
- package/dist/apis/users-api.d.ts +2 -2
- package/dist/auth/auth-store.d.ts +1 -1
- package/dist/auth/build-auth.d.ts +3 -3
- package/dist/auth/build-auth.js +8 -8
- package/dist/auth/cookie-auth.d.ts +1 -1
- package/dist/auth/cookie-auth.js +2 -2
- package/dist/auth/doover-auth.d.ts +2 -2
- package/dist/auth/doover-token-auth.d.ts +3 -3
- package/dist/auth/doover-token-auth.js +13 -13
- package/dist/auth/index.d.ts +10 -0
- package/dist/auth/index.js +15 -0
- package/dist/client/data-client.d.ts +17 -14
- package/dist/client/doover-client.d.ts +9 -7
- package/dist/client/doover-client.js +44 -42
- package/dist/client/errors.d.ts +2 -2
- package/dist/client/errors.js +4 -4
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +12 -0
- package/dist/client/local-agent-client.d.ts +3 -3
- package/dist/client/local-agent-client.js +19 -19
- package/dist/client/multiplex-client.d.ts +5 -5
- package/dist/client/multiplex-client.js +25 -25
- package/dist/client/multiplex-gateway.d.ts +3 -3
- package/dist/client/multiplex-merge.d.ts +1 -1
- package/dist/client/network-status.d.ts +17 -0
- package/dist/client/network-status.js +70 -0
- package/dist/client/offline-cache.d.ts +9 -4
- package/dist/client/offline-cache.js +34 -22
- package/dist/client/provenance.d.ts +1 -1
- package/dist/client/request-options.d.ts +1 -1
- package/dist/client/singleton.d.ts +2 -2
- package/dist/client/singleton.js +2 -2
- package/dist/client/status-tracker.d.ts +1 -1
- package/dist/esm/apis/_args.d.ts +16 -0
- package/dist/esm/apis/_args.js +27 -0
- package/dist/esm/apis/agents-api.d.ts +196 -0
- package/dist/esm/apis/agents-api.js +327 -0
- package/dist/esm/apis/aggregates-api.d.ts +67 -0
- package/dist/esm/apis/aggregates-api.js +64 -0
- package/dist/esm/apis/alarms-api.d.ts +48 -0
- package/dist/esm/apis/alarms-api.js +75 -0
- package/dist/esm/apis/channels-api.d.ts +83 -0
- package/dist/esm/apis/channels-api.js +65 -0
- package/dist/esm/apis/connections-api.d.ts +45 -0
- package/dist/esm/apis/connections-api.js +44 -0
- package/dist/esm/apis/messages-api.d.ts +128 -0
- package/dist/esm/apis/messages-api.js +179 -0
- package/dist/esm/apis/notifications-api.d.ts +94 -0
- package/dist/esm/apis/notifications-api.js +153 -0
- package/dist/esm/apis/organisations-api.d.ts +26 -0
- package/dist/esm/apis/organisations-api.js +41 -0
- package/dist/esm/apis/permissions-api.d.ts +17 -0
- package/dist/esm/apis/permissions-api.js +23 -0
- package/dist/esm/apis/processors-api.d.ts +56 -0
- package/dist/esm/apis/processors-api.js +97 -0
- package/dist/esm/apis/turn-api.d.ts +7 -0
- package/dist/esm/apis/turn-api.js +8 -0
- package/dist/esm/apis/users-api.d.ts +8 -0
- package/dist/esm/apis/users-api.js +9 -0
- package/dist/esm/auth/auth-profile.d.ts +45 -0
- package/dist/esm/auth/auth-profile.js +68 -0
- package/dist/esm/auth/auth-store.d.ts +14 -0
- package/dist/esm/auth/build-auth.d.ts +38 -0
- package/dist/esm/auth/build-auth.js +92 -0
- package/dist/esm/auth/cookie-auth.d.ts +91 -0
- package/dist/esm/auth/cookie-auth.js +196 -0
- package/dist/esm/auth/doover-auth.d.ts +52 -0
- package/dist/esm/auth/doover-auth.js +28 -0
- package/dist/esm/auth/doover-token-auth.d.ts +39 -0
- package/dist/esm/auth/doover-token-auth.js +217 -0
- package/dist/esm/auth/errors.d.ts +3 -0
- package/dist/esm/auth/errors.js +6 -0
- package/dist/esm/auth/index.d.ts +10 -0
- package/dist/esm/auth/index.js +6 -0
- package/dist/esm/auth/jwt.d.ts +6 -0
- package/dist/esm/auth/jwt.js +26 -0
- package/dist/esm/client/capabilities.d.ts +10 -0
- package/dist/esm/client/capabilities.js +42 -0
- package/dist/esm/client/data-client.d.ts +107 -0
- package/dist/esm/client/doover-client.d.ts +48 -0
- package/dist/esm/client/doover-client.js +96 -0
- package/dist/esm/client/errors.d.ts +32 -0
- package/dist/esm/client/errors.js +64 -0
- package/dist/esm/client/index.d.ts +6 -0
- package/dist/esm/client/index.js +3 -0
- package/dist/esm/client/local-agent-client.d.ts +65 -0
- package/dist/esm/client/local-agent-client.js +225 -0
- package/dist/esm/client/multiplex-client.d.ts +165 -0
- package/dist/esm/client/multiplex-client.js +842 -0
- package/dist/esm/client/multiplex-gateway.d.ts +49 -0
- package/dist/esm/client/multiplex-gateway.js +110 -0
- package/dist/esm/client/multiplex-merge.d.ts +12 -0
- package/dist/esm/client/multiplex-merge.js +38 -0
- package/dist/esm/client/network-status.d.ts +17 -0
- package/dist/esm/client/network-status.js +66 -0
- package/dist/esm/client/offline-cache.d.ts +167 -0
- package/dist/esm/client/offline-cache.js +769 -0
- package/dist/esm/client/provenance.d.ts +60 -0
- package/dist/esm/client/provenance.js +108 -0
- package/dist/esm/client/request-options.d.ts +23 -0
- package/dist/esm/client/request-options.js +23 -0
- package/dist/esm/client/singleton.d.ts +26 -0
- package/dist/esm/client/singleton.js +54 -0
- package/dist/esm/client/stats.d.ts +79 -0
- package/dist/esm/client/stats.js +155 -0
- package/dist/esm/client/status-tracker.d.ts +24 -0
- package/dist/esm/client/status-tracker.js +86 -0
- package/dist/esm/gateway/gateway-client.d.ts +86 -0
- package/dist/esm/gateway/gateway-client.js +463 -0
- package/dist/esm/gateway/index.d.ts +3 -0
- package/dist/esm/gateway/index.js +1 -0
- package/dist/esm/gateway/types.d.ts +142 -0
- package/dist/esm/http/errors.d.ts +19 -0
- package/dist/esm/http/errors.js +22 -0
- package/dist/esm/http/index.d.ts +3 -0
- package/dist/esm/http/index.js +2 -0
- package/dist/esm/http/rest-client.d.ts +64 -0
- package/dist/esm/http/rest-client.js +181 -0
- package/dist/esm/index.d.ts +64 -0
- package/dist/esm/index.js +38 -0
- package/dist/esm/node/config-manager.d.ts +34 -0
- package/dist/esm/node/config-manager.js +140 -0
- package/dist/esm/node/index.d.ts +1 -0
- package/dist/esm/node/index.js +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/react/context.d.ts +23 -0
- package/dist/esm/react/context.js +28 -0
- package/dist/esm/react/index.d.ts +38 -0
- package/dist/esm/react/index.js +21 -0
- package/dist/esm/react/messageRangeStore.d.ts +93 -0
- package/dist/esm/react/messageRangeStore.js +140 -0
- package/dist/esm/react/sharedQueryClient.d.ts +21 -0
- package/dist/esm/react/sharedQueryClient.js +35 -0
- package/dist/esm/react/useAgentChannel.d.ts +8 -0
- package/dist/esm/react/useAgentChannel.js +9 -0
- package/dist/esm/react/useAgentConnections.d.ts +8 -0
- package/dist/esm/react/useAgentConnections.js +20 -0
- package/dist/esm/react/useAgentTokenState.d.ts +70 -0
- package/dist/esm/react/useAgentTokenState.js +127 -0
- package/dist/esm/react/useChannelAggregate.d.ts +64 -0
- package/dist/esm/react/useChannelAggregate.js +77 -0
- package/dist/esm/react/useChannelMessage.d.ts +45 -0
- package/dist/esm/react/useChannelMessage.js +79 -0
- package/dist/esm/react/useChannelMessages.d.ts +83 -0
- package/dist/esm/react/useChannelMessages.js +214 -0
- package/dist/esm/react/useChannelSubscription.d.ts +27 -0
- package/dist/esm/react/useChannelSubscription.js +30 -0
- package/dist/esm/react/useClientStatus.d.ts +10 -0
- package/dist/esm/react/useClientStatus.js +19 -0
- package/dist/esm/react/useConnectionState.d.ts +26 -0
- package/dist/esm/react/useConnectionState.js +45 -0
- package/dist/esm/react/useDeviceMap.d.ts +109 -0
- package/dist/esm/react/useDeviceMap.js +59 -0
- package/dist/esm/react/useInvocationLogs.d.ts +23 -0
- package/dist/esm/react/useInvocationLogs.js +37 -0
- package/dist/esm/react/useMultiAgentAggregates.d.ts +38 -0
- package/dist/esm/react/useMultiAgentAggregates.js +104 -0
- package/dist/esm/react/useMultiAgentChannelMessages.d.ts +79 -0
- package/dist/esm/react/useMultiAgentChannelMessages.js +169 -0
- package/dist/esm/react/useOfflineStatus.d.ts +8 -0
- package/dist/esm/react/useOfflineStatus.js +37 -0
- package/dist/esm/react/useSendMessage.d.ts +16 -0
- package/dist/esm/react/useSendMessage.js +26 -0
- package/dist/esm/react/useSendRpc.d.ts +68 -0
- package/dist/esm/react/useSendRpc.js +164 -0
- package/dist/esm/react/useTurnCredentials.d.ts +12 -0
- package/dist/esm/react/useTurnCredentials.js +22 -0
- package/dist/esm/react/useUpdateAggregate.d.ts +27 -0
- package/dist/esm/react/useUpdateAggregate.js +39 -0
- package/dist/esm/react/useUpdateMessage.d.ts +38 -0
- package/dist/esm/react/useUpdateMessage.js +36 -0
- package/dist/esm/refine/index.d.ts +72 -0
- package/dist/esm/refine/index.js +215 -0
- package/dist/esm/rpc/errors.d.ts +10 -0
- package/dist/esm/rpc/errors.js +19 -0
- package/dist/esm/rpc/index.d.ts +3 -0
- package/dist/esm/rpc/index.js +2 -0
- package/dist/esm/rpc/rpc-dispatcher.d.ts +41 -0
- package/dist/esm/rpc/rpc-dispatcher.js +141 -0
- package/dist/esm/types/audit.d.ts +53 -0
- package/dist/esm/types/audit.js +11 -0
- package/dist/esm/types/batch.d.ts +85 -0
- package/dist/esm/types/batch.js +42 -0
- package/dist/esm/types/common.d.ts +250 -0
- package/dist/esm/types/connection.d.ts +72 -0
- package/dist/esm/types/connection.js +7 -0
- package/dist/esm/types/index.d.ts +9 -0
- package/dist/esm/types/openapi.d.ts +195 -0
- package/dist/esm/types/provenance.d.ts +45 -0
- package/dist/esm/types/viewer.d.ts +122 -0
- package/dist/esm/utils/snowflake.d.ts +21 -0
- package/dist/esm/utils/snowflake.js +33 -0
- package/dist/esm/viewer/doover-data-provider.d.ts +90 -0
- package/dist/esm/viewer/doover-data-provider.js +189 -0
- package/dist/esm/viewer/path-parsing.d.ts +5 -0
- package/dist/esm/viewer/path-parsing.js +35 -0
- package/dist/gateway/gateway-client.d.ts +5 -5
- package/dist/gateway/gateway-client.js +5 -5
- package/dist/gateway/index.d.ts +3 -0
- package/dist/gateway/index.js +5 -0
- package/dist/gateway/types.d.ts +1 -1
- package/dist/http/index.d.ts +3 -0
- package/dist/http/index.js +9 -0
- package/dist/http/rest-client.d.ts +5 -3
- package/dist/http/rest-client.js +2 -2
- package/dist/index.d.ts +64 -62
- package/dist/index.js +92 -89
- package/dist/node/config-manager.d.ts +2 -2
- package/dist/node/config-manager.js +5 -5
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.js +2 -2
- package/dist/react/context.d.ts +1 -1
- package/dist/react/index.d.ts +38 -38
- package/dist/react/index.js +59 -59
- package/dist/react/messageRangeStore.d.ts +1 -1
- package/dist/react/useAgentChannel.d.ts +3 -3
- package/dist/react/useAgentChannel.js +2 -2
- package/dist/react/useAgentConnections.d.ts +1 -1
- package/dist/react/useAgentConnections.js +2 -2
- package/dist/react/useAgentTokenState.d.ts +3 -3
- package/dist/react/useAgentTokenState.js +8 -8
- package/dist/react/useChannelAggregate.d.ts +3 -3
- package/dist/react/useChannelAggregate.js +8 -8
- package/dist/react/useChannelMessage.d.ts +2 -2
- package/dist/react/useChannelMessage.js +4 -4
- package/dist/react/useChannelMessages.d.ts +3 -3
- package/dist/react/useChannelMessages.js +10 -10
- package/dist/react/useChannelSubscription.d.ts +2 -2
- package/dist/react/useChannelSubscription.js +2 -2
- package/dist/react/useClientStatus.d.ts +1 -1
- package/dist/react/useClientStatus.js +2 -2
- package/dist/react/useConnectionState.js +2 -2
- package/dist/react/useDeviceMap.js +2 -2
- package/dist/react/useInvocationLogs.d.ts +1 -1
- package/dist/react/useInvocationLogs.js +2 -2
- package/dist/react/useMultiAgentAggregates.d.ts +1 -1
- package/dist/react/useMultiAgentAggregates.js +5 -5
- package/dist/react/useMultiAgentChannelMessages.d.ts +1 -1
- package/dist/react/useMultiAgentChannelMessages.js +2 -2
- package/dist/react/useOfflineStatus.d.ts +2 -2
- package/dist/react/useOfflineStatus.js +31 -17
- package/dist/react/useSendMessage.d.ts +2 -2
- package/dist/react/useSendMessage.js +2 -2
- package/dist/react/useSendRpc.d.ts +2 -2
- package/dist/react/useSendRpc.js +2 -2
- package/dist/react/useTurnCredentials.d.ts +2 -2
- package/dist/react/useTurnCredentials.js +2 -2
- package/dist/react/useUpdateAggregate.d.ts +3 -3
- package/dist/react/useUpdateAggregate.js +4 -4
- package/dist/react/useUpdateMessage.d.ts +2 -2
- package/dist/react/useUpdateMessage.js +2 -2
- package/dist/refine/index.d.ts +1 -1
- package/dist/rpc/errors.d.ts +1 -1
- package/dist/rpc/index.d.ts +3 -0
- package/dist/rpc/index.js +7 -0
- package/dist/rpc/rpc-dispatcher.d.ts +4 -4
- package/dist/rpc/rpc-dispatcher.js +2 -2
- package/dist/types/common.d.ts +1 -1
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.js +2 -0
- package/dist/types/openapi.d.ts +1 -1
- package/dist/types/viewer.d.ts +2 -2
- package/dist/viewer/doover-data-provider.d.ts +10 -10
- package/dist/viewer/doover-data-provider.js +25 -25
- package/dist/viewer/path-parsing.d.ts +1 -1
- package/package.json +795 -8
- package/dist/test/api-args.test.js +0 -48
- package/dist/test/api-overloads.test.d.ts +0 -9
- package/dist/test/api-overloads.test.js +0 -330
- package/dist/test/apis.test.js +0 -408
- package/dist/test/auth.test.js +0 -708
- package/dist/test/batch-apis.test.js +0 -183
- package/dist/test/capabilities.test.js +0 -27
- package/dist/test/config-manager.test.js +0 -160
- package/dist/test/data-client-errors.test.js +0 -24
- package/dist/test/data-client-shape.test.js +0 -28
- package/dist/test/doover-client-dataclient.test.d.ts +0 -1
- package/dist/test/doover-client-dataclient.test.js +0 -58
- package/dist/test/doover-client-provenance.test.d.ts +0 -1
- package/dist/test/doover-client-provenance.test.js +0 -32
- package/dist/test/doover-client.test.d.ts +0 -1
- package/dist/test/doover-client.test.js +0 -42
- package/dist/test/doover-data-provider.test.d.ts +0 -1
- package/dist/test/doover-data-provider.test.js +0 -657
- package/dist/test/exports.test.d.ts +0 -1
- package/dist/test/exports.test.js +0 -80
- package/dist/test/gateway-client.test.d.ts +0 -1
- package/dist/test/gateway-client.test.js +0 -474
- package/dist/test/gateway-provenance.test.d.ts +0 -1
- package/dist/test/gateway-provenance.test.js +0 -29
- package/dist/test/gateway-subscriptions.test.d.ts +0 -1
- package/dist/test/gateway-subscriptions.test.js +0 -95
- package/dist/test/helpers.d.ts +0 -32
- package/dist/test/helpers.js +0 -115
- package/dist/test/local-agent-client.test.d.ts +0 -1
- package/dist/test/local-agent-client.test.js +0 -202
- package/dist/test/message-range-store.test.d.ts +0 -1
- package/dist/test/message-range-store.test.js +0 -183
- package/dist/test/multiplex-capabilities.test.d.ts +0 -1
- package/dist/test/multiplex-capabilities.test.js +0 -37
- package/dist/test/multiplex-conflicts.test.d.ts +0 -1
- package/dist/test/multiplex-conflicts.test.js +0 -35
- package/dist/test/multiplex-gateway.test.d.ts +0 -1
- package/dist/test/multiplex-gateway.test.js +0 -103
- package/dist/test/multiplex-merge.test.d.ts +0 -1
- package/dist/test/multiplex-merge.test.js +0 -19
- package/dist/test/multiplex-noncore.test.d.ts +0 -1
- package/dist/test/multiplex-noncore.test.js +0 -82
- package/dist/test/multiplex-passthrough.test.d.ts +0 -1
- package/dist/test/multiplex-passthrough.test.js +0 -35
- package/dist/test/multiplex-reads.test.d.ts +0 -1
- package/dist/test/multiplex-reads.test.js +0 -87
- package/dist/test/multiplex-registry.test.d.ts +0 -1
- package/dist/test/multiplex-registry.test.js +0 -81
- package/dist/test/multiplex-routing.test.d.ts +0 -1
- package/dist/test/multiplex-routing.test.js +0 -45
- package/dist/test/multiplex-status.test.d.ts +0 -1
- package/dist/test/multiplex-status.test.js +0 -63
- package/dist/test/multiplex-writes.test.d.ts +0 -1
- package/dist/test/multiplex-writes.test.js +0 -93
- package/dist/test/offline-cache.test.d.ts +0 -1
- package/dist/test/offline-cache.test.js +0 -289
- package/dist/test/provenance-regression.test.d.ts +0 -1
- package/dist/test/provenance-regression.test.js +0 -45
- package/dist/test/provenance-stamper.test.d.ts +0 -1
- package/dist/test/provenance-stamper.test.js +0 -41
- package/dist/test/provenance-type.test.d.ts +0 -1
- package/dist/test/provenance-type.test.js +0 -15
- package/dist/test/react-channel-messages-forward.test.d.ts +0 -1
- package/dist/test/react-channel-messages-forward.test.js +0 -139
- package/dist/test/react-channel-messages-range.test.d.ts +0 -1
- package/dist/test/react-channel-messages-range.test.js +0 -109
- package/dist/test/react-client-status.test.d.ts +0 -1
- package/dist/test/react-client-status.test.js +0 -35
- package/dist/test/react-dataclient.test.d.ts +0 -1
- package/dist/test/react-dataclient.test.js +0 -28
- package/dist/test/react-exports.test.d.ts +0 -1
- package/dist/test/react-exports.test.js +0 -46
- package/dist/test/react-multiagent-messages.test.d.ts +0 -1
- package/dist/test/react-multiagent-messages.test.js +0 -113
- package/dist/test/react-sources-option.test.d.ts +0 -1
- package/dist/test/react-sources-option.test.js +0 -41
- package/dist/test/react.test.d.ts +0 -1
- package/dist/test/react.test.js +0 -482
- package/dist/test/refine.test.d.ts +0 -1
- package/dist/test/refine.test.js +0 -71
- package/dist/test/rest-client.test.d.ts +0 -1
- package/dist/test/rest-client.test.js +0 -197
- package/dist/test/rpc-dispatcher.test.d.ts +0 -1
- package/dist/test/rpc-dispatcher.test.js +0 -251
- package/dist/test/singleton.test.d.ts +0 -1
- package/dist/test/singleton.test.js +0 -62
- package/dist/test/stats-rpc.test.d.ts +0 -1
- package/dist/test/stats-rpc.test.js +0 -69
- package/dist/test/status-tracker.test.d.ts +0 -1
- package/dist/test/status-tracker.test.js +0 -85
- package/dist/test/users-api.test.d.ts +0 -1
- package/dist/test/users-api.test.js +0 -19
- package/dist/test/utils.test.d.ts +0 -1
- package/dist/test/utils.test.js +0 -64
- /package/dist/{test/api-args.test.d.ts → esm/auth/auth-store.js} +0 -0
- /package/dist/{test/apis.test.d.ts → esm/client/data-client.js} +0 -0
- /package/dist/{test/auth.test.d.ts → esm/gateway/types.js} +0 -0
- /package/dist/{test/batch-apis.test.d.ts → esm/types/common.js} +0 -0
- /package/dist/{test/capabilities.test.d.ts → esm/types/index.js} +0 -0
- /package/dist/{test/config-manager.test.d.ts → esm/types/openapi.js} +0 -0
- /package/dist/{test/data-client-errors.test.d.ts → esm/types/provenance.js} +0 -0
- /package/dist/{test/data-client-shape.test.d.ts → esm/types/viewer.js} +0 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo } from "react";
|
|
2
|
+
import { useInfiniteQuery, useQueryClient, } from "@tanstack/react-query";
|
|
3
|
+
import { useDooverClient } from "./context.js";
|
|
4
|
+
export function multiAgentChannelMessagesQueryKey(channelName, agentIds, sources, scope) {
|
|
5
|
+
const sourceDim = sources && sources.length ? [...sources].sort().join(",") : "*";
|
|
6
|
+
const base = [
|
|
7
|
+
"doover",
|
|
8
|
+
"channel",
|
|
9
|
+
channelName,
|
|
10
|
+
"messages",
|
|
11
|
+
[...agentIds].sort().join(","),
|
|
12
|
+
"src",
|
|
13
|
+
sourceDim,
|
|
14
|
+
];
|
|
15
|
+
// Pagination cursors come from the first page's response and are scoped
|
|
16
|
+
// to *that* response's `after`/`fields`. Mixing them under one cache
|
|
17
|
+
// entry would cause `getNextPageParam` to anchor on an unrelated page,
|
|
18
|
+
// so a differently-bounded request must live under its own key.
|
|
19
|
+
const scopeKey = {};
|
|
20
|
+
if (scope?.after)
|
|
21
|
+
scopeKey.after = scope.after;
|
|
22
|
+
if (scope?.fields && scope.fields.length > 0) {
|
|
23
|
+
scopeKey.fields = [...scope.fields].sort();
|
|
24
|
+
}
|
|
25
|
+
return Object.keys(scopeKey).length > 0
|
|
26
|
+
? [...base, scopeKey]
|
|
27
|
+
: base;
|
|
28
|
+
}
|
|
29
|
+
function nextPageParam(lastPage) {
|
|
30
|
+
if (!lastPage)
|
|
31
|
+
return undefined;
|
|
32
|
+
const cursors = lastPage.next_cursors;
|
|
33
|
+
if (cursors) {
|
|
34
|
+
const entries = Object.entries(cursors);
|
|
35
|
+
// Present-but-empty means every agent drained its window: we're done.
|
|
36
|
+
if (entries.length === 0)
|
|
37
|
+
return undefined;
|
|
38
|
+
return {
|
|
39
|
+
agentIds: entries.map(([id]) => id),
|
|
40
|
+
agentBefore: entries.map(([, cursor]) => cursor),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Legacy server: one global `before` for whichever agents were at limit.
|
|
44
|
+
// Those agents whose own cursor is older than `next` re-return a few
|
|
45
|
+
// messages we already hold — harmless, since we dedupe by id below.
|
|
46
|
+
if (typeof lastPage.next === "string" && lastPage.next) {
|
|
47
|
+
return {
|
|
48
|
+
before: lastPage.next,
|
|
49
|
+
...(lastPage.at_limit_agent_ids?.length
|
|
50
|
+
? { agentIds: lastPage.at_limit_agent_ids }
|
|
51
|
+
: {}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
export function useMultiAgentChannelMessages(channelName, agentIds, options) {
|
|
57
|
+
const client = useDooverClient();
|
|
58
|
+
const queryClient = useQueryClient();
|
|
59
|
+
const limit = options?.limit;
|
|
60
|
+
const agentMessageLimit = options?.agentMessageLimit;
|
|
61
|
+
const liveUpdates = options?.liveUpdates ?? true;
|
|
62
|
+
const fields = options?.fields;
|
|
63
|
+
const initialBefore = options?.initialBefore;
|
|
64
|
+
const sources = options?.sources;
|
|
65
|
+
const after = options?.after;
|
|
66
|
+
const autoPaginate = options?.autoPaginate ?? false;
|
|
67
|
+
const maxPages = options?.maxPages ?? 20;
|
|
68
|
+
const key = multiAgentChannelMessagesQueryKey(channelName, agentIds, sources, {
|
|
69
|
+
after,
|
|
70
|
+
fields,
|
|
71
|
+
});
|
|
72
|
+
const prependMessage = useCallback((message) => {
|
|
73
|
+
queryClient.setQueryData(key, (current) => {
|
|
74
|
+
if (!current)
|
|
75
|
+
return current;
|
|
76
|
+
const typed = message;
|
|
77
|
+
const [firstPage, ...rest] = current.pages;
|
|
78
|
+
const firstResults = firstPage?.results ?? [];
|
|
79
|
+
return {
|
|
80
|
+
...current,
|
|
81
|
+
pages: [
|
|
82
|
+
{ ...firstPage, results: [typed, ...firstResults] },
|
|
83
|
+
...rest,
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
// `key` captures every scope dim (agentIds + sources + after + fields);
|
|
89
|
+
// serialise the whole thing so the closure refreshes when any dim
|
|
90
|
+
// changes — listing dims by hand drops live updates whenever the list
|
|
91
|
+
// grows (we used to omit `after`/`fields`).
|
|
92
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
93
|
+
[queryClient, JSON.stringify(key)]);
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
if (!liveUpdates || agentIds.length === 0)
|
|
96
|
+
return;
|
|
97
|
+
const offs = agentIds.map((agentId) => {
|
|
98
|
+
const channel = { agent_id: agentId, name: channelName };
|
|
99
|
+
return client.gateway.subscribeToChannel(channel, {
|
|
100
|
+
onMessage: (msg) => prependMessage(msg),
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
void client.gateway.connect();
|
|
104
|
+
return () => {
|
|
105
|
+
for (const off of offs)
|
|
106
|
+
off();
|
|
107
|
+
};
|
|
108
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
109
|
+
}, [client, channelName, liveUpdates, agentIds.join(",")]);
|
|
110
|
+
const query = useInfiniteQuery({
|
|
111
|
+
queryKey: key,
|
|
112
|
+
enabled: agentIds.length > 0,
|
|
113
|
+
staleTime: Infinity,
|
|
114
|
+
initialPageParam: (initialBefore ? { before: initialBefore } : {}),
|
|
115
|
+
getNextPageParam: nextPageParam,
|
|
116
|
+
queryFn: async ({ pageParam }) => {
|
|
117
|
+
const params = {
|
|
118
|
+
agent_id: pageParam.agentIds ?? agentIds,
|
|
119
|
+
...(pageParam.before ? { before: pageParam.before } : {}),
|
|
120
|
+
...(pageParam.agentBefore ? { agent_before: pageParam.agentBefore } : {}),
|
|
121
|
+
...(limit !== undefined ? { limit } : {}),
|
|
122
|
+
...(agentMessageLimit !== undefined
|
|
123
|
+
? { agent_message_limit: agentMessageLimit }
|
|
124
|
+
: {}),
|
|
125
|
+
...(fields && fields.length > 0 ? { field_name: fields } : {}),
|
|
126
|
+
...(after !== undefined ? { after } : {}),
|
|
127
|
+
};
|
|
128
|
+
// Pass `{ sources }` as a trailing bag only when set — cast through
|
|
129
|
+
// `never` since the TypeScript overloads don't declare it.
|
|
130
|
+
const sourcesArg = sources ? { sources } : undefined;
|
|
131
|
+
const page = await (sourcesArg
|
|
132
|
+
? client.agents.getMultiAgentMessages(channelName, params, sourcesArg)
|
|
133
|
+
: client.agents.getMultiAgentMessages(channelName, params));
|
|
134
|
+
return page;
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (!autoPaginate)
|
|
139
|
+
return;
|
|
140
|
+
if (query.isFetching || !query.hasNextPage)
|
|
141
|
+
return;
|
|
142
|
+
if ((query.data?.pages.length ?? 0) >= maxPages)
|
|
143
|
+
return;
|
|
144
|
+
query.fetchNextPage();
|
|
145
|
+
}, [
|
|
146
|
+
autoPaginate,
|
|
147
|
+
maxPages,
|
|
148
|
+
query.isFetching,
|
|
149
|
+
query.hasNextPage,
|
|
150
|
+
query.fetchNextPage,
|
|
151
|
+
query.data?.pages.length,
|
|
152
|
+
]);
|
|
153
|
+
const messages = useMemo(() => {
|
|
154
|
+
// The legacy single-cursor path (and a live push that races a page
|
|
155
|
+
// fetch) can hand us the same message twice; keep the first copy.
|
|
156
|
+
const seen = new Set();
|
|
157
|
+
const out = [];
|
|
158
|
+
for (const page of query.data?.pages ?? []) {
|
|
159
|
+
for (const message of page.results) {
|
|
160
|
+
if (seen.has(message.id))
|
|
161
|
+
continue;
|
|
162
|
+
seen.add(message.id);
|
|
163
|
+
out.push(message);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return out;
|
|
167
|
+
}, [query.data]);
|
|
168
|
+
return { ...query, messages };
|
|
169
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OfflineStatusSnapshot } from "../client/offline-cache.js";
|
|
2
|
+
export type { OfflineStatusSnapshot } from "../client/offline-cache.js";
|
|
3
|
+
export interface OfflineStatusClient {
|
|
4
|
+
getOfflineStatus(): OfflineStatusSnapshot;
|
|
5
|
+
onOfflineStatusChange(listener: (status: OfflineStatusSnapshot) => void): () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function hasOfflineStatus(client: unknown): client is OfflineStatusClient;
|
|
8
|
+
export declare function useOfflineStatus(): OfflineStatusSnapshot;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useMemo, useSyncExternalStore } from "react";
|
|
2
|
+
import { browserNetworkStatus } from "../client/network-status.js";
|
|
3
|
+
import { useDooverClient } from "./context.js";
|
|
4
|
+
export function hasOfflineStatus(client) {
|
|
5
|
+
return !!client && typeof client === "object" &&
|
|
6
|
+
"getOfflineStatus" in client && typeof client.getOfflineStatus === "function" &&
|
|
7
|
+
"onOfflineStatusChange" in client && typeof client.onOfflineStatusChange === "function";
|
|
8
|
+
}
|
|
9
|
+
const SERVER_OFFLINE_STATUS = {
|
|
10
|
+
online: true, state: "online", isOfflineFallback: false, isExpired: false, at: 0,
|
|
11
|
+
};
|
|
12
|
+
export function useOfflineStatus() {
|
|
13
|
+
const client = useDooverClient();
|
|
14
|
+
const store = useMemo(() => {
|
|
15
|
+
if (hasOfflineStatus(client)) {
|
|
16
|
+
return {
|
|
17
|
+
subscribe: (listener) => client.onOfflineStatusChange(listener),
|
|
18
|
+
getSnapshot: () => client.getOfflineStatus(),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const network = client.networkStatus ?? browserNetworkStatus;
|
|
22
|
+
let previous = network.getSnapshot();
|
|
23
|
+
let snapshot = { ...SERVER_OFFLINE_STATUS, ...previous };
|
|
24
|
+
return {
|
|
25
|
+
subscribe: (listener) => network.subscribe(listener),
|
|
26
|
+
getSnapshot: () => {
|
|
27
|
+
const next = network.getSnapshot();
|
|
28
|
+
if (next !== previous) {
|
|
29
|
+
previous = next;
|
|
30
|
+
snapshot = { ...SERVER_OFFLINE_STATUS, ...next };
|
|
31
|
+
}
|
|
32
|
+
return snapshot;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}, [client]);
|
|
36
|
+
return useSyncExternalStore(store.subscribe, store.getSnapshot, () => SERVER_OFFLINE_STATUS);
|
|
37
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type UseMutationResult } from "@tanstack/react-query";
|
|
2
|
+
import type { MessageStructure } from "../types/common.js";
|
|
3
|
+
import type { ChannelIdentifier } from "../types/viewer.js";
|
|
4
|
+
export interface UseSendMessageOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Restrict the write to these source ids on a `MultiplexClient`. Ignored
|
|
7
|
+
* for a plain `DooverClient` or `LocalAgentClient`.
|
|
8
|
+
*/
|
|
9
|
+
sources?: string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Mutation wrapping `DooverDataProvider.sendMessage`. Posts a JSON message
|
|
13
|
+
* to the channel and resolves with the created `MessageStructure` (including
|
|
14
|
+
* its server-assigned `id` and `timestamp`).
|
|
15
|
+
*/
|
|
16
|
+
export declare function useSendMessage<TData extends object = object>(identifier: ChannelIdentifier, options?: UseSendMessageOptions): UseMutationResult<MessageStructure<TData>, Error, TData>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useMutation } from "@tanstack/react-query";
|
|
2
|
+
import { useDooverClient } from "./context.js";
|
|
3
|
+
/**
|
|
4
|
+
* Mutation wrapping `DooverDataProvider.sendMessage`. Posts a JSON message
|
|
5
|
+
* to the channel and resolves with the created `MessageStructure` (including
|
|
6
|
+
* its server-assigned `id` and `timestamp`).
|
|
7
|
+
*/
|
|
8
|
+
export function useSendMessage(identifier, options) {
|
|
9
|
+
const client = useDooverClient();
|
|
10
|
+
const sources = options?.sources;
|
|
11
|
+
return useMutation({
|
|
12
|
+
mutationFn: (data) => {
|
|
13
|
+
if (!identifier.agentId || !identifier.channelName) {
|
|
14
|
+
return Promise.reject(new Error("Identifier must include agentId and channelName"));
|
|
15
|
+
}
|
|
16
|
+
const id = { agentId: identifier.agentId, channelName: identifier.channelName };
|
|
17
|
+
const body = { data: data };
|
|
18
|
+
// Pass `{ sources }` as a trailing bag only when set — cast through
|
|
19
|
+
// `never` since the TypeScript overloads don't declare it.
|
|
20
|
+
const sourcesArg = sources ? { sources } : undefined;
|
|
21
|
+
return (sourcesArg
|
|
22
|
+
? client.messages.postMessage(id, body, sourcesArg)
|
|
23
|
+
: client.messages.postMessage(id, body));
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type UseMutateAsyncFunction, type UseMutateFunction, type UseMutationResult } from "@tanstack/react-query";
|
|
2
|
+
import type { RpcStatus } from "../types/common.js";
|
|
3
|
+
import type { ChannelIdentifier } from "../types/viewer.js";
|
|
4
|
+
export type RpcCommandId = string;
|
|
5
|
+
export interface RpcStatusEvent<TPending = undefined> {
|
|
6
|
+
commandId: RpcCommandId;
|
|
7
|
+
status: RpcStatus<TPending>;
|
|
8
|
+
timestamp: number;
|
|
9
|
+
}
|
|
10
|
+
export interface SendRpcVariables<TRequest = object> {
|
|
11
|
+
commandId: RpcCommandId;
|
|
12
|
+
request: TRequest;
|
|
13
|
+
/** Optional per-call override of the app_key. */
|
|
14
|
+
app_key?: string;
|
|
15
|
+
}
|
|
16
|
+
interface CommandState<TPending, TResponse> {
|
|
17
|
+
current: RpcStatus<TPending>;
|
|
18
|
+
history: RpcStatusEvent<TPending>[];
|
|
19
|
+
submittedAt: number;
|
|
20
|
+
settledAt?: number;
|
|
21
|
+
data?: TResponse;
|
|
22
|
+
error?: unknown;
|
|
23
|
+
}
|
|
24
|
+
type CommandStatuses<TPending, TResponse> = Record<RpcCommandId, CommandState<TPending, TResponse>>;
|
|
25
|
+
export interface UseSendRpcOptions {
|
|
26
|
+
/** Method name passed on every RPC from this hook. */
|
|
27
|
+
method: string;
|
|
28
|
+
/** Default app_key. Overridable per-call via variables.app_key. */
|
|
29
|
+
app_key?: string;
|
|
30
|
+
/**
|
|
31
|
+
* react-query mutation key. Defaults to
|
|
32
|
+
* `["doover", "agent", agentId, "channel", channelName, "rpc", method]`.
|
|
33
|
+
*/
|
|
34
|
+
mutationKey?: readonly unknown[];
|
|
35
|
+
/** How long to wait to hear from the device at all. See `SendRpcOptions`. */
|
|
36
|
+
timeoutMs?: number;
|
|
37
|
+
/**
|
|
38
|
+
* How long the command may then stay in flight once the device has answered,
|
|
39
|
+
* re-armed on every progress report. See `SendRpcOptions`.
|
|
40
|
+
*/
|
|
41
|
+
pendingTimeoutMs?: number;
|
|
42
|
+
}
|
|
43
|
+
export interface UseSendRpcResult<TRequest, TResponse, TPending> extends Omit<UseMutationResult<TResponse, unknown, SendRpcVariables<TRequest>, void>, "isPending" | "mutate" | "mutateAsync"> {
|
|
44
|
+
/** Most recent status across all commands (by `submittedAt`). */
|
|
45
|
+
currentStatus: RpcStatus<TPending> | undefined;
|
|
46
|
+
commandStatuses: CommandStatuses<TPending, TResponse>;
|
|
47
|
+
getStatus: (commandId: RpcCommandId) => RpcStatus<TPending> | undefined;
|
|
48
|
+
getHistory: (commandId: RpcCommandId) => RpcStatusEvent<TPending>[];
|
|
49
|
+
getCommandState: (commandId: RpcCommandId) => CommandState<TPending, TResponse> | undefined;
|
|
50
|
+
isPending: {
|
|
51
|
+
(): boolean;
|
|
52
|
+
(commandId: RpcCommandId): boolean;
|
|
53
|
+
};
|
|
54
|
+
mutate: UseMutateFunction<TResponse, unknown, SendRpcVariables<TRequest>, void>;
|
|
55
|
+
mutateAsync: UseMutateAsyncFunction<TResponse, unknown, SendRpcVariables<TRequest>, void>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A react-query-integrated RPC hook. Calls
|
|
59
|
+
* `DooverDataProvider.sendRPC(identifier, { method, request, app_key })`
|
|
60
|
+
* under the hood and tracks a per-`commandId` status history so callers can
|
|
61
|
+
* render multi-step progress UIs and error popovers.
|
|
62
|
+
*
|
|
63
|
+
* For low-latency ephemeral commands (camera PTZ etc.) reach for
|
|
64
|
+
* `client.gateway.sendOneShotMessage` directly instead — those are not
|
|
65
|
+
* persisted and don't flow through this hook.
|
|
66
|
+
*/
|
|
67
|
+
export declare function useSendRpc<TRequest = object, TResponse = object, TPending = undefined>(identifier: ChannelIdentifier, options: UseSendRpcOptions): UseSendRpcResult<TRequest, TResponse, TPending>;
|
|
68
|
+
export {};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from "react";
|
|
2
|
+
import { useMutation, } from "@tanstack/react-query";
|
|
3
|
+
import { useDooverClient } from "./context.js";
|
|
4
|
+
const SENT_STATUS = { code: "sent" };
|
|
5
|
+
function isTerminal(status) {
|
|
6
|
+
return status?.code === "success" || status?.code === "error";
|
|
7
|
+
}
|
|
8
|
+
function isPendingCode(status) {
|
|
9
|
+
return (status?.code === "sent" ||
|
|
10
|
+
status?.code === "acknowledged" ||
|
|
11
|
+
status?.code === "deferred" ||
|
|
12
|
+
status?.code === "pending");
|
|
13
|
+
}
|
|
14
|
+
function toErrorStatus(error) {
|
|
15
|
+
if (error instanceof Error)
|
|
16
|
+
return { code: "error", message: error.message };
|
|
17
|
+
if (typeof error === "string")
|
|
18
|
+
return { code: "error", message: error };
|
|
19
|
+
return { code: "error", message: "Unknown RPC error" };
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A react-query-integrated RPC hook. Calls
|
|
23
|
+
* `DooverDataProvider.sendRPC(identifier, { method, request, app_key })`
|
|
24
|
+
* under the hood and tracks a per-`commandId` status history so callers can
|
|
25
|
+
* render multi-step progress UIs and error popovers.
|
|
26
|
+
*
|
|
27
|
+
* For low-latency ephemeral commands (camera PTZ etc.) reach for
|
|
28
|
+
* `client.gateway.sendOneShotMessage` directly instead — those are not
|
|
29
|
+
* persisted and don't flow through this hook.
|
|
30
|
+
*/
|
|
31
|
+
export function useSendRpc(identifier, options) {
|
|
32
|
+
const client = useDooverClient();
|
|
33
|
+
const [commandStatuses, setCommandStatuses] = useState({});
|
|
34
|
+
const mutationKey = options.mutationKey ??
|
|
35
|
+
[
|
|
36
|
+
"doover",
|
|
37
|
+
"agent",
|
|
38
|
+
identifier.agentId,
|
|
39
|
+
"channel",
|
|
40
|
+
identifier.channelName,
|
|
41
|
+
"rpc",
|
|
42
|
+
options.method,
|
|
43
|
+
];
|
|
44
|
+
const appendStatus = useCallback((commandId, status) => {
|
|
45
|
+
const timestamp = Date.now();
|
|
46
|
+
setCommandStatuses((current) => {
|
|
47
|
+
const existing = current[commandId];
|
|
48
|
+
if (!existing || existing.settledAt !== undefined)
|
|
49
|
+
return current;
|
|
50
|
+
return {
|
|
51
|
+
...current,
|
|
52
|
+
[commandId]: {
|
|
53
|
+
...existing,
|
|
54
|
+
current: status,
|
|
55
|
+
history: [...existing.history, { commandId, status, timestamp }],
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
}, []);
|
|
60
|
+
const settleCommand = useCallback((commandId, updates) => {
|
|
61
|
+
setCommandStatuses((current) => {
|
|
62
|
+
const existing = current[commandId];
|
|
63
|
+
if (!existing)
|
|
64
|
+
return current;
|
|
65
|
+
const settledAt = Date.now();
|
|
66
|
+
const next = {
|
|
67
|
+
...existing,
|
|
68
|
+
settledAt,
|
|
69
|
+
};
|
|
70
|
+
if ("data" in updates)
|
|
71
|
+
next.data = updates.data;
|
|
72
|
+
if ("error" in updates)
|
|
73
|
+
next.error = updates.error;
|
|
74
|
+
if (updates.fallbackStatus && !isTerminal(existing.current)) {
|
|
75
|
+
next.current = updates.fallbackStatus;
|
|
76
|
+
next.history = [
|
|
77
|
+
...existing.history,
|
|
78
|
+
{
|
|
79
|
+
commandId,
|
|
80
|
+
status: updates.fallbackStatus,
|
|
81
|
+
timestamp: settledAt,
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
return { ...current, [commandId]: next };
|
|
86
|
+
});
|
|
87
|
+
}, []);
|
|
88
|
+
const mutation = useMutation({
|
|
89
|
+
mutationKey: [...mutationKey],
|
|
90
|
+
mutationFn: async ({ commandId, request, app_key }) => {
|
|
91
|
+
const submittedAt = Date.now();
|
|
92
|
+
setCommandStatuses((current) => ({
|
|
93
|
+
...current,
|
|
94
|
+
[commandId]: {
|
|
95
|
+
current: SENT_STATUS,
|
|
96
|
+
history: [
|
|
97
|
+
{
|
|
98
|
+
commandId,
|
|
99
|
+
status: SENT_STATUS,
|
|
100
|
+
timestamp: submittedAt,
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
submittedAt,
|
|
104
|
+
},
|
|
105
|
+
}));
|
|
106
|
+
const rpcRequest = {
|
|
107
|
+
method: options.method,
|
|
108
|
+
request,
|
|
109
|
+
...(app_key !== undefined
|
|
110
|
+
? { app_key }
|
|
111
|
+
: options.app_key !== undefined
|
|
112
|
+
? { app_key: options.app_key }
|
|
113
|
+
: {}),
|
|
114
|
+
};
|
|
115
|
+
if (!identifier.agentId || !identifier.channelName) {
|
|
116
|
+
throw new Error("Identifier must include agentId and channelName");
|
|
117
|
+
}
|
|
118
|
+
return client.rpc.send({ agentId: identifier.agentId, channelName: identifier.channelName }, rpcRequest, {
|
|
119
|
+
onStatus: (status) => appendStatus(commandId, status),
|
|
120
|
+
...(options.timeoutMs !== undefined
|
|
121
|
+
? { timeoutMs: options.timeoutMs }
|
|
122
|
+
: {}),
|
|
123
|
+
...(options.pendingTimeoutMs !== undefined
|
|
124
|
+
? { pendingTimeoutMs: options.pendingTimeoutMs }
|
|
125
|
+
: {}),
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
onSuccess: (data, variables) => settleCommand(variables.commandId, {
|
|
129
|
+
data,
|
|
130
|
+
fallbackStatus: { code: "success" },
|
|
131
|
+
}),
|
|
132
|
+
onError: (error, variables) => settleCommand(variables.commandId, {
|
|
133
|
+
error,
|
|
134
|
+
fallbackStatus: toErrorStatus(error),
|
|
135
|
+
}),
|
|
136
|
+
});
|
|
137
|
+
const getCommandState = useCallback((commandId) => commandStatuses[commandId], [commandStatuses]);
|
|
138
|
+
const getStatus = useCallback((commandId) => getCommandState(commandId)?.current, [getCommandState]);
|
|
139
|
+
const getHistory = useCallback((commandId) => getCommandState(commandId)?.history ?? [], [getCommandState]);
|
|
140
|
+
const currentStatus = useMemo(() => {
|
|
141
|
+
const latest = Object.values(commandStatuses).reduce((acc, state) => {
|
|
142
|
+
if (!acc || state.submittedAt > acc.submittedAt)
|
|
143
|
+
return state;
|
|
144
|
+
return acc;
|
|
145
|
+
}, undefined);
|
|
146
|
+
return latest?.current;
|
|
147
|
+
}, [commandStatuses]);
|
|
148
|
+
const isPending = ((commandId) => {
|
|
149
|
+
if (commandId === undefined)
|
|
150
|
+
return mutation.isPending;
|
|
151
|
+
return isPendingCode(getStatus(commandId));
|
|
152
|
+
});
|
|
153
|
+
return {
|
|
154
|
+
...mutation,
|
|
155
|
+
mutate: mutation.mutate,
|
|
156
|
+
mutateAsync: mutation.mutateAsync,
|
|
157
|
+
currentStatus,
|
|
158
|
+
commandStatuses,
|
|
159
|
+
getStatus,
|
|
160
|
+
getHistory,
|
|
161
|
+
getCommandState,
|
|
162
|
+
isPending,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type UseQueryResult } from "@tanstack/react-query";
|
|
2
|
+
import type { TurnCredential } from "../types/common.js";
|
|
3
|
+
import type { TurnTokenRequest } from "../types/openapi.js";
|
|
4
|
+
/**
|
|
5
|
+
* Fetch TURN (relay) credentials for a camera stream. Cached for 10 minutes
|
|
6
|
+
* by default since the token has a server-controlled TTL; consumers that
|
|
7
|
+
* need refresh-on-expiry should do so at the call site.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useTurnCredentials(request: TurnTokenRequest, options?: {
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
staleTime?: number;
|
|
12
|
+
}): UseQueryResult<TurnCredential>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useQuery } from "@tanstack/react-query";
|
|
2
|
+
import { useDooverClient } from "./context.js";
|
|
3
|
+
/**
|
|
4
|
+
* Fetch TURN (relay) credentials for a camera stream. Cached for 10 minutes
|
|
5
|
+
* by default since the token has a server-controlled TTL; consumers that
|
|
6
|
+
* need refresh-on-expiry should do so at the call site.
|
|
7
|
+
*/
|
|
8
|
+
export function useTurnCredentials(request, options) {
|
|
9
|
+
const client = useDooverClient();
|
|
10
|
+
return useQuery({
|
|
11
|
+
queryKey: [
|
|
12
|
+
"doover",
|
|
13
|
+
"turn",
|
|
14
|
+
request.role,
|
|
15
|
+
request.device_id ?? null,
|
|
16
|
+
request.camera_name,
|
|
17
|
+
],
|
|
18
|
+
enabled: options?.enabled ?? true,
|
|
19
|
+
staleTime: options?.staleTime ?? 10 * 60 * 1000,
|
|
20
|
+
queryFn: () => client.turn.createTurnToken(request),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type UseMutationResult } from "@tanstack/react-query";
|
|
2
|
+
import type { AggregateMutationParams } from "../apis/aggregates-api.js";
|
|
3
|
+
import type { Aggregate } from "../types/common.js";
|
|
4
|
+
import type { ChannelIdentifier } from "../types/viewer.js";
|
|
5
|
+
export interface UseUpdateAggregateOptions {
|
|
6
|
+
/** If true, use PUT semantics (replace) instead of PATCH (merge). */
|
|
7
|
+
replace?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Forwarded as query params to the aggregate endpoint:
|
|
10
|
+
* `log_update` (record a history message), `clear_attachments`,
|
|
11
|
+
* `suppress_response`. See `AggregateMutationParams`.
|
|
12
|
+
*/
|
|
13
|
+
params?: AggregateMutationParams;
|
|
14
|
+
/**
|
|
15
|
+
* Restrict the write to these source ids on a `MultiplexClient`. Ignored
|
|
16
|
+
* for a plain `DooverClient` or `LocalAgentClient`. Also scopes the
|
|
17
|
+
* react-query cache invalidation to the matching source-dimensioned key.
|
|
18
|
+
*/
|
|
19
|
+
sources?: string[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Mutation wrapping `DooverDataProvider.updateAggregate` (PATCH) or
|
|
23
|
+
* `putAggregate` (PUT when `replace: true`). Also writes the returned
|
|
24
|
+
* aggregate into the react-query cache for its channel so consumers of
|
|
25
|
+
* `useChannelAggregate` see the change immediately.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useUpdateAggregate<TData extends object = object>(identifier: ChannelIdentifier, options?: UseUpdateAggregateOptions): UseMutationResult<Aggregate<TData>, Error, TData>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
2
|
+
import { useDooverClient } from "./context.js";
|
|
3
|
+
import { channelAggregateQueryKey } from "./useChannelAggregate.js";
|
|
4
|
+
/**
|
|
5
|
+
* Mutation wrapping `DooverDataProvider.updateAggregate` (PATCH) or
|
|
6
|
+
* `putAggregate` (PUT when `replace: true`). Also writes the returned
|
|
7
|
+
* aggregate into the react-query cache for its channel so consumers of
|
|
8
|
+
* `useChannelAggregate` see the change immediately.
|
|
9
|
+
*/
|
|
10
|
+
export function useUpdateAggregate(identifier, options) {
|
|
11
|
+
const client = useDooverClient();
|
|
12
|
+
const queryClient = useQueryClient();
|
|
13
|
+
const replace = options?.replace ?? false;
|
|
14
|
+
const params = options?.params;
|
|
15
|
+
const sources = options?.sources;
|
|
16
|
+
return useMutation({
|
|
17
|
+
mutationFn: (data) => {
|
|
18
|
+
if (!identifier.agentId || !identifier.channelName) {
|
|
19
|
+
return Promise.reject(new Error("Identifier must include agentId and channelName"));
|
|
20
|
+
}
|
|
21
|
+
const id = { agentId: identifier.agentId, channelName: identifier.channelName };
|
|
22
|
+
const body = data;
|
|
23
|
+
// Pass `{ sources }` as a trailing bag only when set — cast through
|
|
24
|
+
// `never` since the TypeScript overloads don't declare it.
|
|
25
|
+
const sourcesArg = sources ? { sources } : undefined;
|
|
26
|
+
if (replace) {
|
|
27
|
+
return (sourcesArg
|
|
28
|
+
? client.aggregates.putAggregate(id, body, params, sourcesArg)
|
|
29
|
+
: client.aggregates.putAggregate(id, body, params));
|
|
30
|
+
}
|
|
31
|
+
return (sourcesArg
|
|
32
|
+
? client.aggregates.patchAggregate(id, body, params, sourcesArg)
|
|
33
|
+
: client.aggregates.patchAggregate(id, body, params));
|
|
34
|
+
},
|
|
35
|
+
onSuccess: (aggregate) => {
|
|
36
|
+
queryClient.setQueryData(channelAggregateQueryKey(identifier.agentId, identifier.channelName, sources), aggregate);
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type UseMutationResult } from "@tanstack/react-query";
|
|
2
|
+
import type { MessageBody, MessageMutationParams } from "../apis/messages-api.js";
|
|
3
|
+
import type { ChannelIdentifier } from "../types/viewer.js";
|
|
4
|
+
export interface UpdateMessageCallOptions {
|
|
5
|
+
/**
|
|
6
|
+
* If true, use PUT (replace) instead of PATCH (merge). Falls back to
|
|
7
|
+
* the hook-level `replace` option, which itself defaults to PATCH.
|
|
8
|
+
*/
|
|
9
|
+
replace?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Query params forwarded to the message endpoint. Merged over the
|
|
12
|
+
* hook-level `params` option (per-call keys win).
|
|
13
|
+
*/
|
|
14
|
+
params?: MessageMutationParams;
|
|
15
|
+
}
|
|
16
|
+
export interface UseUpdateMessageOptions extends UpdateMessageCallOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Restrict the write to these source ids on a `MultiplexClient`. Ignored
|
|
19
|
+
* for a plain `DooverClient` or `LocalAgentClient`.
|
|
20
|
+
*/
|
|
21
|
+
sources?: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface UpdateMessageVariables<TBody extends MessageBody = MessageBody> {
|
|
24
|
+
messageId: string;
|
|
25
|
+
body: TBody;
|
|
26
|
+
/**
|
|
27
|
+
* Per-call overrides. Extensible — add new knobs here without breaking
|
|
28
|
+
* the variables shape.
|
|
29
|
+
*/
|
|
30
|
+
options?: UpdateMessageCallOptions;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Mutation wrapping `MessagesApi.patchMessage` or `putMessage`. Bound to a
|
|
34
|
+
* single channel; the message id and body are passed per-call. Each
|
|
35
|
+
* invocation can override `replace` / `params` via `variables.options` for
|
|
36
|
+
* mutation sites that sometimes PUT and sometimes PATCH the same channel.
|
|
37
|
+
*/
|
|
38
|
+
export declare function useUpdateMessage<TBody extends MessageBody = MessageBody>(identifier: ChannelIdentifier, options?: UseUpdateMessageOptions): UseMutationResult<unknown, Error, UpdateMessageVariables<TBody>>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useMutation } from "@tanstack/react-query";
|
|
2
|
+
import { useDooverClient } from "./context.js";
|
|
3
|
+
/**
|
|
4
|
+
* Mutation wrapping `MessagesApi.patchMessage` or `putMessage`. Bound to a
|
|
5
|
+
* single channel; the message id and body are passed per-call. Each
|
|
6
|
+
* invocation can override `replace` / `params` via `variables.options` for
|
|
7
|
+
* mutation sites that sometimes PUT and sometimes PATCH the same channel.
|
|
8
|
+
*/
|
|
9
|
+
export function useUpdateMessage(identifier, options) {
|
|
10
|
+
const client = useDooverClient();
|
|
11
|
+
const defaultReplace = options?.replace ?? false;
|
|
12
|
+
const defaultParams = options?.params;
|
|
13
|
+
const sources = options?.sources;
|
|
14
|
+
return useMutation({
|
|
15
|
+
mutationFn: ({ messageId, body, options: call, }) => {
|
|
16
|
+
if (!identifier.agentId || !identifier.channelName) {
|
|
17
|
+
throw new Error("useUpdateMessage requires both agentId and channelName on the identifier.");
|
|
18
|
+
}
|
|
19
|
+
const replace = call?.replace ?? defaultReplace;
|
|
20
|
+
const params = call?.params || defaultParams
|
|
21
|
+
? { ...defaultParams, ...call?.params }
|
|
22
|
+
: undefined;
|
|
23
|
+
// Pass `{ sources }` as a trailing bag only when set — cast through
|
|
24
|
+
// `never` since the TypeScript overloads don't declare it.
|
|
25
|
+
const sourcesArg = sources ? { sources } : undefined;
|
|
26
|
+
if (replace) {
|
|
27
|
+
return sourcesArg
|
|
28
|
+
? client.messages.putMessage(identifier.agentId, identifier.channelName, messageId, body, params, sourcesArg)
|
|
29
|
+
: client.messages.putMessage(identifier.agentId, identifier.channelName, messageId, body, params);
|
|
30
|
+
}
|
|
31
|
+
return sourcesArg
|
|
32
|
+
? client.messages.patchMessage(identifier.agentId, identifier.channelName, messageId, body, params, sourcesArg)
|
|
33
|
+
: client.messages.patchMessage(identifier.agentId, identifier.channelName, messageId, body, params);
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|