doover-js 0.1.2 → 0.2.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 +104 -10
- package/dist/apis/connections-api.d.ts +6 -0
- package/dist/apis/connections-api.js +8 -0
- package/dist/auth/auth-profile.d.ts +45 -0
- package/dist/auth/auth-profile.js +72 -0
- package/dist/auth/auth-store.d.ts +14 -0
- package/dist/auth/auth-store.js +2 -0
- package/dist/auth/build-auth.d.ts +37 -0
- package/dist/auth/build-auth.js +75 -0
- package/dist/auth/cookie-auth.d.ts +17 -0
- package/dist/auth/cookie-auth.js +29 -0
- package/dist/auth/doover-auth.d.ts +41 -0
- package/dist/auth/doover-auth.js +24 -0
- package/dist/auth/doover-token-auth.d.ts +35 -0
- package/dist/auth/doover-token-auth.js +178 -0
- package/dist/auth/errors.d.ts +3 -0
- package/dist/auth/errors.js +10 -0
- package/dist/auth/jwt.d.ts +6 -0
- package/dist/auth/jwt.js +29 -0
- package/dist/client/doover-client.d.ts +15 -0
- package/dist/client/doover-client.js +45 -4
- package/dist/client/singleton.d.ts +26 -0
- package/dist/client/singleton.js +59 -0
- package/dist/client/stats.d.ts +55 -0
- package/dist/client/stats.js +97 -0
- package/dist/gateway/gateway-client.d.ts +34 -8
- package/dist/gateway/gateway-client.js +147 -52
- package/dist/gateway/types.d.ts +0 -1
- package/dist/http/rest-client.d.ts +21 -3
- package/dist/http/rest-client.js +33 -2
- package/dist/index.d.ts +12 -0
- package/dist/index.js +23 -5
- package/dist/node/config-manager.d.ts +34 -0
- package/dist/node/config-manager.js +177 -0
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +5 -0
- package/dist/react/context.d.ts +19 -0
- package/dist/react/context.js +28 -0
- package/dist/react/index.d.ts +24 -0
- package/dist/react/index.js +40 -0
- package/dist/react/sharedQueryClient.d.ts +21 -0
- package/dist/react/sharedQueryClient.js +39 -0
- package/dist/react/useAgentChannel.d.ts +7 -0
- package/dist/react/useAgentChannel.js +12 -0
- package/dist/react/useAgentConnections.d.ts +8 -0
- package/dist/react/useAgentConnections.js +24 -0
- package/dist/react/useChannelAggregate.d.ts +13 -0
- package/dist/react/useChannelAggregate.js +38 -0
- package/dist/react/useChannelMessages.d.ts +23 -0
- package/dist/react/useChannelMessages.js +56 -0
- package/dist/react/useChannelSubscription.d.ts +16 -0
- package/dist/react/useChannelSubscription.js +43 -0
- package/dist/react/useConnectionState.d.ts +21 -0
- package/dist/react/useConnectionState.js +43 -0
- package/dist/react/useMultiAgentAggregates.d.ts +22 -0
- package/dist/react/useMultiAgentAggregates.js +82 -0
- package/dist/react/useMultiAgentChannelMessages.d.ts +18 -0
- package/dist/react/useMultiAgentChannelMessages.js +78 -0
- package/dist/react/useSendMessage.d.ts +9 -0
- package/dist/react/useSendMessage.js +16 -0
- package/dist/react/useSendRpc.d.ts +61 -0
- package/dist/react/useSendRpc.js +158 -0
- package/dist/react/useTurnCredentials.d.ts +12 -0
- package/dist/react/useTurnCredentials.js +25 -0
- package/dist/react/useUpdateAggregate.d.ts +14 -0
- package/dist/react/useUpdateAggregate.js +25 -0
- package/dist/react/useUpdateMessage.d.ts +17 -0
- package/dist/react/useUpdateMessage.js +24 -0
- package/dist/test/apis.test.js +7 -1
- package/dist/test/auth.test.d.ts +1 -0
- package/dist/test/auth.test.js +502 -0
- package/dist/test/config-manager.test.d.ts +1 -0
- package/dist/test/config-manager.test.js +160 -0
- package/dist/test/doover-client.test.js +13 -0
- package/dist/test/doover-data-provider.test.js +155 -0
- package/dist/test/gateway-client.test.js +122 -8
- package/dist/test/react.test.d.ts +1 -0
- package/dist/test/react.test.js +353 -0
- package/dist/test/singleton.test.d.ts +1 -0
- package/dist/test/singleton.test.js +62 -0
- package/dist/types/common.d.ts +40 -0
- package/dist/viewer/doover-data-provider.d.ts +34 -5
- package/dist/viewer/doover-data-provider.js +96 -9
- package/package.json +33 -2
|
@@ -11,12 +11,19 @@ const errors_1 = require("../http/errors");
|
|
|
11
11
|
const rest_client_1 = require("../http/rest-client");
|
|
12
12
|
const snowflake_1 = require("../utils/snowflake");
|
|
13
13
|
const path_parsing_1 = require("./path-parsing");
|
|
14
|
+
function isRpcMessageData(data) {
|
|
15
|
+
return (typeof data === "object" &&
|
|
16
|
+
data !== null &&
|
|
17
|
+
"status" in data &&
|
|
18
|
+
"method" in data &&
|
|
19
|
+
"request" in data);
|
|
20
|
+
}
|
|
14
21
|
class DooverDataProvider {
|
|
15
|
-
constructor(config) {
|
|
22
|
+
constructor(config, auth) {
|
|
16
23
|
this.config = config;
|
|
17
24
|
this.subscriptions = new Map();
|
|
18
|
-
this.rest = new rest_client_1.RestClient(config);
|
|
19
|
-
this.gateway = new gateway_client_1.GatewayClient(config);
|
|
25
|
+
this.rest = new rest_client_1.RestClient(config, auth);
|
|
26
|
+
this.gateway = new gateway_client_1.GatewayClient(config, auth);
|
|
20
27
|
this.agentsApi = new agents_api_1.AgentsApi(this.rest);
|
|
21
28
|
this.channelsApi = new channels_api_1.ChannelsApi(this.rest);
|
|
22
29
|
this.messagesApi = new messages_api_1.MessagesApi(this.rest);
|
|
@@ -27,6 +34,11 @@ class DooverDataProvider {
|
|
|
27
34
|
const identifier = this.toIdentifier(message.channel.agent_id, message.channel.name);
|
|
28
35
|
this.subscriptions.get(key)?.forEach((entry) => entry.messageCallback(identifier, message));
|
|
29
36
|
});
|
|
37
|
+
this.gateway.on("messageUpdate", (message) => {
|
|
38
|
+
const key = this.channelKey(message.channel.agent_id, message.channel.name);
|
|
39
|
+
const identifier = this.toIdentifier(message.channel.agent_id, message.channel.name);
|
|
40
|
+
this.subscriptions.get(key)?.forEach((entry) => entry.messageUpdateCallback?.(identifier, message));
|
|
41
|
+
});
|
|
30
42
|
this.gateway.on("channelSync", (event) => {
|
|
31
43
|
const key = this.channelKey(event.channel.agent_id, event.channel.name);
|
|
32
44
|
const identifier = this.toIdentifier(event.channel.agent_id, event.channel.name);
|
|
@@ -78,13 +90,17 @@ class DooverDataProvider {
|
|
|
78
90
|
}
|
|
79
91
|
return this.channelsApi.getChannel(identifier.agentId, identifier.channelName);
|
|
80
92
|
}
|
|
81
|
-
async subscribeToChannel(identifier, callback, aggregateCallback) {
|
|
93
|
+
async subscribeToChannel(identifier, callback, aggregateCallback, messageUpdateCallback) {
|
|
82
94
|
const validated = this.requireChannel(identifier);
|
|
83
95
|
const key = this.channelKey(validated.agentId, validated.channelName);
|
|
84
96
|
const entries = this.subscriptions.get(key) ?? [];
|
|
85
|
-
entries.push({
|
|
97
|
+
entries.push({
|
|
98
|
+
messageCallback: callback,
|
|
99
|
+
aggregateCallback,
|
|
100
|
+
messageUpdateCallback,
|
|
101
|
+
});
|
|
86
102
|
this.subscriptions.set(key, entries);
|
|
87
|
-
this.gateway.connect();
|
|
103
|
+
await this.gateway.connect();
|
|
88
104
|
this.gateway.subscribe({
|
|
89
105
|
agent_id: validated.agentId,
|
|
90
106
|
name: validated.channelName,
|
|
@@ -121,13 +137,27 @@ class DooverDataProvider {
|
|
|
121
137
|
}
|
|
122
138
|
return this.aggregatesApi.getAggregate(identifier.agentId, identifier.channelName);
|
|
123
139
|
}
|
|
124
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Fetch a page of messages for a channel.
|
|
142
|
+
*
|
|
143
|
+
* Accepts either a cursor string (legacy — shorthand for `{ before }`)
|
|
144
|
+
* or a `ListMessagesParams` options object.
|
|
145
|
+
*
|
|
146
|
+
* Default limit is 10 for backwards compatibility; pass `limit` explicitly
|
|
147
|
+
* for larger pages.
|
|
148
|
+
*/
|
|
149
|
+
async getMessages(identifier, optionsOrBefore) {
|
|
125
150
|
if (!identifier.agentId || !identifier.channelName) {
|
|
126
151
|
return undefined;
|
|
127
152
|
}
|
|
153
|
+
const options = typeof optionsOrBefore === "string"
|
|
154
|
+
? { before: optionsOrBefore }
|
|
155
|
+
: (optionsOrBefore ?? {});
|
|
128
156
|
const messages = await this.messagesApi.listMessages(identifier.agentId, identifier.channelName, {
|
|
129
|
-
before:
|
|
130
|
-
limit: 10,
|
|
157
|
+
before: options.before ?? (0, snowflake_1.generateSnowflakeIdAtTime)(new Date()),
|
|
158
|
+
limit: options.limit ?? 10,
|
|
159
|
+
...(options.after !== undefined ? { after: options.after } : {}),
|
|
160
|
+
...(options.field_name !== undefined ? { field_name: options.field_name } : {}),
|
|
131
161
|
});
|
|
132
162
|
return messages.reverse();
|
|
133
163
|
}
|
|
@@ -141,6 +171,63 @@ class DooverDataProvider {
|
|
|
141
171
|
data: message,
|
|
142
172
|
});
|
|
143
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Send a message-based RPC to a channel and await a settled response.
|
|
176
|
+
*
|
|
177
|
+
* Wire protocol: POST a message with `{ type: "rpc", ...rpcRequest }`; the
|
|
178
|
+
* server echoes progress via `MessageUpdate` events keyed by the message id,
|
|
179
|
+
* carrying a `status` envelope. Resolves on `success` with the `response`
|
|
180
|
+
* payload, rejects on `error` with the status message.
|
|
181
|
+
*
|
|
182
|
+
* For low-latency ephemeral commands (camera PTZ etc.), use
|
|
183
|
+
* `gateway.sendOneShotMessage` directly instead — that path is not persisted
|
|
184
|
+
* to the database.
|
|
185
|
+
*
|
|
186
|
+
* `onStatus` fires on every intermediate status (`sent`, `acknowledged`,
|
|
187
|
+
* `deferred`, `pending`) and once more on terminal states.
|
|
188
|
+
*/
|
|
189
|
+
sendRPC(identifier, rpcRequest, options) {
|
|
190
|
+
return new Promise((resolve, reject) => {
|
|
191
|
+
let rpcMessageId;
|
|
192
|
+
let settled = false;
|
|
193
|
+
const onUpdate = (_identifier, message) => {
|
|
194
|
+
if (settled)
|
|
195
|
+
return;
|
|
196
|
+
if (rpcMessageId === undefined || message.id !== rpcMessageId)
|
|
197
|
+
return;
|
|
198
|
+
if (!isRpcMessageData(message.data))
|
|
199
|
+
return;
|
|
200
|
+
const rpcMessage = message.data;
|
|
201
|
+
options?.onStatus?.(rpcMessage.status);
|
|
202
|
+
if (rpcMessage.status.code === "success") {
|
|
203
|
+
settled = true;
|
|
204
|
+
void this.unsubscribeFromChannel(identifier, noopMessageCallback);
|
|
205
|
+
resolve(rpcMessage.response);
|
|
206
|
+
}
|
|
207
|
+
else if (rpcMessage.status.code === "error") {
|
|
208
|
+
settled = true;
|
|
209
|
+
void this.unsubscribeFromChannel(identifier, noopMessageCallback);
|
|
210
|
+
reject(rpcMessage.status.message);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
// noopMessageCallback is used as the identity handle for this
|
|
214
|
+
// subscription — subscribe/unsubscribe pair matches by reference.
|
|
215
|
+
const noopMessageCallback = () => { };
|
|
216
|
+
const noopAggregateCallback = () => { };
|
|
217
|
+
this.subscribeToChannel(identifier, noopMessageCallback, noopAggregateCallback, onUpdate)
|
|
218
|
+
.then(() => this.sendMessage(identifier, { type: "rpc", ...rpcRequest }))
|
|
219
|
+
.then((message) => {
|
|
220
|
+
rpcMessageId = message.id;
|
|
221
|
+
})
|
|
222
|
+
.catch((error) => {
|
|
223
|
+
if (settled)
|
|
224
|
+
return;
|
|
225
|
+
settled = true;
|
|
226
|
+
void this.unsubscribeFromChannel(identifier, noopMessageCallback);
|
|
227
|
+
reject(error);
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
}
|
|
144
231
|
updateAggregate(identifier, message) {
|
|
145
232
|
const validated = this.requireChannel(identifier);
|
|
146
233
|
return this.aggregatesApi.patchAggregate(validated.agentId, validated.channelName, message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "doover-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "TypeScript client for Doover.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -8,6 +8,14 @@
|
|
|
8
8
|
".": {
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
10
10
|
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./node": {
|
|
13
|
+
"types": "./dist/node/index.d.ts",
|
|
14
|
+
"default": "./dist/node/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./react": {
|
|
17
|
+
"types": "./dist/react/index.d.ts",
|
|
18
|
+
"default": "./dist/react/index.js"
|
|
11
19
|
}
|
|
12
20
|
},
|
|
13
21
|
"repository": {
|
|
@@ -25,20 +33,43 @@
|
|
|
25
33
|
"build": "tsc",
|
|
26
34
|
"clean": "rm -rf dist",
|
|
27
35
|
"prepublishOnly": "npm run build",
|
|
28
|
-
"test": "mocha --require tsx/cjs \"src/test/**/*.test.ts\""
|
|
36
|
+
"test:node": "mocha --exit --require tsx/cjs \"src/test/**/*.test.ts\"",
|
|
37
|
+
"test:react": "mocha --exit --require global-jsdom/register --require tsx/cjs \"src/test/**/*.test.tsx\"",
|
|
38
|
+
"test": "npm run test:node && npm run test:react"
|
|
29
39
|
},
|
|
30
40
|
"keywords": [
|
|
31
41
|
"doover"
|
|
32
42
|
],
|
|
33
43
|
"license": "Apache-2.0",
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"@tanstack/react-query": "^5",
|
|
46
|
+
"react": "^18 || ^19"
|
|
47
|
+
},
|
|
48
|
+
"peerDependenciesMeta": {
|
|
49
|
+
"@tanstack/react-query": {
|
|
50
|
+
"optional": true
|
|
51
|
+
},
|
|
52
|
+
"react": {
|
|
53
|
+
"optional": true
|
|
54
|
+
}
|
|
55
|
+
},
|
|
34
56
|
"devDependencies": {
|
|
57
|
+
"@tanstack/react-query": "^5.90.2",
|
|
58
|
+
"@testing-library/react": "^16.1.0",
|
|
35
59
|
"@types/chai": "^5.2.2",
|
|
36
60
|
"@types/chai-as-promised": "^7.1.8",
|
|
37
61
|
"@types/mocha": "^10.0.10",
|
|
62
|
+
"@types/node": "^25.6.0",
|
|
63
|
+
"@types/react": "^18.3.17",
|
|
64
|
+
"@types/react-dom": "^18.3.5",
|
|
38
65
|
"@types/sinon": "^17.0.4",
|
|
39
66
|
"chai": "^5.2.1",
|
|
40
67
|
"chai-as-promised": "^8.0.2",
|
|
68
|
+
"global-jsdom": "^25.0.0",
|
|
69
|
+
"jsdom": "^25.0.1",
|
|
41
70
|
"mocha": "^11.1.0",
|
|
71
|
+
"react": "^18.3.1",
|
|
72
|
+
"react-dom": "^18.3.1",
|
|
42
73
|
"sinon": "^21.0.0",
|
|
43
74
|
"tsx": "^4.19.3",
|
|
44
75
|
"typescript": "^5.8.3"
|