doover-js 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -10
- package/dist/apis/connections-api.d.ts +6 -0
- package/dist/apis/connections-api.js +8 -0
- package/dist/auth/auth-profile.d.ts +45 -0
- package/dist/auth/auth-profile.js +72 -0
- package/dist/auth/auth-store.d.ts +14 -0
- package/dist/auth/auth-store.js +2 -0
- package/dist/auth/build-auth.d.ts +37 -0
- package/dist/auth/build-auth.js +75 -0
- package/dist/auth/cookie-auth.d.ts +17 -0
- package/dist/auth/cookie-auth.js +29 -0
- package/dist/auth/doover-auth.d.ts +41 -0
- package/dist/auth/doover-auth.js +24 -0
- package/dist/auth/doover-token-auth.d.ts +35 -0
- package/dist/auth/doover-token-auth.js +178 -0
- package/dist/auth/errors.d.ts +3 -0
- package/dist/auth/errors.js +10 -0
- package/dist/auth/jwt.d.ts +6 -0
- package/dist/auth/jwt.js +29 -0
- package/dist/client/doover-client.d.ts +15 -0
- package/dist/client/doover-client.js +45 -4
- package/dist/client/singleton.d.ts +26 -0
- package/dist/client/singleton.js +59 -0
- package/dist/client/stats.d.ts +55 -0
- package/dist/client/stats.js +97 -0
- package/dist/gateway/gateway-client.d.ts +34 -8
- package/dist/gateway/gateway-client.js +147 -52
- package/dist/gateway/types.d.ts +0 -1
- package/dist/http/rest-client.d.ts +21 -3
- package/dist/http/rest-client.js +33 -2
- package/dist/index.d.ts +12 -0
- package/dist/index.js +23 -5
- package/dist/node/config-manager.d.ts +34 -0
- package/dist/node/config-manager.js +177 -0
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +5 -0
- package/dist/react/context.d.ts +19 -0
- package/dist/react/context.js +28 -0
- package/dist/react/index.d.ts +24 -0
- package/dist/react/index.js +40 -0
- package/dist/react/sharedQueryClient.d.ts +21 -0
- package/dist/react/sharedQueryClient.js +39 -0
- package/dist/react/useAgentChannel.d.ts +7 -0
- package/dist/react/useAgentChannel.js +12 -0
- package/dist/react/useAgentConnections.d.ts +8 -0
- package/dist/react/useAgentConnections.js +24 -0
- package/dist/react/useChannelAggregate.d.ts +13 -0
- package/dist/react/useChannelAggregate.js +38 -0
- package/dist/react/useChannelMessages.d.ts +23 -0
- package/dist/react/useChannelMessages.js +56 -0
- package/dist/react/useChannelSubscription.d.ts +16 -0
- package/dist/react/useChannelSubscription.js +43 -0
- package/dist/react/useConnectionState.d.ts +21 -0
- package/dist/react/useConnectionState.js +43 -0
- package/dist/react/useMultiAgentAggregates.d.ts +22 -0
- package/dist/react/useMultiAgentAggregates.js +82 -0
- package/dist/react/useMultiAgentChannelMessages.d.ts +18 -0
- package/dist/react/useMultiAgentChannelMessages.js +78 -0
- package/dist/react/useSendMessage.d.ts +9 -0
- package/dist/react/useSendMessage.js +16 -0
- package/dist/react/useSendRpc.d.ts +61 -0
- package/dist/react/useSendRpc.js +158 -0
- package/dist/react/useTurnCredentials.d.ts +12 -0
- package/dist/react/useTurnCredentials.js +25 -0
- package/dist/react/useUpdateAggregate.d.ts +14 -0
- package/dist/react/useUpdateAggregate.js +25 -0
- package/dist/react/useUpdateMessage.d.ts +17 -0
- package/dist/react/useUpdateMessage.js +24 -0
- package/dist/test/apis.test.js +7 -1
- package/dist/test/auth.test.d.ts +1 -0
- package/dist/test/auth.test.js +502 -0
- package/dist/test/config-manager.test.d.ts +1 -0
- package/dist/test/config-manager.test.js +160 -0
- package/dist/test/doover-client.test.js +13 -0
- package/dist/test/doover-data-provider.test.js +155 -0
- package/dist/test/gateway-client.test.js +122 -8
- package/dist/test/react.test.d.ts +1 -0
- package/dist/test/react.test.js +353 -0
- package/dist/test/singleton.test.d.ts +1 -0
- package/dist/test/singleton.test.js +62 -0
- package/dist/types/common.d.ts +40 -0
- package/dist/viewer/doover-data-provider.d.ts +34 -5
- package/dist/viewer/doover-data-provider.js +96 -9
- package/package.json +33 -2
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const chai_1 = require("chai");
|
|
7
|
+
const chai_as_promised_1 = __importDefault(require("chai-as-promised"));
|
|
8
|
+
const mocha_1 = require("mocha");
|
|
9
|
+
const sinon_1 = __importDefault(require("sinon"));
|
|
10
|
+
const auth_profile_1 = require("../auth/auth-profile");
|
|
11
|
+
const build_auth_1 = require("../auth/build-auth");
|
|
12
|
+
const cookie_auth_1 = require("../auth/cookie-auth");
|
|
13
|
+
const doover_token_auth_1 = require("../auth/doover-token-auth");
|
|
14
|
+
const errors_1 = require("../auth/errors");
|
|
15
|
+
const jwt_1 = require("../auth/jwt");
|
|
16
|
+
const doover_client_1 = require("../client/doover-client");
|
|
17
|
+
const gateway_client_1 = require("../gateway/gateway-client");
|
|
18
|
+
const rest_client_1 = require("../http/rest-client");
|
|
19
|
+
const helpers_1 = require("./helpers");
|
|
20
|
+
(0, chai_1.use)(chai_as_promised_1.default);
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Helper: create a minimal JWT with a given `exp` claim
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
function makeJwt(exp) {
|
|
25
|
+
const header = Buffer.from(JSON.stringify({ alg: "HS256" })).toString("base64url");
|
|
26
|
+
const payload = Buffer.from(JSON.stringify({ exp })).toString("base64url");
|
|
27
|
+
return `${header}.${payload}.fakesig`;
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Helper: in-memory AuthProfileStore
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
class MemoryProfileStore {
|
|
33
|
+
constructor() {
|
|
34
|
+
this.currentProfile = null;
|
|
35
|
+
this.current = null;
|
|
36
|
+
this.profiles = new Map();
|
|
37
|
+
this.writeCalled = 0;
|
|
38
|
+
}
|
|
39
|
+
get(name) {
|
|
40
|
+
return this.profiles.get(name);
|
|
41
|
+
}
|
|
42
|
+
create(entry) {
|
|
43
|
+
this.profiles.set(entry.profile, entry);
|
|
44
|
+
}
|
|
45
|
+
delete(name) {
|
|
46
|
+
this.profiles.delete(name);
|
|
47
|
+
}
|
|
48
|
+
write() {
|
|
49
|
+
this.writeCalled++;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// CookieAuth
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
(0, mocha_1.describe)("CookieAuth", () => {
|
|
56
|
+
(0, mocha_1.it)("sends no auth header and uses credentials: include", async () => {
|
|
57
|
+
const auth = new cookie_auth_1.CookieAuth();
|
|
58
|
+
(0, chai_1.expect)(await auth.getHttpHeaders()).to.deep.equal({});
|
|
59
|
+
(0, chai_1.expect)(auth.getFetchCredentials()).to.equal("include");
|
|
60
|
+
});
|
|
61
|
+
(0, mocha_1.it)("prepareWebSocket returns the URL unchanged", async () => {
|
|
62
|
+
const auth = new cookie_auth_1.CookieAuth();
|
|
63
|
+
const result = await auth.prepareWebSocket("wss://example.com/ws", true);
|
|
64
|
+
(0, chai_1.expect)(result).to.deep.equal({ url: "wss://example.com/ws" });
|
|
65
|
+
});
|
|
66
|
+
(0, mocha_1.it)("ensureReady resolves immediately", async () => {
|
|
67
|
+
const auth = new cookie_auth_1.CookieAuth();
|
|
68
|
+
await auth.ensureReady(); // should not throw
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// DooverTokenAuth
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
(0, mocha_1.describe)("DooverTokenAuth", () => {
|
|
75
|
+
(0, mocha_1.afterEach)(() => sinon_1.default.restore());
|
|
76
|
+
(0, mocha_1.it)("sends bearer header and uses credentials: omit", async () => {
|
|
77
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({ token: "tok123" });
|
|
78
|
+
(0, chai_1.expect)(await auth.getHttpHeaders()).to.deep.equal({
|
|
79
|
+
Authorization: "Bearer tok123",
|
|
80
|
+
});
|
|
81
|
+
(0, chai_1.expect)(auth.getFetchCredentials()).to.equal("omit");
|
|
82
|
+
});
|
|
83
|
+
(0, mocha_1.it)("returns empty headers when no token is set", async () => {
|
|
84
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({});
|
|
85
|
+
(0, chai_1.expect)(await auth.getHttpHeaders()).to.deep.equal({});
|
|
86
|
+
});
|
|
87
|
+
(0, mocha_1.it)("setToken updates the token", async () => {
|
|
88
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({ token: "old" });
|
|
89
|
+
auth.setToken("new-token");
|
|
90
|
+
(0, chai_1.expect)(await auth.getHttpHeaders()).to.deep.equal({
|
|
91
|
+
Authorization: "Bearer new-token",
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
// -- Refresh behaviour ----------------------------------------------------
|
|
95
|
+
(0, mocha_1.it)("does not refresh when token is clearly valid", async () => {
|
|
96
|
+
const farFuture = Date.now() + 3600000;
|
|
97
|
+
const fetchMock = (0, helpers_1.createFetchMock)();
|
|
98
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({
|
|
99
|
+
token: "valid",
|
|
100
|
+
tokenExpires: new Date(farFuture),
|
|
101
|
+
refreshToken: "rt",
|
|
102
|
+
authServerUrl: "https://auth.example.com",
|
|
103
|
+
authServerClientId: "client-1",
|
|
104
|
+
fetchImpl: fetchMock,
|
|
105
|
+
});
|
|
106
|
+
await auth.ensureReady();
|
|
107
|
+
(0, chai_1.expect)(fetchMock.callCount).to.equal(0);
|
|
108
|
+
});
|
|
109
|
+
(0, mocha_1.it)("triggers refresh when token is missing", async () => {
|
|
110
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => (0, helpers_1.createJsonResponse)({
|
|
111
|
+
access_token: "new-tok",
|
|
112
|
+
expires_in: 3600,
|
|
113
|
+
}));
|
|
114
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({
|
|
115
|
+
token: null,
|
|
116
|
+
refreshToken: "rt",
|
|
117
|
+
authServerUrl: "https://auth.example.com",
|
|
118
|
+
authServerClientId: "client-1",
|
|
119
|
+
fetchImpl: fetchMock,
|
|
120
|
+
});
|
|
121
|
+
await auth.ensureReady();
|
|
122
|
+
(0, chai_1.expect)(fetchMock.callCount).to.equal(1);
|
|
123
|
+
(0, chai_1.expect)(await auth.getHttpHeaders()).to.deep.equal({
|
|
124
|
+
Authorization: "Bearer new-tok",
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
(0, mocha_1.it)("triggers refresh within the 30-second expiry buffer", async () => {
|
|
128
|
+
const almostExpired = Date.now() + 15000; // 15 s left
|
|
129
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => (0, helpers_1.createJsonResponse)({
|
|
130
|
+
access_token: "refreshed-tok",
|
|
131
|
+
expires_in: 3600,
|
|
132
|
+
}));
|
|
133
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({
|
|
134
|
+
token: "old-tok",
|
|
135
|
+
tokenExpires: new Date(almostExpired),
|
|
136
|
+
refreshToken: "rt",
|
|
137
|
+
authServerUrl: "https://auth.example.com",
|
|
138
|
+
authServerClientId: "client-1",
|
|
139
|
+
fetchImpl: fetchMock,
|
|
140
|
+
});
|
|
141
|
+
await auth.ensureReady();
|
|
142
|
+
(0, chai_1.expect)(fetchMock.callCount).to.equal(1);
|
|
143
|
+
(0, chai_1.expect)(await auth.getHttpHeaders()).to.deep.equal({
|
|
144
|
+
Authorization: "Bearer refreshed-tok",
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
(0, mocha_1.it)("throws DooverAuthError when refresh metadata is incomplete", async () => {
|
|
148
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({
|
|
149
|
+
token: null,
|
|
150
|
+
// No refreshToken, authServerUrl, or authServerClientId
|
|
151
|
+
});
|
|
152
|
+
await (0, chai_1.expect)(auth.ensureReady()).to.be.rejectedWith(errors_1.DooverAuthError, /missing authServerUrl/);
|
|
153
|
+
});
|
|
154
|
+
(0, mocha_1.it)("throws DooverAuthError when refresh HTTP request fails", async () => {
|
|
155
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => (0, helpers_1.createJsonResponse)({ error: "invalid_grant" }, { status: 400 }));
|
|
156
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({
|
|
157
|
+
token: null,
|
|
158
|
+
refreshToken: "rt",
|
|
159
|
+
authServerUrl: "https://auth.example.com",
|
|
160
|
+
authServerClientId: "client-1",
|
|
161
|
+
fetchImpl: fetchMock,
|
|
162
|
+
});
|
|
163
|
+
await (0, chai_1.expect)(auth.ensureReady()).to.be.rejectedWith(errors_1.DooverAuthError, /status 400/);
|
|
164
|
+
});
|
|
165
|
+
(0, mocha_1.it)("writes refreshed token back to the attached ConfigManager", async () => {
|
|
166
|
+
const store = new MemoryProfileStore();
|
|
167
|
+
const profile = new auth_profile_1.AuthProfile({
|
|
168
|
+
profile: "test",
|
|
169
|
+
refreshToken: "rt",
|
|
170
|
+
authServerUrl: "https://auth.example.com",
|
|
171
|
+
authServerClientId: "client-1",
|
|
172
|
+
});
|
|
173
|
+
store.create(profile);
|
|
174
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => (0, helpers_1.createJsonResponse)({
|
|
175
|
+
access_token: "refreshed",
|
|
176
|
+
expires_in: 3600,
|
|
177
|
+
refresh_token: "new-rt",
|
|
178
|
+
}));
|
|
179
|
+
// Construct with no token so refresh is triggered
|
|
180
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({
|
|
181
|
+
refreshToken: "rt",
|
|
182
|
+
authServerUrl: "https://auth.example.com",
|
|
183
|
+
authServerClientId: "client-1",
|
|
184
|
+
fetchImpl: fetchMock,
|
|
185
|
+
});
|
|
186
|
+
auth.attachProfile(profile, store);
|
|
187
|
+
await auth.ensureReady();
|
|
188
|
+
(0, chai_1.expect)(profile.token).to.equal("refreshed");
|
|
189
|
+
(0, chai_1.expect)(profile.refreshToken).to.equal("new-rt");
|
|
190
|
+
(0, chai_1.expect)(store.writeCalled).to.equal(1);
|
|
191
|
+
});
|
|
192
|
+
// -- WebSocket auth -------------------------------------------------------
|
|
193
|
+
(0, mocha_1.it)("prepareWebSocket uses Authorization header when canUseHeaders is true", async () => {
|
|
194
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({ token: "ws-tok" });
|
|
195
|
+
const result = await auth.prepareWebSocket("wss://ws.example.com", true);
|
|
196
|
+
(0, chai_1.expect)(result.url).to.equal("wss://ws.example.com");
|
|
197
|
+
(0, chai_1.expect)(result.headers).to.deep.equal({
|
|
198
|
+
Authorization: "Bearer ws-tok",
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
(0, mocha_1.it)("prepareWebSocket appends ?token= when canUseHeaders is false", async () => {
|
|
202
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({ token: "ws-tok" });
|
|
203
|
+
const result = await auth.prepareWebSocket("wss://ws.example.com/path", false);
|
|
204
|
+
(0, chai_1.expect)(result.url).to.equal("wss://ws.example.com/path?token=ws-tok");
|
|
205
|
+
(0, chai_1.expect)(result.headers).to.be.undefined;
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
// JWT expiry decoding
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
(0, mocha_1.describe)("JWT decodeTokenExpiry", () => {
|
|
212
|
+
(0, mocha_1.it)("decodes token exp claim", () => {
|
|
213
|
+
const exp = Math.floor(Date.now() / 1000) + 3600;
|
|
214
|
+
const token = makeJwt(exp);
|
|
215
|
+
const result = (0, jwt_1.decodeTokenExpiry)(token);
|
|
216
|
+
(0, chai_1.expect)(result).to.be.instanceOf(Date);
|
|
217
|
+
(0, chai_1.expect)(result.getTime()).to.equal(exp * 1000);
|
|
218
|
+
});
|
|
219
|
+
(0, mocha_1.it)("returns null for tokens without exp", () => {
|
|
220
|
+
const header = Buffer.from(JSON.stringify({ alg: "HS256" })).toString("base64url");
|
|
221
|
+
const payload = Buffer.from(JSON.stringify({ sub: "user" })).toString("base64url");
|
|
222
|
+
(0, chai_1.expect)((0, jwt_1.decodeTokenExpiry)(`${header}.${payload}.sig`)).to.equal(null);
|
|
223
|
+
});
|
|
224
|
+
(0, mocha_1.it)("returns null for malformed tokens", () => {
|
|
225
|
+
(0, chai_1.expect)((0, jwt_1.decodeTokenExpiry)("not-a-jwt")).to.equal(null);
|
|
226
|
+
(0, chai_1.expect)((0, jwt_1.decodeTokenExpiry)("")).to.equal(null);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
// AuthProfile parse / dump
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
(0, mocha_1.describe)("AuthProfile", () => {
|
|
233
|
+
(0, mocha_1.it)("parses reduced-format config lines", () => {
|
|
234
|
+
const lines = [
|
|
235
|
+
"TOKEN=abc123",
|
|
236
|
+
"TOKEN_EXPIRES=2026-01-01T00:00:00.000Z",
|
|
237
|
+
"AGENT_ID=agent-1",
|
|
238
|
+
"BASE_URL=https://control.example.com",
|
|
239
|
+
"BASE_DATA_URL=https://data.example.com",
|
|
240
|
+
"REFRESH_TOKEN=rt-xyz",
|
|
241
|
+
"REFRESH_TOKEN_ID=rti-1",
|
|
242
|
+
"AUTH_SERVER_URL=https://auth.example.com",
|
|
243
|
+
"AUTH_SERVER_CLIENT_ID=client-1",
|
|
244
|
+
];
|
|
245
|
+
const profile = auth_profile_1.AuthProfile.parse("prod", lines);
|
|
246
|
+
(0, chai_1.expect)(profile.profile).to.equal("prod");
|
|
247
|
+
(0, chai_1.expect)(profile.token).to.equal("abc123");
|
|
248
|
+
(0, chai_1.expect)(profile.tokenExpires).to.equal("2026-01-01T00:00:00.000Z");
|
|
249
|
+
(0, chai_1.expect)(profile.agentId).to.equal("agent-1");
|
|
250
|
+
(0, chai_1.expect)(profile.controlBaseUrl).to.equal("https://control.example.com");
|
|
251
|
+
(0, chai_1.expect)(profile.dataBaseUrl).to.equal("https://data.example.com");
|
|
252
|
+
(0, chai_1.expect)(profile.refreshToken).to.equal("rt-xyz");
|
|
253
|
+
(0, chai_1.expect)(profile.refreshTokenId).to.equal("rti-1");
|
|
254
|
+
(0, chai_1.expect)(profile.authServerUrl).to.equal("https://auth.example.com");
|
|
255
|
+
(0, chai_1.expect)(profile.authServerClientId).to.equal("client-1");
|
|
256
|
+
});
|
|
257
|
+
(0, mocha_1.it)("dumps back to the same reduced format", () => {
|
|
258
|
+
const profile = new auth_profile_1.AuthProfile({
|
|
259
|
+
profile: "test",
|
|
260
|
+
token: "tok",
|
|
261
|
+
agentId: "a1",
|
|
262
|
+
refreshToken: "rt",
|
|
263
|
+
});
|
|
264
|
+
const dumped = profile.dump();
|
|
265
|
+
(0, chai_1.expect)(dumped).to.include("TOKEN=tok");
|
|
266
|
+
(0, chai_1.expect)(dumped).to.include("AGENT_ID=a1");
|
|
267
|
+
(0, chai_1.expect)(dumped).to.include("REFRESH_TOKEN=rt");
|
|
268
|
+
// Null fields should be absent
|
|
269
|
+
(0, chai_1.expect)(dumped).not.to.include("TOKEN_EXPIRES");
|
|
270
|
+
(0, chai_1.expect)(dumped).not.to.include("BASE_URL");
|
|
271
|
+
});
|
|
272
|
+
(0, mocha_1.it)("dumpBlock includes the [profile=...] header", () => {
|
|
273
|
+
const profile = new auth_profile_1.AuthProfile({ profile: "dev", token: "t1" });
|
|
274
|
+
const block = profile.dumpBlock();
|
|
275
|
+
(0, chai_1.expect)(block).to.match(/^\[profile=dev\]/);
|
|
276
|
+
(0, chai_1.expect)(block).to.include("TOKEN=t1");
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
// ---------------------------------------------------------------------------
|
|
280
|
+
// buildAuth
|
|
281
|
+
// ---------------------------------------------------------------------------
|
|
282
|
+
(0, mocha_1.describe)("buildAuth", () => {
|
|
283
|
+
(0, mocha_1.it)("returns provided auth as-is", () => {
|
|
284
|
+
const auth = new cookie_auth_1.CookieAuth();
|
|
285
|
+
(0, chai_1.expect)((0, build_auth_1.buildAuth)({ auth })).to.equal(auth);
|
|
286
|
+
});
|
|
287
|
+
(0, mocha_1.it)("throws when auth is combined with raw auth config", () => {
|
|
288
|
+
const auth = new cookie_auth_1.CookieAuth();
|
|
289
|
+
(0, chai_1.expect)(() => (0, build_auth_1.buildAuth)({ auth, token: "tok" })).to.throw(errors_1.DooverAuthError, /Cannot combine/);
|
|
290
|
+
});
|
|
291
|
+
(0, mocha_1.it)("builds CookieAuth when no token-related input is present", () => {
|
|
292
|
+
(0, chai_1.expect)((0, build_auth_1.buildAuth)({})).to.be.instanceOf(cookie_auth_1.CookieAuth);
|
|
293
|
+
});
|
|
294
|
+
(0, mocha_1.it)("builds DooverTokenAuth when token is provided", () => {
|
|
295
|
+
const auth = (0, build_auth_1.buildAuth)({ token: "tok" });
|
|
296
|
+
(0, chai_1.expect)(auth).to.be.instanceOf(doover_token_auth_1.DooverTokenAuth);
|
|
297
|
+
});
|
|
298
|
+
(0, mocha_1.it)("builds DooverTokenAuth from an AuthProfile with token", () => {
|
|
299
|
+
const profile = new auth_profile_1.AuthProfile({ profile: "test", token: "t1" });
|
|
300
|
+
const auth = (0, build_auth_1.buildAuth)({ profile });
|
|
301
|
+
(0, chai_1.expect)(auth).to.be.instanceOf(doover_token_auth_1.DooverTokenAuth);
|
|
302
|
+
});
|
|
303
|
+
(0, mocha_1.it)("explicit raw fields override profile-loaded values", async () => {
|
|
304
|
+
const profile = new auth_profile_1.AuthProfile({ profile: "test", token: "profile-tok" });
|
|
305
|
+
const auth = (0, build_auth_1.buildAuth)({ profile, token: "override-tok" });
|
|
306
|
+
(0, chai_1.expect)(auth).to.be.instanceOf(doover_token_auth_1.DooverTokenAuth);
|
|
307
|
+
(0, chai_1.expect)(await auth.getHttpHeaders()).to.deep.equal({
|
|
308
|
+
Authorization: "Bearer override-tok",
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
(0, mocha_1.it)("resolves a string profile via configManager", () => {
|
|
312
|
+
const store = new MemoryProfileStore();
|
|
313
|
+
store.create(new auth_profile_1.AuthProfile({ profile: "staging", token: "st" }));
|
|
314
|
+
const auth = (0, build_auth_1.buildAuth)({ profile: "staging", configManager: store });
|
|
315
|
+
(0, chai_1.expect)(auth).to.be.instanceOf(doover_token_auth_1.DooverTokenAuth);
|
|
316
|
+
});
|
|
317
|
+
(0, mocha_1.it)("throws when profile is a string without configManager", () => {
|
|
318
|
+
(0, chai_1.expect)(() => (0, build_auth_1.buildAuth)({ profile: "staging" })).to.throw(errors_1.DooverAuthError, /configManager/);
|
|
319
|
+
});
|
|
320
|
+
(0, mocha_1.it)("throws when string profile is not found in configManager", () => {
|
|
321
|
+
const store = new MemoryProfileStore();
|
|
322
|
+
(0, chai_1.expect)(() => (0, build_auth_1.buildAuth)({ profile: "nope", configManager: store })).to.throw(errors_1.DooverAuthError, /not found/);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
// ---------------------------------------------------------------------------
|
|
326
|
+
// DooverClient shared auth instance
|
|
327
|
+
// ---------------------------------------------------------------------------
|
|
328
|
+
(0, mocha_1.describe)("DooverClient auth sharing", () => {
|
|
329
|
+
(0, mocha_1.beforeEach)(() => {
|
|
330
|
+
(0, helpers_1.installSessionStorageMock)();
|
|
331
|
+
helpers_1.MockWebSocket.reset();
|
|
332
|
+
Object.defineProperty(globalThis, "WebSocket", {
|
|
333
|
+
value: helpers_1.MockWebSocket,
|
|
334
|
+
configurable: true,
|
|
335
|
+
writable: true,
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
(0, mocha_1.it)("shares one auth instance across REST and gateway", () => {
|
|
339
|
+
const client = new doover_client_1.DooverClient({
|
|
340
|
+
dataRestUrl: "https://api.example.com",
|
|
341
|
+
controlApiUrl: "https://control.example.com",
|
|
342
|
+
dataWssUrl: "wss://ws.example.com",
|
|
343
|
+
token: "shared-tok",
|
|
344
|
+
fetchImpl: (0, helpers_1.createFetchMock)(),
|
|
345
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
346
|
+
});
|
|
347
|
+
(0, chai_1.expect)(client.auth).to.be.instanceOf(doover_token_auth_1.DooverTokenAuth);
|
|
348
|
+
(0, chai_1.expect)(client.rest.auth).to.equal(client.auth);
|
|
349
|
+
// viewer's internal rest and gateway should also share the same auth
|
|
350
|
+
(0, chai_1.expect)(client.viewer.rest.auth).to.equal(client.auth);
|
|
351
|
+
});
|
|
352
|
+
(0, mocha_1.it)("defaults to CookieAuth when no auth inputs are provided", () => {
|
|
353
|
+
const client = new doover_client_1.DooverClient({
|
|
354
|
+
dataRestUrl: "https://api.example.com",
|
|
355
|
+
controlApiUrl: "https://control.example.com",
|
|
356
|
+
dataWssUrl: "wss://ws.example.com",
|
|
357
|
+
fetchImpl: (0, helpers_1.createFetchMock)(),
|
|
358
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
359
|
+
});
|
|
360
|
+
(0, chai_1.expect)(client.auth).to.be.instanceOf(cookie_auth_1.CookieAuth);
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
// ---------------------------------------------------------------------------
|
|
364
|
+
// GatewayClient auth integration
|
|
365
|
+
// ---------------------------------------------------------------------------
|
|
366
|
+
(0, mocha_1.describe)("GatewayClient auth integration", () => {
|
|
367
|
+
(0, mocha_1.beforeEach)(() => {
|
|
368
|
+
helpers_1.MockWebSocket.reset();
|
|
369
|
+
Object.defineProperty(globalThis, "WebSocket", {
|
|
370
|
+
value: helpers_1.MockWebSocket,
|
|
371
|
+
configurable: true,
|
|
372
|
+
writable: true,
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
(0, mocha_1.afterEach)(() => sinon_1.default.restore());
|
|
376
|
+
(0, mocha_1.it)("appends ?token= when using token auth without webSocketFactory", async () => {
|
|
377
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({ token: "gw-tok" });
|
|
378
|
+
const gw = new gateway_client_1.GatewayClient({
|
|
379
|
+
dataRestUrl: "https://api.example.com",
|
|
380
|
+
controlApiUrl: "https://control.example.com",
|
|
381
|
+
dataWssUrl: "wss://ws.example.com",
|
|
382
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
383
|
+
}, auth);
|
|
384
|
+
await gw.connect();
|
|
385
|
+
const ws = helpers_1.MockWebSocket.instances[0];
|
|
386
|
+
(0, chai_1.expect)(ws.url).to.equal("wss://ws.example.com/?token=gw-tok");
|
|
387
|
+
});
|
|
388
|
+
(0, mocha_1.it)("uses webSocketFactory with Authorization header for token auth", async () => {
|
|
389
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({ token: "factory-tok" });
|
|
390
|
+
let capturedHeaders;
|
|
391
|
+
const factory = (opts) => {
|
|
392
|
+
capturedHeaders = opts.headers;
|
|
393
|
+
return new helpers_1.MockWebSocket(opts.url);
|
|
394
|
+
};
|
|
395
|
+
const gw = new gateway_client_1.GatewayClient({
|
|
396
|
+
dataRestUrl: "https://api.example.com",
|
|
397
|
+
controlApiUrl: "https://control.example.com",
|
|
398
|
+
dataWssUrl: "wss://ws.example.com",
|
|
399
|
+
webSocketFactory: factory,
|
|
400
|
+
}, auth);
|
|
401
|
+
await gw.connect();
|
|
402
|
+
(0, chai_1.expect)(capturedHeaders).to.deep.equal({
|
|
403
|
+
Authorization: "Bearer factory-tok",
|
|
404
|
+
});
|
|
405
|
+
// URL should NOT have the token query param
|
|
406
|
+
const ws = helpers_1.MockWebSocket.instances[0];
|
|
407
|
+
(0, chai_1.expect)(ws.url).to.equal("wss://ws.example.com");
|
|
408
|
+
});
|
|
409
|
+
(0, mocha_1.it)("cookie auth leaves websocket URL unchanged", async () => {
|
|
410
|
+
const auth = new cookie_auth_1.CookieAuth();
|
|
411
|
+
const gw = new gateway_client_1.GatewayClient({
|
|
412
|
+
dataRestUrl: "https://api.example.com",
|
|
413
|
+
controlApiUrl: "https://control.example.com",
|
|
414
|
+
dataWssUrl: "wss://ws.example.com",
|
|
415
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
416
|
+
}, auth);
|
|
417
|
+
await gw.connect();
|
|
418
|
+
const ws = helpers_1.MockWebSocket.instances[0];
|
|
419
|
+
(0, chai_1.expect)(ws.url).to.equal("wss://ws.example.com");
|
|
420
|
+
});
|
|
421
|
+
(0, mocha_1.it)("reconnect uses newly refreshed token", async () => {
|
|
422
|
+
let callCount = 0;
|
|
423
|
+
const fetchMock = (0, helpers_1.createFetchMock)(() => {
|
|
424
|
+
callCount++;
|
|
425
|
+
return (0, helpers_1.createJsonResponse)({
|
|
426
|
+
access_token: `refreshed-${callCount}`,
|
|
427
|
+
expires_in: 3600,
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({
|
|
431
|
+
token: null,
|
|
432
|
+
refreshToken: "rt",
|
|
433
|
+
authServerUrl: "https://auth.example.com",
|
|
434
|
+
authServerClientId: "c1",
|
|
435
|
+
fetchImpl: fetchMock,
|
|
436
|
+
});
|
|
437
|
+
const gw = new gateway_client_1.GatewayClient({
|
|
438
|
+
dataRestUrl: "https://api.example.com",
|
|
439
|
+
controlApiUrl: "https://control.example.com",
|
|
440
|
+
dataWssUrl: "wss://ws.example.com",
|
|
441
|
+
webSocketImpl: helpers_1.MockWebSocket,
|
|
442
|
+
}, auth);
|
|
443
|
+
await gw.connect();
|
|
444
|
+
const ws1 = helpers_1.MockWebSocket.instances[0];
|
|
445
|
+
(0, chai_1.expect)(ws1.url).to.include("token=refreshed-1");
|
|
446
|
+
// Simulate disconnect + reconnect
|
|
447
|
+
gw.disconnect();
|
|
448
|
+
// Clear the token to force a re-refresh
|
|
449
|
+
auth.setToken(null);
|
|
450
|
+
await gw.connect();
|
|
451
|
+
const ws2 = helpers_1.MockWebSocket.instances[1];
|
|
452
|
+
(0, chai_1.expect)(ws2.url).to.include("token=refreshed-2");
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
// ---------------------------------------------------------------------------
|
|
456
|
+
// RestClient auth integration
|
|
457
|
+
// ---------------------------------------------------------------------------
|
|
458
|
+
(0, mocha_1.describe)("RestClient auth integration", () => {
|
|
459
|
+
(0, mocha_1.beforeEach)(() => (0, helpers_1.installSessionStorageMock)());
|
|
460
|
+
(0, mocha_1.it)("sends Authorization header with token auth", async () => {
|
|
461
|
+
const auth = new doover_token_auth_1.DooverTokenAuth({ token: "rest-tok" });
|
|
462
|
+
const fetchMock = (0, helpers_1.createFetchMock)();
|
|
463
|
+
const client = new rest_client_1.RestClient({
|
|
464
|
+
dataRestUrl: "https://api.example.com",
|
|
465
|
+
controlApiUrl: "https://control.example.com",
|
|
466
|
+
dataWssUrl: "wss://ws.example.com",
|
|
467
|
+
fetchImpl: fetchMock,
|
|
468
|
+
}, auth);
|
|
469
|
+
await client.get("/items");
|
|
470
|
+
const [, init] = fetchMock.getCall(0).args;
|
|
471
|
+
const headers = init?.headers;
|
|
472
|
+
(0, chai_1.expect)(headers.get("Authorization")).to.equal("Bearer rest-tok");
|
|
473
|
+
(0, chai_1.expect)(init?.credentials).to.equal("omit");
|
|
474
|
+
});
|
|
475
|
+
(0, mocha_1.it)("uses credentials: include with cookie auth", async () => {
|
|
476
|
+
const auth = new cookie_auth_1.CookieAuth();
|
|
477
|
+
const fetchMock = (0, helpers_1.createFetchMock)();
|
|
478
|
+
const client = new rest_client_1.RestClient({
|
|
479
|
+
dataRestUrl: "https://api.example.com",
|
|
480
|
+
controlApiUrl: "https://control.example.com",
|
|
481
|
+
dataWssUrl: "wss://ws.example.com",
|
|
482
|
+
fetchImpl: fetchMock,
|
|
483
|
+
}, auth);
|
|
484
|
+
await client.get("/items");
|
|
485
|
+
const [, init] = fetchMock.getCall(0).args;
|
|
486
|
+
const headers = init?.headers;
|
|
487
|
+
(0, chai_1.expect)(headers.get("Authorization")).to.equal(null);
|
|
488
|
+
(0, chai_1.expect)(init?.credentials).to.equal("include");
|
|
489
|
+
});
|
|
490
|
+
(0, mocha_1.it)("uses credentials: include when no auth is provided (backward compat)", async () => {
|
|
491
|
+
const fetchMock = (0, helpers_1.createFetchMock)();
|
|
492
|
+
const client = new rest_client_1.RestClient({
|
|
493
|
+
dataRestUrl: "https://api.example.com",
|
|
494
|
+
controlApiUrl: "https://control.example.com",
|
|
495
|
+
dataWssUrl: "wss://ws.example.com",
|
|
496
|
+
fetchImpl: fetchMock,
|
|
497
|
+
});
|
|
498
|
+
await client.get("/items");
|
|
499
|
+
const [, init] = fetchMock.getCall(0).args;
|
|
500
|
+
(0, chai_1.expect)(init?.credentials).to.equal("include");
|
|
501
|
+
});
|
|
502
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const chai_1 = require("chai");
|
|
37
|
+
const mocha_1 = require("mocha");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const os = __importStar(require("os"));
|
|
41
|
+
const config_manager_1 = require("../node/config-manager");
|
|
42
|
+
const auth_profile_1 = require("../auth/auth-profile");
|
|
43
|
+
function tmpConfigPath() {
|
|
44
|
+
return path.join(os.tmpdir(), `doover-test-${Date.now()}-${Math.random().toString(36).slice(2)}`, "config");
|
|
45
|
+
}
|
|
46
|
+
function cleanup(configPath) {
|
|
47
|
+
try {
|
|
48
|
+
fs.unlinkSync(configPath);
|
|
49
|
+
}
|
|
50
|
+
catch { /* ignore */ }
|
|
51
|
+
try {
|
|
52
|
+
fs.rmdirSync(path.dirname(configPath));
|
|
53
|
+
}
|
|
54
|
+
catch { /* ignore */ }
|
|
55
|
+
}
|
|
56
|
+
(0, mocha_1.describe)("ConfigManager", () => {
|
|
57
|
+
const paths = [];
|
|
58
|
+
(0, mocha_1.afterEach)(() => {
|
|
59
|
+
for (const p of paths) {
|
|
60
|
+
cleanup(p);
|
|
61
|
+
}
|
|
62
|
+
paths.length = 0;
|
|
63
|
+
});
|
|
64
|
+
(0, mocha_1.it)("starts empty when config file does not exist", () => {
|
|
65
|
+
const p = tmpConfigPath();
|
|
66
|
+
paths.push(p);
|
|
67
|
+
const mgr = new config_manager_1.ConfigManager(p);
|
|
68
|
+
(0, chai_1.expect)(mgr.currentProfile).to.equal(null);
|
|
69
|
+
(0, chai_1.expect)(mgr.current).to.equal(null);
|
|
70
|
+
(0, chai_1.expect)(mgr.get("any")).to.be.undefined;
|
|
71
|
+
});
|
|
72
|
+
(0, mocha_1.it)("parses a reduced-format Doover2 config file", () => {
|
|
73
|
+
const p = tmpConfigPath();
|
|
74
|
+
paths.push(p);
|
|
75
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
76
|
+
fs.writeFileSync(p, [
|
|
77
|
+
"[profile=prod]",
|
|
78
|
+
"TOKEN=abc123",
|
|
79
|
+
"AGENT_ID=agent-1",
|
|
80
|
+
"REFRESH_TOKEN=rt-xyz",
|
|
81
|
+
"AUTH_SERVER_URL=https://auth.example.com",
|
|
82
|
+
"AUTH_SERVER_CLIENT_ID=client-1",
|
|
83
|
+
"",
|
|
84
|
+
"[profile=staging]",
|
|
85
|
+
"TOKEN=stg-tok",
|
|
86
|
+
].join("\n"), "utf-8");
|
|
87
|
+
const mgr = new config_manager_1.ConfigManager(p);
|
|
88
|
+
(0, chai_1.expect)(mgr.currentProfile).to.equal("prod");
|
|
89
|
+
const prod = mgr.get("prod");
|
|
90
|
+
(0, chai_1.expect)(prod).to.not.be.undefined;
|
|
91
|
+
(0, chai_1.expect)(prod.token).to.equal("abc123");
|
|
92
|
+
(0, chai_1.expect)(prod.agentId).to.equal("agent-1");
|
|
93
|
+
(0, chai_1.expect)(prod.refreshToken).to.equal("rt-xyz");
|
|
94
|
+
const staging = mgr.get("staging");
|
|
95
|
+
(0, chai_1.expect)(staging).to.not.be.undefined;
|
|
96
|
+
(0, chai_1.expect)(staging.token).to.equal("stg-tok");
|
|
97
|
+
});
|
|
98
|
+
(0, mocha_1.it)("preserves legacy Doover1 blocks verbatim", () => {
|
|
99
|
+
const p = tmpConfigPath();
|
|
100
|
+
paths.push(p);
|
|
101
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
102
|
+
const legacyBlock = "[legacy-section]\nSOME_KEY=some_value\nOTHER=123";
|
|
103
|
+
fs.writeFileSync(p, `${legacyBlock}\n\n[profile=prod]\nTOKEN=t1\n`, "utf-8");
|
|
104
|
+
const mgr = new config_manager_1.ConfigManager(p);
|
|
105
|
+
mgr.write();
|
|
106
|
+
const written = fs.readFileSync(p, "utf-8");
|
|
107
|
+
// The legacy block should appear verbatim before the managed profile
|
|
108
|
+
(0, chai_1.expect)(written).to.include("[legacy-section]\nSOME_KEY=some_value\nOTHER=123");
|
|
109
|
+
(0, chai_1.expect)(written).to.include("[profile=prod]\nTOKEN=t1");
|
|
110
|
+
});
|
|
111
|
+
(0, mocha_1.it)("rewrites legacy Doover2 blocks back in reduced format", () => {
|
|
112
|
+
const p = tmpConfigPath();
|
|
113
|
+
paths.push(p);
|
|
114
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
115
|
+
fs.writeFileSync(p, "[profile=test]\nTOKEN=old\nAGENT_ID=a1\n", "utf-8");
|
|
116
|
+
const mgr = new config_manager_1.ConfigManager(p);
|
|
117
|
+
// Modify the profile
|
|
118
|
+
const profile = mgr.get("test");
|
|
119
|
+
profile.token = "new-token";
|
|
120
|
+
mgr.create(profile);
|
|
121
|
+
mgr.write();
|
|
122
|
+
const written = fs.readFileSync(p, "utf-8");
|
|
123
|
+
(0, chai_1.expect)(written).to.include("TOKEN=new-token");
|
|
124
|
+
(0, chai_1.expect)(written).to.include("AGENT_ID=a1");
|
|
125
|
+
});
|
|
126
|
+
(0, mocha_1.it)("write() creates the .doover directory if missing", () => {
|
|
127
|
+
const p = tmpConfigPath();
|
|
128
|
+
paths.push(p);
|
|
129
|
+
const mgr = new config_manager_1.ConfigManager(p);
|
|
130
|
+
const profile = new auth_profile_1.AuthProfile({ profile: "test", token: "t" });
|
|
131
|
+
mgr.create(profile);
|
|
132
|
+
mgr.write();
|
|
133
|
+
(0, chai_1.expect)(fs.existsSync(p)).to.equal(true);
|
|
134
|
+
const content = fs.readFileSync(p, "utf-8");
|
|
135
|
+
(0, chai_1.expect)(content).to.include("[profile=test]");
|
|
136
|
+
(0, chai_1.expect)(content).to.include("TOKEN=t");
|
|
137
|
+
});
|
|
138
|
+
(0, mocha_1.it)("delete removes a managed profile", () => {
|
|
139
|
+
const p = tmpConfigPath();
|
|
140
|
+
paths.push(p);
|
|
141
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
142
|
+
fs.writeFileSync(p, "[profile=a]\nTOKEN=1\n\n[profile=b]\nTOKEN=2\n", "utf-8");
|
|
143
|
+
const mgr = new config_manager_1.ConfigManager(p);
|
|
144
|
+
(0, chai_1.expect)(mgr.get("a")).to.not.be.undefined;
|
|
145
|
+
mgr.delete("a");
|
|
146
|
+
(0, chai_1.expect)(mgr.get("a")).to.be.undefined;
|
|
147
|
+
mgr.write();
|
|
148
|
+
const written = fs.readFileSync(p, "utf-8");
|
|
149
|
+
(0, chai_1.expect)(written).not.to.include("[profile=a]");
|
|
150
|
+
(0, chai_1.expect)(written).to.include("[profile=b]");
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
(0, mocha_1.describe)("doover-js/node exports", () => {
|
|
154
|
+
(0, mocha_1.it)("exports ConfigManager from the node subpath", () => {
|
|
155
|
+
// Verify the node subpath module re-exports ConfigManager
|
|
156
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
157
|
+
const nodeExports = require("../node/index");
|
|
158
|
+
(0, chai_1.expect)(nodeExports.ConfigManager).to.equal(config_manager_1.ConfigManager);
|
|
159
|
+
});
|
|
160
|
+
});
|