doover-js 0.1.2 → 0.2.0-alpha.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/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 +2 -0
- package/dist/client/doover-client.js +16 -3
- package/dist/gateway/gateway-client.d.ts +4 -2
- package/dist/gateway/gateway-client.js +24 -8
- package/dist/http/rest-client.d.ts +10 -3
- package/dist/http/rest-client.js +16 -2
- package/dist/index.d.ts +9 -0
- package/dist/index.js +17 -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/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/viewer/doover-data-provider.d.ts +2 -1
- package/dist/viewer/doover-data-provider.js +4 -4
- package/package.json +6 -1
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DooverTokenAuth = void 0;
|
|
4
|
+
const doover_auth_1 = require("./doover-auth");
|
|
5
|
+
const errors_1 = require("./errors");
|
|
6
|
+
const jwt_1 = require("./jwt");
|
|
7
|
+
/** Buffer in milliseconds before expiry at which we trigger a refresh (30 s). */
|
|
8
|
+
const REFRESH_BUFFER_MS = 30000;
|
|
9
|
+
class DooverTokenAuth extends doover_auth_1.DooverAuth {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super();
|
|
12
|
+
this.refreshInFlight = null;
|
|
13
|
+
this.token = options.token ?? null;
|
|
14
|
+
this.tokenExpires = this.resolveExpiry(options.tokenExpires, options.token ?? null);
|
|
15
|
+
this.refreshToken = options.refreshToken ?? null;
|
|
16
|
+
this.refreshTokenId = options.refreshTokenId ?? null;
|
|
17
|
+
this.authServerUrl = options.authServerUrl ?? null;
|
|
18
|
+
this.authServerClientId = options.authServerClientId ?? null;
|
|
19
|
+
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
20
|
+
}
|
|
21
|
+
// ------------------------------------------------------------------
|
|
22
|
+
// DooverAuth interface
|
|
23
|
+
// ------------------------------------------------------------------
|
|
24
|
+
async getHttpHeaders() {
|
|
25
|
+
if (!this.token) {
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
return { Authorization: `Bearer ${this.token}` };
|
|
29
|
+
}
|
|
30
|
+
getFetchCredentials() {
|
|
31
|
+
return "omit";
|
|
32
|
+
}
|
|
33
|
+
async prepareWebSocket(url, canUseHeaders) {
|
|
34
|
+
if (!this.token) {
|
|
35
|
+
return { url };
|
|
36
|
+
}
|
|
37
|
+
if (canUseHeaders) {
|
|
38
|
+
return {
|
|
39
|
+
url,
|
|
40
|
+
headers: { Authorization: `Bearer ${this.token}` },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Append token as a query parameter for browser-style WebSocket.
|
|
44
|
+
const parsed = new URL(url);
|
|
45
|
+
parsed.searchParams.set("token", this.token);
|
|
46
|
+
return { url: parsed.toString() };
|
|
47
|
+
}
|
|
48
|
+
setToken(token, tokenExpires) {
|
|
49
|
+
this.token = token;
|
|
50
|
+
this.tokenExpires = this.resolveExpiry(tokenExpires, token);
|
|
51
|
+
}
|
|
52
|
+
async ensureReady() {
|
|
53
|
+
if (!this.needsRefresh()) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Deduplicate concurrent refresh attempts.
|
|
57
|
+
if (!this.refreshInFlight) {
|
|
58
|
+
this.refreshInFlight = this.refresh().finally(() => {
|
|
59
|
+
this.refreshInFlight = null;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return this.refreshInFlight;
|
|
63
|
+
}
|
|
64
|
+
// ------------------------------------------------------------------
|
|
65
|
+
// Profile attachment override — load refresh metadata from profile
|
|
66
|
+
// ------------------------------------------------------------------
|
|
67
|
+
attachProfile(profile, configManager) {
|
|
68
|
+
super.attachProfile(profile, configManager);
|
|
69
|
+
// Back-fill fields from the profile where not already set.
|
|
70
|
+
if (!this.token && profile.token) {
|
|
71
|
+
this.token = profile.token;
|
|
72
|
+
}
|
|
73
|
+
if (!this.tokenExpires && profile.tokenExpires) {
|
|
74
|
+
this.tokenExpires = new Date(profile.tokenExpires);
|
|
75
|
+
}
|
|
76
|
+
if (!this.tokenExpires && this.token) {
|
|
77
|
+
this.tokenExpires = (0, jwt_1.decodeTokenExpiry)(this.token);
|
|
78
|
+
}
|
|
79
|
+
if (!this.refreshToken && profile.refreshToken) {
|
|
80
|
+
this.refreshToken = profile.refreshToken;
|
|
81
|
+
}
|
|
82
|
+
if (!this.refreshTokenId && profile.refreshTokenId) {
|
|
83
|
+
this.refreshTokenId = profile.refreshTokenId;
|
|
84
|
+
}
|
|
85
|
+
if (!this.authServerUrl && profile.authServerUrl) {
|
|
86
|
+
this.authServerUrl = profile.authServerUrl;
|
|
87
|
+
}
|
|
88
|
+
if (!this.authServerClientId && profile.authServerClientId) {
|
|
89
|
+
this.authServerClientId = profile.authServerClientId;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// ------------------------------------------------------------------
|
|
93
|
+
// Internal
|
|
94
|
+
// ------------------------------------------------------------------
|
|
95
|
+
needsRefresh() {
|
|
96
|
+
if (!this.token) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
if (!this.tokenExpires) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
return this.tokenExpires.getTime() - Date.now() < REFRESH_BUFFER_MS;
|
|
103
|
+
}
|
|
104
|
+
async refresh() {
|
|
105
|
+
if (!this.authServerUrl ||
|
|
106
|
+
!this.refreshToken ||
|
|
107
|
+
!this.authServerClientId) {
|
|
108
|
+
throw new errors_1.DooverAuthError("Cannot refresh token: missing authServerUrl, refreshToken, or authServerClientId");
|
|
109
|
+
}
|
|
110
|
+
const url = new URL(`${this.authServerUrl}/oauth2/token`);
|
|
111
|
+
url.searchParams.set("grant_type", "refresh_token");
|
|
112
|
+
if (this.token) {
|
|
113
|
+
url.searchParams.set("access_token", this.token);
|
|
114
|
+
}
|
|
115
|
+
url.searchParams.set("refresh_token", this.refreshToken);
|
|
116
|
+
url.searchParams.set("client_id", this.authServerClientId);
|
|
117
|
+
let response;
|
|
118
|
+
try {
|
|
119
|
+
response = await this.fetchImpl(url.toString(), {
|
|
120
|
+
method: "POST",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
throw new errors_1.DooverAuthError(`Token refresh request failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
125
|
+
}
|
|
126
|
+
if (!response.ok) {
|
|
127
|
+
throw new errors_1.DooverAuthError(`Token refresh failed with status ${response.status}`);
|
|
128
|
+
}
|
|
129
|
+
const body = (await response.json());
|
|
130
|
+
if (!body.access_token) {
|
|
131
|
+
throw new errors_1.DooverAuthError("Token refresh response did not contain an access_token");
|
|
132
|
+
}
|
|
133
|
+
this.token = body.access_token;
|
|
134
|
+
this.tokenExpires =
|
|
135
|
+
typeof body.expires_in === "number"
|
|
136
|
+
? new Date(Date.now() + body.expires_in * 1000)
|
|
137
|
+
: (0, jwt_1.decodeTokenExpiry)(body.access_token);
|
|
138
|
+
if (body.refresh_token) {
|
|
139
|
+
this.refreshToken = body.refresh_token;
|
|
140
|
+
}
|
|
141
|
+
// Persist back to profile / config manager.
|
|
142
|
+
this.persistToProfile();
|
|
143
|
+
}
|
|
144
|
+
persistToProfile() {
|
|
145
|
+
if (!this.profile) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
this.profile.token = this.token;
|
|
149
|
+
this.profile.tokenExpires = this.tokenExpires
|
|
150
|
+
? this.tokenExpires.toISOString()
|
|
151
|
+
: null;
|
|
152
|
+
if (this.refreshToken) {
|
|
153
|
+
this.profile.refreshToken = this.refreshToken;
|
|
154
|
+
}
|
|
155
|
+
if (this.configManager) {
|
|
156
|
+
try {
|
|
157
|
+
this.configManager.create(this.profile);
|
|
158
|
+
this.configManager.write();
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
throw new errors_1.DooverAuthError(`Failed to persist refreshed token: ${err instanceof Error ? err.message : String(err)}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
resolveExpiry(explicit, token) {
|
|
166
|
+
if (explicit instanceof Date) {
|
|
167
|
+
return explicit;
|
|
168
|
+
}
|
|
169
|
+
if (typeof explicit === "number") {
|
|
170
|
+
return new Date(explicit);
|
|
171
|
+
}
|
|
172
|
+
if (token) {
|
|
173
|
+
return (0, jwt_1.decodeTokenExpiry)(token);
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
exports.DooverTokenAuth = DooverTokenAuth;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DooverAuthError = void 0;
|
|
4
|
+
class DooverAuthError extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "DooverAuthError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
exports.DooverAuthError = DooverAuthError;
|
package/dist/auth/jwt.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decodeTokenExpiry = decodeTokenExpiry;
|
|
4
|
+
/**
|
|
5
|
+
* Decode the `exp` claim from a JWT without verifying the signature.
|
|
6
|
+
* Returns the expiry as a `Date`, or `null` if the token has no `exp` claim
|
|
7
|
+
* or cannot be decoded.
|
|
8
|
+
*/
|
|
9
|
+
function decodeTokenExpiry(token) {
|
|
10
|
+
try {
|
|
11
|
+
const parts = token.split(".");
|
|
12
|
+
if (parts.length < 2) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
// Base64url → Base64 → decode
|
|
16
|
+
const base64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
17
|
+
const json = typeof atob === "function"
|
|
18
|
+
? atob(base64)
|
|
19
|
+
: Buffer.from(base64, "base64").toString("utf-8");
|
|
20
|
+
const payload = JSON.parse(json);
|
|
21
|
+
if (typeof payload.exp !== "number") {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return new Date(payload.exp * 1000);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -8,10 +8,12 @@ import { NotificationsApi } from "../apis/notifications-api";
|
|
|
8
8
|
import { PermissionsApi } from "../apis/permissions-api";
|
|
9
9
|
import { ProcessorsApi } from "../apis/processors-api";
|
|
10
10
|
import { TurnApi } from "../apis/turn-api";
|
|
11
|
+
import type { DooverAuth } from "../auth/doover-auth";
|
|
11
12
|
import { GatewayClient } from "../gateway/gateway-client";
|
|
12
13
|
import { RestClient, type DooverClientConfig } from "../http/rest-client";
|
|
13
14
|
import { DooverDataProvider } from "../viewer/doover-data-provider";
|
|
14
15
|
export declare class DooverClient {
|
|
16
|
+
readonly auth: DooverAuth;
|
|
15
17
|
readonly rest: RestClient;
|
|
16
18
|
readonly viewer: DooverDataProvider;
|
|
17
19
|
readonly channels: ChannelsApi;
|
|
@@ -11,13 +11,26 @@ const notifications_api_1 = require("../apis/notifications-api");
|
|
|
11
11
|
const permissions_api_1 = require("../apis/permissions-api");
|
|
12
12
|
const processors_api_1 = require("../apis/processors-api");
|
|
13
13
|
const turn_api_1 = require("../apis/turn-api");
|
|
14
|
+
const build_auth_1 = require("../auth/build-auth");
|
|
14
15
|
const gateway_client_1 = require("../gateway/gateway-client");
|
|
15
16
|
const rest_client_1 = require("../http/rest-client");
|
|
16
17
|
const doover_data_provider_1 = require("../viewer/doover-data-provider");
|
|
17
18
|
class DooverClient {
|
|
18
19
|
constructor(config) {
|
|
19
|
-
this.
|
|
20
|
-
|
|
20
|
+
this.auth = (0, build_auth_1.buildAuth)({
|
|
21
|
+
auth: config.auth,
|
|
22
|
+
profile: config.profile,
|
|
23
|
+
configManager: config.configManager,
|
|
24
|
+
token: config.token,
|
|
25
|
+
tokenExpires: config.tokenExpires,
|
|
26
|
+
refreshToken: config.refreshToken,
|
|
27
|
+
refreshTokenId: config.refreshTokenId,
|
|
28
|
+
authServerUrl: config.authServerUrl,
|
|
29
|
+
authServerClientId: config.authServerClientId,
|
|
30
|
+
fetchImpl: config.fetchImpl,
|
|
31
|
+
});
|
|
32
|
+
this.rest = new rest_client_1.RestClient(config, this.auth);
|
|
33
|
+
this.viewer = new doover_data_provider_1.DooverDataProvider(config, this.auth);
|
|
21
34
|
this.channels = new channels_api_1.ChannelsApi(this.rest);
|
|
22
35
|
this.messages = new messages_api_1.MessagesApi(this.rest);
|
|
23
36
|
this.aggregates = new aggregates_api_1.AggregatesApi(this.rest);
|
|
@@ -28,7 +41,7 @@ class DooverClient {
|
|
|
28
41
|
this.processors = new processors_api_1.ProcessorsApi(this.rest);
|
|
29
42
|
this.turn = new turn_api_1.TurnApi(this.rest);
|
|
30
43
|
this.agents = new agents_api_1.AgentsApi(this.rest);
|
|
31
|
-
this.gateway = new gateway_client_1.GatewayClient(config);
|
|
44
|
+
this.gateway = new gateway_client_1.GatewayClient(config, this.auth);
|
|
32
45
|
}
|
|
33
46
|
}
|
|
34
47
|
exports.DooverClient = DooverClient;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DooverAuth } from "../auth/doover-auth";
|
|
1
2
|
import type { DooverClientConfig } from "../http/rest-client";
|
|
2
3
|
import type { GatewayListenerMap, WebSocketSession } from "./types";
|
|
3
4
|
import type { ChannelRef, JSONValue } from "../types/common";
|
|
@@ -11,8 +12,9 @@ export declare class GatewayClient {
|
|
|
11
12
|
private reconnectTimer;
|
|
12
13
|
private listeners;
|
|
13
14
|
private subscriptions;
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
private readonly auth;
|
|
16
|
+
constructor(config: DooverClientConfig, auth?: DooverAuth);
|
|
17
|
+
connect(): Promise<void>;
|
|
16
18
|
disconnect(code?: number, reason?: string): void;
|
|
17
19
|
on<K extends keyof GatewayListenerMap>(eventName: K, listener: GatewayListenerMap[K]): void;
|
|
18
20
|
off<K extends keyof GatewayListenerMap>(eventName: K, listener: GatewayListenerMap[K]): void;
|
|
@@ -4,7 +4,7 @@ exports.GatewayClient = void 0;
|
|
|
4
4
|
const errors_1 = require("../http/errors");
|
|
5
5
|
const snowflake_1 = require("../utils/snowflake");
|
|
6
6
|
class GatewayClient {
|
|
7
|
-
constructor(config) {
|
|
7
|
+
constructor(config, auth) {
|
|
8
8
|
this.config = config;
|
|
9
9
|
this.socket = null;
|
|
10
10
|
this.session = null;
|
|
@@ -29,13 +29,29 @@ class GatewayClient {
|
|
|
29
29
|
heartbeatAck: new Set(),
|
|
30
30
|
};
|
|
31
31
|
this.subscriptions = new Map();
|
|
32
|
+
this.auth = auth ?? null;
|
|
32
33
|
}
|
|
33
|
-
connect() {
|
|
34
|
+
async connect() {
|
|
34
35
|
if (this.socket && this.socket.readyState <= WebSocket.OPEN) {
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
if (this.auth) {
|
|
39
|
+
await this.auth.ensureReady();
|
|
40
|
+
}
|
|
41
|
+
const hasFactory = !!this.config.webSocketFactory;
|
|
42
|
+
const wsParams = this.auth
|
|
43
|
+
? await this.auth.prepareWebSocket(this.config.dataWssUrl, hasFactory)
|
|
44
|
+
: { url: this.config.dataWssUrl };
|
|
45
|
+
if (this.config.webSocketFactory) {
|
|
46
|
+
this.socket = this.config.webSocketFactory({
|
|
47
|
+
url: wsParams.url,
|
|
48
|
+
headers: wsParams.headers,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
const WebSocketImpl = this.config.webSocketImpl ?? WebSocket;
|
|
53
|
+
this.socket = new WebSocketImpl(wsParams.url);
|
|
54
|
+
}
|
|
39
55
|
this.socket.onopen = () => this.emit("open");
|
|
40
56
|
this.socket.onclose = (event) => {
|
|
41
57
|
this.stopHeartbeat();
|
|
@@ -66,7 +82,7 @@ class GatewayClient {
|
|
|
66
82
|
diff_only: options?.diff_only ?? false,
|
|
67
83
|
});
|
|
68
84
|
if (!this.isConnected()) {
|
|
69
|
-
this.connect();
|
|
85
|
+
void this.connect();
|
|
70
86
|
return;
|
|
71
87
|
}
|
|
72
88
|
this.send({
|
|
@@ -93,7 +109,7 @@ class GatewayClient {
|
|
|
93
109
|
}
|
|
94
110
|
syncChannel(channel) {
|
|
95
111
|
if (!this.isConnected()) {
|
|
96
|
-
this.connect();
|
|
112
|
+
void this.connect();
|
|
97
113
|
return;
|
|
98
114
|
}
|
|
99
115
|
this.send({
|
|
@@ -106,7 +122,7 @@ class GatewayClient {
|
|
|
106
122
|
}
|
|
107
123
|
sendOneShotMessage(channel, data) {
|
|
108
124
|
if (!this.isConnected()) {
|
|
109
|
-
this.connect();
|
|
125
|
+
void this.connect();
|
|
110
126
|
return;
|
|
111
127
|
}
|
|
112
128
|
this.send({
|
|
@@ -248,7 +264,7 @@ class GatewayClient {
|
|
|
248
264
|
}
|
|
249
265
|
this.reconnectTimer = setTimeout(() => {
|
|
250
266
|
this.reconnectTimer = null;
|
|
251
|
-
this.connect();
|
|
267
|
+
void this.connect();
|
|
252
268
|
}, 1000);
|
|
253
269
|
}
|
|
254
270
|
channelKey(channel) {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import type { AuthConfig } from "../auth/build-auth";
|
|
2
|
+
import type { DooverAuth } from "../auth/doover-auth";
|
|
3
|
+
export interface DooverClientConfig extends AuthConfig {
|
|
2
4
|
dataRestUrl: string;
|
|
3
5
|
controlApiUrl: string;
|
|
4
6
|
dataWssUrl: string;
|
|
@@ -7,6 +9,10 @@ export interface DooverClientConfig {
|
|
|
7
9
|
impersonateUserStorageKey?: string;
|
|
8
10
|
fetchImpl?: typeof fetch;
|
|
9
11
|
webSocketImpl?: typeof WebSocket;
|
|
12
|
+
webSocketFactory?: (options: {
|
|
13
|
+
url: string;
|
|
14
|
+
headers?: Record<string, string>;
|
|
15
|
+
}) => WebSocket;
|
|
10
16
|
}
|
|
11
17
|
export interface RequestOptions {
|
|
12
18
|
baseUrl?: string;
|
|
@@ -20,8 +26,9 @@ export interface RequestOptions {
|
|
|
20
26
|
type QueryValue = string | number | boolean | null | undefined | Array<string | number | boolean>;
|
|
21
27
|
type QueryParams = Record<string, QueryValue> | object;
|
|
22
28
|
export declare class RestClient {
|
|
23
|
-
readonly config: Required<Pick<DooverClientConfig, "dataRestUrl" | "controlApiUrl" | "dataWssUrl" | "sharing" | "impersonateUserStorageKey">> & Pick<DooverClientConfig, "organisationId" | "fetchImpl" | "webSocketImpl">;
|
|
24
|
-
|
|
29
|
+
readonly config: Required<Pick<DooverClientConfig, "dataRestUrl" | "controlApiUrl" | "dataWssUrl" | "sharing" | "impersonateUserStorageKey">> & Pick<DooverClientConfig, "organisationId" | "fetchImpl" | "webSocketImpl" | "webSocketFactory">;
|
|
30
|
+
readonly auth: DooverAuth | null;
|
|
31
|
+
constructor(config: DooverClientConfig, auth?: DooverAuth);
|
|
25
32
|
request<T>(options: RequestOptions): Promise<T>;
|
|
26
33
|
get<T>(path: string, query?: RequestOptions["query"], baseUrl?: string): Promise<T>;
|
|
27
34
|
post<T>(path: string, body?: RequestOptions["body"], query?: RequestOptions["query"], baseUrl?: string): Promise<T>;
|
package/dist/http/rest-client.js
CHANGED
|
@@ -3,19 +3,30 @@ 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
7
|
this.config = {
|
|
8
8
|
...config,
|
|
9
9
|
sharing: config.sharing ?? "internal",
|
|
10
10
|
organisationId: config.organisationId ?? null,
|
|
11
11
|
impersonateUserStorageKey: config.impersonateUserStorageKey ?? "impersonate_user_id",
|
|
12
12
|
};
|
|
13
|
+
this.auth = auth ?? null;
|
|
13
14
|
}
|
|
14
15
|
async request(options) {
|
|
16
|
+
if (this.auth) {
|
|
17
|
+
await this.auth.ensureReady();
|
|
18
|
+
}
|
|
15
19
|
const method = options.method ?? "GET";
|
|
16
20
|
const url = this.buildUrl(options.baseUrl ?? this.config.dataRestUrl, options.path, options.query);
|
|
17
21
|
const headers = new Headers(options.headers);
|
|
18
22
|
const body = this.normalizeBody(options.body, headers);
|
|
23
|
+
// Merge auth headers.
|
|
24
|
+
if (this.auth) {
|
|
25
|
+
const authHeaders = await this.auth.getHttpHeaders();
|
|
26
|
+
for (const [key, value] of Object.entries(authHeaders)) {
|
|
27
|
+
headers.set(key, value);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
19
30
|
if (!options.omitSharingHeader) {
|
|
20
31
|
headers.set("X-Doover-Sharing", this.config.sharing);
|
|
21
32
|
}
|
|
@@ -26,12 +37,15 @@ class RestClient {
|
|
|
26
37
|
if (impersonated) {
|
|
27
38
|
headers.set("X-Doover-Assume", impersonated);
|
|
28
39
|
}
|
|
40
|
+
const credentials = this.auth
|
|
41
|
+
? this.auth.getFetchCredentials()
|
|
42
|
+
: "include";
|
|
29
43
|
const fetchImpl = this.config.fetchImpl ?? fetch;
|
|
30
44
|
const response = await fetchImpl(url, {
|
|
31
45
|
method,
|
|
32
46
|
headers,
|
|
33
47
|
body,
|
|
34
|
-
credentials
|
|
48
|
+
credentials,
|
|
35
49
|
});
|
|
36
50
|
const payload = await this.parseResponse(response);
|
|
37
51
|
if (!response.ok) {
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,15 @@ export { NotificationsApi } from "./apis/notifications-api";
|
|
|
9
9
|
export { PermissionsApi } from "./apis/permissions-api";
|
|
10
10
|
export { ProcessorsApi } from "./apis/processors-api";
|
|
11
11
|
export { TurnApi } from "./apis/turn-api";
|
|
12
|
+
export { DooverAuth } from "./auth/doover-auth";
|
|
13
|
+
export { CookieAuth } from "./auth/cookie-auth";
|
|
14
|
+
export { DooverTokenAuth } from "./auth/doover-token-auth";
|
|
15
|
+
export { AuthProfile } from "./auth/auth-profile";
|
|
16
|
+
export type { AuthProfileData } from "./auth/auth-profile";
|
|
17
|
+
export type { AuthProfileStore } from "./auth/auth-store";
|
|
18
|
+
export { DooverAuthError } from "./auth/errors";
|
|
19
|
+
export { buildAuth } from "./auth/build-auth";
|
|
20
|
+
export type { AuthConfig } from "./auth/build-auth";
|
|
12
21
|
export { GatewayClient } from "./gateway/gateway-client";
|
|
13
22
|
export type * from "./gateway/types";
|
|
14
23
|
export { RestClient } from "./http/rest-client";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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.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
6
|
var agents_api_1 = require("./apis/agents-api");
|
|
@@ -23,14 +23,26 @@ var processors_api_1 = require("./apis/processors-api");
|
|
|
23
23
|
Object.defineProperty(exports, "ProcessorsApi", { enumerable: true, get: function () { return processors_api_1.ProcessorsApi; } });
|
|
24
24
|
var turn_api_1 = require("./apis/turn-api");
|
|
25
25
|
Object.defineProperty(exports, "TurnApi", { enumerable: true, get: function () { return turn_api_1.TurnApi; } });
|
|
26
|
+
var doover_auth_1 = require("./auth/doover-auth");
|
|
27
|
+
Object.defineProperty(exports, "DooverAuth", { enumerable: true, get: function () { return doover_auth_1.DooverAuth; } });
|
|
28
|
+
var cookie_auth_1 = require("./auth/cookie-auth");
|
|
29
|
+
Object.defineProperty(exports, "CookieAuth", { enumerable: true, get: function () { return cookie_auth_1.CookieAuth; } });
|
|
30
|
+
var doover_token_auth_1 = require("./auth/doover-token-auth");
|
|
31
|
+
Object.defineProperty(exports, "DooverTokenAuth", { enumerable: true, get: function () { return doover_token_auth_1.DooverTokenAuth; } });
|
|
32
|
+
var auth_profile_1 = require("./auth/auth-profile");
|
|
33
|
+
Object.defineProperty(exports, "AuthProfile", { enumerable: true, get: function () { return auth_profile_1.AuthProfile; } });
|
|
34
|
+
var errors_1 = require("./auth/errors");
|
|
35
|
+
Object.defineProperty(exports, "DooverAuthError", { enumerable: true, get: function () { return errors_1.DooverAuthError; } });
|
|
36
|
+
var build_auth_1 = require("./auth/build-auth");
|
|
37
|
+
Object.defineProperty(exports, "buildAuth", { enumerable: true, get: function () { return build_auth_1.buildAuth; } });
|
|
26
38
|
var gateway_client_1 = require("./gateway/gateway-client");
|
|
27
39
|
Object.defineProperty(exports, "GatewayClient", { enumerable: true, get: function () { return gateway_client_1.GatewayClient; } });
|
|
28
40
|
var rest_client_1 = require("./http/rest-client");
|
|
29
41
|
Object.defineProperty(exports, "RestClient", { enumerable: true, get: function () { return rest_client_1.RestClient; } });
|
|
30
|
-
var
|
|
31
|
-
Object.defineProperty(exports, "DooverApiError", { enumerable: true, get: function () { return
|
|
32
|
-
Object.defineProperty(exports, "DooverGatewayError", { enumerable: true, get: function () { return
|
|
33
|
-
Object.defineProperty(exports, "DooverValidationError", { enumerable: true, get: function () { return
|
|
42
|
+
var errors_2 = require("./http/errors");
|
|
43
|
+
Object.defineProperty(exports, "DooverApiError", { enumerable: true, get: function () { return errors_2.DooverApiError; } });
|
|
44
|
+
Object.defineProperty(exports, "DooverGatewayError", { enumerable: true, get: function () { return errors_2.DooverGatewayError; } });
|
|
45
|
+
Object.defineProperty(exports, "DooverValidationError", { enumerable: true, get: function () { return errors_2.DooverValidationError; } });
|
|
34
46
|
var doover_data_provider_1 = require("./viewer/doover-data-provider");
|
|
35
47
|
Object.defineProperty(exports, "DooverDataProvider", { enumerable: true, get: function () { return doover_data_provider_1.DooverDataProvider; } });
|
|
36
48
|
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
|
+
}
|