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,196 @@
|
|
|
1
|
+
import type { AgentAggregate, BatchMessagesResponse } from "../types/openapi.js";
|
|
2
|
+
import type { AgentsResponse, GetAgentsOptions } from "../types/viewer.js";
|
|
3
|
+
import type { RestClient } from "../http/rest-client.js";
|
|
4
|
+
import type { DooverRequestOptions } from "../client/request-options.js";
|
|
5
|
+
export interface MultiAgentMessagesParams {
|
|
6
|
+
agent_id: string[];
|
|
7
|
+
/**
|
|
8
|
+
* Per-agent `before` cursors, parallel to `agent_id`. When set, must
|
|
9
|
+
* be the same length as `agent_id`; each agent then uses its own
|
|
10
|
+
* cursor as the upper bound instead of the global `before`. This is
|
|
11
|
+
* how paginating clients should resume from a previous response's
|
|
12
|
+
* `next_cursors` map — each agent paginates independently with no
|
|
13
|
+
* inter-agent "watermark retain".
|
|
14
|
+
*/
|
|
15
|
+
agent_before?: string[];
|
|
16
|
+
before?: string;
|
|
17
|
+
after?: string;
|
|
18
|
+
limit?: number;
|
|
19
|
+
agent_message_limit?: number;
|
|
20
|
+
field_name?: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* One token-posture knob across all three layers, so a UI can show
|
|
24
|
+
* "inherited from organisation" vs "overridden on this device" and offer a reset
|
|
25
|
+
* without duplicating the precedence rule client-side.
|
|
26
|
+
*/
|
|
27
|
+
export interface TokenPolicyField<T> {
|
|
28
|
+
/** What is actually enforced: `agent_override` if set, else `org_default`. */
|
|
29
|
+
effective: T | null;
|
|
30
|
+
/** This device's override. `null` means it inherits. */
|
|
31
|
+
agent_override: T | null;
|
|
32
|
+
/** The organisation-wide default inherited when not overridden. */
|
|
33
|
+
org_default: T | null;
|
|
34
|
+
}
|
|
35
|
+
export interface AgentTokenState {
|
|
36
|
+
/**
|
|
37
|
+
* Unix-ms revocation floor: every long-lived credential issued before this is
|
|
38
|
+
* rejected. `null` means nothing has ever been revoked for this agent.
|
|
39
|
+
*/
|
|
40
|
+
tokens_valid_from: number | null;
|
|
41
|
+
/** Auth kill-switch — while true, every auth attempt is rejected. */
|
|
42
|
+
auth_locked: boolean;
|
|
43
|
+
self_rotation: TokenPolicyField<boolean>;
|
|
44
|
+
max_age_ms: TokenPolicyField<number>;
|
|
45
|
+
reuse_grace_ms: TokenPolicyField<number>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* A token-posture override. `null` on any field means "inherit the organisation
|
|
49
|
+
* default"; there is no way to express "explicitly off, ignoring the default",
|
|
50
|
+
* because every knob here is off when absent.
|
|
51
|
+
*/
|
|
52
|
+
export interface AgentTokenPolicy {
|
|
53
|
+
/** Allow the device to trade its own credential for a fresh one. */
|
|
54
|
+
self_rotation?: boolean | null;
|
|
55
|
+
/**
|
|
56
|
+
* Hard maximum credential age. Only valid alongside `self_rotation` — without
|
|
57
|
+
* it the device cannot rotate before the deadline and will be locked out.
|
|
58
|
+
*/
|
|
59
|
+
max_age_ms?: number | null;
|
|
60
|
+
/**
|
|
61
|
+
* Grace window after a rotation before a stale credential counts as reuse.
|
|
62
|
+
* Setting this opts the device into *automatic* lockout on reuse detection.
|
|
63
|
+
*/
|
|
64
|
+
reuse_grace_ms?: number | null;
|
|
65
|
+
}
|
|
66
|
+
export interface ResourcePermission {
|
|
67
|
+
permission_id: string;
|
|
68
|
+
permission: string;
|
|
69
|
+
}
|
|
70
|
+
export interface AdhocTokenResponse {
|
|
71
|
+
/** Shown once. Not retrievable afterwards. */
|
|
72
|
+
token: string;
|
|
73
|
+
token_id: string | null;
|
|
74
|
+
}
|
|
75
|
+
export interface DeviceTokenResponse {
|
|
76
|
+
/** Shown once. Not stored anywhere and not retrievable afterwards. */
|
|
77
|
+
token: string;
|
|
78
|
+
/** Unix-ms issuance time, which is what the revocation floor compares against. */
|
|
79
|
+
issued_at_ms: number | null;
|
|
80
|
+
}
|
|
81
|
+
export interface MultiAgentAggregatesParams {
|
|
82
|
+
agent_id: string[];
|
|
83
|
+
/**
|
|
84
|
+
* Project the response to only the named top-level keys of each aggregate's
|
|
85
|
+
* `data`. Useful for large aggregates (e.g. `tag_values`) when the caller
|
|
86
|
+
* only needs a subset of the tag tree.
|
|
87
|
+
*/
|
|
88
|
+
field_name?: string[];
|
|
89
|
+
}
|
|
90
|
+
export declare class AgentsApi {
|
|
91
|
+
private readonly rest;
|
|
92
|
+
private readonly controlApiUrl?;
|
|
93
|
+
constructor(rest: RestClient, controlApiUrl?: string | undefined);
|
|
94
|
+
listAgents(options?: GetAgentsOptions): Promise<AgentsResponse>;
|
|
95
|
+
listAgents(requestOptions?: DooverRequestOptions): Promise<AgentsResponse>;
|
|
96
|
+
listAgents(options?: GetAgentsOptions, requestOptions?: DooverRequestOptions): Promise<AgentsResponse>;
|
|
97
|
+
/**
|
|
98
|
+
* Batch-fetch recent messages for many agents. Auto-chunks `agent_id`
|
|
99
|
+
* (and the parallel `agent_before` cursors, if given) at MULTI_AGENT_CHUNK_SIZE
|
|
100
|
+
* so each request's URL stays under CloudFront's 8,192-byte quota. Chunks
|
|
101
|
+
* are fetched in parallel and merged: `results`/`count` concat-and-sum,
|
|
102
|
+
* `next_cursors`/`at_limit_agent_ids` union, legacy `next` becomes the
|
|
103
|
+
* lexically-highest cursor across at-limit agents.
|
|
104
|
+
*/
|
|
105
|
+
getMultiAgentMessages(channelName: string, params: MultiAgentMessagesParams): Promise<BatchMessagesResponse>;
|
|
106
|
+
/**
|
|
107
|
+
* Batch-fetch aggregates for many agents. Auto-chunks `agent_id` so each
|
|
108
|
+
* request's URL stays under CloudFront's hard 8,192-byte URL quota — each
|
|
109
|
+
* agent contributes ~30 chars (`agent_id=<snowflake>&`), so the chunk size
|
|
110
|
+
* below caps the query string at ~7.5KB even before the base URL. Chunks
|
|
111
|
+
* are fetched in parallel and merged into one `{ results, count }` so
|
|
112
|
+
* callers never have to think about the limit.
|
|
113
|
+
*/
|
|
114
|
+
getMultiAgentAggregates(channelName: string, params: MultiAgentAggregatesParams): Promise<{
|
|
115
|
+
results: AgentAggregate[];
|
|
116
|
+
count: number;
|
|
117
|
+
}>;
|
|
118
|
+
/**
|
|
119
|
+
* Read an agent's credential state: the revocation floor, the auth
|
|
120
|
+
* kill-switch, and the token posture resolved across the per-agent override
|
|
121
|
+
* and the organisation default.
|
|
122
|
+
*
|
|
123
|
+
* Requires `AgentTokenRead`, which is read-only — a caller can display
|
|
124
|
+
* credential state (including an auth-lock banner, often the only explanation
|
|
125
|
+
* for why a device is offline) without being able to change any of it.
|
|
126
|
+
*/
|
|
127
|
+
getTokenState(agentId: string): Promise<AgentTokenState>;
|
|
128
|
+
/**
|
|
129
|
+
* Replace an agent's token-posture override. Omitted or null fields mean
|
|
130
|
+
* "inherit the organisation default" — a full replacement rather than a
|
|
131
|
+
* merge, so clearing an override back to inherited is expressible.
|
|
132
|
+
*
|
|
133
|
+
* Rejected server-side if the resolved posture sets `max_age_ms` without
|
|
134
|
+
* `self_rotation`: a device that can't self-rotate has no way to trade its
|
|
135
|
+
* token in before the max age elapses, making that combination a scheduled
|
|
136
|
+
* outage.
|
|
137
|
+
*/
|
|
138
|
+
setTokenPolicy(agentId: string, policy: AgentTokenPolicy): Promise<{
|
|
139
|
+
effective: AgentTokenPolicy;
|
|
140
|
+
}>;
|
|
141
|
+
/**
|
|
142
|
+
* Set or clear the auth kill-switch. While locked, every auth attempt for the
|
|
143
|
+
* agent is rejected regardless of token validity.
|
|
144
|
+
*
|
|
145
|
+
* doover-data sets this automatically on suspected token reuse, so clearing it
|
|
146
|
+
* is a routine incident-response action rather than an exotic one.
|
|
147
|
+
*/
|
|
148
|
+
setAuthLock(agentId: string, locked: boolean): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* Revoke every outstanding long-lived credential for an agent by advancing the
|
|
151
|
+
* revocation floor. Mints nothing.
|
|
152
|
+
*
|
|
153
|
+
* This takes the device offline until it is re-provisioned. Break-glass:
|
|
154
|
+
* confirm before calling.
|
|
155
|
+
*/
|
|
156
|
+
revokeAllTokens(agentId: string): Promise<{
|
|
157
|
+
tokens_valid_from: number;
|
|
158
|
+
}>;
|
|
159
|
+
/**
|
|
160
|
+
* Set the revocation floor to an explicit point, in either direction. `0` or
|
|
161
|
+
* `null` clears it.
|
|
162
|
+
*
|
|
163
|
+
* `revokeAllTokens` is the normal way to revoke. Lowering the floor reverses a
|
|
164
|
+
* revocation, so it is for undoing one made by mistake — not for recovering
|
|
165
|
+
* from a leak, where you should issue fresh credentials instead.
|
|
166
|
+
*/
|
|
167
|
+
setRevocationFloor(agentId: string, tokensValidFrom: number | null): Promise<{
|
|
168
|
+
tokens_valid_from: number | null;
|
|
169
|
+
}>;
|
|
170
|
+
/**
|
|
171
|
+
* Mint a short-lived scoped JWT for ad-hoc access to an agent — debugging, a
|
|
172
|
+
* one-off script, an integration.
|
|
173
|
+
*
|
|
174
|
+
* This is the way to give a *person* access to a device. The device's own
|
|
175
|
+
* long-lived credential is deliberately not obtainable through the API: it is
|
|
176
|
+
* minted into an installer bundle and never shown. Expiry stands in for
|
|
177
|
+
* revocation here, so keep `timeout` as short as the task allows.
|
|
178
|
+
*/
|
|
179
|
+
createAdhocToken(agentId: string, options?: {
|
|
180
|
+
permissions?: ResourcePermission[];
|
|
181
|
+
timeout?: number;
|
|
182
|
+
}): Promise<AdhocTokenResponse>;
|
|
183
|
+
/**
|
|
184
|
+
* Mint the device's long-lived credential and return it once, for manual
|
|
185
|
+
* provisioning — pasting into a device's config by hand. The installer download
|
|
186
|
+
* mints one into the bundle for you; this is the equivalent for a device you're
|
|
187
|
+
* configuring yourself.
|
|
188
|
+
*
|
|
189
|
+
* Always additive: the revocation floor is left alone, so minting can never
|
|
190
|
+
* knock a running device offline. `revoke_existing` is intentionally not
|
|
191
|
+
* exposed here — revoking is `revokeAllTokens`, a separate deliberate act.
|
|
192
|
+
*
|
|
193
|
+
* Returned once and stored nowhere. If it's lost, mint another.
|
|
194
|
+
*/
|
|
195
|
+
createDeviceToken(agentId: string): Promise<DeviceTokenResponse>;
|
|
196
|
+
}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { addTimestampToMessage } from "../utils/snowflake.js";
|
|
2
|
+
function isPlainObject(value) {
|
|
3
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
|
+
}
|
|
5
|
+
function buildUserDisplayName(rawUser) {
|
|
6
|
+
const source = isPlainObject(rawUser)
|
|
7
|
+
? rawUser
|
|
8
|
+
: {};
|
|
9
|
+
const firstName = typeof source.first_name === "string" ? source.first_name.trim() : "";
|
|
10
|
+
const lastName = typeof source.last_name === "string" ? source.last_name.trim() : "";
|
|
11
|
+
const fullName = `${firstName} ${lastName}`.trim();
|
|
12
|
+
if (fullName !== "") {
|
|
13
|
+
return fullName;
|
|
14
|
+
}
|
|
15
|
+
if (typeof source.username === "string" && source.username !== "") {
|
|
16
|
+
return source.username;
|
|
17
|
+
}
|
|
18
|
+
if (typeof source.email === "string" && source.email !== "") {
|
|
19
|
+
return source.email;
|
|
20
|
+
}
|
|
21
|
+
if (typeof source.id === "string" && source.id !== "") {
|
|
22
|
+
return source.id;
|
|
23
|
+
}
|
|
24
|
+
return String(source.id ?? "");
|
|
25
|
+
}
|
|
26
|
+
function coerceExtraConfig(value) {
|
|
27
|
+
return isPlainObject(value) ? value : {};
|
|
28
|
+
}
|
|
29
|
+
function normalizeAgentEntry(rawAgent) {
|
|
30
|
+
const source = isPlainObject(rawAgent)
|
|
31
|
+
? rawAgent
|
|
32
|
+
: {};
|
|
33
|
+
const fixedLocation = source.fixed_location;
|
|
34
|
+
const normalizedFixedLocation = isPlainObject(fixedLocation) &&
|
|
35
|
+
typeof fixedLocation.latitude === "number" &&
|
|
36
|
+
typeof fixedLocation.longitude === "number"
|
|
37
|
+
? {
|
|
38
|
+
latitude: fixedLocation.latitude,
|
|
39
|
+
longitude: fixedLocation.longitude,
|
|
40
|
+
}
|
|
41
|
+
: { latitude: 0, longitude: 0 };
|
|
42
|
+
const faIcon = typeof source.fa_icon === "string" && source.fa_icon.length > 0
|
|
43
|
+
? source.fa_icon
|
|
44
|
+
: "fa-solid fa-robot";
|
|
45
|
+
return {
|
|
46
|
+
...source,
|
|
47
|
+
id: typeof source.id === "string" ? source.id : String(source.id ?? ""),
|
|
48
|
+
organisation: typeof source.organisation === "string" ? source.organisation : "",
|
|
49
|
+
name: typeof source.name === "string" ? source.name : "",
|
|
50
|
+
display_name: typeof source.display_name === "string" ? source.display_name : "",
|
|
51
|
+
archived: typeof source.archived === "boolean" ? source.archived : false,
|
|
52
|
+
group: typeof source.group === "string" ? source.group : "",
|
|
53
|
+
fa_icon: faIcon,
|
|
54
|
+
type: source.type === "device" ||
|
|
55
|
+
source.type === "dashboard" ||
|
|
56
|
+
source.type === "organisation" ||
|
|
57
|
+
source.type === "user"
|
|
58
|
+
? source.type
|
|
59
|
+
: "device",
|
|
60
|
+
fixed_location: normalizedFixedLocation,
|
|
61
|
+
extra_config: coerceExtraConfig(source.extra_config),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function normalizeOrganisationEntry(rawOrganisation) {
|
|
65
|
+
const source = isPlainObject(rawOrganisation)
|
|
66
|
+
? rawOrganisation
|
|
67
|
+
: {};
|
|
68
|
+
const name = typeof source.name === "string" ? source.name : "";
|
|
69
|
+
const rootGroup = isPlainObject(source.root_group) ? source.root_group : null;
|
|
70
|
+
const groupName = rootGroup && typeof rootGroup.name === "string" ? rootGroup.name : "";
|
|
71
|
+
return {
|
|
72
|
+
id: typeof source.id === "string" ? source.id : String(source.id ?? ""),
|
|
73
|
+
organisation: name,
|
|
74
|
+
name,
|
|
75
|
+
display_name: name,
|
|
76
|
+
archived: typeof source.archived === "boolean" ? source.archived : false,
|
|
77
|
+
group: groupName,
|
|
78
|
+
fa_icon: "fa-solid fa-building",
|
|
79
|
+
type: "organisation",
|
|
80
|
+
fixed_location: { latitude: 0, longitude: 0 },
|
|
81
|
+
extra_config: coerceExtraConfig(source.extra_config),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function normalizeUserEntry(rawUser) {
|
|
85
|
+
const source = isPlainObject(rawUser)
|
|
86
|
+
? rawUser
|
|
87
|
+
: {};
|
|
88
|
+
const id = typeof source.id === "string" ? source.id : String(source.id ?? "");
|
|
89
|
+
const username = typeof source.username === "string" ? source.username : "";
|
|
90
|
+
const email = typeof source.email === "string" ? source.email : "";
|
|
91
|
+
const name = username !== "" ? username : email !== "" ? email : id;
|
|
92
|
+
return {
|
|
93
|
+
id,
|
|
94
|
+
organisation: "",
|
|
95
|
+
name,
|
|
96
|
+
display_name: buildUserDisplayName(source),
|
|
97
|
+
archived: false,
|
|
98
|
+
group: "",
|
|
99
|
+
fa_icon: "fa-solid fa-user",
|
|
100
|
+
type: "user",
|
|
101
|
+
fixed_location: { latitude: 0, longitude: 0 },
|
|
102
|
+
extra_config: coerceExtraConfig(source.custom_data),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export class AgentsApi {
|
|
106
|
+
constructor(rest, controlApiUrl) {
|
|
107
|
+
this.rest = rest;
|
|
108
|
+
this.controlApiUrl = controlApiUrl;
|
|
109
|
+
}
|
|
110
|
+
async listAgents(options, _requestOptions) {
|
|
111
|
+
const agentOptions = options;
|
|
112
|
+
const query = {};
|
|
113
|
+
if (agentOptions?.includeArchived)
|
|
114
|
+
query["include-archived"] = true;
|
|
115
|
+
if (agentOptions?.includeOrganisations)
|
|
116
|
+
query["include-organisations"] = true;
|
|
117
|
+
if (agentOptions?.includeUsers)
|
|
118
|
+
query["include-users"] = true;
|
|
119
|
+
const raw = await this.rest.request({
|
|
120
|
+
path: "/agents/",
|
|
121
|
+
baseUrl: this.controlApiUrl,
|
|
122
|
+
omitSharingHeader: true,
|
|
123
|
+
query: Object.keys(query).length > 0 ? query : undefined,
|
|
124
|
+
});
|
|
125
|
+
const rawAgents = Array.isArray(raw.agents) ? raw.agents : [];
|
|
126
|
+
const normalizedAgents = rawAgents.map(normalizeAgentEntry);
|
|
127
|
+
if (!agentOptions?.mergeIncludedAsAgents) {
|
|
128
|
+
return { ...raw, agents: normalizedAgents };
|
|
129
|
+
}
|
|
130
|
+
const merged = [...normalizedAgents];
|
|
131
|
+
if (agentOptions.includeOrganisations) {
|
|
132
|
+
const rawOrgs = Array.isArray(raw.organisations)
|
|
133
|
+
? raw.organisations
|
|
134
|
+
: [];
|
|
135
|
+
for (const org of rawOrgs)
|
|
136
|
+
merged.push(normalizeOrganisationEntry(org));
|
|
137
|
+
}
|
|
138
|
+
if (agentOptions.includeUsers) {
|
|
139
|
+
const rawUsers = Array.isArray(raw.users) ? raw.users : [];
|
|
140
|
+
for (const user of rawUsers)
|
|
141
|
+
merged.push(normalizeUserEntry(user));
|
|
142
|
+
}
|
|
143
|
+
return { ...raw, agents: merged, results: merged, count: merged.length };
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Batch-fetch recent messages for many agents. Auto-chunks `agent_id`
|
|
147
|
+
* (and the parallel `agent_before` cursors, if given) at MULTI_AGENT_CHUNK_SIZE
|
|
148
|
+
* so each request's URL stays under CloudFront's 8,192-byte quota. Chunks
|
|
149
|
+
* are fetched in parallel and merged: `results`/`count` concat-and-sum,
|
|
150
|
+
* `next_cursors`/`at_limit_agent_ids` union, legacy `next` becomes the
|
|
151
|
+
* lexically-highest cursor across at-limit agents.
|
|
152
|
+
*/
|
|
153
|
+
async getMultiAgentMessages(channelName, params) {
|
|
154
|
+
const path = `/agents/channels/${channelName}/messages`;
|
|
155
|
+
const { agent_id, agent_before, ...rest } = params;
|
|
156
|
+
const stampTimestamps = (response) => ({
|
|
157
|
+
...response,
|
|
158
|
+
results: response.results.map((message) => "timestamp" in message ? message : addTimestampToMessage(message)),
|
|
159
|
+
});
|
|
160
|
+
if (agent_id.length <= MULTI_AGENT_CHUNK_SIZE) {
|
|
161
|
+
const response = await this.rest.get(path, params);
|
|
162
|
+
return stampTimestamps(response);
|
|
163
|
+
}
|
|
164
|
+
if (agent_before && agent_before.length !== agent_id.length) {
|
|
165
|
+
throw new Error("agent_before must be the same length as agent_id when set");
|
|
166
|
+
}
|
|
167
|
+
const chunks = [];
|
|
168
|
+
for (let i = 0; i < agent_id.length; i += MULTI_AGENT_CHUNK_SIZE) {
|
|
169
|
+
chunks.push({
|
|
170
|
+
agent_id: agent_id.slice(i, i + MULTI_AGENT_CHUNK_SIZE),
|
|
171
|
+
...(agent_before
|
|
172
|
+
? { agent_before: agent_before.slice(i, i + MULTI_AGENT_CHUNK_SIZE) }
|
|
173
|
+
: {}),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
const responses = await Promise.all(chunks.map((chunk) => this.rest
|
|
177
|
+
.get(path, { ...rest, ...chunk })
|
|
178
|
+
.then(stampTimestamps)));
|
|
179
|
+
// Merge: results/count concat-and-sum; next_cursors merge; at_limit_agent_ids
|
|
180
|
+
// concat (both keyed by agent id, unique across chunks). Legacy `next` is the
|
|
181
|
+
// lexically-highest oldest-cursor across at-limit agents — snowflakes sort
|
|
182
|
+
// lexically since they're equal-width digit strings.
|
|
183
|
+
const merged = {
|
|
184
|
+
results: responses.flatMap((r) => r.results),
|
|
185
|
+
count: responses.reduce((acc, r) => acc + r.count, 0),
|
|
186
|
+
};
|
|
187
|
+
const nexts = responses
|
|
188
|
+
.map((r) => r.next)
|
|
189
|
+
.filter((n) => typeof n === "string" && n.length > 0);
|
|
190
|
+
if (nexts.length > 0) {
|
|
191
|
+
merged.next = nexts.reduce((a, b) => (a > b ? a : b));
|
|
192
|
+
}
|
|
193
|
+
const cursors = {};
|
|
194
|
+
for (const r of responses) {
|
|
195
|
+
if (r.next_cursors)
|
|
196
|
+
Object.assign(cursors, r.next_cursors);
|
|
197
|
+
}
|
|
198
|
+
if (Object.keys(cursors).length > 0)
|
|
199
|
+
merged.next_cursors = cursors;
|
|
200
|
+
const atLimit = responses.flatMap((r) => r.at_limit_agent_ids ?? []);
|
|
201
|
+
if (atLimit.length > 0)
|
|
202
|
+
merged.at_limit_agent_ids = atLimit;
|
|
203
|
+
return merged;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Batch-fetch aggregates for many agents. Auto-chunks `agent_id` so each
|
|
207
|
+
* request's URL stays under CloudFront's hard 8,192-byte URL quota — each
|
|
208
|
+
* agent contributes ~30 chars (`agent_id=<snowflake>&`), so the chunk size
|
|
209
|
+
* below caps the query string at ~7.5KB even before the base URL. Chunks
|
|
210
|
+
* are fetched in parallel and merged into one `{ results, count }` so
|
|
211
|
+
* callers never have to think about the limit.
|
|
212
|
+
*/
|
|
213
|
+
async getMultiAgentAggregates(channelName, params) {
|
|
214
|
+
const path = `/agents/channels/${channelName}/aggregates`;
|
|
215
|
+
const { agent_id, ...rest } = params;
|
|
216
|
+
if (agent_id.length <= MULTI_AGENT_CHUNK_SIZE) {
|
|
217
|
+
return this.rest.get(path, params);
|
|
218
|
+
}
|
|
219
|
+
const chunks = [];
|
|
220
|
+
for (let i = 0; i < agent_id.length; i += MULTI_AGENT_CHUNK_SIZE) {
|
|
221
|
+
chunks.push(agent_id.slice(i, i + MULTI_AGENT_CHUNK_SIZE));
|
|
222
|
+
}
|
|
223
|
+
const responses = await Promise.all(chunks.map((chunk) => this.rest.get(path, {
|
|
224
|
+
...rest,
|
|
225
|
+
agent_id: chunk,
|
|
226
|
+
})));
|
|
227
|
+
return {
|
|
228
|
+
results: responses.flatMap((r) => r.results),
|
|
229
|
+
count: responses.reduce((acc, r) => acc + r.count, 0),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Read an agent's credential state: the revocation floor, the auth
|
|
234
|
+
* kill-switch, and the token posture resolved across the per-agent override
|
|
235
|
+
* and the organisation default.
|
|
236
|
+
*
|
|
237
|
+
* Requires `AgentTokenRead`, which is read-only — a caller can display
|
|
238
|
+
* credential state (including an auth-lock banner, often the only explanation
|
|
239
|
+
* for why a device is offline) without being able to change any of it.
|
|
240
|
+
*/
|
|
241
|
+
getTokenState(agentId) {
|
|
242
|
+
return this.rest.get(`/agents/${agentId}/token_state`);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Replace an agent's token-posture override. Omitted or null fields mean
|
|
246
|
+
* "inherit the organisation default" — a full replacement rather than a
|
|
247
|
+
* merge, so clearing an override back to inherited is expressible.
|
|
248
|
+
*
|
|
249
|
+
* Rejected server-side if the resolved posture sets `max_age_ms` without
|
|
250
|
+
* `self_rotation`: a device that can't self-rotate has no way to trade its
|
|
251
|
+
* token in before the max age elapses, making that combination a scheduled
|
|
252
|
+
* outage.
|
|
253
|
+
*/
|
|
254
|
+
setTokenPolicy(agentId, policy) {
|
|
255
|
+
return this.rest.put(`/agents/${agentId}/token_policy`, policy);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Set or clear the auth kill-switch. While locked, every auth attempt for the
|
|
259
|
+
* agent is rejected regardless of token validity.
|
|
260
|
+
*
|
|
261
|
+
* doover-data sets this automatically on suspected token reuse, so clearing it
|
|
262
|
+
* is a routine incident-response action rather than an exotic one.
|
|
263
|
+
*/
|
|
264
|
+
setAuthLock(agentId, locked) {
|
|
265
|
+
return this.rest.post(`/agents/${agentId}/auth_lock`, { locked });
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Revoke every outstanding long-lived credential for an agent by advancing the
|
|
269
|
+
* revocation floor. Mints nothing.
|
|
270
|
+
*
|
|
271
|
+
* This takes the device offline until it is re-provisioned. Break-glass:
|
|
272
|
+
* confirm before calling.
|
|
273
|
+
*/
|
|
274
|
+
revokeAllTokens(agentId) {
|
|
275
|
+
return this.rest.post(`/agents/${agentId}/token/revoke_all`, {});
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Set the revocation floor to an explicit point, in either direction. `0` or
|
|
279
|
+
* `null` clears it.
|
|
280
|
+
*
|
|
281
|
+
* `revokeAllTokens` is the normal way to revoke. Lowering the floor reverses a
|
|
282
|
+
* revocation, so it is for undoing one made by mistake — not for recovering
|
|
283
|
+
* from a leak, where you should issue fresh credentials instead.
|
|
284
|
+
*/
|
|
285
|
+
setRevocationFloor(agentId, tokensValidFrom) {
|
|
286
|
+
return this.rest.post(`/agents/${agentId}/token/floor`, { tokens_valid_from: tokensValidFrom });
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Mint a short-lived scoped JWT for ad-hoc access to an agent — debugging, a
|
|
290
|
+
* one-off script, an integration.
|
|
291
|
+
*
|
|
292
|
+
* This is the way to give a *person* access to a device. The device's own
|
|
293
|
+
* long-lived credential is deliberately not obtainable through the API: it is
|
|
294
|
+
* minted into an installer bundle and never shown. Expiry stands in for
|
|
295
|
+
* revocation here, so keep `timeout` as short as the task allows.
|
|
296
|
+
*/
|
|
297
|
+
createAdhocToken(agentId, options = {}) {
|
|
298
|
+
return this.rest.post(`/agents/${agentId}/token`, {
|
|
299
|
+
format: "jwt",
|
|
300
|
+
permissions: options.permissions ?? [],
|
|
301
|
+
timeout: options.timeout,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Mint the device's long-lived credential and return it once, for manual
|
|
306
|
+
* provisioning — pasting into a device's config by hand. The installer download
|
|
307
|
+
* mints one into the bundle for you; this is the equivalent for a device you're
|
|
308
|
+
* configuring yourself.
|
|
309
|
+
*
|
|
310
|
+
* Always additive: the revocation floor is left alone, so minting can never
|
|
311
|
+
* knock a running device offline. `revoke_existing` is intentionally not
|
|
312
|
+
* exposed here — revoking is `revokeAllTokens`, a separate deliberate act.
|
|
313
|
+
*
|
|
314
|
+
* Returned once and stored nowhere. If it's lost, mint another.
|
|
315
|
+
*/
|
|
316
|
+
createDeviceToken(agentId) {
|
|
317
|
+
return this.rest.post(`/agents/${agentId}/token`, {
|
|
318
|
+
format: "mini_v1",
|
|
319
|
+
revoke_existing: false,
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// CloudFront fronts the channels-rest API with a hard 8,192-byte URL quota.
|
|
324
|
+
// Each agent adds ~30 chars (`agent_id=<19-digit snowflake>&`), so 250 IDs
|
|
325
|
+
// is ~7.5KB of query string — comfortably under the cap with room for the
|
|
326
|
+
// base URL and any `field_name` params.
|
|
327
|
+
const MULTI_AGENT_CHUNK_SIZE = 250;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { RestClient } from "../http/rest-client.js";
|
|
2
|
+
import type { Aggregate } from "../types/openapi.js";
|
|
3
|
+
import type { DooverRequestOptions } from "../client/request-options.js";
|
|
4
|
+
import { type BatchAggregateResponse, type BatchAggregateUpdateItem } from "../types/batch.js";
|
|
5
|
+
export interface AggregateMutationParams {
|
|
6
|
+
suppress_response?: boolean;
|
|
7
|
+
clear_attachments?: boolean;
|
|
8
|
+
log_update?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare class AggregatesApi {
|
|
11
|
+
private readonly rest;
|
|
12
|
+
constructor(rest: RestClient);
|
|
13
|
+
/**
|
|
14
|
+
* Merge-patch aggregates across many agents and channels in one request.
|
|
15
|
+
*
|
|
16
|
+
* Replaces N single-agent PATCHes with one round trip, which is the point:
|
|
17
|
+
* it removes the per-request HTTP, auth, routing and tracing overhead, and
|
|
18
|
+
* shrinks synchronised write bursts. It does *not* reduce DynamoDB writes —
|
|
19
|
+
* the server still issues one `UpdateItem` per aggregate, capped at four
|
|
20
|
+
* concurrently — so callers should still coalesce on the client rather than
|
|
21
|
+
* relying on this to absorb a storm.
|
|
22
|
+
*
|
|
23
|
+
* Batches over {@link MAX_BATCH_ITEMS} are split automatically and the
|
|
24
|
+
* responses merged, so a caller can pass an arbitrarily long list. An empty
|
|
25
|
+
* list resolves to an empty response without issuing a request.
|
|
26
|
+
*
|
|
27
|
+
* Partial success is normal: inspect `items` and retry only the entries
|
|
28
|
+
* whose `success` is false. Successful entries are never rolled back.
|
|
29
|
+
*/
|
|
30
|
+
batchPatchAggregates(items: BatchAggregateUpdateItem[]): Promise<BatchAggregateResponse>;
|
|
31
|
+
batchPatchAggregates(items: BatchAggregateUpdateItem[], requestOptions: DooverRequestOptions): Promise<BatchAggregateResponse>;
|
|
32
|
+
private _batchPatchAggregates;
|
|
33
|
+
getAggregate(agentId: string, channelName: string): Promise<Aggregate>;
|
|
34
|
+
getAggregate(agentId: string, channelName: string, requestOptions: DooverRequestOptions): Promise<Aggregate>;
|
|
35
|
+
getAggregate(identifier: {
|
|
36
|
+
agentId: string;
|
|
37
|
+
channelName: string;
|
|
38
|
+
}): Promise<Aggregate>;
|
|
39
|
+
getAggregate(identifier: {
|
|
40
|
+
agentId: string;
|
|
41
|
+
channelName: string;
|
|
42
|
+
}, requestOptions: DooverRequestOptions): Promise<Aggregate>;
|
|
43
|
+
private _getAggregate;
|
|
44
|
+
putAggregate(agentId: string, channelName: string, body: Record<string, unknown> | FormData, params?: AggregateMutationParams): Promise<Aggregate>;
|
|
45
|
+
putAggregate(identifier: {
|
|
46
|
+
agentId: string;
|
|
47
|
+
channelName: string;
|
|
48
|
+
}, body: Record<string, unknown> | FormData, params?: AggregateMutationParams): Promise<Aggregate>;
|
|
49
|
+
private _putAggregate;
|
|
50
|
+
patchAggregate(agentId: string, channelName: string, body: Record<string, unknown> | FormData, params?: AggregateMutationParams): Promise<Aggregate>;
|
|
51
|
+
patchAggregate(identifier: {
|
|
52
|
+
agentId: string;
|
|
53
|
+
channelName: string;
|
|
54
|
+
}, body: Record<string, unknown> | FormData, params?: AggregateMutationParams): Promise<Aggregate>;
|
|
55
|
+
private _patchAggregate;
|
|
56
|
+
getAggregateAttachment(agentId: string, channelName: string, attachmentId: string): Promise<Blob>;
|
|
57
|
+
getAggregateAttachment(agentId: string, channelName: string, attachmentId: string, requestOptions: DooverRequestOptions): Promise<Blob>;
|
|
58
|
+
getAggregateAttachment(identifier: {
|
|
59
|
+
agentId: string;
|
|
60
|
+
channelName: string;
|
|
61
|
+
}, attachmentId: string): Promise<Blob>;
|
|
62
|
+
getAggregateAttachment(identifier: {
|
|
63
|
+
agentId: string;
|
|
64
|
+
channelName: string;
|
|
65
|
+
}, attachmentId: string, requestOptions: DooverRequestOptions): Promise<Blob>;
|
|
66
|
+
private _getAggregateAttachment;
|
|
67
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { resolveChannelArgs } from "./_args.js";
|
|
2
|
+
import { chunkBatchItems, mergeBatchResponses, } from "../types/batch.js";
|
|
3
|
+
export class AggregatesApi {
|
|
4
|
+
constructor(rest) {
|
|
5
|
+
this.rest = rest;
|
|
6
|
+
}
|
|
7
|
+
batchPatchAggregates(...args) {
|
|
8
|
+
return this._batchPatchAggregates(args[0]);
|
|
9
|
+
}
|
|
10
|
+
async _batchPatchAggregates(items) {
|
|
11
|
+
if (items.length === 0) {
|
|
12
|
+
return { items: [], count: 0, succeeded: 0, failed: 0 };
|
|
13
|
+
}
|
|
14
|
+
const responses = [];
|
|
15
|
+
// Sequential: the point of batching is to stop hammering the write path,
|
|
16
|
+
// so firing every chunk at once would defeat it.
|
|
17
|
+
for (const chunk of chunkBatchItems(items)) {
|
|
18
|
+
responses.push(await this.rest.patch("/agents/aggregates", {
|
|
19
|
+
items: chunk,
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
return mergeBatchResponses(responses);
|
|
23
|
+
}
|
|
24
|
+
getAggregate(...args) {
|
|
25
|
+
const { agentId, channelName } = resolveChannelArgs(args);
|
|
26
|
+
return this._getAggregate(agentId, channelName);
|
|
27
|
+
}
|
|
28
|
+
_getAggregate(agentId, channelName) {
|
|
29
|
+
return this.rest.get(`/agents/${agentId}/channels/${channelName}/aggregate`);
|
|
30
|
+
}
|
|
31
|
+
putAggregate(...args) {
|
|
32
|
+
if (typeof args[0] === "string") {
|
|
33
|
+
const [agentId, channelName, body, params] = args;
|
|
34
|
+
return this._putAggregate(agentId, channelName, body, params);
|
|
35
|
+
}
|
|
36
|
+
const id = args[0];
|
|
37
|
+
return this._putAggregate(id.agentId, id.channelName, args[1], args[2]);
|
|
38
|
+
}
|
|
39
|
+
_putAggregate(agentId, channelName, body, params) {
|
|
40
|
+
return this.rest.put(`/agents/${agentId}/channels/${channelName}/aggregate`, body, params);
|
|
41
|
+
}
|
|
42
|
+
patchAggregate(...args) {
|
|
43
|
+
if (typeof args[0] === "string") {
|
|
44
|
+
const [agentId, channelName, body, params] = args;
|
|
45
|
+
return this._patchAggregate(agentId, channelName, body, params);
|
|
46
|
+
}
|
|
47
|
+
const id = args[0];
|
|
48
|
+
return this._patchAggregate(id.agentId, id.channelName, args[1], args[2]);
|
|
49
|
+
}
|
|
50
|
+
_patchAggregate(agentId, channelName, body, params) {
|
|
51
|
+
return this.rest.patch(`/agents/${agentId}/channels/${channelName}/aggregate`, body, params);
|
|
52
|
+
}
|
|
53
|
+
getAggregateAttachment(...args) {
|
|
54
|
+
if (typeof args[0] === "string") {
|
|
55
|
+
const [agentId, channelName, attachmentId] = args;
|
|
56
|
+
return this._getAggregateAttachment(agentId, channelName, attachmentId);
|
|
57
|
+
}
|
|
58
|
+
const id = args[0];
|
|
59
|
+
return this._getAggregateAttachment(id.agentId, id.channelName, args[1]);
|
|
60
|
+
}
|
|
61
|
+
_getAggregateAttachment(agentId, channelName, attachmentId) {
|
|
62
|
+
return this.rest.get(`/agents/${agentId}/channels/${channelName}/aggregate/attachments/${attachmentId}`);
|
|
63
|
+
}
|
|
64
|
+
}
|