doover-js 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +35 -0
- package/dist/apis/agents-api.d.ts +22 -0
- package/dist/apis/agents-api.js +20 -0
- package/dist/apis/aggregates-api.d.ts +15 -0
- package/dist/apis/aggregates-api.js +21 -0
- package/dist/apis/alarms-api.d.ts +12 -0
- package/dist/apis/alarms-api.js +27 -0
- package/dist/apis/channels-api.d.ts +27 -0
- package/dist/apis/channels-api.js +24 -0
- package/dist/apis/connections-api.d.ts +23 -0
- package/dist/apis/connections-api.js +24 -0
- package/dist/apis/messages-api.d.ts +32 -0
- package/dist/apis/messages-api.js +45 -0
- package/dist/apis/notifications-api.d.ts +23 -0
- package/dist/apis/notifications-api.js +54 -0
- package/dist/apis/permissions-api.d.ts +9 -0
- package/dist/apis/permissions-api.js +18 -0
- package/dist/apis/processors-api.d.ts +21 -0
- package/dist/apis/processors-api.js +45 -0
- package/dist/apis/turn-api.d.ts +7 -0
- package/dist/apis/turn-api.js +12 -0
- package/dist/client/doover-client.d.ts +29 -0
- package/dist/client/doover-client.js +34 -0
- package/dist/gateway/gateway-client.d.ts +37 -0
- package/dist/gateway/gateway-client.js +258 -0
- package/dist/gateway/types.d.ts +135 -0
- package/dist/gateway/types.js +2 -0
- package/dist/http/errors.d.ts +19 -0
- package/dist/http/errors.js +28 -0
- package/dist/http/rest-client.d.ts +35 -0
- package/dist/http/rest-client.js +129 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +41 -0
- package/dist/test/apis.test.d.ts +1 -0
- package/dist/test/apis.test.js +248 -0
- package/dist/test/doover-client.test.d.ts +1 -0
- package/dist/test/doover-client.test.js +29 -0
- package/dist/test/doover-data-provider.test.d.ts +1 -0
- package/dist/test/doover-data-provider.test.js +228 -0
- package/dist/test/gateway-client.test.d.ts +1 -0
- package/dist/test/gateway-client.test.js +235 -0
- package/dist/test/helpers.d.ts +32 -0
- package/dist/test/helpers.js +115 -0
- package/dist/test/rest-client.test.d.ts +1 -0
- package/dist/test/rest-client.test.js +115 -0
- package/dist/test/utils.test.d.ts +1 -0
- package/dist/test/utils.test.js +54 -0
- package/dist/types/common.d.ts +130 -0
- package/dist/types/common.js +2 -0
- package/dist/types/openapi.d.ts +144 -0
- package/dist/types/openapi.js +2 -0
- package/dist/types/viewer.d.ts +70 -0
- package/dist/types/viewer.js +2 -0
- package/dist/utils/snowflake.d.ts +13 -0
- package/dist/utils/snowflake.js +26 -0
- package/dist/viewer/doover-data-provider.d.ts +55 -0
- package/dist/viewer/doover-data-provider.js +191 -0
- package/dist/viewer/path-parsing.d.ts +5 -0
- package/dist/viewer/path-parsing.js +38 -0
- package/package.json +46 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DooverDataProvider = void 0;
|
|
4
|
+
const agents_api_1 = require("../apis/agents-api");
|
|
5
|
+
const aggregates_api_1 = require("../apis/aggregates-api");
|
|
6
|
+
const channels_api_1 = require("../apis/channels-api");
|
|
7
|
+
const connections_api_1 = require("../apis/connections-api");
|
|
8
|
+
const messages_api_1 = require("../apis/messages-api");
|
|
9
|
+
const gateway_client_1 = require("../gateway/gateway-client");
|
|
10
|
+
const errors_1 = require("../http/errors");
|
|
11
|
+
const rest_client_1 = require("../http/rest-client");
|
|
12
|
+
const snowflake_1 = require("../utils/snowflake");
|
|
13
|
+
const path_parsing_1 = require("./path-parsing");
|
|
14
|
+
class DooverDataProvider {
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.subscriptions = new Map();
|
|
18
|
+
this.rest = new rest_client_1.RestClient(config);
|
|
19
|
+
this.gateway = new gateway_client_1.GatewayClient(config);
|
|
20
|
+
this.agentsApi = new agents_api_1.AgentsApi(this.rest);
|
|
21
|
+
this.channelsApi = new channels_api_1.ChannelsApi(this.rest);
|
|
22
|
+
this.messagesApi = new messages_api_1.MessagesApi(this.rest);
|
|
23
|
+
this.aggregatesApi = new aggregates_api_1.AggregatesApi(this.rest);
|
|
24
|
+
this.connectionsApi = new connections_api_1.ConnectionsApi(this.rest);
|
|
25
|
+
this.gateway.on("messageCreate", (message) => {
|
|
26
|
+
const key = this.channelKey(message.channel.agent_id, message.channel.name);
|
|
27
|
+
const identifier = this.toIdentifier(message.channel.agent_id, message.channel.name);
|
|
28
|
+
this.subscriptions.get(key)?.forEach((entry) => entry.messageCallback(identifier, message));
|
|
29
|
+
});
|
|
30
|
+
this.gateway.on("channelSync", (event) => {
|
|
31
|
+
const key = this.channelKey(event.channel.agent_id, event.channel.name);
|
|
32
|
+
const identifier = this.toIdentifier(event.channel.agent_id, event.channel.name);
|
|
33
|
+
this.subscriptions.get(key)?.forEach((entry) => entry.aggregateCallback(identifier, event.aggregate));
|
|
34
|
+
});
|
|
35
|
+
this.gateway.on("aggregateUpdate", (event) => {
|
|
36
|
+
const key = this.channelKey(event.channel.agent_id, event.channel.name);
|
|
37
|
+
const identifier = this.toIdentifier(event.channel.agent_id, event.channel.name);
|
|
38
|
+
this.subscriptions.get(key)?.forEach((entry) => entry.aggregateCallback(identifier, event.aggregate));
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
getMe() {
|
|
42
|
+
return this.rest.get("/users/me", undefined, this.config.controlApiUrl);
|
|
43
|
+
}
|
|
44
|
+
getAgents() {
|
|
45
|
+
return this.rest.get("/agents", undefined, this.config.controlApiUrl);
|
|
46
|
+
}
|
|
47
|
+
async getChannels(identifier, options) {
|
|
48
|
+
if (!identifier.agentId) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return this.channelsApi.listChannels(identifier.agentId, {
|
|
52
|
+
include_archived: options?.includeArchived,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
createChannel(identifier, channelName, options) {
|
|
56
|
+
if (!identifier.agentId) {
|
|
57
|
+
throw new errors_1.DooverValidationError("Identifier must contain agentId");
|
|
58
|
+
}
|
|
59
|
+
return this.channelsApi.putChannel(identifier.agentId, channelName, {
|
|
60
|
+
is_private: options?.is_private ?? false,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
archiveChannel(identifier) {
|
|
64
|
+
const validated = this.requireChannel(identifier);
|
|
65
|
+
return this.rest.post(`/agents/${validated.agentId}/channels/${validated.channelName}/archive`, {});
|
|
66
|
+
}
|
|
67
|
+
unarchiveChannel(identifier) {
|
|
68
|
+
const validated = this.requireChannel(identifier);
|
|
69
|
+
return this.rest.post(`/agents/${validated.agentId}/channels/${validated.channelName}/unarchive`, {});
|
|
70
|
+
}
|
|
71
|
+
getChannel(identifier) {
|
|
72
|
+
if (!identifier.agentId || !identifier.channelName) {
|
|
73
|
+
return Promise.resolve(undefined);
|
|
74
|
+
}
|
|
75
|
+
return this.channelsApi.getChannel(identifier.agentId, identifier.channelName);
|
|
76
|
+
}
|
|
77
|
+
async subscribeToChannel(identifier, callback, aggregateCallback) {
|
|
78
|
+
const validated = this.requireChannel(identifier);
|
|
79
|
+
const key = this.channelKey(validated.agentId, validated.channelName);
|
|
80
|
+
const entries = this.subscriptions.get(key) ?? [];
|
|
81
|
+
entries.push({ messageCallback: callback, aggregateCallback });
|
|
82
|
+
this.subscriptions.set(key, entries);
|
|
83
|
+
this.gateway.connect();
|
|
84
|
+
this.gateway.subscribe({
|
|
85
|
+
agent_id: validated.agentId,
|
|
86
|
+
name: validated.channelName,
|
|
87
|
+
});
|
|
88
|
+
return Promise.resolve();
|
|
89
|
+
}
|
|
90
|
+
async unsubscribeFromChannel(identifier, callback) {
|
|
91
|
+
const validated = this.requireChannel(identifier);
|
|
92
|
+
const key = this.channelKey(validated.agentId, validated.channelName);
|
|
93
|
+
const entries = this.subscriptions.get(key);
|
|
94
|
+
if (!entries) {
|
|
95
|
+
return Promise.reject(new errors_1.DooverValidationError("Not Currently Subscribed to Channel"));
|
|
96
|
+
}
|
|
97
|
+
const next = entries.filter((entry) => entry.messageCallback !== callback);
|
|
98
|
+
if (next.length === 0) {
|
|
99
|
+
this.subscriptions.delete(key);
|
|
100
|
+
this.gateway.unsubscribe({
|
|
101
|
+
agent_id: validated.agentId,
|
|
102
|
+
name: validated.channelName,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
this.subscriptions.set(key, next);
|
|
107
|
+
}
|
|
108
|
+
return Promise.resolve();
|
|
109
|
+
}
|
|
110
|
+
async getAggregate(identifier) {
|
|
111
|
+
if (!identifier.agentId || !identifier.channelName) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
const channel = await this.channelsApi.getChannel(identifier.agentId, identifier.channelName);
|
|
115
|
+
if (channel.aggregate) {
|
|
116
|
+
return channel.aggregate;
|
|
117
|
+
}
|
|
118
|
+
return this.aggregatesApi.getAggregate(identifier.agentId, identifier.channelName);
|
|
119
|
+
}
|
|
120
|
+
async getMessages(identifier, beforeId) {
|
|
121
|
+
if (!identifier.agentId || !identifier.channelName) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
const messages = await this.messagesApi.listMessages(identifier.agentId, identifier.channelName, {
|
|
125
|
+
before: beforeId ?? (0, snowflake_1.generateSnowflakeIdAtTime)(new Date()),
|
|
126
|
+
limit: 10,
|
|
127
|
+
});
|
|
128
|
+
return messages.reverse();
|
|
129
|
+
}
|
|
130
|
+
deleteMessage(identifier, messageId) {
|
|
131
|
+
const validated = this.requireChannel(identifier);
|
|
132
|
+
return this.messagesApi.deleteMessage(validated.agentId, validated.channelName, messageId);
|
|
133
|
+
}
|
|
134
|
+
sendMessage(identifier, message) {
|
|
135
|
+
const validated = this.requireChannel(identifier);
|
|
136
|
+
return this.messagesApi.postMessage(validated.agentId, validated.channelName, {
|
|
137
|
+
data: message,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
updateAggregate(identifier, message) {
|
|
141
|
+
const validated = this.requireChannel(identifier);
|
|
142
|
+
return this.aggregatesApi.patchAggregate(validated.agentId, validated.channelName, message);
|
|
143
|
+
}
|
|
144
|
+
putAggregate(identifier, message) {
|
|
145
|
+
const validated = this.requireChannel(identifier);
|
|
146
|
+
return this.aggregatesApi.putAggregate(validated.agentId, validated.channelName, message);
|
|
147
|
+
}
|
|
148
|
+
getChannelSubscriptions(identifier) {
|
|
149
|
+
const validated = this.requireChannel(identifier);
|
|
150
|
+
return this.connectionsApi.getChannelSubscriptions(validated.agentId, validated.channelName);
|
|
151
|
+
}
|
|
152
|
+
getAgentConnections(identifier) {
|
|
153
|
+
if (!identifier.agentId) {
|
|
154
|
+
return Promise.reject(new errors_1.DooverValidationError("Invalid Identifier"));
|
|
155
|
+
}
|
|
156
|
+
return this.connectionsApi.getAgentConnections(identifier.agentId);
|
|
157
|
+
}
|
|
158
|
+
getIdentifierFromPath(path, searchParams) {
|
|
159
|
+
return (0, path_parsing_1.getIdentifierFromPath)(path, searchParams);
|
|
160
|
+
}
|
|
161
|
+
getAgentInfo(agentId) {
|
|
162
|
+
return Promise.resolve({
|
|
163
|
+
id: agentId,
|
|
164
|
+
name: agentId,
|
|
165
|
+
display_name: agentId,
|
|
166
|
+
type: "device",
|
|
167
|
+
fa_icon: "fa-solid fa-robot",
|
|
168
|
+
organisation: "Organisation",
|
|
169
|
+
group: "group",
|
|
170
|
+
archived: false,
|
|
171
|
+
fixed_location: { latitude: 0, longitude: 0 },
|
|
172
|
+
extra_config: {},
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
requireChannel(identifier) {
|
|
176
|
+
if (!identifier.agentId || !identifier.channelName) {
|
|
177
|
+
throw new errors_1.DooverValidationError("Identifier must contain agentId and channelName");
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
agentId: identifier.agentId,
|
|
181
|
+
channelName: identifier.channelName,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
channelKey(agentId, channelName) {
|
|
185
|
+
return `${agentId}/${channelName}`;
|
|
186
|
+
}
|
|
187
|
+
toIdentifier(agentId, channelName) {
|
|
188
|
+
return { agentId, channelName };
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
exports.DooverDataProvider = DooverDataProvider;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getIdentifierFromPath = getIdentifierFromPath;
|
|
4
|
+
function getIdentifierFromPath(path, _searchParams) {
|
|
5
|
+
const cleaned = path.replace(/^\/+|\/+$/g, "");
|
|
6
|
+
const parts = cleaned ? cleaned.split("/") : [];
|
|
7
|
+
if (parts.length === 1) {
|
|
8
|
+
return {
|
|
9
|
+
identifier: {
|
|
10
|
+
agentId: parts[0],
|
|
11
|
+
channelName: undefined,
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
if (parts.length === 2) {
|
|
16
|
+
return {
|
|
17
|
+
identifier: {
|
|
18
|
+
agentId: parts[0],
|
|
19
|
+
channelName: parts[1],
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (parts.length > 2) {
|
|
24
|
+
return {
|
|
25
|
+
identifier: {
|
|
26
|
+
agentId: parts[0],
|
|
27
|
+
channelName: parts[1],
|
|
28
|
+
},
|
|
29
|
+
aggregatePath: parts.slice(2).join("/"),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
identifier: {
|
|
34
|
+
agentId: undefined,
|
|
35
|
+
channelName: undefined,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "doover-js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript client for Doover.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/get-doover/doover-js.git"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/get-doover/doover-js#readme",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/get-doover/doover-js/issues"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc",
|
|
26
|
+
"clean": "rm -rf dist",
|
|
27
|
+
"prepublishOnly": "npm run build",
|
|
28
|
+
"test": "mocha --require tsx/cjs \"src/test/**/*.test.ts\""
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"doover"
|
|
32
|
+
],
|
|
33
|
+
"license": "Apache-2.0",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/chai": "^5.2.2",
|
|
36
|
+
"@types/chai-as-promised": "^7.1.8",
|
|
37
|
+
"@types/mocha": "^10.0.10",
|
|
38
|
+
"@types/sinon": "^17.0.4",
|
|
39
|
+
"chai": "^5.2.1",
|
|
40
|
+
"chai-as-promised": "^8.0.2",
|
|
41
|
+
"mocha": "^11.1.0",
|
|
42
|
+
"sinon": "^21.0.0",
|
|
43
|
+
"tsx": "^4.19.3",
|
|
44
|
+
"typescript": "^5.8.3"
|
|
45
|
+
}
|
|
46
|
+
}
|