doover-js 0.6.4 → 0.6.6
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/dist/apis/_args.js +9 -4
- package/dist/apis/agents-api.d.ts +3 -0
- package/dist/apis/agents-api.js +8 -7
- package/dist/apis/aggregates-api.d.ts +11 -0
- package/dist/apis/channels-api.d.ts +19 -0
- package/dist/apis/messages-api.d.ts +6 -0
- package/dist/apis/organisations-api.d.ts +26 -0
- package/dist/apis/organisations-api.js +45 -0
- package/dist/auth/cookie-auth.d.ts +1 -0
- package/dist/auth/cookie-auth.js +3 -0
- package/dist/auth/doover-auth.d.ts +5 -0
- package/dist/auth/doover-token-auth.d.ts +1 -0
- package/dist/auth/doover-token-auth.js +5 -0
- package/dist/client/doover-client.d.ts +2 -0
- package/dist/client/doover-client.js +2 -0
- package/dist/client/errors.d.ts +9 -0
- package/dist/client/errors.js +21 -1
- package/dist/client/offline-cache.d.ts +162 -0
- package/dist/client/offline-cache.js +757 -0
- package/dist/client/request-options.d.ts +23 -0
- package/dist/client/request-options.js +30 -0
- package/dist/http/rest-client.js +5 -2
- package/dist/index.d.ts +7 -1
- package/dist/index.js +12 -1
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +4 -1
- package/dist/react/useChannelAggregate.d.ts +3 -0
- package/dist/react/useChannelAggregate.js +3 -0
- package/dist/react/useChannelMessages.d.ts +3 -0
- package/dist/react/useChannelMessages.js +3 -1
- package/dist/react/useOfflineStatus.d.ts +8 -0
- package/dist/react/useOfflineStatus.js +27 -0
- package/dist/refine/index.d.ts +72 -0
- package/dist/refine/index.js +219 -0
- package/dist/test/api-overloads.test.js +45 -0
- package/dist/test/auth.test.js +19 -0
- package/dist/test/exports.test.js +5 -1
- package/dist/test/offline-cache.test.d.ts +1 -0
- package/dist/test/offline-cache.test.js +289 -0
- package/dist/test/react-exports.test.js +1 -0
- package/dist/test/refine.test.d.ts +1 -0
- package/dist/test/refine.test.js +71 -0
- package/dist/types/viewer.d.ts +37 -0
- package/package.json +9 -1
|
@@ -47,6 +47,10 @@ const doover = __importStar(require("../index"));
|
|
|
47
47
|
(0, chai_1.expect)(doover.ALL_CAPABILITIES).to.be.an("array");
|
|
48
48
|
(0, chai_1.expect)(doover.UnsupportedCapabilityError).to.be.a("function");
|
|
49
49
|
(0, chai_1.expect)(doover.AmbiguousWriteError).to.be.a("function");
|
|
50
|
+
(0, chai_1.expect)(doover.DooverOfflineError).to.be.a("function");
|
|
51
|
+
(0, chai_1.expect)(doover.OfflineDataClient).to.be.a("function");
|
|
52
|
+
(0, chai_1.expect)(doover.MemoryOfflineStorageAdapter).to.be.a("function");
|
|
53
|
+
(0, chai_1.expect)(doover.requestOptions).to.be.a("function");
|
|
50
54
|
});
|
|
51
55
|
(0, mocha_1.it)("type-only exports resolve (compile-time)", () => {
|
|
52
56
|
// If any of these types are removed from the public index the import above
|
|
@@ -69,7 +73,7 @@ const doover = __importStar(require("../index"));
|
|
|
69
73
|
(0, chai_1.expect)(true).to.equal(true); // keep mocha happy
|
|
70
74
|
});
|
|
71
75
|
(0, mocha_1.it)("exports the full Phase-1..4 surface", () => {
|
|
72
|
-
for (const name of ["ALL_CAPABILITIES", "UnsupportedCapabilityError", "AmbiguousWriteError", "LocalAgentClient", "MultiplexClient", "DooverClient"]) {
|
|
76
|
+
for (const name of ["ALL_CAPABILITIES", "UnsupportedCapabilityError", "AmbiguousWriteError", "DooverOfflineError", "LocalAgentClient", "MultiplexClient", "DooverClient", "OfflineDataClient", "MemoryOfflineStorageAdapter", "requestOptions"]) {
|
|
73
77
|
(0, chai_1.expect)(doover[name], name).to.exist;
|
|
74
78
|
}
|
|
75
79
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const chai_1 = require("chai");
|
|
4
|
+
const mocha_1 = require("mocha");
|
|
5
|
+
const doover_client_1 = require("../client/doover-client");
|
|
6
|
+
const offline_cache_1 = require("../client/offline-cache");
|
|
7
|
+
const request_options_1 = require("../client/request-options");
|
|
8
|
+
const errors_1 = require("../client/errors");
|
|
9
|
+
const snowflake_1 = require("../utils/snowflake");
|
|
10
|
+
const helpers_1 = require("./helpers");
|
|
11
|
+
function makeOnlineClient(fetchImpl) {
|
|
12
|
+
return new doover_client_1.DooverClient({
|
|
13
|
+
dataRestUrl: "https://api.example.com",
|
|
14
|
+
controlApiUrl: "https://control.example.com",
|
|
15
|
+
dataWssUrl: "wss://ws.example.com",
|
|
16
|
+
fetchImpl,
|
|
17
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
18
|
+
disableBrowserLifecycleHooks: true,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
(0, mocha_1.describe)("requestOptions", () => {
|
|
22
|
+
(0, mocha_1.it)("marks a request-options bag explicitly", () => {
|
|
23
|
+
const options = (0, request_options_1.requestOptions)({
|
|
24
|
+
sources: ["cloud"],
|
|
25
|
+
cache: { policy: "tag-values-history" },
|
|
26
|
+
});
|
|
27
|
+
(0, chai_1.expect)(options[request_options_1.REQUEST_OPTIONS_SYMBOL]).to.equal(true);
|
|
28
|
+
(0, chai_1.expect)(options.sources).to.deep.equal(["cloud"]);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
(0, mocha_1.describe)("OfflineDataClient", () => {
|
|
32
|
+
(0, mocha_1.it)("caches reads covered by a stored channel policy and serves them offline", async () => {
|
|
33
|
+
let online = true;
|
|
34
|
+
const messageId = (0, snowflake_1.generateSnowflakeIdAtTime)(new Date("2026-06-10T00:00:00Z"));
|
|
35
|
+
const fetchMock = (0, helpers_1.createFetchMock)((url) => {
|
|
36
|
+
if (url.includes("/agents/a1/channels/tag_values/messages")) {
|
|
37
|
+
return (0, helpers_1.createJsonResponse)([
|
|
38
|
+
{
|
|
39
|
+
id: messageId,
|
|
40
|
+
data: { value: 42 },
|
|
41
|
+
attachments: [],
|
|
42
|
+
author_id: "u1",
|
|
43
|
+
channel: { agent_id: "a1", name: "tag_values" },
|
|
44
|
+
},
|
|
45
|
+
]);
|
|
46
|
+
}
|
|
47
|
+
return (0, helpers_1.createJsonResponse)({ ok: true });
|
|
48
|
+
});
|
|
49
|
+
const storage = new offline_cache_1.MemoryOfflineStorageAdapter();
|
|
50
|
+
const client = new offline_cache_1.OfflineDataClient({
|
|
51
|
+
client: makeOnlineClient(fetchMock),
|
|
52
|
+
storage,
|
|
53
|
+
scope: { userId: "u1", organisationId: "org1", sourceId: "cloud" },
|
|
54
|
+
isOnline: () => online,
|
|
55
|
+
});
|
|
56
|
+
client.setChannelPolicy({
|
|
57
|
+
id: "tag-values-history",
|
|
58
|
+
channel: { agentId: "a1", channelName: "tag_values" },
|
|
59
|
+
messages: { mode: "latest", count: 100 },
|
|
60
|
+
});
|
|
61
|
+
const onlineMessages = await client.messages.listMessages({ agentId: "a1", channelName: "tag_values" }, { limit: 100, order: "asc" });
|
|
62
|
+
(0, chai_1.expect)(onlineMessages.map((message) => message.data)).to.deep.equal([{ value: 42 }]);
|
|
63
|
+
online = false;
|
|
64
|
+
const offlineMessages = await client.messages.listMessages({ agentId: "a1", channelName: "tag_values" }, { limit: 100, order: "asc" });
|
|
65
|
+
(0, chai_1.expect)(offlineMessages).to.deep.equal(onlineMessages);
|
|
66
|
+
(0, chai_1.expect)(fetchMock.callCount).to.equal(1);
|
|
67
|
+
});
|
|
68
|
+
(0, mocha_1.it)("supports per-call cache opt-in for discovery reads", async () => {
|
|
69
|
+
let online = true;
|
|
70
|
+
const fetchMock = (0, helpers_1.createFetchMock)((url) => {
|
|
71
|
+
if (url.includes("/agents/")) {
|
|
72
|
+
return (0, helpers_1.createJsonResponse)({
|
|
73
|
+
agents: [
|
|
74
|
+
{
|
|
75
|
+
id: "a1",
|
|
76
|
+
organisation: "org1",
|
|
77
|
+
name: "pump",
|
|
78
|
+
display_name: "Pump",
|
|
79
|
+
archived: false,
|
|
80
|
+
group: "",
|
|
81
|
+
type: "device",
|
|
82
|
+
fixed_location: { latitude: 0, longitude: 0 },
|
|
83
|
+
extra_config: {},
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
count: 1,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return (0, helpers_1.createJsonResponse)({ ok: true });
|
|
90
|
+
});
|
|
91
|
+
const client = new offline_cache_1.OfflineDataClient({
|
|
92
|
+
client: makeOnlineClient(fetchMock),
|
|
93
|
+
storage: new offline_cache_1.MemoryOfflineStorageAdapter(),
|
|
94
|
+
scope: { userId: "u1", organisationId: "org1", sourceId: "cloud" },
|
|
95
|
+
isOnline: () => online,
|
|
96
|
+
});
|
|
97
|
+
const onlineAgents = await client.agents.listAgents((0, request_options_1.requestOptions)({ cache: { mode: "read-through", policy: "agents" } }));
|
|
98
|
+
(0, chai_1.expect)((onlineAgents.agents ?? []).map((agent) => agent.id)).to.deep.equal(["a1"]);
|
|
99
|
+
online = false;
|
|
100
|
+
const offlineAgents = await client.agents.listAgents((0, request_options_1.requestOptions)({ cache: { mode: "read-through", policy: "agents" } }));
|
|
101
|
+
(0, chai_1.expect)(offlineAgents).to.deep.equal(onlineAgents);
|
|
102
|
+
(0, chai_1.expect)(fetchMock.callCount).to.equal(1);
|
|
103
|
+
});
|
|
104
|
+
(0, mocha_1.it)("fails writes immediately while offline", async () => {
|
|
105
|
+
const fetchMock = (0, helpers_1.createFetchMock)();
|
|
106
|
+
const client = new offline_cache_1.OfflineDataClient({
|
|
107
|
+
client: makeOnlineClient(fetchMock),
|
|
108
|
+
storage: new offline_cache_1.MemoryOfflineStorageAdapter(),
|
|
109
|
+
scope: { userId: "u1", organisationId: "org1", sourceId: "cloud" },
|
|
110
|
+
isOnline: () => false,
|
|
111
|
+
});
|
|
112
|
+
let error;
|
|
113
|
+
try {
|
|
114
|
+
await client.messages.postMessage({ agentId: "a1", channelName: "commands" }, { data: { run: true } });
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
error = err;
|
|
118
|
+
}
|
|
119
|
+
(0, chai_1.expect)(error).to.be.instanceOf(errors_1.DooverOfflineError);
|
|
120
|
+
(0, chai_1.expect)(fetchMock.callCount).to.equal(0);
|
|
121
|
+
});
|
|
122
|
+
(0, mocha_1.it)("honours cache: false even when a stored policy exists", async () => {
|
|
123
|
+
let online = true;
|
|
124
|
+
const fetchMock = (0, helpers_1.createFetchMock)((url) => {
|
|
125
|
+
if (url.includes("/agents/a1/channels/tag_values/messages")) {
|
|
126
|
+
return (0, helpers_1.createJsonResponse)([
|
|
127
|
+
{
|
|
128
|
+
id: (0, snowflake_1.generateSnowflakeIdAtTime)(new Date("2026-06-10T00:00:00Z")),
|
|
129
|
+
data: { value: 1 },
|
|
130
|
+
attachments: [],
|
|
131
|
+
author_id: "u1",
|
|
132
|
+
channel: { agent_id: "a1", name: "tag_values" },
|
|
133
|
+
},
|
|
134
|
+
]);
|
|
135
|
+
}
|
|
136
|
+
return (0, helpers_1.createJsonResponse)({ ok: true });
|
|
137
|
+
});
|
|
138
|
+
const client = new offline_cache_1.OfflineDataClient({
|
|
139
|
+
client: makeOnlineClient(fetchMock),
|
|
140
|
+
storage: new offline_cache_1.MemoryOfflineStorageAdapter(),
|
|
141
|
+
scope: { userId: "u1", organisationId: "org1", sourceId: "cloud" },
|
|
142
|
+
isOnline: () => online,
|
|
143
|
+
});
|
|
144
|
+
client.setChannelPolicy({
|
|
145
|
+
id: "tag-values-history",
|
|
146
|
+
channel: { agentId: "a1", channelName: "tag_values" },
|
|
147
|
+
messages: { mode: "latest", count: 100 },
|
|
148
|
+
});
|
|
149
|
+
await client.messages.listMessages({ agentId: "a1", channelName: "tag_values" }, { limit: 100, order: "asc" }, (0, request_options_1.requestOptions)({ cache: false }));
|
|
150
|
+
online = false;
|
|
151
|
+
let error;
|
|
152
|
+
try {
|
|
153
|
+
await client.messages.listMessages({ agentId: "a1", channelName: "tag_values" }, { limit: 100, order: "asc" }, (0, request_options_1.requestOptions)({ cache: false }));
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
error = err;
|
|
157
|
+
}
|
|
158
|
+
(0, chai_1.expect)(error).to.be.instanceOf(errors_1.DooverOfflineError);
|
|
159
|
+
});
|
|
160
|
+
(0, mocha_1.it)("tracks expired cached records and requires allowExpired to read them", async () => {
|
|
161
|
+
let online = true;
|
|
162
|
+
const fetchMock = (0, helpers_1.createFetchMock)((url) => {
|
|
163
|
+
if (url.includes("/agents/"))
|
|
164
|
+
return (0, helpers_1.createJsonResponse)({ agents: [], count: 0 });
|
|
165
|
+
return (0, helpers_1.createJsonResponse)({ ok: true });
|
|
166
|
+
});
|
|
167
|
+
const client = new offline_cache_1.OfflineDataClient({
|
|
168
|
+
client: makeOnlineClient(fetchMock),
|
|
169
|
+
storage: new offline_cache_1.MemoryOfflineStorageAdapter(),
|
|
170
|
+
scope: { userId: "u1", organisationId: "org1", sourceId: "cloud" },
|
|
171
|
+
isOnline: () => online,
|
|
172
|
+
});
|
|
173
|
+
await client.agents.listAgents((0, request_options_1.requestOptions)({ cache: { mode: "read-through", retentionMs: 1 } }));
|
|
174
|
+
await new Promise((resolve) => setTimeout(resolve, 5));
|
|
175
|
+
online = false;
|
|
176
|
+
let error;
|
|
177
|
+
try {
|
|
178
|
+
await client.agents.listAgents((0, request_options_1.requestOptions)({ cache: { mode: "read-through" } }));
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
error = err;
|
|
182
|
+
}
|
|
183
|
+
(0, chai_1.expect)(error).to.be.instanceOf(errors_1.DooverOfflineError);
|
|
184
|
+
(0, chai_1.expect)(client.getOfflineStatus().state).to.equal("cache-miss");
|
|
185
|
+
const expired = await client.agents.listAgents((0, request_options_1.requestOptions)({ cache: { mode: "read-through", allowExpired: true } }));
|
|
186
|
+
(0, chai_1.expect)(expired.agents).to.deep.equal([]);
|
|
187
|
+
(0, chai_1.expect)(client.getOfflineStatus().isExpired).to.equal(true);
|
|
188
|
+
});
|
|
189
|
+
(0, mocha_1.it)("persists gateway messages into latest-N cache according to channel policy", async () => {
|
|
190
|
+
let online = true;
|
|
191
|
+
const fetchMock = (0, helpers_1.createFetchMock)();
|
|
192
|
+
const client = new offline_cache_1.OfflineDataClient({
|
|
193
|
+
client: makeOnlineClient(fetchMock),
|
|
194
|
+
storage: new offline_cache_1.MemoryOfflineStorageAdapter(),
|
|
195
|
+
scope: { userId: "u1", organisationId: "org1", sourceId: "cloud" },
|
|
196
|
+
isOnline: () => online,
|
|
197
|
+
});
|
|
198
|
+
client.setChannelPolicy({
|
|
199
|
+
id: "camera-latest",
|
|
200
|
+
channel: { agentId: "a1", channelName: "camera" },
|
|
201
|
+
messages: { mode: "latest", count: 2 },
|
|
202
|
+
});
|
|
203
|
+
client.gateway.subscribeToChannel({ agent_id: "a1", name: "camera" }, {});
|
|
204
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
205
|
+
const ws = helpers_1.MockWebSocket.instances[helpers_1.MockWebSocket.instances.length - 1];
|
|
206
|
+
ws.open();
|
|
207
|
+
ws.receive({ op: 0, t: "Hello", d: {} });
|
|
208
|
+
ws.receive({
|
|
209
|
+
op: 0,
|
|
210
|
+
t: "Ready",
|
|
211
|
+
d: { session_id: "s1", session_token: "t1", subscriptions: [] },
|
|
212
|
+
});
|
|
213
|
+
for (const [idx, iso] of [
|
|
214
|
+
"2026-06-10T00:00:00Z",
|
|
215
|
+
"2026-06-10T00:01:00Z",
|
|
216
|
+
"2026-06-10T00:02:00Z",
|
|
217
|
+
].entries()) {
|
|
218
|
+
ws.receive({
|
|
219
|
+
op: 0,
|
|
220
|
+
t: "MessageCreate",
|
|
221
|
+
d: {
|
|
222
|
+
id: (0, snowflake_1.generateSnowflakeIdAtTime)(new Date(iso)),
|
|
223
|
+
data: { idx },
|
|
224
|
+
attachments: [],
|
|
225
|
+
author_id: "u1",
|
|
226
|
+
channel: { agent_id: "a1", name: "camera" },
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
231
|
+
online = false;
|
|
232
|
+
const messages = await client.messages.listMessages({ agentId: "a1", channelName: "camera" }, { limit: 10, order: "asc" });
|
|
233
|
+
(0, chai_1.expect)(messages.map((message) => message.data)).to.deep.equal([
|
|
234
|
+
{ idx: 1 },
|
|
235
|
+
{ idx: 2 },
|
|
236
|
+
]);
|
|
237
|
+
(0, chai_1.expect)(client.getOfflineStatus().state).to.equal("cache-fallback");
|
|
238
|
+
});
|
|
239
|
+
(0, mocha_1.it)("notifies offline status listeners when cached data is used", async () => {
|
|
240
|
+
let online = true;
|
|
241
|
+
const fetchMock = (0, helpers_1.createFetchMock)((url) => {
|
|
242
|
+
if (url.includes("/agents/"))
|
|
243
|
+
return (0, helpers_1.createJsonResponse)({ agents: [], count: 0 });
|
|
244
|
+
return (0, helpers_1.createJsonResponse)({ ok: true });
|
|
245
|
+
});
|
|
246
|
+
const client = new offline_cache_1.OfflineDataClient({
|
|
247
|
+
client: makeOnlineClient(fetchMock),
|
|
248
|
+
storage: new offline_cache_1.MemoryOfflineStorageAdapter(),
|
|
249
|
+
scope: { userId: "u1", organisationId: "org1", sourceId: "cloud" },
|
|
250
|
+
isOnline: () => online,
|
|
251
|
+
});
|
|
252
|
+
const seen = [];
|
|
253
|
+
const off = client.onOfflineStatusChange((status) => seen.push(status.state));
|
|
254
|
+
await client.agents.listAgents((0, request_options_1.requestOptions)({ cache: { mode: "read-through" } }));
|
|
255
|
+
online = false;
|
|
256
|
+
await client.agents.listAgents((0, request_options_1.requestOptions)({ cache: { mode: "read-through" } }));
|
|
257
|
+
off();
|
|
258
|
+
(0, chai_1.expect)(seen).to.include("online");
|
|
259
|
+
(0, chai_1.expect)(seen).to.include("cache-fallback");
|
|
260
|
+
});
|
|
261
|
+
(0, mocha_1.it)("caches selected attachment blobs through the blob storage adapter", async () => {
|
|
262
|
+
let online = true;
|
|
263
|
+
const fetchMock = (0, helpers_1.createFetchMock)((url) => {
|
|
264
|
+
if (url.includes("/attachments/thumb1")) {
|
|
265
|
+
return (0, helpers_1.createBlobResponse)("thumbnail-bytes", {
|
|
266
|
+
headers: { "content-type": "image/jpeg" },
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
return (0, helpers_1.createJsonResponse)({ ok: true });
|
|
270
|
+
});
|
|
271
|
+
const client = new offline_cache_1.OfflineDataClient({
|
|
272
|
+
client: makeOnlineClient(fetchMock),
|
|
273
|
+
storage: new offline_cache_1.MemoryOfflineStorageAdapter(),
|
|
274
|
+
scope: { userId: "u1", organisationId: "org1", sourceId: "cloud" },
|
|
275
|
+
isOnline: () => online,
|
|
276
|
+
});
|
|
277
|
+
client.setChannelPolicy({
|
|
278
|
+
id: "camera-thumbnails",
|
|
279
|
+
channel: { agentId: "a1", channelName: "camera" },
|
|
280
|
+
messageAttachments: { include: "metadata-and-selected-blobs" },
|
|
281
|
+
});
|
|
282
|
+
const onlineBlob = await client.messages.getMessageAttachment({ agentId: "a1", channelName: "camera" }, "m1", "thumb1");
|
|
283
|
+
(0, chai_1.expect)(await onlineBlob.text()).to.equal("thumbnail-bytes");
|
|
284
|
+
online = false;
|
|
285
|
+
const offlineBlob = await client.messages.getMessageAttachment({ agentId: "a1", channelName: "camera" }, "m1", "thumb1");
|
|
286
|
+
(0, chai_1.expect)(await offlineBlob.text()).to.equal("thumbnail-bytes");
|
|
287
|
+
(0, chai_1.expect)(fetchMock.callCount).to.equal(1);
|
|
288
|
+
});
|
|
289
|
+
});
|
|
@@ -39,6 +39,7 @@ const r = __importStar(require("../react"));
|
|
|
39
39
|
(0, mocha_1.describe)("react exports", () => {
|
|
40
40
|
(0, mocha_1.it)("exports useClientStatus and the key helpers", () => {
|
|
41
41
|
(0, chai_1.expect)(r.useClientStatus).to.be.a("function");
|
|
42
|
+
(0, chai_1.expect)(r.useOfflineStatus).to.be.a("function");
|
|
42
43
|
(0, chai_1.expect)(r.channelAggregateQueryKey).to.be.a("function");
|
|
43
44
|
(0, chai_1.expect)(r.useConnectionState).to.be.a("function"); // still exported (soft-deprecated)
|
|
44
45
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const chai_1 = require("chai");
|
|
4
|
+
const mocha_1 = require("mocha");
|
|
5
|
+
const refine_1 = require("../refine");
|
|
6
|
+
const rest_client_1 = require("../http/rest-client");
|
|
7
|
+
const helpers_1 = require("./helpers");
|
|
8
|
+
(0, mocha_1.describe)("createRefineDataProvider", () => {
|
|
9
|
+
(0, mocha_1.it)("builds list requests with api_path, pagination, sorters, filters and organisation header", async () => {
|
|
10
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => (0, helpers_1.createJsonResponse)({ count: 1, results: [{ id: "1", name: "Device" }] }));
|
|
11
|
+
const rest = new rest_client_1.RestClient({
|
|
12
|
+
dataRestUrl: "https://data.example.com/api",
|
|
13
|
+
controlApiUrl: "https://control.example.com",
|
|
14
|
+
dataWssUrl: "wss://data.example.com/gateway",
|
|
15
|
+
organisationId: "org-1",
|
|
16
|
+
fetchImpl: fetchMock,
|
|
17
|
+
});
|
|
18
|
+
const provider = (0, refine_1.createRefineDataProvider)(rest);
|
|
19
|
+
const result = await provider.getList({
|
|
20
|
+
resource: "devices",
|
|
21
|
+
pagination: { currentPage: 2, pageSize: 25 },
|
|
22
|
+
sorters: [{ field: "name", order: "desc" }],
|
|
23
|
+
filters: [
|
|
24
|
+
{ field: "search", operator: "contains", value: "pump" },
|
|
25
|
+
{ field: "archived", operator: "eq", value: false },
|
|
26
|
+
],
|
|
27
|
+
meta: { api_path: "organisations/:organisationId/devices", organisationId: "org-2" },
|
|
28
|
+
});
|
|
29
|
+
(0, chai_1.expect)(result).to.deep.equal({
|
|
30
|
+
data: [{ id: "1", name: "Device" }],
|
|
31
|
+
total: 1,
|
|
32
|
+
});
|
|
33
|
+
(0, chai_1.expect)(fetchMock.callCount).to.equal(1);
|
|
34
|
+
const [url, init] = fetchMock.getCall(0).args;
|
|
35
|
+
(0, chai_1.expect)(url).to.equal("https://control.example.com/organisations/org-2/devices/?page=2&per_page=25&ordering=-name&search=pump&archived=false");
|
|
36
|
+
(0, chai_1.expect)((init?.headers).get("X-Doover-Organisation")).to.equal("org-1");
|
|
37
|
+
const explicit = await provider.getList({
|
|
38
|
+
resource: "devices",
|
|
39
|
+
meta: { organisation: "org-3" },
|
|
40
|
+
});
|
|
41
|
+
(0, chai_1.expect)(explicit.total).to.equal(1);
|
|
42
|
+
(0, chai_1.expect)((fetchMock.getCall(1).args[1]?.headers).get("X-Doover-Organisation")).to.equal("org-3");
|
|
43
|
+
});
|
|
44
|
+
(0, mocha_1.it)("renames object fields and sends JSON mutations through RestClient", async () => {
|
|
45
|
+
const fetchMock = (0, helpers_1.createFetchMock)((_url, init) => (0, helpers_1.createJsonResponse)(JSON.parse(String(init?.body))));
|
|
46
|
+
const rest = new rest_client_1.RestClient({
|
|
47
|
+
dataRestUrl: "https://data.example.com/api",
|
|
48
|
+
controlApiUrl: "https://control.example.com",
|
|
49
|
+
dataWssUrl: "wss://data.example.com/gateway",
|
|
50
|
+
fetchImpl: fetchMock,
|
|
51
|
+
});
|
|
52
|
+
const provider = (0, refine_1.createRefineDataProvider)(rest);
|
|
53
|
+
const result = await provider.update({
|
|
54
|
+
resource: "devices",
|
|
55
|
+
id: "device-1",
|
|
56
|
+
variables: { group: { id: "group-1", name: "Group" } },
|
|
57
|
+
meta: { renameFields: { group: "group_id" } },
|
|
58
|
+
});
|
|
59
|
+
(0, chai_1.expect)(result.data).to.deep.equal({
|
|
60
|
+
group: "group-1",
|
|
61
|
+
group_id: "group-1",
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
(0, mocha_1.describe)("getApiPath", () => {
|
|
66
|
+
(0, mocha_1.it)("falls back across api_path candidates", () => {
|
|
67
|
+
(0, chai_1.expect)((0, refine_1.getApiPath)("domains", {
|
|
68
|
+
api_path: ["organisations/:organisationId/domains", "organisations/domains"],
|
|
69
|
+
})).to.equal("organisations/domains");
|
|
70
|
+
});
|
|
71
|
+
});
|
package/dist/types/viewer.d.ts
CHANGED
|
@@ -29,6 +29,43 @@ export interface User {
|
|
|
29
29
|
__source?: SourceProvenance;
|
|
30
30
|
[key: string]: unknown;
|
|
31
31
|
}
|
|
32
|
+
export interface Theme {
|
|
33
|
+
[key: string]: unknown;
|
|
34
|
+
}
|
|
35
|
+
export interface OrganisationDomain {
|
|
36
|
+
id: string;
|
|
37
|
+
hostname: string;
|
|
38
|
+
default: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface Organisation {
|
|
41
|
+
id: string;
|
|
42
|
+
name: string;
|
|
43
|
+
archived: boolean;
|
|
44
|
+
application_id: string;
|
|
45
|
+
domains: OrganisationDomain[];
|
|
46
|
+
root_group?: unknown;
|
|
47
|
+
retention_period?: number;
|
|
48
|
+
legacy_doover_api_key?: string | null;
|
|
49
|
+
llm_api_key?: string | null;
|
|
50
|
+
extra_config?: Record<string, unknown>;
|
|
51
|
+
theme?: Theme;
|
|
52
|
+
__source?: SourceProvenance;
|
|
53
|
+
[key: string]: unknown;
|
|
54
|
+
}
|
|
55
|
+
export interface CustomerSite {
|
|
56
|
+
id: string;
|
|
57
|
+
name: string;
|
|
58
|
+
application_id: string;
|
|
59
|
+
archived: boolean;
|
|
60
|
+
theme: Theme;
|
|
61
|
+
}
|
|
62
|
+
export interface PaginatedResponse<T> {
|
|
63
|
+
count: number;
|
|
64
|
+
results: T[];
|
|
65
|
+
next?: string | null;
|
|
66
|
+
previous?: string | null;
|
|
67
|
+
[key: string]: unknown;
|
|
68
|
+
}
|
|
32
69
|
export interface GetAgentsOptions {
|
|
33
70
|
includeArchived?: boolean;
|
|
34
71
|
includeOrganisations?: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "doover-js",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.6",
|
|
4
4
|
"description": "TypeScript client for Doover.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
"./react": {
|
|
17
17
|
"types": "./dist/react/index.d.ts",
|
|
18
18
|
"default": "./dist/react/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./refine": {
|
|
21
|
+
"types": "./dist/refine/index.d.ts",
|
|
22
|
+
"default": "./dist/refine/index.js"
|
|
19
23
|
}
|
|
20
24
|
},
|
|
21
25
|
"repository": {
|
|
@@ -42,10 +46,14 @@
|
|
|
42
46
|
],
|
|
43
47
|
"license": "Apache-2.0",
|
|
44
48
|
"peerDependencies": {
|
|
49
|
+
"@refinedev/core": "^5",
|
|
45
50
|
"@tanstack/react-query": "^5",
|
|
46
51
|
"react": "^18 || ^19"
|
|
47
52
|
},
|
|
48
53
|
"peerDependenciesMeta": {
|
|
54
|
+
"@refinedev/core": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
49
57
|
"@tanstack/react-query": {
|
|
50
58
|
"optional": true
|
|
51
59
|
},
|