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.
Files changed (84) hide show
  1. package/README.md +104 -10
  2. package/dist/apis/connections-api.d.ts +6 -0
  3. package/dist/apis/connections-api.js +8 -0
  4. package/dist/auth/auth-profile.d.ts +45 -0
  5. package/dist/auth/auth-profile.js +72 -0
  6. package/dist/auth/auth-store.d.ts +14 -0
  7. package/dist/auth/auth-store.js +2 -0
  8. package/dist/auth/build-auth.d.ts +37 -0
  9. package/dist/auth/build-auth.js +75 -0
  10. package/dist/auth/cookie-auth.d.ts +17 -0
  11. package/dist/auth/cookie-auth.js +29 -0
  12. package/dist/auth/doover-auth.d.ts +41 -0
  13. package/dist/auth/doover-auth.js +24 -0
  14. package/dist/auth/doover-token-auth.d.ts +35 -0
  15. package/dist/auth/doover-token-auth.js +178 -0
  16. package/dist/auth/errors.d.ts +3 -0
  17. package/dist/auth/errors.js +10 -0
  18. package/dist/auth/jwt.d.ts +6 -0
  19. package/dist/auth/jwt.js +29 -0
  20. package/dist/client/doover-client.d.ts +15 -0
  21. package/dist/client/doover-client.js +45 -4
  22. package/dist/client/singleton.d.ts +26 -0
  23. package/dist/client/singleton.js +59 -0
  24. package/dist/client/stats.d.ts +55 -0
  25. package/dist/client/stats.js +97 -0
  26. package/dist/gateway/gateway-client.d.ts +34 -8
  27. package/dist/gateway/gateway-client.js +147 -52
  28. package/dist/gateway/types.d.ts +0 -1
  29. package/dist/http/rest-client.d.ts +21 -3
  30. package/dist/http/rest-client.js +33 -2
  31. package/dist/index.d.ts +12 -0
  32. package/dist/index.js +23 -5
  33. package/dist/node/config-manager.d.ts +34 -0
  34. package/dist/node/config-manager.js +177 -0
  35. package/dist/node/index.d.ts +1 -0
  36. package/dist/node/index.js +5 -0
  37. package/dist/react/context.d.ts +19 -0
  38. package/dist/react/context.js +28 -0
  39. package/dist/react/index.d.ts +24 -0
  40. package/dist/react/index.js +40 -0
  41. package/dist/react/sharedQueryClient.d.ts +21 -0
  42. package/dist/react/sharedQueryClient.js +39 -0
  43. package/dist/react/useAgentChannel.d.ts +7 -0
  44. package/dist/react/useAgentChannel.js +12 -0
  45. package/dist/react/useAgentConnections.d.ts +8 -0
  46. package/dist/react/useAgentConnections.js +24 -0
  47. package/dist/react/useChannelAggregate.d.ts +13 -0
  48. package/dist/react/useChannelAggregate.js +38 -0
  49. package/dist/react/useChannelMessages.d.ts +23 -0
  50. package/dist/react/useChannelMessages.js +56 -0
  51. package/dist/react/useChannelSubscription.d.ts +16 -0
  52. package/dist/react/useChannelSubscription.js +43 -0
  53. package/dist/react/useConnectionState.d.ts +21 -0
  54. package/dist/react/useConnectionState.js +43 -0
  55. package/dist/react/useMultiAgentAggregates.d.ts +22 -0
  56. package/dist/react/useMultiAgentAggregates.js +82 -0
  57. package/dist/react/useMultiAgentChannelMessages.d.ts +18 -0
  58. package/dist/react/useMultiAgentChannelMessages.js +78 -0
  59. package/dist/react/useSendMessage.d.ts +9 -0
  60. package/dist/react/useSendMessage.js +16 -0
  61. package/dist/react/useSendRpc.d.ts +61 -0
  62. package/dist/react/useSendRpc.js +158 -0
  63. package/dist/react/useTurnCredentials.d.ts +12 -0
  64. package/dist/react/useTurnCredentials.js +25 -0
  65. package/dist/react/useUpdateAggregate.d.ts +14 -0
  66. package/dist/react/useUpdateAggregate.js +25 -0
  67. package/dist/react/useUpdateMessage.d.ts +17 -0
  68. package/dist/react/useUpdateMessage.js +24 -0
  69. package/dist/test/apis.test.js +7 -1
  70. package/dist/test/auth.test.d.ts +1 -0
  71. package/dist/test/auth.test.js +502 -0
  72. package/dist/test/config-manager.test.d.ts +1 -0
  73. package/dist/test/config-manager.test.js +160 -0
  74. package/dist/test/doover-client.test.js +13 -0
  75. package/dist/test/doover-data-provider.test.js +155 -0
  76. package/dist/test/gateway-client.test.js +122 -8
  77. package/dist/test/react.test.d.ts +1 -0
  78. package/dist/test/react.test.js +353 -0
  79. package/dist/test/singleton.test.d.ts +1 -0
  80. package/dist/test/singleton.test.js +62 -0
  81. package/dist/types/common.d.ts +40 -0
  82. package/dist/viewer/doover-data-provider.d.ts +34 -5
  83. package/dist/viewer/doover-data-provider.js +96 -9
  84. package/package.json +33 -2
