@alwaysmeticulous/client 2.308.0 → 2.311.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/dist/api/__tests__/agent.api.spec.js +69 -2
- package/dist/api/__tests__/agent.api.spec.js.map +1 -1
- package/dist/api/agent.api.d.ts +74 -2
- package/dist/api/agent.api.d.ts.map +1 -1
- package/dist/api/agent.api.js +58 -7
- package/dist/api/agent.api.js.map +1 -1
- package/dist/api/agentic-session-generation.api.d.ts +222 -0
- package/dist/api/agentic-session-generation.api.d.ts.map +1 -0
- package/dist/api/agentic-session-generation.api.js +109 -0
- package/dist/api/agentic-session-generation.api.js.map +1 -0
- package/dist/api/project-deployments.api.d.ts +21 -0
- package/dist/api/project-deployments.api.d.ts.map +1 -1
- package/dist/api/project-deployments.api.js +15 -14
- package/dist/api/project-deployments.api.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -4
- package/dist/index.js.map +1 -1
- package/dist/oauth/__tests__/oauth-device-login.spec.d.ts +2 -0
- package/dist/oauth/__tests__/oauth-device-login.spec.d.ts.map +1 -0
- package/dist/oauth/__tests__/oauth-device-login.spec.js +310 -0
- package/dist/oauth/__tests__/oauth-device-login.spec.js.map +1 -0
- package/dist/oauth/oauth-constants.d.ts +1 -0
- package/dist/oauth/oauth-constants.d.ts.map +1 -1
- package/dist/oauth/oauth-constants.js +23 -9
- package/dist/oauth/oauth-constants.js.map +1 -1
- package/dist/oauth/oauth-device-login.d.ts +3 -0
- package/dist/oauth/oauth-device-login.d.ts.map +1 -0
- package/dist/oauth/oauth-device-login.js +169 -0
- package/dist/oauth/oauth-device-login.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="4c9291f6-ed20-5fe9-8a45-7d2690d55b38")}catch(e){}}();
|
|
3
|
+
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
+
}) : function(o, v) {
|
|
18
|
+
o["default"] = v;
|
|
19
|
+
});
|
|
20
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
21
|
+
var ownKeys = function(o) {
|
|
22
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
23
|
+
var ar = [];
|
|
24
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
25
|
+
return ar;
|
|
26
|
+
};
|
|
27
|
+
return ownKeys(o);
|
|
28
|
+
};
|
|
29
|
+
return function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
const vitest_1 = require("vitest");
|
|
39
|
+
const oauth_pkce_1 = require("../oauth-pkce");
|
|
40
|
+
// Real performDeviceLogin() calls storeOAuthTokens() on success, which writes
|
|
41
|
+
// to ~/.meticulous/oauth-tokens.json. Mock it so the success-path tests below
|
|
42
|
+
// can't overwrite a developer's real login or fail with EPERM in locked-down CI.
|
|
43
|
+
vitest_1.vi.mock("../oauth-token-store", () => ({
|
|
44
|
+
storeOAuthTokens: vitest_1.vi.fn(),
|
|
45
|
+
}));
|
|
46
|
+
const DEVICE_AUTHORIZATION_ENDPOINT = "https://issuer.example/device";
|
|
47
|
+
const TOKEN_ENDPOINT = "https://issuer.example/token";
|
|
48
|
+
const jsonResponse = (status, body) => ({
|
|
49
|
+
ok: status >= 200 && status < 300,
|
|
50
|
+
status,
|
|
51
|
+
text: () => Promise.resolve(JSON.stringify(body)),
|
|
52
|
+
json: () => Promise.resolve(body),
|
|
53
|
+
});
|
|
54
|
+
const discoveryResponse = ({ omitDeviceAuthorizationEndpoint = false, } = {}) => jsonResponse(200, {
|
|
55
|
+
token_endpoint: TOKEN_ENDPOINT,
|
|
56
|
+
...(omitDeviceAuthorizationEndpoint
|
|
57
|
+
? {}
|
|
58
|
+
: { device_authorization_endpoint: DEVICE_AUTHORIZATION_ENDPOINT }),
|
|
59
|
+
});
|
|
60
|
+
const deviceAuthorizationResponse = ({ interval, expiresIn = 600, } = {}) => jsonResponse(200, {
|
|
61
|
+
device_code: "device-code-1",
|
|
62
|
+
user_code: "ABCD-EFGH",
|
|
63
|
+
verification_uri: DEVICE_AUTHORIZATION_ENDPOINT,
|
|
64
|
+
expires_in: expiresIn,
|
|
65
|
+
...(interval !== undefined ? { interval } : {}),
|
|
66
|
+
});
|
|
67
|
+
(0, vitest_1.describe)("performDeviceLogin", () => {
|
|
68
|
+
let fetchMock;
|
|
69
|
+
(0, vitest_1.beforeEach)(() => {
|
|
70
|
+
vitest_1.vi.resetModules();
|
|
71
|
+
vitest_1.vi.useFakeTimers();
|
|
72
|
+
fetchMock = vitest_1.vi.fn();
|
|
73
|
+
vitest_1.vi.stubGlobal("fetch", fetchMock);
|
|
74
|
+
});
|
|
75
|
+
(0, vitest_1.afterEach)(() => {
|
|
76
|
+
vitest_1.vi.useRealTimers();
|
|
77
|
+
vitest_1.vi.unstubAllGlobals();
|
|
78
|
+
});
|
|
79
|
+
const importPerformDeviceLogin = async () => {
|
|
80
|
+
const module = await Promise.resolve().then(() => __importStar(require("../oauth-device-login")));
|
|
81
|
+
return module.performDeviceLogin;
|
|
82
|
+
};
|
|
83
|
+
(0, vitest_1.it)("succeeds after a couple of pending polls", async () => {
|
|
84
|
+
fetchMock
|
|
85
|
+
.mockResolvedValueOnce(discoveryResponse())
|
|
86
|
+
.mockResolvedValueOnce(deviceAuthorizationResponse({ interval: 5 }))
|
|
87
|
+
.mockResolvedValueOnce(jsonResponse(400, { error: "authorization_pending" }))
|
|
88
|
+
.mockResolvedValueOnce(jsonResponse(400, { error: "authorization_pending" }))
|
|
89
|
+
.mockResolvedValueOnce(jsonResponse(200, {
|
|
90
|
+
access_token: "access-1",
|
|
91
|
+
refresh_token: "refresh-1",
|
|
92
|
+
expires_in: 300,
|
|
93
|
+
id_token: "id-1",
|
|
94
|
+
}));
|
|
95
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
96
|
+
const resultPromise = performDeviceLogin();
|
|
97
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
98
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
99
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
100
|
+
const tokens = await resultPromise;
|
|
101
|
+
(0, vitest_1.expect)(tokens.accessToken).toBe("access-1");
|
|
102
|
+
(0, vitest_1.expect)(tokens.refreshToken).toBe("refresh-1");
|
|
103
|
+
(0, vitest_1.expect)(tokens.idToken).toBe("id-1");
|
|
104
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(5);
|
|
105
|
+
const deviceAuthCall = fetchMock.mock.calls[1];
|
|
106
|
+
(0, vitest_1.expect)(deviceAuthCall?.[0]).toBe(DEVICE_AUTHORIZATION_ENDPOINT);
|
|
107
|
+
const deviceAuthBody = new URLSearchParams(deviceAuthCall?.[1]?.body);
|
|
108
|
+
const codeChallenge = deviceAuthBody.get("code_challenge");
|
|
109
|
+
(0, vitest_1.expect)(codeChallenge).toBeTruthy();
|
|
110
|
+
(0, vitest_1.expect)(deviceAuthBody.get("code_challenge_method")).toBe("S256");
|
|
111
|
+
const tokenCall = fetchMock.mock.calls[2];
|
|
112
|
+
(0, vitest_1.expect)(tokenCall?.[0]).toBe(TOKEN_ENDPOINT);
|
|
113
|
+
const tokenCallBody = new URLSearchParams(tokenCall?.[1]?.body);
|
|
114
|
+
(0, vitest_1.expect)(tokenCallBody.get("grant_type")).toBe("urn:ietf:params:oauth:grant-type:device_code");
|
|
115
|
+
const codeVerifier = tokenCallBody.get("code_verifier");
|
|
116
|
+
(0, vitest_1.expect)(codeVerifier).toBeTruthy();
|
|
117
|
+
(0, vitest_1.expect)((0, oauth_pkce_1.generateCodeChallenge)(codeVerifier ?? "")).toBe(codeChallenge);
|
|
118
|
+
});
|
|
119
|
+
(0, vitest_1.it)("increases the interval by 5s on slow_down and keeps polling", async () => {
|
|
120
|
+
fetchMock
|
|
121
|
+
.mockResolvedValueOnce(discoveryResponse())
|
|
122
|
+
.mockResolvedValueOnce(deviceAuthorizationResponse({ interval: 5 }))
|
|
123
|
+
.mockResolvedValueOnce(jsonResponse(400, { error: "slow_down" }))
|
|
124
|
+
.mockResolvedValueOnce(jsonResponse(200, {
|
|
125
|
+
access_token: "access-2",
|
|
126
|
+
refresh_token: "refresh-2",
|
|
127
|
+
expires_in: 300,
|
|
128
|
+
}));
|
|
129
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
130
|
+
const resultPromise = performDeviceLogin();
|
|
131
|
+
// First poll fires at t=5s (the initial interval) and returns slow_down,
|
|
132
|
+
// bumping the interval to 10s.
|
|
133
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
134
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(3);
|
|
135
|
+
// A poll at the old 5s cadence (t=10s) must NOT have fired yet, since the
|
|
136
|
+
// interval grew to 10s after the slow_down response.
|
|
137
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
138
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(3);
|
|
139
|
+
// The next poll happens once the full 10s interval has elapsed (t=15s).
|
|
140
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
141
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(4);
|
|
142
|
+
const tokens = await resultPromise;
|
|
143
|
+
(0, vitest_1.expect)(tokens.accessToken).toBe("access-2");
|
|
144
|
+
});
|
|
145
|
+
(0, vitest_1.it)("does not grow the interval on authorization_pending", async () => {
|
|
146
|
+
fetchMock
|
|
147
|
+
.mockResolvedValueOnce(discoveryResponse())
|
|
148
|
+
.mockResolvedValueOnce(deviceAuthorizationResponse({ interval: 5 }))
|
|
149
|
+
.mockResolvedValueOnce(jsonResponse(400, { error: "authorization_pending" }))
|
|
150
|
+
.mockResolvedValueOnce(jsonResponse(200, {
|
|
151
|
+
access_token: "access-3",
|
|
152
|
+
refresh_token: "refresh-3",
|
|
153
|
+
expires_in: 300,
|
|
154
|
+
}));
|
|
155
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
156
|
+
const resultPromise = performDeviceLogin();
|
|
157
|
+
// First poll fires at t=5s (the initial interval) and returns pending.
|
|
158
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
159
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(3);
|
|
160
|
+
// A poll at t=9s must NOT have fired yet, since a pending response leaves
|
|
161
|
+
// the 5s interval unchanged (unlike slow_down, which grows it).
|
|
162
|
+
await vitest_1.vi.advanceTimersByTimeAsync(4000);
|
|
163
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(3);
|
|
164
|
+
// The next poll happens once the unchanged 5s interval has elapsed (t=10s).
|
|
165
|
+
await vitest_1.vi.advanceTimersByTimeAsync(1000);
|
|
166
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(4);
|
|
167
|
+
const tokens = await resultPromise;
|
|
168
|
+
(0, vitest_1.expect)(tokens.accessToken).toBe("access-3");
|
|
169
|
+
});
|
|
170
|
+
(0, vitest_1.it)("throws a clear error when the user denies the login", async () => {
|
|
171
|
+
fetchMock
|
|
172
|
+
.mockResolvedValueOnce(discoveryResponse())
|
|
173
|
+
.mockResolvedValueOnce(deviceAuthorizationResponse({ interval: 5 }))
|
|
174
|
+
.mockResolvedValueOnce(jsonResponse(400, { error: "access_denied" }));
|
|
175
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
176
|
+
const resultPromise = performDeviceLogin();
|
|
177
|
+
const expectation = (0, vitest_1.expect)(resultPromise).rejects.toThrow("Login was denied.");
|
|
178
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
179
|
+
await expectation;
|
|
180
|
+
});
|
|
181
|
+
(0, vitest_1.it)("throws a clear error when the server reports the device code expired", async () => {
|
|
182
|
+
fetchMock
|
|
183
|
+
.mockResolvedValueOnce(discoveryResponse())
|
|
184
|
+
.mockResolvedValueOnce(deviceAuthorizationResponse({ interval: 5 }))
|
|
185
|
+
.mockResolvedValueOnce(jsonResponse(400, { error: "expired_token" }));
|
|
186
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
187
|
+
const resultPromise = performDeviceLogin();
|
|
188
|
+
const expectation = (0, vitest_1.expect)(resultPromise).rejects.toThrow("Device code expired, run login again.");
|
|
189
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
190
|
+
await expectation;
|
|
191
|
+
});
|
|
192
|
+
(0, vitest_1.it)("makes a final poll at the deadline before giving up locally", async () => {
|
|
193
|
+
fetchMock
|
|
194
|
+
.mockResolvedValueOnce(discoveryResponse())
|
|
195
|
+
.mockResolvedValueOnce(deviceAuthorizationResponse({ interval: 5, expiresIn: 8 }))
|
|
196
|
+
.mockResolvedValueOnce(jsonResponse(400, { error: "authorization_pending" }))
|
|
197
|
+
.mockResolvedValueOnce(jsonResponse(400, { error: "authorization_pending" }));
|
|
198
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
199
|
+
const resultPromise = performDeviceLogin();
|
|
200
|
+
const expectation = (0, vitest_1.expect)(resultPromise).rejects.toThrow("Device code expired, run login again.");
|
|
201
|
+
// First poll at t=5s: still within the 8s deadline.
|
|
202
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
203
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(3);
|
|
204
|
+
// Remaining lifetime is 3s, so the sleep is capped to that instead of the
|
|
205
|
+
// full 5s interval, and a final poll fires right at the t=8s deadline.
|
|
206
|
+
await vitest_1.vi.advanceTimersByTimeAsync(3000);
|
|
207
|
+
await expectation;
|
|
208
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(4);
|
|
209
|
+
});
|
|
210
|
+
(0, vitest_1.it)("succeeds when approval arrives after the last pending poll but before expiry", async () => {
|
|
211
|
+
fetchMock
|
|
212
|
+
.mockResolvedValueOnce(discoveryResponse())
|
|
213
|
+
.mockResolvedValueOnce(deviceAuthorizationResponse({ interval: 5, expiresIn: 8 }))
|
|
214
|
+
.mockResolvedValueOnce(jsonResponse(400, { error: "authorization_pending" }))
|
|
215
|
+
.mockResolvedValueOnce(jsonResponse(200, {
|
|
216
|
+
access_token: "access-late",
|
|
217
|
+
refresh_token: "refresh-late",
|
|
218
|
+
expires_in: 300,
|
|
219
|
+
}));
|
|
220
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
221
|
+
const resultPromise = performDeviceLogin();
|
|
222
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
223
|
+
await vitest_1.vi.advanceTimersByTimeAsync(3000);
|
|
224
|
+
const tokens = await resultPromise;
|
|
225
|
+
(0, vitest_1.expect)(tokens.accessToken).toBe("access-late");
|
|
226
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(4);
|
|
227
|
+
});
|
|
228
|
+
(0, vitest_1.it)("throws a clear error when the device authorization grant is not enabled on the realm", async () => {
|
|
229
|
+
fetchMock.mockResolvedValueOnce(discoveryResponse({ omitDeviceAuthorizationEndpoint: true }));
|
|
230
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
231
|
+
await (0, vitest_1.expect)(performDeviceLogin()).rejects.toThrow(/device_authorization_endpoint/);
|
|
232
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(1);
|
|
233
|
+
});
|
|
234
|
+
(0, vitest_1.it)("throws a clear error when Keycloak rejects the client as unauthorized for the device grant", async () => {
|
|
235
|
+
// Verified against a real Keycloak 26.2.5: discovery still advertises
|
|
236
|
+
// `device_authorization_endpoint` even when the grant is disabled on this
|
|
237
|
+
// specific client (it's realm-level, not per-client) — Keycloak instead
|
|
238
|
+
// rejects the device-authorization POST itself with `unauthorized_client`.
|
|
239
|
+
fetchMock.mockResolvedValueOnce(discoveryResponse()).mockResolvedValueOnce(jsonResponse(400, {
|
|
240
|
+
error: "unauthorized_client",
|
|
241
|
+
error_description: "Client is not allowed to initiate OAuth 2.0 Device Authorization Grant. The flow is disabled for the client.",
|
|
242
|
+
}));
|
|
243
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
244
|
+
await (0, vitest_1.expect)(performDeviceLogin()).rejects.toThrow(/not enabled for the meticulous-cli client/);
|
|
245
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(2);
|
|
246
|
+
});
|
|
247
|
+
(0, vitest_1.it)("throws a clear error when the device authorization response is missing expires_in", async () => {
|
|
248
|
+
fetchMock.mockResolvedValueOnce(discoveryResponse()).mockResolvedValueOnce(jsonResponse(200, {
|
|
249
|
+
device_code: "device-code-1",
|
|
250
|
+
user_code: "ABCD-EFGH",
|
|
251
|
+
verification_uri: DEVICE_AUTHORIZATION_ENDPOINT,
|
|
252
|
+
// expires_in omitted
|
|
253
|
+
}));
|
|
254
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
255
|
+
await (0, vitest_1.expect)(performDeviceLogin()).rejects.toThrow(/expires_in/);
|
|
256
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(2);
|
|
257
|
+
});
|
|
258
|
+
(0, vitest_1.it)("throws a clear error when the device authorization response is missing user_code", async () => {
|
|
259
|
+
fetchMock.mockResolvedValueOnce(discoveryResponse()).mockResolvedValueOnce(jsonResponse(200, {
|
|
260
|
+
device_code: "device-code-1",
|
|
261
|
+
verification_uri: DEVICE_AUTHORIZATION_ENDPOINT,
|
|
262
|
+
expires_in: 600,
|
|
263
|
+
}));
|
|
264
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
265
|
+
await (0, vitest_1.expect)(performDeviceLogin()).rejects.toThrow(/user_code/);
|
|
266
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(2);
|
|
267
|
+
});
|
|
268
|
+
(0, vitest_1.it)("tolerates a transient network error while polling and keeps going", async () => {
|
|
269
|
+
fetchMock
|
|
270
|
+
.mockResolvedValueOnce(discoveryResponse())
|
|
271
|
+
.mockResolvedValueOnce(deviceAuthorizationResponse({ interval: 5 }))
|
|
272
|
+
.mockRejectedValueOnce(new Error("network blip"))
|
|
273
|
+
.mockResolvedValueOnce(jsonResponse(200, {
|
|
274
|
+
access_token: "access-4",
|
|
275
|
+
refresh_token: "refresh-4",
|
|
276
|
+
expires_in: 300,
|
|
277
|
+
}));
|
|
278
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
279
|
+
const resultPromise = performDeviceLogin();
|
|
280
|
+
// The network error at t=5s doesn't grow the interval or abort the flow,
|
|
281
|
+
// so the next poll still fires at the unchanged 5s cadence (t=10s).
|
|
282
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
283
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(3);
|
|
284
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
285
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(4);
|
|
286
|
+
const tokens = await resultPromise;
|
|
287
|
+
(0, vitest_1.expect)(tokens.accessToken).toBe("access-4");
|
|
288
|
+
});
|
|
289
|
+
(0, vitest_1.it)("tolerates a transient 5xx from the token endpoint and keeps polling", async () => {
|
|
290
|
+
fetchMock
|
|
291
|
+
.mockResolvedValueOnce(discoveryResponse())
|
|
292
|
+
.mockResolvedValueOnce(deviceAuthorizationResponse({ interval: 5 }))
|
|
293
|
+
.mockResolvedValueOnce(jsonResponse(503, "Service Unavailable"))
|
|
294
|
+
.mockResolvedValueOnce(jsonResponse(200, {
|
|
295
|
+
access_token: "access-5",
|
|
296
|
+
refresh_token: "refresh-5",
|
|
297
|
+
expires_in: 300,
|
|
298
|
+
}));
|
|
299
|
+
const performDeviceLogin = await importPerformDeviceLogin();
|
|
300
|
+
const resultPromise = performDeviceLogin();
|
|
301
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
302
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(3);
|
|
303
|
+
await vitest_1.vi.advanceTimersByTimeAsync(5000);
|
|
304
|
+
(0, vitest_1.expect)(fetchMock).toHaveBeenCalledTimes(4);
|
|
305
|
+
const tokens = await resultPromise;
|
|
306
|
+
(0, vitest_1.expect)(tokens.accessToken).toBe("access-5");
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
//# sourceMappingURL=oauth-device-login.spec.js.map
|
|
310
|
+
//# debugId=4c9291f6-ed20-5fe9-8a45-7d2690d55b38
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-device-login.spec.js","sources":["../../../src/oauth/__tests__/oauth-device-login.spec.ts"],"sourceRoot":"","names":[],"mappings":"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","debugId":"4c9291f6-ed20-5fe9-8a45-7d2690d55b38"}
|
|
@@ -2,5 +2,6 @@ export declare const KEYCLOAK_ISSUER_URL: string;
|
|
|
2
2
|
export declare const CLI_CLIENT_ID = "meticulous-cli";
|
|
3
3
|
export declare const OAUTH_SCOPES = "openid email profile offline_access";
|
|
4
4
|
export declare const getTokenEndpoint: () => Promise<string>;
|
|
5
|
+
export declare const getDeviceAuthorizationEndpoint: () => Promise<string>;
|
|
5
6
|
export declare const getWebappBaseUrl: () => string;
|
|
6
7
|
//# sourceMappingURL=oauth-constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-constants.d.ts","sourceRoot":"","sources":["../../src/oauth/oauth-constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,QAEoB,CAAC;AAErD,eAAO,MAAM,aAAa,mBAAmB,CAAC;AAE9C,eAAO,MAAM,YAAY,wCAAwC,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth-constants.d.ts","sourceRoot":"","sources":["../../src/oauth/oauth-constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,QAEoB,CAAC;AAErD,eAAO,MAAM,aAAa,mBAAmB,CAAC;AAE9C,eAAO,MAAM,YAAY,wCAAwC,CAAC;AAgClE,eAAO,MAAM,gBAAgB,QAAa,OAAO,CAAC,MAAM,CAGvD,CAAC;AAEF,eAAO,MAAM,8BAA8B,QAAa,OAAO,CAAC,MAAM,CAUrE,CAAC;AAIF,eAAO,MAAM,gBAAgB,QAAO,MAenC,CAAC"}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="4836117c-ca38-52ca-af60-a97d89220835")}catch(e){}}();
|
|
3
3
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.getWebappBaseUrl = exports.getTokenEndpoint = exports.OAUTH_SCOPES = exports.CLI_CLIENT_ID = exports.KEYCLOAK_ISSUER_URL = void 0;
|
|
5
|
+
exports.getWebappBaseUrl = exports.getDeviceAuthorizationEndpoint = exports.getTokenEndpoint = exports.OAUTH_SCOPES = exports.CLI_CLIENT_ID = exports.KEYCLOAK_ISSUER_URL = void 0;
|
|
6
6
|
exports.KEYCLOAK_ISSUER_URL = process.env["METICULOUS_OAUTH_ISSUER_URL"] ||
|
|
7
7
|
"https://app.meticulous.ai/auth/realms/meticulous";
|
|
8
8
|
exports.CLI_CLIENT_ID = "meticulous-cli";
|
|
9
9
|
exports.OAUTH_SCOPES = "openid email profile offline_access";
|
|
10
10
|
const WELL_KNOWN_PATH = "/.well-known/openid-configuration";
|
|
11
|
-
let
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
14
|
-
return
|
|
11
|
+
let cachedOidcConfiguration = null;
|
|
12
|
+
const getOidcConfiguration = async () => {
|
|
13
|
+
if (cachedOidcConfiguration) {
|
|
14
|
+
return cachedOidcConfiguration;
|
|
15
15
|
}
|
|
16
16
|
const response = await fetch(`${exports.KEYCLOAK_ISSUER_URL}${WELL_KNOWN_PATH}`);
|
|
17
17
|
if (!response.ok) {
|
|
@@ -21,10 +21,24 @@ const getTokenEndpoint = async () => {
|
|
|
21
21
|
if (!config.token_endpoint) {
|
|
22
22
|
throw new Error("OpenID configuration missing token_endpoint");
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
return
|
|
24
|
+
cachedOidcConfiguration = config;
|
|
25
|
+
return cachedOidcConfiguration;
|
|
26
|
+
};
|
|
27
|
+
const getTokenEndpoint = async () => {
|
|
28
|
+
const config = await getOidcConfiguration();
|
|
29
|
+
return config.token_endpoint;
|
|
26
30
|
};
|
|
27
31
|
exports.getTokenEndpoint = getTokenEndpoint;
|
|
32
|
+
const getDeviceAuthorizationEndpoint = async () => {
|
|
33
|
+
const config = await getOidcConfiguration();
|
|
34
|
+
if (!config.device_authorization_endpoint) {
|
|
35
|
+
throw new Error("OpenID configuration missing device_authorization_endpoint. " +
|
|
36
|
+
"The OAuth 2.0 Device Authorization Grant is not enabled for the " +
|
|
37
|
+
`meticulous-cli client on this realm (${exports.KEYCLOAK_ISSUER_URL}).`);
|
|
38
|
+
}
|
|
39
|
+
return config.device_authorization_endpoint;
|
|
40
|
+
};
|
|
41
|
+
exports.getDeviceAuthorizationEndpoint = getDeviceAuthorizationEndpoint;
|
|
28
42
|
const DEFAULT_WEBAPP_BASE_URL = "https://app.meticulous.ai";
|
|
29
43
|
const getWebappBaseUrl = () => {
|
|
30
44
|
const apiUrlFromEnv = process.env["METICULOUS_API_URL"];
|
|
@@ -39,4 +53,4 @@ const getWebappBaseUrl = () => {
|
|
|
39
53
|
};
|
|
40
54
|
exports.getWebappBaseUrl = getWebappBaseUrl;
|
|
41
55
|
//# sourceMappingURL=oauth-constants.js.map
|
|
42
|
-
//# debugId=
|
|
56
|
+
//# debugId=4836117c-ca38-52ca-af60-a97d89220835
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-constants.js","sources":["../../src/oauth/oauth-constants.ts"],"sourceRoot":"","names":[],"mappings":";;;;;AAAa,QAAA,mBAAmB,GAC9B,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC;IAC1C,kDAAkD,CAAC;AAExC,QAAA,aAAa,GAAG,gBAAgB,CAAC;AAEjC,QAAA,YAAY,GAAG,qCAAqC,CAAC;AAElE,MAAM,eAAe,GAAG,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"oauth-constants.js","sources":["../../src/oauth/oauth-constants.ts"],"sourceRoot":"","names":[],"mappings":";;;;;AAAa,QAAA,mBAAmB,GAC9B,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC;IAC1C,kDAAkD,CAAC;AAExC,QAAA,aAAa,GAAG,gBAAgB,CAAC;AAEjC,QAAA,YAAY,GAAG,qCAAqC,CAAC;AAElE,MAAM,eAAe,GAAG,mCAAmC,CAAC;AAO5D,IAAI,uBAAuB,GAA6B,IAAI,CAAC;AAE7D,MAAM,oBAAoB,GAAG,KAAK,IAAgC,EAAE;IAClE,IAAI,uBAAuB,EAAE,CAAC;QAC5B,OAAO,uBAAuB,CAAC;IACjC,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,2BAAmB,GAAG,eAAe,EAAE,CAAC,CAAC;IACzE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CACb,yCAAyC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAClF,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAsB,CAAC;IAC5D,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IAED,uBAAuB,GAAG,MAAM,CAAC;IACjC,OAAO,uBAAuB,CAAC;AACjC,CAAC,CAAC;AAEK,MAAM,gBAAgB,GAAG,KAAK,IAAqB,EAAE;IAC1D,MAAM,MAAM,GAAG,MAAM,oBAAoB,EAAE,CAAC;IAC5C,OAAO,MAAM,CAAC,cAAc,CAAC;AAC/B,CAAC,CAAC;AAHW,QAAA,gBAAgB,oBAG3B;AAEK,MAAM,8BAA8B,GAAG,KAAK,IAAqB,EAAE;IACxE,MAAM,MAAM,GAAG,MAAM,oBAAoB,EAAE,CAAC;IAC5C,IAAI,CAAC,MAAM,CAAC,6BAA6B,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,8DAA8D;YAC5D,kEAAkE;YAClE,wCAAwC,2BAAmB,IAAI,CAClE,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,6BAA6B,CAAC;AAC9C,CAAC,CAAC;AAVW,QAAA,8BAA8B,kCAUzC;AAEF,MAAM,uBAAuB,GAAG,2BAA2B,CAAC;AAErD,MAAM,gBAAgB,GAAG,GAAW,EAAE;IAC3C,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAExD,IAAI,aAAa,IAAI,aAAa,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACzD,yEAAyE;QACzE,mCAAmC;QACnC,OAAO,aAAa;aACjB,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC;aACxB,OAAO,CACN,iBAAiB,EACjB,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,aAAa,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAClD,CAAC;IACN,CAAC;IAED,OAAO,uBAAuB,CAAC;AACjC,CAAC,CAAC;AAfW,QAAA,gBAAgB,oBAe3B","debugId":"4836117c-ca38-52ca-af60-a97d89220835"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-device-login.d.ts","sourceRoot":"","sources":["../../src/oauth/oauth-device-login.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AA2B7D,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,iBAAiB,CA+BpE,CAAC"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c23e572f-3089-543e-a18d-04649f6856ee")}catch(e){}}();
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.performDeviceLogin = void 0;
|
|
6
|
+
const common_1 = require("@alwaysmeticulous/common");
|
|
7
|
+
const oauth_constants_1 = require("./oauth-constants");
|
|
8
|
+
const oauth_pkce_1 = require("./oauth-pkce");
|
|
9
|
+
const oauth_token_store_1 = require("./oauth-token-store");
|
|
10
|
+
const DEFAULT_POLL_INTERVAL_SECONDS = 5;
|
|
11
|
+
const SLOW_DOWN_INCREMENT_SECONDS = 5;
|
|
12
|
+
const performDeviceLogin = async () => {
|
|
13
|
+
const logger = (0, common_1.initLogger)();
|
|
14
|
+
// PKCE binds the token poll to this process: Keycloak enforces the client's
|
|
15
|
+
// PKCE policy on the device authorization endpoint too.
|
|
16
|
+
const codeVerifier = (0, oauth_pkce_1.generateCodeVerifier)();
|
|
17
|
+
const authorization = await requestDeviceAuthorization({
|
|
18
|
+
codeChallenge: (0, oauth_pkce_1.generateCodeChallenge)(codeVerifier),
|
|
19
|
+
});
|
|
20
|
+
const webappBaseUrl = (0, oauth_constants_1.getWebappBaseUrl)();
|
|
21
|
+
const cliLoginParams = new URLSearchParams({
|
|
22
|
+
user_code: authorization.user_code,
|
|
23
|
+
issuer: oauth_constants_1.KEYCLOAK_ISSUER_URL,
|
|
24
|
+
});
|
|
25
|
+
logger.info(`On any device, open: ${webappBaseUrl}/cli-device-login?${cliLoginParams.toString()} ` +
|
|
26
|
+
`and confirm the code: ${authorization.user_code}`);
|
|
27
|
+
logger.info(authorization.verification_uri_complete
|
|
28
|
+
? `If that doesn't work, open ${authorization.verification_uri_complete}`
|
|
29
|
+
: `If that doesn't work, open ${authorization.verification_uri} and enter the code manually: ${authorization.user_code}`);
|
|
30
|
+
const tokens = await pollForTokens({ authorization, codeVerifier });
|
|
31
|
+
(0, oauth_token_store_1.storeOAuthTokens)(tokens);
|
|
32
|
+
logger.info("Authentication successful.");
|
|
33
|
+
return tokens;
|
|
34
|
+
};
|
|
35
|
+
exports.performDeviceLogin = performDeviceLogin;
|
|
36
|
+
const requestDeviceAuthorization = async ({ codeChallenge, }) => {
|
|
37
|
+
const deviceAuthorizationEndpoint = await (0, oauth_constants_1.getDeviceAuthorizationEndpoint)();
|
|
38
|
+
const body = new URLSearchParams({
|
|
39
|
+
client_id: oauth_constants_1.CLI_CLIENT_ID,
|
|
40
|
+
scope: oauth_constants_1.OAUTH_SCOPES,
|
|
41
|
+
code_challenge: codeChallenge,
|
|
42
|
+
code_challenge_method: "S256",
|
|
43
|
+
});
|
|
44
|
+
const response = await fetch(deviceAuthorizationEndpoint, {
|
|
45
|
+
method: "POST",
|
|
46
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
47
|
+
body: body.toString(),
|
|
48
|
+
});
|
|
49
|
+
const bodyText = await response.text();
|
|
50
|
+
if (!response.ok) {
|
|
51
|
+
// Discovery advertises `device_authorization_endpoint` at the realm level
|
|
52
|
+
// regardless of whether the grant is enabled on this specific client, so
|
|
53
|
+
// disabling it only on `meticulous-cli` isn't caught by
|
|
54
|
+
// `getDeviceAuthorizationEndpoint()`. Keycloak instead rejects the request
|
|
55
|
+
// itself with `unauthorized_client` — catch that here for the same clear
|
|
56
|
+
// message.
|
|
57
|
+
if (parseOAuthErrorCode(bodyText) === "unauthorized_client") {
|
|
58
|
+
throw new Error("The OAuth 2.0 Device Authorization Grant is not enabled for the " +
|
|
59
|
+
`meticulous-cli client on this realm (${oauth_constants_1.KEYCLOAK_ISSUER_URL}).`);
|
|
60
|
+
}
|
|
61
|
+
throw new Error(`Device authorization request failed: ${response.status} ${bodyText}`);
|
|
62
|
+
}
|
|
63
|
+
return parseDeviceAuthorizationResponse(bodyText);
|
|
64
|
+
};
|
|
65
|
+
const REQUIRED_DEVICE_AUTHORIZATION_STRING_FIELDS = [
|
|
66
|
+
"device_code",
|
|
67
|
+
"user_code",
|
|
68
|
+
"verification_uri",
|
|
69
|
+
];
|
|
70
|
+
const parseDeviceAuthorizationResponse = (bodyText) => {
|
|
71
|
+
const data = JSON.parse(bodyText);
|
|
72
|
+
for (const field of REQUIRED_DEVICE_AUTHORIZATION_STRING_FIELDS) {
|
|
73
|
+
if (typeof data[field] !== "string" || data[field].length === 0) {
|
|
74
|
+
throw new Error(`Device authorization response missing required field "${field}".`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (typeof data.expires_in !== "number" ||
|
|
78
|
+
!Number.isFinite(data.expires_in)) {
|
|
79
|
+
throw new Error('Device authorization response missing a valid "expires_in".');
|
|
80
|
+
}
|
|
81
|
+
return data;
|
|
82
|
+
};
|
|
83
|
+
const pollForTokens = async ({ authorization, codeVerifier, }) => {
|
|
84
|
+
const tokenEndpoint = await (0, oauth_constants_1.getTokenEndpoint)();
|
|
85
|
+
const deadline = Date.now() + authorization.expires_in * 1000;
|
|
86
|
+
let intervalSeconds = authorization.interval ?? DEFAULT_POLL_INTERVAL_SECONDS;
|
|
87
|
+
for (;;) {
|
|
88
|
+
const remainingMs = deadline - Date.now();
|
|
89
|
+
if (remainingMs <= 0) {
|
|
90
|
+
throw new Error("Device code expired, run login again.");
|
|
91
|
+
}
|
|
92
|
+
// Cap the sleep to the remaining lifetime so a final token request still
|
|
93
|
+
// fires before the local deadline, instead of giving up one interval early.
|
|
94
|
+
await sleep(Math.min(intervalSeconds * 1000, remainingMs));
|
|
95
|
+
const result = await requestDeviceToken({
|
|
96
|
+
tokenEndpoint,
|
|
97
|
+
deviceCode: authorization.device_code,
|
|
98
|
+
codeVerifier,
|
|
99
|
+
});
|
|
100
|
+
if (result.kind === "success") {
|
|
101
|
+
return result.tokens;
|
|
102
|
+
}
|
|
103
|
+
if (result.kind === "slow_down") {
|
|
104
|
+
intervalSeconds += SLOW_DOWN_INCREMENT_SECONDS;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const requestDeviceToken = async ({ tokenEndpoint, deviceCode, codeVerifier, }) => {
|
|
109
|
+
const body = new URLSearchParams({
|
|
110
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
111
|
+
device_code: deviceCode,
|
|
112
|
+
client_id: oauth_constants_1.CLI_CLIENT_ID,
|
|
113
|
+
code_verifier: codeVerifier,
|
|
114
|
+
});
|
|
115
|
+
let response;
|
|
116
|
+
let bodyText;
|
|
117
|
+
try {
|
|
118
|
+
response = await fetch(tokenEndpoint, {
|
|
119
|
+
method: "POST",
|
|
120
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
121
|
+
body: body.toString(),
|
|
122
|
+
});
|
|
123
|
+
bodyText = await response.text();
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Transient network blip: keep polling until the local deadline instead
|
|
127
|
+
// of aborting an otherwise-valid, in-progress login.
|
|
128
|
+
return { kind: "pending" };
|
|
129
|
+
}
|
|
130
|
+
if (response.ok) {
|
|
131
|
+
const data = JSON.parse(bodyText);
|
|
132
|
+
return { kind: "success", tokens: mapTokenResponse(data) };
|
|
133
|
+
}
|
|
134
|
+
if (response.status >= 500) {
|
|
135
|
+
// Transient server error (5xx): same reasoning as the network-error case.
|
|
136
|
+
return { kind: "pending" };
|
|
137
|
+
}
|
|
138
|
+
const errorCode = parseOAuthErrorCode(bodyText);
|
|
139
|
+
if (errorCode === "authorization_pending") {
|
|
140
|
+
return { kind: "pending" };
|
|
141
|
+
}
|
|
142
|
+
if (errorCode === "slow_down") {
|
|
143
|
+
return { kind: "slow_down" };
|
|
144
|
+
}
|
|
145
|
+
if (errorCode === "access_denied") {
|
|
146
|
+
throw new Error("Login was denied.");
|
|
147
|
+
}
|
|
148
|
+
if (errorCode === "expired_token") {
|
|
149
|
+
throw new Error("Device code expired, run login again.");
|
|
150
|
+
}
|
|
151
|
+
throw new Error(`Device token request failed: ${response.status} ${bodyText}`);
|
|
152
|
+
};
|
|
153
|
+
const parseOAuthErrorCode = (bodyText) => {
|
|
154
|
+
try {
|
|
155
|
+
return JSON.parse(bodyText).error;
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const mapTokenResponse = (data) => ({
|
|
162
|
+
accessToken: data.access_token,
|
|
163
|
+
refreshToken: data.refresh_token,
|
|
164
|
+
expiresAt: Math.floor(Date.now() / 1000) + data.expires_in,
|
|
165
|
+
idToken: data.id_token,
|
|
166
|
+
});
|
|
167
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
168
|
+
//# sourceMappingURL=oauth-device-login.js.map
|
|
169
|
+
//# debugId=c23e572f-3089-543e-a18d-04649f6856ee
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-device-login.js","sources":["../../src/oauth/oauth-device-login.ts"],"sourceRoot":"","names":[],"mappings":";;;;;AAAA,qDAAsD;AACtD,uDAO2B;AAC3B,6CAA2E;AAE3E,2DAAuD;AAEvD,MAAM,6BAA6B,GAAG,CAAC,CAAC;AACxC,MAAM,2BAA2B,GAAG,CAAC,CAAC;AAuB/B,MAAM,kBAAkB,GAAG,KAAK,IAAgC,EAAE;IACvE,MAAM,MAAM,GAAG,IAAA,mBAAU,GAAE,CAAC;IAE5B,4EAA4E;IAC5E,wDAAwD;IACxD,MAAM,YAAY,GAAG,IAAA,iCAAoB,GAAE,CAAC;IAC5C,MAAM,aAAa,GAAG,MAAM,0BAA0B,CAAC;QACrD,aAAa,EAAE,IAAA,kCAAqB,EAAC,YAAY,CAAC;KACnD,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,IAAA,kCAAgB,GAAE,CAAC;IACzC,MAAM,cAAc,GAAG,IAAI,eAAe,CAAC;QACzC,SAAS,EAAE,aAAa,CAAC,SAAS;QAClC,MAAM,EAAE,qCAAmB;KAC5B,CAAC,CAAC;IACH,MAAM,CAAC,IAAI,CACT,wBAAwB,aAAa,qBAAqB,cAAc,CAAC,QAAQ,EAAE,GAAG;QACpF,yBAAyB,aAAa,CAAC,SAAS,EAAE,CACrD,CAAC;IACF,MAAM,CAAC,IAAI,CACT,aAAa,CAAC,yBAAyB;QACrC,CAAC,CAAC,8BAA8B,aAAa,CAAC,yBAAyB,EAAE;QACzE,CAAC,CAAC,8BAA8B,aAAa,CAAC,gBAAgB,iCAAiC,aAAa,CAAC,SAAS,EAAE,CAC3H,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,CAAC;IAEpE,IAAA,oCAAgB,EAAC,MAAM,CAAC,CAAC;IACzB,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAE1C,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AA/BW,QAAA,kBAAkB,sBA+B7B;AAEF,MAAM,0BAA0B,GAAG,KAAK,EAAE,EACxC,aAAa,GAGd,EAAwC,EAAE;IACzC,MAAM,2BAA2B,GAAG,MAAM,IAAA,gDAA8B,GAAE,CAAC;IAE3E,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;QAC/B,SAAS,EAAE,+BAAa;QACxB,KAAK,EAAE,8BAAY;QACnB,cAAc,EAAE,aAAa;QAC7B,qBAAqB,EAAE,MAAM;KAC9B,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,2BAA2B,EAAE;QACxD,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;QAChE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;KACtB,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACvC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,0EAA0E;QAC1E,yEAAyE;QACzE,wDAAwD;QACxD,2EAA2E;QAC3E,yEAAyE;QACzE,WAAW;QACX,IAAI,mBAAmB,CAAC,QAAQ,CAAC,KAAK,qBAAqB,EAAE,CAAC;YAC5D,MAAM,IAAI,KAAK,CACb,kEAAkE;gBAChE,wCAAwC,qCAAmB,IAAI,CAClE,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,KAAK,CACb,wCAAwC,QAAQ,CAAC,MAAM,IAAI,QAAQ,EAAE,CACtE,CAAC;IACJ,CAAC;IAED,OAAO,gCAAgC,CAAC,QAAQ,CAAC,CAAC;AACpD,CAAC,CAAC;AAEF,MAAM,2CAA2C,GAAG;IAClD,aAAa;IACb,WAAW;IACX,kBAAkB;CACV,CAAC;AAEX,MAAM,gCAAgC,GAAG,CACvC,QAAgB,EACa,EAAE;IAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAyC,CAAC;IAE1E,KAAK,MAAM,KAAK,IAAI,2CAA2C,EAAE,CAAC;QAChE,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CACb,yDAAyD,KAAK,IAAI,CACnE,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IACE,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ;QACnC,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,EACjC,CAAC;QACD,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAED,OAAO,IAAmC,CAAC;AAC7C,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,KAAK,EAAE,EAC3B,aAAa,EACb,YAAY,GAIb,EAA8B,EAAE;IAC/B,MAAM,aAAa,GAAG,MAAM,IAAA,kCAAgB,GAAE,CAAC;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,UAAU,GAAG,IAAI,CAAC;IAC9D,IAAI,eAAe,GAAG,aAAa,CAAC,QAAQ,IAAI,6BAA6B,CAAC;IAE9E,SAAS,CAAC;QACR,MAAM,WAAW,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1C,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QAC3D,CAAC;QAED,yEAAyE;QACzE,4EAA4E;QAC5E,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,GAAG,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;QAE3D,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC;YACtC,aAAa;YACb,UAAU,EAAE,aAAa,CAAC,WAAW;YACrC,YAAY;SACb,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC9B,OAAO,MAAM,CAAC,MAAM,CAAC;QACvB,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAChC,eAAe,IAAI,2BAA2B,CAAC;QACjD,CAAC;IACH,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,KAAK,EAAE,EAChC,aAAa,EACb,UAAU,EACV,YAAY,GAKb,EAAkC,EAAE;IACnC,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC;QAC/B,UAAU,EAAE,8CAA8C;QAC1D,WAAW,EAAE,UAAU;QACvB,SAAS,EAAE,+BAAa;QACxB,aAAa,EAAE,YAAY;KAC5B,CAAC,CAAC;IAEH,IAAI,QAAkB,CAAC;IACvB,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE;YACpC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;SACtB,CAAC,CAAC;QACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,wEAAwE;QACxE,qDAAqD;QACrD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAA+B,CAAC;QAChE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC;IAC7D,CAAC;IAED,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;QAC3B,0EAA0E;QAC1E,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED,MAAM,SAAS,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAEhD,IAAI,SAAS,KAAK,uBAAuB,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC7B,CAAC;IACD,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;QAC9B,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;IAC/B,CAAC;IACD,IAAI,SAAS,KAAK,eAAe,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACvC,CAAC;IACD,IAAI,SAAS,KAAK,eAAe,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,IAAI,KAAK,CACb,gCAAgC,QAAQ,CAAC,MAAM,IAAI,QAAQ,EAAE,CAC9D,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,QAAgB,EAAsB,EAAE;IACnE,IAAI,CAAC;QACH,OAAQ,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAwB,CAAC,KAAK,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CACvB,IAAgC,EACb,EAAE,CAAC,CAAC;IACvB,WAAW,EAAE,IAAI,CAAC,YAAY;IAC9B,YAAY,EAAE,IAAI,CAAC,aAAa;IAChC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU;IAC1D,OAAO,EAAE,IAAI,CAAC,QAAQ;CACvB,CAAC,CAAC;AAEH,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE,CAC1C,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC","debugId":"c23e572f-3089-543e-a18d-04649f6856ee"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "2.
|
|
1
|
+
export declare const VERSION = "2.311.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
|
@@ -5,6 +5,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
5
5
|
exports.VERSION = void 0;
|
|
6
6
|
// AUTO-GENERATED by scripts/generate-version.mjs — do not edit by hand.
|
|
7
7
|
// Regenerated from package.json on every build.
|
|
8
|
-
exports.VERSION = "2.
|
|
8
|
+
exports.VERSION = "2.311.0";
|
|
9
9
|
//# sourceMappingURL=version.js.map
|
|
10
10
|
//# debugId=ac10f4cc-7a38-5615-8b9d-956b50ad79da
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alwaysmeticulous/client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.311.0",
|
|
4
4
|
"description": "Helper methods for using the Meticulous backend API",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"loglevel": "^1.8.0",
|
|
13
13
|
"proxy-agent": "^6.4.0",
|
|
14
14
|
"undici": "^6.24.1",
|
|
15
|
-
"@alwaysmeticulous/
|
|
16
|
-
"@alwaysmeticulous/
|
|
15
|
+
"@alwaysmeticulous/common": "2.310.0",
|
|
16
|
+
"@alwaysmeticulous/api": "2.310.0"
|
|
17
17
|
},
|
|
18
18
|
"author": {
|
|
19
19
|
"name": "The Meticulous Team",
|