@@ -3,15 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GatewayClient = void 0;
4
4
  const errors_1 = require("../http/errors");
5
5
  const snowflake_1 = require("../utils/snowflake");
6
+ const RECONNECT_BASE_MS = 1000;
7
+ const RECONNECT_CAP_MS = 30000;
6
8
  class GatewayClient {
7
- constructor(config) {
9
+ constructor(config, auth) {
8
10
  this.config = config;
9
11
  this.socket = null;
10
12
  this.session = null;
11
- this.heartbeatTimer = null;
12
- this.lastHeartbeatAt = null;
13
- this.missedHeartbeats = 0;
14
13
  this.reconnectTimer = null;
14
+ this.reconnectAttempts = 0;
15
+ /** Set when the consumer explicitly disconnects — suppresses reconnect. */
16
+ this.explicitlyDisconnected = false;
17
+ /** Guards against concurrent connect() callers creating duplicate sockets. */
18
+ this.opening = false;
15
19
  this.listeners = {
16
20
  ready: new Set(),
17
21
  channelSync: new Set(),
@@ -26,31 +30,87 @@ class GatewayClient {
26
30
  sessionCancelled: new Set(),
27
31
  open: new Set(),
28
32
  close: new Set(),
29
- heartbeatAck: new Set(),
30
33
  };
31
34
  this.subscriptions = new Map();
35
+ this.stats = null;
36
+ this.handleVisibilityChange = () => {
37
+ if (typeof document === "undefined")
38
+ return;
39
+ if (document.visibilityState !== "visible")
40
+ return;
41
+ this.tryImmediateReconnect();
42
+ };
43
+ this.handleOnline = () => {
44
+ this.tryImmediateReconnect();
45
+ };
46
+ this.auth = auth ?? null;
47
+ this.installLifecycleListeners();
48
+ }
49
+ /** Attach a stats collector. Call with `null` to detach. */
50
+ setStats(stats) {
51
+ this.stats = stats;
32
52
  }
33
- connect() {
53
+ async connect() {
54
+ this.explicitlyDisconnected = false;
34
55
  if (this.socket && this.socket.readyState <= WebSocket.OPEN) {
35
56
  return;
36
57
  }
37
- const WebSocketImpl = this.config.webSocketImpl ?? WebSocket;
38
- this.socket = new WebSocketImpl(this.config.dataWssUrl);
39
- this.socket.onopen = () => this.emit("open");
40
- this.socket.onclose = (event) => {
41
- this.stopHeartbeat();
58
+ // De-dupe concurrent callers. Without this, N simultaneous
59
+ // `subscribeToChannel(...)` calls each await auth, then each create
60
+ // their own socket — the last one wins `this.socket`, but the earlier
61
+ // sockets' `onmessage` handlers still fire and try to send() through
62
+ // `this.socket` (a newer, not-yet-open socket → throws). The flag is
63
+ // cleared synchronously as soon as the new socket is assigned in
64
+ // `openSocket`, so reconnects after close still work.
65
+ if (this.opening) {
66
+ return;
67
+ }
68
+ this.opening = true;
69
+ try {
70
+ await this.openSocket();
71
+ }
72
+ finally {
73
+ this.opening = false;
74
+ }
75
+ }
76
+ async openSocket() {
77
+ if (this.auth) {
78
+ await this.auth.ensureReady();
79
+ }
80
+ const hasFactory = !!this.config.webSocketFactory;
81
+ const wsParams = this.auth
82
+ ? await this.auth.prepareWebSocket(this.config.dataWssUrl, hasFactory)
83
+ : { url: this.config.dataWssUrl };
84
+ let socket;
85
+ if (this.config.webSocketFactory) {
86
+ socket = this.config.webSocketFactory({
87
+ url: wsParams.url,
88
+ headers: wsParams.headers,
89
+ });
90
+ }
91
+ else {
92
+ const WebSocketImpl = this.config.webSocketImpl ?? WebSocket;
93
+ socket = new WebSocketImpl(wsParams.url);
94
+ }
95
+ this.socket = socket;
96
+ // Release the concurrency gate synchronously now that the new socket is
97
+ // assigned — any subsequent connect() will see it via `this.socket`.
98
+ this.opening = false;
99
+ socket.onopen = () => this.emit("open");
100
+ socket.onclose = (event) => {
42
101
  this.emit("close", event);
43
102
  this.scheduleReconnect();
44
103
  };
45
- this.socket.onerror = () => undefined;
46
- this.socket.onmessage = (event) => this.handleMessage(event.data);
104
+ socket.onerror = () => undefined;
105
+ socket.onmessage = (event) => this.handleMessage(event.data);
47
106
  }
48
107
  disconnect(code, reason) {
49
- this.stopHeartbeat();
108
+ this.explicitlyDisconnected = true;
50
109
  if (this.reconnectTimer) {
51
110
  clearTimeout(this.reconnectTimer);
52
111
  this.reconnectTimer = null;
53
112
  }
113
+ this.reconnectAttempts = 0;
54
114
  this.socket?.close(code, reason);
55
115
  this.socket = null;
56
116
  }
@@ -66,7 +126,7 @@ class GatewayClient {
66
126
  diff_only: options?.diff_only ?? false,
67
127
  });
68
128
  if (!this.isConnected()) {
69
- this.connect();
129
+ void this.connect();
70
130
  return;
71
131
  }
72
132
  this.send({
@@ -93,7 +153,7 @@ class GatewayClient {
93
153
  }
94
154
  syncChannel(channel) {
95
155
  if (!this.isConnected()) {
96
- this.connect();
156
+ void this.connect();
97
157
  return;
98
158
  }
99
159
  this.send({
@@ -106,7 +166,7 @@ class GatewayClient {
106
166
  }
107
167
  sendOneShotMessage(channel, data) {
108
168
  if (!this.isConnected()) {
109
- this.connect();
169
+ void this.connect();
110
170
  return;
111
171
  }
112
172
  this.send({
@@ -120,20 +180,44 @@ class GatewayClient {
120
180
  getSession() {
121
181
  return this.session;
122
182
  }
123
- getLatency() {
124
- return this.lastHeartbeatAt === null ? null : Date.now() - this.lastHeartbeatAt;
125
- }
126
183
  isConnected() {
127
184
  return this.socket?.readyState === WebSocket.OPEN;
128
185
  }
186
+ /** Number of channels the gateway is currently subscribed to. */
187
+ getSubscriptionCount() {
188
+ return this.subscriptions.size;
189
+ }
190
+ /** Snapshot of currently subscribed channels (for debug/inspection). */
191
+ getSubscriptions() {
192
+ return [...this.subscriptions.values()].map((s) => s.channel);
193
+ }
194
+ /**
195
+ * Force a fresh connection: close the current socket (without suppressing
196
+ * reconnects) and immediately open a new one. Useful for a manual
197
+ * "reconnect now" control in debug UIs.
198
+ */
199
+ async reconnect() {
200
+ if (this.reconnectTimer) {
201
+ clearTimeout(this.reconnectTimer);
202
+ this.reconnectTimer = null;
203
+ }
204
+ this.reconnectAttempts = 0;
205
+ // Drop the session so the new socket identifies fresh (op 10) rather
206
+ // than attempting to resume a just-closed session (op 11) that the
207
+ // server has already torn down.
208
+ this.session = null;
209
+ if (this.socket) {
210
+ // Suppress the auto-reconnect path so we don't double-schedule.
211
+ const prev = this.socket;
212
+ prev.onclose = null;
213
+ prev.close(1000, "manual reconnect");
214
+ this.socket = null;
215
+ }
216
+ await this.connect();
217
+ }
129
218
  handleMessage(raw) {
219
+ this.stats?.recordGatewayReceived();
130
220
  const message = JSON.parse(raw);
131
- if (message.op === 2) {
132
- this.missedHeartbeats = 0;
133
- const latency = this.lastHeartbeatAt === null ? null : Date.now() - this.lastHeartbeatAt;
134
- this.emit("heartbeatAck", latency);
135
- return;
136
- }
137
221
  if (message.op === 3) {
138
222
  this.session = null;
139
223
  this.emit("sessionCancelled");
@@ -145,9 +229,9 @@ class GatewayClient {
145
229
  switch (message.t) {
146
230
  case "Hello":
147
231
  this.identifyOrResume();
148
- this.startHeartbeat();
149
232
  break;
150
233
  case "Ready":
234
+ this.reconnectAttempts = 0;
151
235
  this.session = message.d;
152
236
  this.emit("ready", message.d);
153
237
  this.resubscribeAll();
@@ -209,33 +293,12 @@ class GatewayClient {
209
293
  this.subscribe(entry.channel, { diff_only: entry.diff_only });
210
294
  }
211
295
  }
212
- startHeartbeat() {
213
- this.stopHeartbeat();
214
- this.heartbeatTimer = setInterval(() => {
215
- if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
216
- return;
217
- }
218
- this.lastHeartbeatAt = Date.now();
219
- this.missedHeartbeats += 1;
220
- if (this.missedHeartbeats > 3) {
221
- this.socket.close(4000, "Missed heartbeats");
222
- return;
223
- }
224
- this.send({ op: 1, d: {} });
225
- }, 20000);
226
- }
227
- stopHeartbeat() {
228
- if (this.heartbeatTimer) {
229
- clearInterval(this.heartbeatTimer);
230
- this.heartbeatTimer = null;
231
- }
232
- this.missedHeartbeats = 0;
233
- }
234
296
  send(payload) {
235
297
  if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
236
298
  throw new errors_1.DooverGatewayError("WebSocket is not connected");
237
299
  }
238
300
  this.socket.send(JSON.stringify(payload));
301
+ this.stats?.recordGatewaySent();
239
302
  }
240
303
  emit(eventName, ...args) {
241
304
  this.listeners[eventName].forEach((listener) => {
@@ -243,13 +306,45 @@ class GatewayClient {
243
306
  });
244
307
  }
245
308
  scheduleReconnect() {
246
- if (this.reconnectTimer) {
309
+ if (this.reconnectTimer || this.explicitlyDisconnected) {
247
310
  return;
248
311
  }
312
+ const delay = this.computeReconnectDelay();
313
+ this.reconnectAttempts += 1;
249
314
  this.reconnectTimer = setTimeout(() => {
250
315
  this.reconnectTimer = null;
251
- this.connect();
252
- }, 1000);
316
+ void this.connect();
317
+ }, delay);
318
+ }
319
+ /** Exponential backoff with full-jitter, capped at RECONNECT_CAP_MS. */
320
+ computeReconnectDelay() {
321
+ const exp = Math.min(RECONNECT_CAP_MS, RECONNECT_BASE_MS * 2 ** this.reconnectAttempts);
322
+ return Math.floor(Math.random() * exp);
323
+ }
324
+ installLifecycleListeners() {
325
+ if (this.config.disableBrowserLifecycleHooks)
326
+ return;
327
+ if (typeof document !== "undefined" && typeof document.addEventListener === "function") {
328
+ document.addEventListener("visibilitychange", this.handleVisibilityChange);
329
+ }
330
+ if (typeof window !== "undefined" && typeof window.addEventListener === "function") {
331
+ window.addEventListener("online", this.handleOnline);
332
+ }
333
+ }
334
+ /**
335
+ * Called by lifecycle hooks when we have a strong signal that the network
336
+ * or tab has come back — skip the backoff schedule and reconnect now.
337
+ */
338
+ tryImmediateReconnect() {
339
+ if (this.explicitlyDisconnected)
340
+ return;
341
+ if (this.isConnected())
342
+ return;
343
+ if (this.reconnectTimer) {
344
+ clearTimeout(this.reconnectTimer);
345
+ this.reconnectTimer = null;
346
+ }
347
+ void this.connect();
253
348
  }
254
349
  channelKey(channel) {
255
350
  return `${channel.agent_id}/${channel.name}`;
@@ -131,5 +131,4 @@ export interface GatewayListenerMap {
131
131
  sessionCancelled: () => void;
132
132
  open: () => void;
133
133
  close: (event: CloseEvent) => void;
134
- heartbeatAck: (latencyMs: number | null) => void;
135
134
  }
@@ -1,4 +1,7 @@
1
- export interface DooverClientConfig {
1
+ import type { AuthConfig } from "../auth/build-auth";
2
+ import type { DooverAuth } from "../auth/doover-auth";
3
+ import type { DooverStatsCollector } from "../client/stats";
4
+ export interface DooverClientConfig extends AuthConfig {
2
5
  dataRestUrl: string;
3
6
  controlApiUrl: string;
4
7
  dataWssUrl: string;
@@ -7,6 +10,16 @@ export interface DooverClientConfig {
7
10
  impersonateUserStorageKey?: string;
8
11
  fetchImpl?: typeof fetch;
9
12
  webSocketImpl?: typeof WebSocket;
13
+ webSocketFactory?: (options: {
14
+ url: string;
15
+ headers?: Record<string, string>;
16
+ }) => WebSocket;
17
+ /**
18
+ * When true, disables the GatewayClient's browser lifecycle listeners
19
+ * (visibilitychange, online). Defaults to false — hooks are on by default
20
+ * in browsers and automatically skipped in non-browser environments.
21
+ */
22
+ disableBrowserLifecycleHooks?: boolean;
10
23
  }
11
24
  export interface RequestOptions {
12
25
  baseUrl?: string;
@@ -20,9 +33,14 @@ export interface RequestOptions {
20
33
  type QueryValue = string | number | boolean | null | undefined | Array<string | number | boolean>;
21
34
  type QueryParams = Record<string, QueryValue> | object;
22
35
  export declare class RestClient {
23
- readonly config: Required<Pick<DooverClientConfig, "dataRestUrl" | "controlApiUrl" | "dataWssUrl" | "sharing" | "impersonateUserStorageKey">> & Pick<DooverClientConfig, "organisationId" | "fetchImpl" | "webSocketImpl">;
24
- constructor(config: DooverClientConfig);
36
+ readonly config: Required<Pick<DooverClientConfig, "dataRestUrl" | "controlApiUrl" | "dataWssUrl" | "sharing" | "impersonateUserStorageKey">> & Pick<DooverClientConfig, "organisationId" | "fetchImpl" | "webSocketImpl" | "webSocketFactory">;
37
+ readonly auth: DooverAuth | null;
38
+ private stats;
39
+ constructor(config: DooverClientConfig, auth?: DooverAuth);
40
+ /** Attach a stats collector. Call with `null` to detach. */
41
+ setStats(stats: DooverStatsCollector | null): void;
25
42
  request<T>(options: RequestOptions): Promise<T>;
43
+ private doRequest;
26
44
  get<T>(path: string, query?: RequestOptions["query"], baseUrl?: string): Promise<T>;
27
45
  post<T>(path: string, body?: RequestOptions["body"], query?: RequestOptions["query"], baseUrl?: string): Promise<T>;
28
46
  put<T>(path: string, body?: RequestOptions["body"], query?: RequestOptions["query"], baseUrl?: string): Promise<T>;
@@ -3,19 +3,47 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RestClient = void 0;
4
4
  const errors_1 = require("./errors");
5
5
  class RestClient {
6
- constructor(config) {
6
+ constructor(config, auth) {
7
+ this.stats = null;
7
8
  this.config = {
8
9
  ...config,
9
10
  sharing: config.sharing ?? "internal",
10
11
  organisationId: config.organisationId ?? null,
11
12
  impersonateUserStorageKey: config.impersonateUserStorageKey ?? "impersonate_user_id",
12
13
  };
14
+ this.auth = auth ?? null;
15
+ }
16
+ /** Attach a stats collector. Call with `null` to detach. */
17
+ setStats(stats) {
18
+ this.stats = stats;
13
19
  }
14
20
  async request(options) {
21
+ const startedAt = this.stats?.recordRestStart() ?? null;
22
+ try {
23
+ const payload = await this.doRequest(options);
24
+ this.stats?.recordRestEnd(startedAt, true);
25
+ return payload;
26
+ }
27
+ catch (err) {
28
+ this.stats?.recordRestEnd(startedAt, false);
29
+ throw err;
30
+ }
31
+ }
32
+ async doRequest(options) {
33
+ if (this.auth) {
34
+ await this.auth.ensureReady();
35
+ }
15
36
  const method = options.method ?? "GET";
16
37
  const url = this.buildUrl(options.baseUrl ?? this.config.dataRestUrl, options.path, options.query);
17
38
  const headers = new Headers(options.headers);
18
39
  const body = this.normalizeBody(options.body, headers);
40
+ // Merge auth headers.
41
+ if (this.auth) {
42
+ const authHeaders = await this.auth.getHttpHeaders();
43
+ for (const [key, value] of Object.entries(authHeaders)) {
44
+ headers.set(key, value);
45
+ }
46
+ }
19
47
  if (!options.omitSharingHeader) {
20
48
  headers.set("X-Doover-Sharing", this.config.sharing);
21
49
  }
@@ -26,12 +54,15 @@ class RestClient {
26
54
  if (impersonated) {
27
55
  headers.set("X-Doover-Assume", impersonated);
28
56
  }
57
+ const credentials = this.auth
58
+ ? this.auth.getFetchCredentials()
59
+ : "include";
29
60
  const fetchImpl = this.config.fetchImpl ?? fetch;
30
61
  const response = await fetchImpl(url, {
31
62
  method,
32
63
  headers,
33
64
  body,
34
- credentials: "include",
65
+ credentials,
35
66
  });
36
67
  const payload = await this.parseResponse(response);
37
68
  if (!response.ok) {
package/dist/index.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  export { DooverClient } from "./client/doover-client";
2
+ export { getDooverClient, peekDooverClient, resetDooverClient, } from "./client/singleton";
3
+ export { DooverStatsCollector } from "./client/stats";
4
+ export type { DooverStatsSnapshot, RestStatsSnapshot, GatewayStatsSnapshot, } from "./client/stats";
2
5
  export { AgentsApi } from "./apis/agents-api";
3
6
  export { AggregatesApi } from "./apis/aggregates-api";
4
7
  export { AlarmsApi } from "./apis/alarms-api";
@@ -9,6 +12,15 @@ export { NotificationsApi } from "./apis/notifications-api";
9
12
  export { PermissionsApi } from "./apis/permissions-api";
10
13
  export { ProcessorsApi } from "./apis/processors-api";
11
14
  export { TurnApi } from "./apis/turn-api";
15
+ export { DooverAuth } from "./auth/doover-auth";
16
+ export { CookieAuth } from "./auth/cookie-auth";
17
+ export { DooverTokenAuth } from "./auth/doover-token-auth";
18
+ export { AuthProfile } from "./auth/auth-profile";
19
+ export type { AuthProfileData } from "./auth/auth-profile";
20
+ export type { AuthProfileStore } from "./auth/auth-store";
21
+ export { DooverAuthError } from "./auth/errors";
22
+ export { buildAuth } from "./auth/build-auth";
23
+ export type { AuthConfig } from "./auth/build-auth";
12
24
  export { GatewayClient } from "./gateway/gateway-client";
13
25
  export type * from "./gateway/types";
14
26
  export { RestClient } from "./http/rest-client";
package/dist/index.js CHANGED
@@ -1,8 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateSnowflakeIdAtTime = exports.extractSnowflakeId = exports.addTimestampToMessage = exports.getIdentifierFromPath = exports.DooverDataProvider = exports.DooverValidationError = exports.DooverGatewayError = exports.DooverApiError = exports.RestClient = exports.GatewayClient = exports.TurnApi = exports.ProcessorsApi = exports.PermissionsApi = exports.NotificationsApi = exports.MessagesApi = exports.ConnectionsApi = exports.ChannelsApi = exports.AlarmsApi = exports.AggregatesApi = exports.AgentsApi = exports.DooverClient = void 0;
3
+ exports.generateSnowflakeIdAtTime = exports.extractSnowflakeId = exports.addTimestampToMessage = exports.getIdentifierFromPath = exports.DooverDataProvider = exports.DooverValidationError = exports.DooverGatewayError = exports.DooverApiError = exports.RestClient = exports.GatewayClient = exports.buildAuth = exports.DooverAuthError = exports.AuthProfile = exports.DooverTokenAuth = exports.CookieAuth = exports.DooverAuth = exports.TurnApi = exports.ProcessorsApi = exports.PermissionsApi = exports.NotificationsApi = exports.MessagesApi = exports.ConnectionsApi = exports.ChannelsApi = exports.AlarmsApi = exports.AggregatesApi = exports.AgentsApi = exports.DooverStatsCollector = exports.resetDooverClient = exports.peekDooverClient = exports.getDooverClient = exports.DooverClient = void 0;
4
4
  var doover_client_1 = require("./client/doover-client");
5
5
  Object.defineProperty(exports, "DooverClient", { enumerable: true, get: function () { return doover_client_1.DooverClient; } });
6
+ var singleton_1 = require("./client/singleton");
7
+ Object.defineProperty(exports, "getDooverClient", { enumerable: true, get: function () { return singleton_1.getDooverClient; } });
8
+ Object.defineProperty(exports, "peekDooverClient", { enumerable: true, get: function () { return singleton_1.peekDooverClient; } });
9
+ Object.defineProperty(exports, "resetDooverClient", { enumerable: true, get: function () { return singleton_1.resetDooverClient; } });
10
+ var stats_1 = require("./client/stats");
11
+ Object.defineProperty(exports, "DooverStatsCollector", { enumerable: true, get: function () { return stats_1.DooverStatsCollector; } });
6
12
  var agents_api_1 = require("./apis/agents-api");
7
13
  Object.defineProperty(exports, "AgentsApi", { enumerable: true, get: function () { return agents_api_1.AgentsApi; } });
8
14
  var aggregates_api_1 = require("./apis/aggregates-api");
@@ -23,14 +29,26 @@ var processors_api_1 = require("./apis/processors-api");
23
29
  Object.defineProperty(exports, "ProcessorsApi", { enumerable: true, get: function () { return processors_api_1.ProcessorsApi; } });
24
30
  var turn_api_1 = require("./apis/turn-api");
25
31
  Object.defineProperty(exports, "TurnApi", { enumerable: true, get: function () { return turn_api_1.TurnApi; } });
32
+ var doover_auth_1 = require("./auth/doover-auth");
33
+ Object.defineProperty(exports, "DooverAuth", { enumerable: true, get: function () { return doover_auth_1.DooverAuth; } });
34
+ var cookie_auth_1 = require("./auth/cookie-auth");
35
+ Object.defineProperty(exports, "CookieAuth", { enumerable: true, get: function () { return cookie_auth_1.CookieAuth; } });
36
+ var doover_token_auth_1 = require("./auth/doover-token-auth");
37
+ Object.defineProperty(exports, "DooverTokenAuth", { enumerable: true, get: function () { return doover_token_auth_1.DooverTokenAuth; } });
38
+ var auth_profile_1 = require("./auth/auth-profile");
39
+ Object.defineProperty(exports, "AuthProfile", { enumerable: true, get: function () { return auth_profile_1.AuthProfile; } });
40
+ var errors_1 = require("./auth/errors");
41
+ Object.defineProperty(exports, "DooverAuthError", { enumerable: true, get: function () { return errors_1.DooverAuthError; } });
42
+ var build_auth_1 = require("./auth/build-auth");
43
+ Object.defineProperty(exports, "buildAuth", { enumerable: true, get: function () { return build_auth_1.buildAuth; } });
26
44
  var gateway_client_1 = require("./gateway/gateway-client");
27
45
  Object.defineProperty(exports, "GatewayClient", { enumerable: true, get: function () { return gateway_client_1.GatewayClient; } });
28
46
  var rest_client_1 = require("./http/rest-client");
29
47
  Object.defineProperty(exports, "RestClient", { enumerable: true, get: function () { return rest_client_1.RestClient; } });
30
- var errors_1 = require("./http/errors");
31
- Object.defineProperty(exports, "DooverApiError", { enumerable: true, get: function () { return errors_1.DooverApiError; } });
32
- Object.defineProperty(exports, "DooverGatewayError", { enumerable: true, get: function () { return errors_1.DooverGatewayError; } });
33
- Object.defineProperty(exports, "DooverValidationError", { enumerable: true, get: function () { return errors_1.DooverValidationError; } });
48
+ var errors_2 = require("./http/errors");
49
+ Object.defineProperty(exports, "DooverApiError", { enumerable: true, get: function () { return errors_2.DooverApiError; } });
50
+ Object.defineProperty(exports, "DooverGatewayError", { enumerable: true, get: function () { return errors_2.DooverGatewayError; } });
51
+ Object.defineProperty(exports, "DooverValidationError", { enumerable: true, get: function () { return errors_2.DooverValidationError; } });
34
52
  var doover_data_provider_1 = require("./viewer/doover-data-provider");
35
53
  Object.defineProperty(exports, "DooverDataProvider", { enumerable: true, get: function () { return doover_data_provider_1.DooverDataProvider; } });
36
54
  var path_parsing_1 = require("./viewer/path-parsing");
@@ -0,0 +1,34 @@
1
+ import { AuthProfile } from "../auth/auth-profile";
2
+ import type { AuthProfileStore } from "../auth/auth-store";
3
+ /**
4
+ * File-backed profile store compatible with pydoover's config format.
5
+ *
6
+ * Reads `~/.doover/config` (or a custom path) synchronously on construction,
7
+ * matching Python's eager-read model.
8
+ *
9
+ * Behaviour:
10
+ * - Doover2 `[profile=...]` blocks are parsed into `AuthProfile` entries.
11
+ * - Legacy Doover1 `[...]` blocks and unrecognised raw blocks are preserved
12
+ * verbatim in their original order and written back unchanged.
13
+ * - `write()` creates the `~/.doover` directory if missing.
14
+ */
15
+ export declare class ConfigManager implements AuthProfileStore {
16
+ currentProfile: string | null;
17
+ current: AuthProfile | null;
18
+ /** Parsed Doover2 profiles keyed by profile name. */
19
+ private profiles;
20
+ /**
21
+ * Ordered list of *blocks* in the file as they were originally read. Each
22
+ * entry is either a `{ type: "managed"; name: string }` reference into
23
+ * `this.profiles`, or a `{ type: "raw"; text: string }` blob that is
24
+ * preserved verbatim.
25
+ */
26
+ private blocks;
27
+ private readonly configPath;
28
+ constructor(configPath?: string);
29
+ get(profileName: string): AuthProfile | undefined;
30
+ create(entry: AuthProfile): void;
31
+ delete(profileName: string): void;
32
+ write(): void;
33
+ private read;
34
+ }