@walkeros/cli 4.5.0 → 4.6.0-next-1788817472881
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/CHANGELOG.md +36 -0
- package/dist/cli.js +1556 -1326
- package/dist/index.d.ts +3107 -491
- package/dist/index.js +728 -347
- package/dist/index.js.map +1 -1
- package/openapi/spec.json +9867 -6216
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -139,9 +139,17 @@ function createCLILoggerConfig(options = {}) {
|
|
|
139
139
|
// at DEBUG, ERROR always reaches the handler (and the ring) even without
|
|
140
140
|
// --verbose.
|
|
141
141
|
level: Level.DEBUG,
|
|
142
|
-
handler: (level, message,
|
|
142
|
+
handler: (level, message, context2, scope) => {
|
|
143
143
|
const scopePath = scope.length > 0 ? `[${scope.join(":")}] ` : "";
|
|
144
|
-
|
|
144
|
+
let meta = "";
|
|
145
|
+
if (Object.keys(context2).length > 0) {
|
|
146
|
+
try {
|
|
147
|
+
meta = ` ${JSON.stringify(context2)}`;
|
|
148
|
+
} catch {
|
|
149
|
+
meta = " [unserializable context]";
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const fullMessage = scrubSecrets(`${scopePath}${message}${meta}`);
|
|
145
153
|
try {
|
|
146
154
|
options.onLine?.(level, fullMessage);
|
|
147
155
|
} catch {
|
|
@@ -260,7 +268,9 @@ import {
|
|
|
260
268
|
writeFileSync,
|
|
261
269
|
mkdirSync,
|
|
262
270
|
unlinkSync,
|
|
263
|
-
existsSync
|
|
271
|
+
existsSync,
|
|
272
|
+
chmodSync,
|
|
273
|
+
renameSync
|
|
264
274
|
} from "fs";
|
|
265
275
|
import { join } from "path";
|
|
266
276
|
import { homedir } from "os";
|
|
@@ -281,15 +291,33 @@ function readConfig() {
|
|
|
281
291
|
return null;
|
|
282
292
|
}
|
|
283
293
|
}
|
|
284
|
-
function
|
|
294
|
+
function replaceConfigFile(config) {
|
|
285
295
|
const dir = getConfigDir();
|
|
286
|
-
mkdirSync(dir, { recursive: true });
|
|
296
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
287
297
|
const configPath = getConfigPath();
|
|
288
|
-
|
|
298
|
+
const tempPath = `${configPath}.tmp`;
|
|
299
|
+
writeFileSync(tempPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
300
|
+
chmodSync(tempPath, 384);
|
|
301
|
+
renameSync(tempPath, configPath);
|
|
302
|
+
}
|
|
303
|
+
function writeConfig(config) {
|
|
304
|
+
replaceConfigFile({ ...readConfig() ?? {}, ...config });
|
|
305
|
+
}
|
|
306
|
+
function clearAuthFields() {
|
|
307
|
+
const config = readConfig();
|
|
308
|
+
if (!config) return;
|
|
309
|
+
const {
|
|
310
|
+
token: _token,
|
|
311
|
+
accessToken: _accessToken,
|
|
312
|
+
accessTokenExpiresAt: _accessTokenExpiresAt,
|
|
313
|
+
refreshToken: _refreshToken,
|
|
314
|
+
email: _email,
|
|
315
|
+
...rest
|
|
316
|
+
} = config;
|
|
317
|
+
replaceConfigFile(rest);
|
|
289
318
|
}
|
|
290
319
|
function writeTelemetryOnlyConfig(partial) {
|
|
291
|
-
|
|
292
|
-
writeConfig({ ...existing, ...partial });
|
|
320
|
+
writeConfig(partial);
|
|
293
321
|
}
|
|
294
322
|
function deleteConfig() {
|
|
295
323
|
const configPath = getConfigPath();
|
|
@@ -323,7 +351,7 @@ function clearDefaultProject() {
|
|
|
323
351
|
const config = readConfig();
|
|
324
352
|
if (!config) return;
|
|
325
353
|
const { defaultProjectId: _removed, ...rest } = config;
|
|
326
|
-
|
|
354
|
+
replaceConfigFile(rest);
|
|
327
355
|
}
|
|
328
356
|
function resolveToken() {
|
|
329
357
|
const envToken = process.env.WALKEROS_TOKEN;
|
|
@@ -348,6 +376,336 @@ var init_config_file = __esm({
|
|
|
348
376
|
}
|
|
349
377
|
});
|
|
350
378
|
|
|
379
|
+
// src/lib/config-lock.ts
|
|
380
|
+
import { closeSync, mkdirSync as mkdirSync2, openSync, statSync, unlinkSync as unlinkSync2 } from "fs";
|
|
381
|
+
function getConfigLockPath() {
|
|
382
|
+
return `${getConfigPath()}.lock`;
|
|
383
|
+
}
|
|
384
|
+
function hasCode(value) {
|
|
385
|
+
return typeof value === "object" && value !== null && "code" in value;
|
|
386
|
+
}
|
|
387
|
+
function isAlreadyLocked(error) {
|
|
388
|
+
return hasCode(error) && error.code === "EEXIST";
|
|
389
|
+
}
|
|
390
|
+
function delay(ms) {
|
|
391
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
392
|
+
}
|
|
393
|
+
function breakIfStale(lockPath) {
|
|
394
|
+
try {
|
|
395
|
+
const age = Date.now() - statSync(lockPath).mtimeMs;
|
|
396
|
+
if (age < STALE_MS) return false;
|
|
397
|
+
unlinkSync2(lockPath);
|
|
398
|
+
return true;
|
|
399
|
+
} catch {
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
async function withConfigLock(fn) {
|
|
404
|
+
const lockPath = getConfigLockPath();
|
|
405
|
+
mkdirSync2(getConfigDir(), { recursive: true, mode: 448 });
|
|
406
|
+
const deadline = Date.now() + TIMEOUT_MS;
|
|
407
|
+
for (; ; ) {
|
|
408
|
+
let handle;
|
|
409
|
+
try {
|
|
410
|
+
handle = openSync(lockPath, "wx", 384);
|
|
411
|
+
} catch (error) {
|
|
412
|
+
if (!isAlreadyLocked(error)) throw error;
|
|
413
|
+
if (breakIfStale(lockPath)) continue;
|
|
414
|
+
if (Date.now() >= deadline) {
|
|
415
|
+
throw new Error(
|
|
416
|
+
`Timed out waiting for the walkerOS config lock at ${lockPath}. Remove the file if no other walkeros process is running.`
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
await delay(RETRY_MS);
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
closeSync(handle);
|
|
423
|
+
try {
|
|
424
|
+
return await fn();
|
|
425
|
+
} finally {
|
|
426
|
+
try {
|
|
427
|
+
unlinkSync2(lockPath);
|
|
428
|
+
} catch {
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
var STALE_MS, RETRY_MS, TIMEOUT_MS;
|
|
434
|
+
var init_config_lock = __esm({
|
|
435
|
+
"src/lib/config-lock.ts"() {
|
|
436
|
+
"use strict";
|
|
437
|
+
init_config_file();
|
|
438
|
+
STALE_MS = 15e3;
|
|
439
|
+
RETRY_MS = 100;
|
|
440
|
+
TIMEOUT_MS = 1e4;
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// src/core/oauth-client.ts
|
|
445
|
+
import { z } from "zod";
|
|
446
|
+
async function readJson(response) {
|
|
447
|
+
try {
|
|
448
|
+
return await response.json();
|
|
449
|
+
} catch {
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
function errorCode(body) {
|
|
454
|
+
const parsed = ErrorSchema.safeParse(body);
|
|
455
|
+
return parsed.success ? parsed.data.error : null;
|
|
456
|
+
}
|
|
457
|
+
function describe(response, body) {
|
|
458
|
+
const parsed = ErrorSchema.safeParse(body);
|
|
459
|
+
if (parsed.success) {
|
|
460
|
+
return parsed.data.error_description ? `${parsed.data.error}: ${parsed.data.error_description}` : parsed.data.error;
|
|
461
|
+
}
|
|
462
|
+
return `HTTP ${response.status}`;
|
|
463
|
+
}
|
|
464
|
+
function post(fetchFn, url, form, signal) {
|
|
465
|
+
return fetchFn(url, {
|
|
466
|
+
method: "POST",
|
|
467
|
+
headers: { ...FORM_HEADERS },
|
|
468
|
+
body: new URLSearchParams(form).toString(),
|
|
469
|
+
...signal ? { signal } : {}
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
function toTokenSet(body) {
|
|
473
|
+
const parsed = TokenSchema.safeParse(body);
|
|
474
|
+
if (!parsed.success) throw new Error("Malformed token response");
|
|
475
|
+
return {
|
|
476
|
+
accessToken: parsed.data.access_token,
|
|
477
|
+
accessTokenExpiresAt: new Date(
|
|
478
|
+
Date.now() + parsed.data.expires_in * 1e3
|
|
479
|
+
).toISOString(),
|
|
480
|
+
refreshToken: parsed.data.refresh_token ?? null
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
async function startDeviceAuthorization(appUrl, fetchFn = globalThis.fetch) {
|
|
484
|
+
const response = await post(
|
|
485
|
+
fetchFn,
|
|
486
|
+
`${appUrl}/api/oauth/device_authorization`,
|
|
487
|
+
{
|
|
488
|
+
client_id: CLI_CLIENT_ID,
|
|
489
|
+
scope: CLI_SCOPE,
|
|
490
|
+
// RFC 8707. The token comes back bound to the API, so a leaked CLI token
|
|
491
|
+
// cannot be replayed against the MCP resource.
|
|
492
|
+
resource: `${appUrl}/api`
|
|
493
|
+
}
|
|
494
|
+
);
|
|
495
|
+
const body = await readJson(response);
|
|
496
|
+
if (!response.ok) throw new Error(describe(response, body));
|
|
497
|
+
const parsed = DeviceAuthorizationSchema.safeParse(body);
|
|
498
|
+
if (!parsed.success)
|
|
499
|
+
throw new Error("Malformed device authorization response");
|
|
500
|
+
return {
|
|
501
|
+
deviceCode: parsed.data.device_code,
|
|
502
|
+
userCode: parsed.data.user_code,
|
|
503
|
+
verificationUri: parsed.data.verification_uri,
|
|
504
|
+
verificationUriComplete: parsed.data.verification_uri_complete ?? parsed.data.verification_uri,
|
|
505
|
+
expiresIn: parsed.data.expires_in,
|
|
506
|
+
interval: parsed.data.interval
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
async function pollDeviceToken(appUrl, deviceCode, fetchFn = globalThis.fetch, signal) {
|
|
510
|
+
let response;
|
|
511
|
+
try {
|
|
512
|
+
response = await post(
|
|
513
|
+
fetchFn,
|
|
514
|
+
`${appUrl}/api/oauth/token`,
|
|
515
|
+
{
|
|
516
|
+
grant_type: DEVICE_CODE_GRANT,
|
|
517
|
+
device_code: deviceCode,
|
|
518
|
+
client_id: CLI_CLIENT_ID
|
|
519
|
+
},
|
|
520
|
+
signal
|
|
521
|
+
);
|
|
522
|
+
} catch (error) {
|
|
523
|
+
if (signal?.aborted) return { status: "pending" };
|
|
524
|
+
throw error;
|
|
525
|
+
}
|
|
526
|
+
const body = await readJson(response);
|
|
527
|
+
if (response.ok) {
|
|
528
|
+
try {
|
|
529
|
+
return { status: "ok", tokens: toTokenSet(body) };
|
|
530
|
+
} catch (error) {
|
|
531
|
+
return {
|
|
532
|
+
status: "error",
|
|
533
|
+
error: error instanceof Error ? error.message : String(error)
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
switch (errorCode(body)) {
|
|
538
|
+
case "authorization_pending":
|
|
539
|
+
return { status: "pending" };
|
|
540
|
+
case "slow_down":
|
|
541
|
+
return { status: "slow_down" };
|
|
542
|
+
case "access_denied":
|
|
543
|
+
return { status: "denied" };
|
|
544
|
+
case "expired_token":
|
|
545
|
+
return { status: "expired" };
|
|
546
|
+
default:
|
|
547
|
+
return { status: "error", error: describe(response, body) };
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
async function refreshTokens(appUrl, refreshToken, fetchFn = globalThis.fetch) {
|
|
551
|
+
const response = await post(
|
|
552
|
+
fetchFn,
|
|
553
|
+
`${appUrl}/api/oauth/token`,
|
|
554
|
+
{
|
|
555
|
+
grant_type: "refresh_token",
|
|
556
|
+
refresh_token: refreshToken,
|
|
557
|
+
client_id: CLI_CLIENT_ID
|
|
558
|
+
},
|
|
559
|
+
AbortSignal.timeout(REFRESH_TIMEOUT_MS)
|
|
560
|
+
);
|
|
561
|
+
const body = await readJson(response);
|
|
562
|
+
if (!response.ok) {
|
|
563
|
+
if (errorCode(body) === "invalid_grant") return null;
|
|
564
|
+
throw new Error(describe(response, body));
|
|
565
|
+
}
|
|
566
|
+
return toTokenSet(body);
|
|
567
|
+
}
|
|
568
|
+
async function revokeRefreshToken(appUrl, refreshToken, fetchFn = globalThis.fetch) {
|
|
569
|
+
try {
|
|
570
|
+
await post(
|
|
571
|
+
fetchFn,
|
|
572
|
+
`${appUrl}/api/oauth/revoke`,
|
|
573
|
+
{
|
|
574
|
+
token: refreshToken,
|
|
575
|
+
token_type_hint: "refresh_token",
|
|
576
|
+
client_id: CLI_CLIENT_ID
|
|
577
|
+
},
|
|
578
|
+
AbortSignal.timeout(REVOKE_TIMEOUT_MS)
|
|
579
|
+
);
|
|
580
|
+
} catch {
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
var CLI_CLIENT_ID, CLI_SCOPE, DEVICE_CODE_GRANT, REFRESH_TIMEOUT_MS, REVOKE_TIMEOUT_MS, FORM_HEADERS, DeviceAuthorizationSchema, TokenSchema, ErrorSchema;
|
|
584
|
+
var init_oauth_client = __esm({
|
|
585
|
+
"src/core/oauth-client.ts"() {
|
|
586
|
+
"use strict";
|
|
587
|
+
CLI_CLIENT_ID = "walkeros-cli";
|
|
588
|
+
CLI_SCOPE = "read write offline_access";
|
|
589
|
+
DEVICE_CODE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
|
|
590
|
+
REFRESH_TIMEOUT_MS = 1e4;
|
|
591
|
+
REVOKE_TIMEOUT_MS = 5e3;
|
|
592
|
+
FORM_HEADERS = {
|
|
593
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
594
|
+
Accept: "application/json"
|
|
595
|
+
};
|
|
596
|
+
DeviceAuthorizationSchema = z.object({
|
|
597
|
+
device_code: z.string().min(1),
|
|
598
|
+
user_code: z.string().min(1),
|
|
599
|
+
verification_uri: z.string().min(1),
|
|
600
|
+
verification_uri_complete: z.string().min(1).optional(),
|
|
601
|
+
expires_in: z.number().int().nonnegative(),
|
|
602
|
+
interval: z.number().int().nonnegative()
|
|
603
|
+
});
|
|
604
|
+
TokenSchema = z.object({
|
|
605
|
+
access_token: z.string().min(1),
|
|
606
|
+
expires_in: z.number().int().nonnegative(),
|
|
607
|
+
refresh_token: z.string().min(1).optional()
|
|
608
|
+
});
|
|
609
|
+
ErrorSchema = z.object({
|
|
610
|
+
error: z.string().min(1),
|
|
611
|
+
error_description: z.string().optional()
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
// src/core/auth.ts
|
|
617
|
+
function noticeLegacyToken() {
|
|
618
|
+
if (legacyNoticeShown) return;
|
|
619
|
+
legacyNoticeShown = true;
|
|
620
|
+
process.stderr.write(
|
|
621
|
+
"walkerOS: using a static token from your config. Run `walkeros login` to switch to a session that refreshes automatically.\n"
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
function isFresh(config, nowMs) {
|
|
625
|
+
if (!config.accessToken || !config.accessTokenExpiresAt) return false;
|
|
626
|
+
const expiresAt = Date.parse(config.accessTokenExpiresAt);
|
|
627
|
+
if (Number.isNaN(expiresAt)) return false;
|
|
628
|
+
return expiresAt - nowMs > REFRESH_SKEW_MS;
|
|
629
|
+
}
|
|
630
|
+
async function resolveAccessToken(opts) {
|
|
631
|
+
const envToken = process.env.WALKEROS_TOKEN;
|
|
632
|
+
if (envToken) return envToken;
|
|
633
|
+
const now = opts?.now ?? Date.now;
|
|
634
|
+
const config = readConfig();
|
|
635
|
+
if (!config) return null;
|
|
636
|
+
if (config.token) {
|
|
637
|
+
noticeLegacyToken();
|
|
638
|
+
return config.token;
|
|
639
|
+
}
|
|
640
|
+
if (!config.refreshToken) {
|
|
641
|
+
return isFresh(config, now()) ? config.accessToken ?? null : null;
|
|
642
|
+
}
|
|
643
|
+
if (isFresh(config, now())) return config.accessToken ?? null;
|
|
644
|
+
return withConfigLock(async () => {
|
|
645
|
+
const current = readConfig();
|
|
646
|
+
if (!current?.refreshToken) return current?.accessToken ?? null;
|
|
647
|
+
if (isFresh(current, now())) return current.accessToken ?? null;
|
|
648
|
+
let rotated;
|
|
649
|
+
try {
|
|
650
|
+
rotated = await refreshTokens(
|
|
651
|
+
resolveAppUrl(),
|
|
652
|
+
current.refreshToken,
|
|
653
|
+
opts?.fetch
|
|
654
|
+
);
|
|
655
|
+
} catch (error) {
|
|
656
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
657
|
+
throw new Error(
|
|
658
|
+
`Could not reach ${resolveAppUrl()} to refresh your session: ${reason}. Your saved session was kept, so try again once the connection is back.`
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
if (rotated === null) {
|
|
662
|
+
clearAuthFields();
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
writeConfig({
|
|
666
|
+
accessToken: rotated.accessToken,
|
|
667
|
+
accessTokenExpiresAt: rotated.accessTokenExpiresAt,
|
|
668
|
+
// A server that rotates no new refresh token leaves the current one in
|
|
669
|
+
// force; overwriting it with null would end the session on the next call.
|
|
670
|
+
refreshToken: rotated.refreshToken ?? current.refreshToken
|
|
671
|
+
});
|
|
672
|
+
return rotated.accessToken;
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
async function getAuthHeaders() {
|
|
676
|
+
const token = await resolveAccessToken();
|
|
677
|
+
if (!token) return {};
|
|
678
|
+
return { Authorization: `Bearer ${token}` };
|
|
679
|
+
}
|
|
680
|
+
function credentialSource() {
|
|
681
|
+
if (process.env.WALKEROS_TOKEN) return "env";
|
|
682
|
+
const config = readConfig();
|
|
683
|
+
if (config?.token || config?.accessToken) return "config";
|
|
684
|
+
return null;
|
|
685
|
+
}
|
|
686
|
+
function resolveRunToken() {
|
|
687
|
+
return resolveDeployToken() ?? resolveToken()?.token ?? null;
|
|
688
|
+
}
|
|
689
|
+
function requireProjectId() {
|
|
690
|
+
const projectId = process.env.WALKEROS_PROJECT_ID || getDefaultProject();
|
|
691
|
+
if (!projectId)
|
|
692
|
+
throw new Error(
|
|
693
|
+
"No project selected. Set WALKEROS_PROJECT_ID or configure a default project."
|
|
694
|
+
);
|
|
695
|
+
return projectId;
|
|
696
|
+
}
|
|
697
|
+
var REFRESH_SKEW_MS, legacyNoticeShown;
|
|
698
|
+
var init_auth = __esm({
|
|
699
|
+
"src/core/auth.ts"() {
|
|
700
|
+
"use strict";
|
|
701
|
+
init_config_file();
|
|
702
|
+
init_config_lock();
|
|
703
|
+
init_oauth_client();
|
|
704
|
+
REFRESH_SKEW_MS = 6e4;
|
|
705
|
+
legacyNoticeShown = false;
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
|
|
351
709
|
// src/core/client-context.ts
|
|
352
710
|
function setClientContext(input) {
|
|
353
711
|
const envType = process.env.WALKEROS_CLIENT_TYPE;
|
|
@@ -395,7 +753,7 @@ function buildHeaders(token, headers) {
|
|
|
395
753
|
}
|
|
396
754
|
async function apiFetch(path20, init) {
|
|
397
755
|
const baseUrl = resolveAppUrl();
|
|
398
|
-
const token =
|
|
756
|
+
const token = await resolveAccessToken();
|
|
399
757
|
return fetch(`${baseUrl}${path20}`, {
|
|
400
758
|
...init,
|
|
401
759
|
headers: buildHeaders(token, init?.headers)
|
|
@@ -413,7 +771,7 @@ async function publicFetch(path20, init) {
|
|
|
413
771
|
}
|
|
414
772
|
async function deployFetch(path20, init) {
|
|
415
773
|
const baseUrl = resolveAppUrl();
|
|
416
|
-
const token = resolveDeployToken() ??
|
|
774
|
+
const token = resolveDeployToken() ?? await resolveAccessToken();
|
|
417
775
|
if (!token)
|
|
418
776
|
throw new Error(
|
|
419
777
|
"No authentication token available. Set WALKEROS_DEPLOY_TOKEN or run walkeros auth login."
|
|
@@ -427,6 +785,7 @@ var init_http = __esm({
|
|
|
427
785
|
"src/core/http.ts"() {
|
|
428
786
|
"use strict";
|
|
429
787
|
init_config_file();
|
|
788
|
+
init_auth();
|
|
430
789
|
init_client_context();
|
|
431
790
|
}
|
|
432
791
|
});
|
|
@@ -442,8 +801,15 @@ function isUrl(str) {
|
|
|
442
801
|
return false;
|
|
443
802
|
}
|
|
444
803
|
}
|
|
804
|
+
function isAppOrigin(url) {
|
|
805
|
+
try {
|
|
806
|
+
return new URL(url).origin === new URL(resolveAppUrl()).origin;
|
|
807
|
+
} catch {
|
|
808
|
+
return false;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
445
811
|
async function fetchContentString(url) {
|
|
446
|
-
const token =
|
|
812
|
+
const token = isAppOrigin(url) ? await resolveAccessToken() : null;
|
|
447
813
|
const response = await fetch(url, {
|
|
448
814
|
headers: mergeAuthHeaders(token)
|
|
449
815
|
});
|
|
@@ -516,6 +882,7 @@ var init_utils = __esm({
|
|
|
516
882
|
"src/config/utils.ts"() {
|
|
517
883
|
"use strict";
|
|
518
884
|
init_http();
|
|
885
|
+
init_auth();
|
|
519
886
|
init_config_file();
|
|
520
887
|
}
|
|
521
888
|
});
|
|
@@ -720,34 +1087,6 @@ var init_stdin = __esm({
|
|
|
720
1087
|
}
|
|
721
1088
|
});
|
|
722
1089
|
|
|
723
|
-
// src/core/auth.ts
|
|
724
|
-
function getToken() {
|
|
725
|
-
const result = resolveToken();
|
|
726
|
-
return result?.token;
|
|
727
|
-
}
|
|
728
|
-
function getAuthHeaders() {
|
|
729
|
-
const token = getToken();
|
|
730
|
-
if (!token) return {};
|
|
731
|
-
return { Authorization: `Bearer ${token}` };
|
|
732
|
-
}
|
|
733
|
-
function resolveRunToken() {
|
|
734
|
-
return resolveDeployToken() ?? resolveToken()?.token ?? null;
|
|
735
|
-
}
|
|
736
|
-
function requireProjectId() {
|
|
737
|
-
const projectId = process.env.WALKEROS_PROJECT_ID || getDefaultProject();
|
|
738
|
-
if (!projectId)
|
|
739
|
-
throw new Error(
|
|
740
|
-
"No project selected. Set WALKEROS_PROJECT_ID or configure a default project."
|
|
741
|
-
);
|
|
742
|
-
return projectId;
|
|
743
|
-
}
|
|
744
|
-
var init_auth = __esm({
|
|
745
|
-
"src/core/auth.ts"() {
|
|
746
|
-
"use strict";
|
|
747
|
-
init_config_file();
|
|
748
|
-
}
|
|
749
|
-
});
|
|
750
|
-
|
|
751
1090
|
// src/core/sse.ts
|
|
752
1091
|
function parseSSEEvents(buffer) {
|
|
753
1092
|
const events = [];
|
|
@@ -1222,13 +1561,13 @@ function validateReference(type, name, ref) {
|
|
|
1222
1561
|
return;
|
|
1223
1562
|
}
|
|
1224
1563
|
const hasPackage = !!ref.package;
|
|
1225
|
-
const
|
|
1226
|
-
if (hasPackage &&
|
|
1564
|
+
const hasCode2 = hasCodeReference(ref.code);
|
|
1565
|
+
if (hasPackage && hasCode2) {
|
|
1227
1566
|
throw new Error(
|
|
1228
1567
|
`${type} "${name}": Cannot specify both package and code. Use one or the other.`
|
|
1229
1568
|
);
|
|
1230
1569
|
}
|
|
1231
|
-
if (!hasPackage && !
|
|
1570
|
+
if (!hasPackage && !hasCode2) {
|
|
1232
1571
|
throw new Error(`${type} "${name}": Must specify either package or code.`);
|
|
1233
1572
|
}
|
|
1234
1573
|
}
|
|
@@ -1500,7 +1839,7 @@ function backoffForAttempt(index) {
|
|
|
1500
1839
|
const spread = base * JITTER;
|
|
1501
1840
|
return base + (Math.random() * 2 - 1) * spread;
|
|
1502
1841
|
}
|
|
1503
|
-
function
|
|
1842
|
+
function delay2(ms) {
|
|
1504
1843
|
return new Promise((resolve5) => {
|
|
1505
1844
|
setTimeout(resolve5, ms);
|
|
1506
1845
|
});
|
|
@@ -1542,7 +1881,7 @@ async function withPacoteRetry(fn, label, options = {}) {
|
|
|
1542
1881
|
maxTotalMs - (Date.now() - start)
|
|
1543
1882
|
);
|
|
1544
1883
|
if (sleepMs <= 0) break;
|
|
1545
|
-
await
|
|
1884
|
+
await delay2(sleepMs);
|
|
1546
1885
|
}
|
|
1547
1886
|
throw new Error(
|
|
1548
1887
|
`Failed ${label} after ${made} attempts: ${describeError(lastError)}`
|
|
@@ -3969,14 +4308,14 @@ __export(cache_exports, {
|
|
|
3969
4308
|
});
|
|
3970
4309
|
import {
|
|
3971
4310
|
existsSync as existsSync3,
|
|
3972
|
-
mkdirSync as
|
|
4311
|
+
mkdirSync as mkdirSync5,
|
|
3973
4312
|
copyFileSync,
|
|
3974
4313
|
writeFileSync as writeFileSync4,
|
|
3975
4314
|
readFileSync as readFileSync3
|
|
3976
4315
|
} from "fs";
|
|
3977
4316
|
import { join as join6 } from "path";
|
|
3978
4317
|
function writeCache(cacheDir, bundlePath, configContent, version) {
|
|
3979
|
-
|
|
4318
|
+
mkdirSync5(cacheDir, { recursive: true });
|
|
3980
4319
|
copyFileSync(bundlePath, join6(cacheDir, "flow.mjs"));
|
|
3981
4320
|
writeFileSync4(join6(cacheDir, "config.json"), configContent, "utf-8");
|
|
3982
4321
|
const meta = { version, timestamp: Date.now() };
|
|
@@ -4057,7 +4396,7 @@ var env_file_exports = {};
|
|
|
4057
4396
|
__export(env_file_exports, {
|
|
4058
4397
|
loadEnvFile: () => loadEnvFile
|
|
4059
4398
|
});
|
|
4060
|
-
import { readFileSync as readFileSync5, statSync } from "fs";
|
|
4399
|
+
import { readFileSync as readFileSync5, statSync as statSync2 } from "fs";
|
|
4061
4400
|
function parseLine(line) {
|
|
4062
4401
|
const trimmed = line.trim();
|
|
4063
4402
|
if (trimmed === "" || trimmed.startsWith("#")) return void 0;
|
|
@@ -4072,7 +4411,7 @@ function parseLine(line) {
|
|
|
4072
4411
|
return { key, value };
|
|
4073
4412
|
}
|
|
4074
4413
|
function loadEnvFile(filePath) {
|
|
4075
|
-
const stats =
|
|
4414
|
+
const stats = statSync2(filePath);
|
|
4076
4415
|
if (process.platform !== "win32") {
|
|
4077
4416
|
const mode = stats.mode & 511;
|
|
4078
4417
|
if (mode & 36) {
|
|
@@ -4316,13 +4655,13 @@ function installTimerInterception(options = {}) {
|
|
|
4316
4655
|
setInterval: Reflect.get(target, "setInterval"),
|
|
4317
4656
|
clearInterval: Reflect.get(target, "clearInterval")
|
|
4318
4657
|
});
|
|
4319
|
-
const trackedSetTimeout = (callback,
|
|
4658
|
+
const trackedSetTimeout = (callback, delay5, ...args) => {
|
|
4320
4659
|
if (typeof callback !== "function") return 0;
|
|
4321
4660
|
const id = nextId++;
|
|
4322
4661
|
pending.set(id, {
|
|
4323
4662
|
id,
|
|
4324
4663
|
callback,
|
|
4325
|
-
delay:
|
|
4664
|
+
delay: delay5 ?? 0,
|
|
4326
4665
|
type: "timeout",
|
|
4327
4666
|
args,
|
|
4328
4667
|
cleared: false
|
|
@@ -4335,13 +4674,13 @@ function installTimerInterception(options = {}) {
|
|
|
4335
4674
|
const entry = pending.get(numId);
|
|
4336
4675
|
if (entry) entry.cleared = true;
|
|
4337
4676
|
};
|
|
4338
|
-
const trackedSetInterval = (callback,
|
|
4677
|
+
const trackedSetInterval = (callback, delay5, ...args) => {
|
|
4339
4678
|
if (typeof callback !== "function") return 0;
|
|
4340
4679
|
const id = nextId++;
|
|
4341
4680
|
pending.set(id, {
|
|
4342
4681
|
id,
|
|
4343
4682
|
callback,
|
|
4344
|
-
delay:
|
|
4683
|
+
delay: delay5 ?? 0,
|
|
4345
4684
|
type: "interval",
|
|
4346
4685
|
args,
|
|
4347
4686
|
cleared: false
|
|
@@ -5688,14 +6027,14 @@ import { join as join8 } from "path";
|
|
|
5688
6027
|
import { Level as Level2 } from "@walkeros/core";
|
|
5689
6028
|
|
|
5690
6029
|
// src/commands/run/error-sink.ts
|
|
5691
|
-
import { mkdirSync as
|
|
6030
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
5692
6031
|
import { join as join4 } from "path";
|
|
5693
6032
|
function errorSinkPath(cacheDir) {
|
|
5694
6033
|
return join4(cacheDir, "errors.jsonl");
|
|
5695
6034
|
}
|
|
5696
6035
|
function ensureSinkDir(cacheDir) {
|
|
5697
6036
|
try {
|
|
5698
|
-
|
|
6037
|
+
mkdirSync3(cacheDir, { recursive: true });
|
|
5699
6038
|
} catch {
|
|
5700
6039
|
}
|
|
5701
6040
|
}
|
|
@@ -5833,7 +6172,7 @@ init_stdin();
|
|
|
5833
6172
|
import {
|
|
5834
6173
|
createReadStream,
|
|
5835
6174
|
existsSync as existsSync2,
|
|
5836
|
-
mkdirSync as
|
|
6175
|
+
mkdirSync as mkdirSync4,
|
|
5837
6176
|
rmSync,
|
|
5838
6177
|
writeFileSync as writeFileSync3
|
|
5839
6178
|
} from "fs";
|
|
@@ -5903,7 +6242,7 @@ function backoffForAttempt2(index) {
|
|
|
5903
6242
|
const spread = base * JITTER2;
|
|
5904
6243
|
return base + (Math.random() * 2 - 1) * spread;
|
|
5905
6244
|
}
|
|
5906
|
-
function
|
|
6245
|
+
function delay3(ms) {
|
|
5907
6246
|
return new Promise((resolve5) => {
|
|
5908
6247
|
setTimeout(resolve5, ms);
|
|
5909
6248
|
});
|
|
@@ -5950,7 +6289,7 @@ async function fetchWithRetry(url, options = {}) {
|
|
|
5950
6289
|
maxTotalMs - (Date.now() - start)
|
|
5951
6290
|
);
|
|
5952
6291
|
if (sleepMs <= 0) break;
|
|
5953
|
-
await
|
|
6292
|
+
await delay3(sleepMs);
|
|
5954
6293
|
}
|
|
5955
6294
|
const cause = lastReason ? describeReason(lastReason) : "no attempts made";
|
|
5956
6295
|
throw new Error(`Fetch failed after ${made} attempts: ${cause}`);
|
|
@@ -5977,7 +6316,7 @@ function isArchive(value, contentType) {
|
|
|
5977
6316
|
function writeBundleToDisk(writePath, content) {
|
|
5978
6317
|
const dir = dirname4(writePath);
|
|
5979
6318
|
if (!existsSync2(dir)) {
|
|
5980
|
-
|
|
6319
|
+
mkdirSync4(dir, { recursive: true });
|
|
5981
6320
|
}
|
|
5982
6321
|
writeFileSync3(writePath, content, "utf-8");
|
|
5983
6322
|
}
|
|
@@ -6000,7 +6339,7 @@ async function fetchTextToDisk(response, writePath) {
|
|
|
6000
6339
|
}
|
|
6001
6340
|
async function extractToDir(source, destDir) {
|
|
6002
6341
|
if (!existsSync2(destDir)) {
|
|
6003
|
-
|
|
6342
|
+
mkdirSync4(destDir, { recursive: true });
|
|
6004
6343
|
}
|
|
6005
6344
|
const entryPath = join5(destDir, ARCHIVE_ENTRY);
|
|
6006
6345
|
for (const member of [ARCHIVE_ENTRY, "node_modules", "package.json"]) {
|
|
@@ -6655,93 +6994,93 @@ init_asset_resolver();
|
|
|
6655
6994
|
import { existsSync as existsSync4 } from "fs";
|
|
6656
6995
|
|
|
6657
6996
|
// src/schemas/primitives.ts
|
|
6658
|
-
import { z } from "@walkeros/core/dev";
|
|
6659
|
-
var PortSchema =
|
|
6660
|
-
var FilePathSchema =
|
|
6997
|
+
import { z as z2 } from "@walkeros/core/dev";
|
|
6998
|
+
var PortSchema = z2.number().int("Port must be an integer").min(1, "Port must be at least 1").max(65535, "Port must be at most 65535").describe("HTTP server port number");
|
|
6999
|
+
var FilePathSchema = z2.string().min(1, "File path cannot be empty").describe("Path to configuration file");
|
|
6661
7000
|
|
|
6662
7001
|
// src/schemas/run.ts
|
|
6663
|
-
import { z as
|
|
6664
|
-
var RunOptionsSchema =
|
|
7002
|
+
import { z as z3 } from "@walkeros/core/dev";
|
|
7003
|
+
var RunOptionsSchema = z3.object({
|
|
6665
7004
|
flow: FilePathSchema,
|
|
6666
7005
|
port: PortSchema.default(8080),
|
|
6667
|
-
flowName:
|
|
7006
|
+
flowName: z3.string().optional().describe("Specific flow name to run")
|
|
6668
7007
|
});
|
|
6669
7008
|
|
|
6670
7009
|
// src/schemas/validate.ts
|
|
6671
|
-
import { z as
|
|
6672
|
-
var ValidationTypeSchema =
|
|
6673
|
-
var ValidateOptionsSchema =
|
|
6674
|
-
flow:
|
|
6675
|
-
path:
|
|
7010
|
+
import { z as z4 } from "@walkeros/core/dev";
|
|
7011
|
+
var ValidationTypeSchema = z4.enum(["contract", "event", "flow", "mapping"]).describe('Validation type: "event", "flow", "mapping", or "contract"');
|
|
7012
|
+
var ValidateOptionsSchema = z4.object({
|
|
7013
|
+
flow: z4.string().optional().describe("Flow name for multi-flow configs"),
|
|
7014
|
+
path: z4.string().optional().describe(
|
|
6676
7015
|
'Entry path for package schema validation (e.g., "destinations.snowplow", "sources.browser")'
|
|
6677
7016
|
)
|
|
6678
7017
|
});
|
|
6679
7018
|
var ValidateInputShape = {
|
|
6680
7019
|
type: ValidationTypeSchema,
|
|
6681
|
-
input:
|
|
6682
|
-
flow:
|
|
6683
|
-
path:
|
|
7020
|
+
input: z4.string().min(1).describe("JSON string, file path, or URL to validate"),
|
|
7021
|
+
flow: z4.string().optional().describe("Flow name for multi-flow configs"),
|
|
7022
|
+
path: z4.string().optional().describe(
|
|
6684
7023
|
'Entry path for package schema validation (e.g., "destinations.snowplow"). When provided, validates the entry against its package JSON Schema instead of using --type.'
|
|
6685
7024
|
)
|
|
6686
7025
|
};
|
|
6687
|
-
var ValidateInputSchema =
|
|
7026
|
+
var ValidateInputSchema = z4.object(ValidateInputShape);
|
|
6688
7027
|
|
|
6689
7028
|
// src/schemas/bundle.ts
|
|
6690
|
-
import { z as
|
|
6691
|
-
var BundleOptionsSchema =
|
|
6692
|
-
silent:
|
|
6693
|
-
verbose:
|
|
6694
|
-
stats:
|
|
6695
|
-
cache:
|
|
6696
|
-
flowName:
|
|
7029
|
+
import { z as z5 } from "@walkeros/core/dev";
|
|
7030
|
+
var BundleOptionsSchema = z5.object({
|
|
7031
|
+
silent: z5.boolean().optional().describe("Suppress all output"),
|
|
7032
|
+
verbose: z5.boolean().optional().describe("Enable verbose logging"),
|
|
7033
|
+
stats: z5.boolean().optional().default(true).describe("Return bundle statistics"),
|
|
7034
|
+
cache: z5.boolean().optional().default(true).describe("Enable package caching"),
|
|
7035
|
+
flowName: z5.string().optional().describe("Flow name for multi-flow configs")
|
|
6697
7036
|
});
|
|
6698
7037
|
var BundleInputShape = {
|
|
6699
7038
|
configPath: FilePathSchema.describe(
|
|
6700
7039
|
"Path to flow configuration file (JSON or JavaScript), URL, or inline JSON string"
|
|
6701
7040
|
),
|
|
6702
|
-
flow:
|
|
6703
|
-
stats:
|
|
6704
|
-
output:
|
|
7041
|
+
flow: z5.string().optional().describe("Flow name for multi-flow configs"),
|
|
7042
|
+
stats: z5.boolean().optional().default(true).describe("Return bundle statistics"),
|
|
7043
|
+
output: z5.string().optional().describe("Output file path (defaults to config-defined)")
|
|
6705
7044
|
};
|
|
6706
|
-
var BundleInputSchema =
|
|
7045
|
+
var BundleInputSchema = z5.object(BundleInputShape);
|
|
6707
7046
|
|
|
6708
7047
|
// src/schemas/simulate.ts
|
|
6709
|
-
import { z as
|
|
6710
|
-
var PlatformSchema =
|
|
6711
|
-
var SimulateOptionsSchema =
|
|
6712
|
-
silent:
|
|
6713
|
-
verbose:
|
|
6714
|
-
json:
|
|
7048
|
+
import { z as z6 } from "@walkeros/core/dev";
|
|
7049
|
+
var PlatformSchema = z6.enum(["web", "server"]).describe("Platform type for event processing");
|
|
7050
|
+
var SimulateOptionsSchema = z6.object({
|
|
7051
|
+
silent: z6.boolean().optional().describe("Suppress all output"),
|
|
7052
|
+
verbose: z6.boolean().optional().describe("Enable verbose logging"),
|
|
7053
|
+
json: z6.boolean().optional().describe("Format output as JSON")
|
|
6715
7054
|
});
|
|
6716
7055
|
var SimulateInputShape = {
|
|
6717
7056
|
configPath: FilePathSchema.describe(
|
|
6718
7057
|
"Path to flow configuration file, URL, or inline JSON string"
|
|
6719
7058
|
),
|
|
6720
|
-
event:
|
|
7059
|
+
event: z6.string().min(1).optional().describe(
|
|
6721
7060
|
"Event as JSON string, file path, or URL. For sources: { content, trigger?, env? }."
|
|
6722
7061
|
),
|
|
6723
|
-
flow:
|
|
7062
|
+
flow: z6.string().optional().describe("Flow name for multi-flow configs"),
|
|
6724
7063
|
platform: PlatformSchema.optional().describe("Override platform detection"),
|
|
6725
|
-
step:
|
|
7064
|
+
step: z6.string().optional().describe(
|
|
6726
7065
|
'Step target in type.name format (e.g. "source.browser", "destination.gtag")'
|
|
6727
7066
|
)
|
|
6728
7067
|
};
|
|
6729
|
-
var SimulateInputSchema =
|
|
7068
|
+
var SimulateInputSchema = z6.object(SimulateInputShape);
|
|
6730
7069
|
|
|
6731
7070
|
// src/schemas/push.ts
|
|
6732
|
-
import { z as
|
|
6733
|
-
var PushOptionsSchema =
|
|
6734
|
-
silent:
|
|
6735
|
-
verbose:
|
|
6736
|
-
json:
|
|
7071
|
+
import { z as z7 } from "@walkeros/core/dev";
|
|
7072
|
+
var PushOptionsSchema = z7.object({
|
|
7073
|
+
silent: z7.boolean().optional().describe("Suppress all output"),
|
|
7074
|
+
verbose: z7.boolean().optional().describe("Enable verbose logging"),
|
|
7075
|
+
json: z7.boolean().optional().describe("Format output as JSON")
|
|
6737
7076
|
});
|
|
6738
7077
|
var PushInputShape = {
|
|
6739
7078
|
configPath: FilePathSchema.describe("Path to flow configuration file"),
|
|
6740
|
-
event:
|
|
6741
|
-
flow:
|
|
7079
|
+
event: z7.string().min(1).describe("Event as JSON string, file path, or URL"),
|
|
7080
|
+
flow: z7.string().optional().describe("Flow name for multi-flow configs"),
|
|
6742
7081
|
platform: PlatformSchema.optional().describe("Override platform detection")
|
|
6743
7082
|
};
|
|
6744
|
-
var PushInputSchema =
|
|
7083
|
+
var PushInputSchema = z7.object(PushInputShape);
|
|
6745
7084
|
|
|
6746
7085
|
// src/commands/run/validators.ts
|
|
6747
7086
|
function validateFlowFile(filePath) {
|
|
@@ -8262,7 +8601,7 @@ function validateMapping(input) {
|
|
|
8262
8601
|
// src/commands/validate/validators/entry.ts
|
|
8263
8602
|
import Ajv from "ajv";
|
|
8264
8603
|
import { fetchPackageSchema } from "@walkeros/core";
|
|
8265
|
-
var CLIENT_HEADER = "walkeros-cli/4.
|
|
8604
|
+
var CLIENT_HEADER = "walkeros-cli/4.6.0-next-1788817472881";
|
|
8266
8605
|
var SECTIONS = ["destinations", "sources", "transformers"];
|
|
8267
8606
|
function resolveEntry(path20, flowConfig) {
|
|
8268
8607
|
const flows = flowConfig.flows;
|
|
@@ -8514,29 +8853,23 @@ async function validateCommand(options) {
|
|
|
8514
8853
|
|
|
8515
8854
|
// src/commands/login/index.ts
|
|
8516
8855
|
init_cli_logger();
|
|
8856
|
+
init_oauth_client();
|
|
8517
8857
|
init_config_file();
|
|
8518
|
-
import {
|
|
8519
|
-
import { z as z7 } from "zod";
|
|
8520
|
-
var DeviceCodeResponseSchema = z7.object({
|
|
8521
|
-
deviceCode: z7.string().min(1),
|
|
8522
|
-
userCode: z7.string().min(1),
|
|
8523
|
-
verificationUri: z7.string().min(1),
|
|
8524
|
-
verificationUriComplete: z7.string().optional(),
|
|
8525
|
-
// Server protocol allows 0 for both (e.g. fast retry / already expired).
|
|
8526
|
-
expiresIn: z7.number().int().nonnegative(),
|
|
8527
|
-
interval: z7.number().int().nonnegative()
|
|
8528
|
-
});
|
|
8529
|
-
var TokenResponseSchema = z7.object({
|
|
8530
|
-
token: z7.string().min(1),
|
|
8531
|
-
email: z7.string().min(1)
|
|
8532
|
-
});
|
|
8858
|
+
import { z as z8 } from "zod";
|
|
8533
8859
|
var POLL_TIMEOUT_BUFFER_MS = 5e3;
|
|
8534
|
-
var DEFAULT_POLL_TIMEOUT_MS = 6e4;
|
|
8535
8860
|
var DEFAULT_POLL_INTERVAL_MS = 5e3;
|
|
8861
|
+
var MIN_SERVER_POLL_INTERVAL_MS = 1e3;
|
|
8862
|
+
var DEFAULT_POLL_TIMEOUT_MS = 9e5;
|
|
8863
|
+
var SLOW_DOWN_STEP_MS = 5e3;
|
|
8864
|
+
var TIMED_OUT = "Authorization timed out. Please try again.";
|
|
8865
|
+
var WhoamiSchema = z8.object({ email: z8.string().min(1) });
|
|
8536
8866
|
async function openInBrowser(url) {
|
|
8537
8867
|
const { default: open } = await import("open");
|
|
8538
8868
|
await open(url);
|
|
8539
8869
|
}
|
|
8870
|
+
function delay4(ms) {
|
|
8871
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
8872
|
+
}
|
|
8540
8873
|
async function loginCommand(options) {
|
|
8541
8874
|
const logger = createCLILogger(options);
|
|
8542
8875
|
try {
|
|
@@ -8544,8 +8877,11 @@ async function loginCommand(options) {
|
|
|
8544
8877
|
if (options.json) {
|
|
8545
8878
|
logger.json(result);
|
|
8546
8879
|
} else if (result.success) {
|
|
8547
|
-
logger.info(`Logged in as ${result.email}`);
|
|
8548
|
-
logger.info(
|
|
8880
|
+
if (result.email) logger.info(`Logged in as ${result.email}`);
|
|
8881
|
+
else logger.info("Logged in.");
|
|
8882
|
+
logger.info(`Session stored in ${result.configPath}`);
|
|
8883
|
+
} else if (result.error) {
|
|
8884
|
+
logger.error(result.error);
|
|
8549
8885
|
}
|
|
8550
8886
|
process.exit(result.success ? 0 : 1);
|
|
8551
8887
|
} catch (error) {
|
|
@@ -8558,264 +8894,141 @@ async function loginCommand(options) {
|
|
|
8558
8894
|
process.exit(1);
|
|
8559
8895
|
}
|
|
8560
8896
|
}
|
|
8561
|
-
async function
|
|
8562
|
-
const appUrl = options.url || resolveAppUrl();
|
|
8563
|
-
const f = options.fetch ?? globalThis.fetch;
|
|
8564
|
-
const response = await f(`${appUrl}/api/auth/device/code`, {
|
|
8565
|
-
method: "POST",
|
|
8566
|
-
headers: { "Content-Type": "application/json" },
|
|
8567
|
-
body: JSON.stringify({})
|
|
8568
|
-
});
|
|
8569
|
-
if (!response.ok) {
|
|
8570
|
-
throw new Error("Failed to request device code");
|
|
8571
|
-
}
|
|
8572
|
-
let raw;
|
|
8897
|
+
async function fetchEmail(appUrl, accessToken, fetchFn) {
|
|
8573
8898
|
try {
|
|
8574
|
-
|
|
8899
|
+
const response = await fetchFn(`${appUrl}/api/auth/whoami`, {
|
|
8900
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
8901
|
+
});
|
|
8902
|
+
if (!response.ok) return void 0;
|
|
8903
|
+
const parsed = WhoamiSchema.safeParse(await response.json());
|
|
8904
|
+
return parsed.success ? parsed.data.email : void 0;
|
|
8575
8905
|
} catch {
|
|
8576
|
-
|
|
8577
|
-
}
|
|
8578
|
-
const parsed = DeviceCodeResponseSchema.safeParse(raw);
|
|
8579
|
-
if (!parsed.success) {
|
|
8580
|
-
throw new Error("Malformed device code response");
|
|
8906
|
+
return void 0;
|
|
8581
8907
|
}
|
|
8582
|
-
return {
|
|
8583
|
-
deviceCode: parsed.data.deviceCode,
|
|
8584
|
-
userCode: parsed.data.userCode,
|
|
8585
|
-
verificationUri: parsed.data.verificationUri,
|
|
8586
|
-
verificationUriComplete: parsed.data.verificationUriComplete,
|
|
8587
|
-
expiresIn: parsed.data.expiresIn,
|
|
8588
|
-
interval: parsed.data.interval
|
|
8589
|
-
};
|
|
8590
8908
|
}
|
|
8591
|
-
async function
|
|
8909
|
+
async function persistSession(appUrl, tokens, fetchFn) {
|
|
8910
|
+
writeConfig({
|
|
8911
|
+
accessToken: tokens.accessToken,
|
|
8912
|
+
accessTokenExpiresAt: tokens.accessTokenExpiresAt,
|
|
8913
|
+
refreshToken: tokens.refreshToken ?? void 0,
|
|
8914
|
+
appUrl,
|
|
8915
|
+
// Drop the static token this session replaces, so the deprecated path
|
|
8916
|
+
// cannot outlive the login that retired it.
|
|
8917
|
+
token: void 0
|
|
8918
|
+
});
|
|
8919
|
+
const email = await fetchEmail(appUrl, tokens.accessToken, fetchFn);
|
|
8920
|
+
writeConfig({ email });
|
|
8921
|
+
}
|
|
8922
|
+
async function completeDeviceLogin(deviceCode, options = {}) {
|
|
8923
|
+
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
8592
8924
|
const appUrl = options.url || resolveAppUrl();
|
|
8593
|
-
const
|
|
8594
|
-
const timeoutMs = options.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;
|
|
8925
|
+
const deadline = Date.now() + (options.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS);
|
|
8595
8926
|
let intervalMs = options.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
if (
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
} catch (err) {
|
|
8612
|
-
clearTimeout(timeoutHandle);
|
|
8613
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
8614
|
-
break;
|
|
8615
|
-
}
|
|
8616
|
-
throw err;
|
|
8617
|
-
} finally {
|
|
8618
|
-
clearTimeout(timeoutHandle);
|
|
8619
|
-
}
|
|
8620
|
-
const data = await safeJsonParse(tokenResponse);
|
|
8621
|
-
if (data === MALFORMED) {
|
|
8622
|
-
return {
|
|
8623
|
-
success: false,
|
|
8624
|
-
status: "error",
|
|
8625
|
-
error: "Server returned malformed response"
|
|
8626
|
-
};
|
|
8627
|
-
}
|
|
8628
|
-
if (tokenResponse.ok) {
|
|
8629
|
-
if (data.token === void 0) {
|
|
8630
|
-
continue;
|
|
8631
|
-
}
|
|
8632
|
-
const tokenParsed = TokenResponseSchema.safeParse(data);
|
|
8633
|
-
if (!tokenParsed.success) {
|
|
8634
|
-
return {
|
|
8635
|
-
success: false,
|
|
8636
|
-
status: "error",
|
|
8637
|
-
error: "Server returned malformed token response"
|
|
8638
|
-
};
|
|
8639
|
-
}
|
|
8640
|
-
const { token, email } = tokenParsed.data;
|
|
8641
|
-
writeConfig({ token, email, appUrl });
|
|
8642
|
-
const configPath = getConfigPath();
|
|
8643
|
-
return {
|
|
8644
|
-
success: true,
|
|
8645
|
-
status: "authenticated",
|
|
8646
|
-
email,
|
|
8647
|
-
configPath
|
|
8648
|
-
};
|
|
8649
|
-
}
|
|
8650
|
-
if (data.error === "authorization_pending") continue;
|
|
8651
|
-
if (data.error === "slow_down") {
|
|
8652
|
-
intervalMs += 5e3;
|
|
8927
|
+
let attempts = 0;
|
|
8928
|
+
let waiting = "pending";
|
|
8929
|
+
while (Date.now() + intervalMs <= deadline) {
|
|
8930
|
+
if (options.maxPollAttempts !== void 0 && attempts >= options.maxPollAttempts)
|
|
8931
|
+
break;
|
|
8932
|
+
attempts += 1;
|
|
8933
|
+
await delay4(intervalMs);
|
|
8934
|
+
const poll = await pollDeviceToken(
|
|
8935
|
+
appUrl,
|
|
8936
|
+
deviceCode,
|
|
8937
|
+
fetchFn,
|
|
8938
|
+
AbortSignal.timeout(Math.max(1, deadline - Date.now()))
|
|
8939
|
+
);
|
|
8940
|
+
if (poll.status === "pending") {
|
|
8941
|
+
waiting = "pending";
|
|
8653
8942
|
continue;
|
|
8654
8943
|
}
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
} else if (errField && typeof errField === "object" && "message" in errField && typeof errField.message === "string") {
|
|
8660
|
-
errorMsg = errField.message;
|
|
8661
|
-
} else {
|
|
8662
|
-
errorMsg = "Authorization failed";
|
|
8663
|
-
}
|
|
8664
|
-
return { success: false, status: "error", error: errorMsg };
|
|
8665
|
-
}
|
|
8666
|
-
return { success: false, status: "pending" };
|
|
8667
|
-
}
|
|
8668
|
-
var MALFORMED = /* @__PURE__ */ Symbol("malformed-json");
|
|
8669
|
-
async function safeJsonParse(response) {
|
|
8670
|
-
try {
|
|
8671
|
-
const parsed = await response.json();
|
|
8672
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
8673
|
-
return parsed;
|
|
8944
|
+
if (poll.status === "slow_down") {
|
|
8945
|
+
waiting = "slow_down";
|
|
8946
|
+
intervalMs += SLOW_DOWN_STEP_MS;
|
|
8947
|
+
continue;
|
|
8674
8948
|
}
|
|
8675
|
-
return
|
|
8676
|
-
|
|
8677
|
-
return
|
|
8949
|
+
if (poll.status !== "ok") return poll;
|
|
8950
|
+
await persistSession(appUrl, poll.tokens, fetchFn);
|
|
8951
|
+
return { status: "ok" };
|
|
8678
8952
|
}
|
|
8953
|
+
return { status: waiting };
|
|
8679
8954
|
}
|
|
8680
8955
|
async function login(options = {}) {
|
|
8681
|
-
const
|
|
8682
|
-
const
|
|
8683
|
-
let
|
|
8956
|
+
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
8957
|
+
const appUrl = options.url || resolveAppUrl();
|
|
8958
|
+
let authorization;
|
|
8684
8959
|
try {
|
|
8685
|
-
|
|
8686
|
-
url: urlOption,
|
|
8687
|
-
fetch: fetchOption
|
|
8688
|
-
});
|
|
8960
|
+
authorization = await startDeviceAuthorization(appUrl, fetchFn);
|
|
8689
8961
|
} catch {
|
|
8690
8962
|
return { success: false, error: "Failed to request device code" };
|
|
8691
8963
|
}
|
|
8692
|
-
const
|
|
8693
|
-
|
|
8694
|
-
verificationUri,
|
|
8695
|
-
verificationUriComplete,
|
|
8696
|
-
expiresIn,
|
|
8697
|
-
interval,
|
|
8698
|
-
deviceCode
|
|
8699
|
-
} = codeResult;
|
|
8700
|
-
const prompt = (msg) => process.stderr.write(msg + "\n");
|
|
8964
|
+
const target = authorization.verificationUriComplete;
|
|
8965
|
+
const prompt = (message) => process.stderr.write(message + "\n");
|
|
8701
8966
|
prompt(`
|
|
8702
|
-
! Your one-time code: ${userCode}`);
|
|
8703
|
-
prompt(` Authorize here: ${
|
|
8967
|
+
! Your one-time code: ${authorization.userCode}`);
|
|
8968
|
+
prompt(` Authorize here: ${target}
|
|
8704
8969
|
`);
|
|
8705
8970
|
const opener = options.openUrl ?? openInBrowser;
|
|
8706
8971
|
try {
|
|
8707
|
-
await opener(
|
|
8972
|
+
await opener(target);
|
|
8708
8973
|
prompt(" Opening browser...");
|
|
8709
8974
|
} catch {
|
|
8710
8975
|
prompt(" Could not open browser. Visit the URL manually.");
|
|
8711
8976
|
}
|
|
8712
8977
|
prompt(" Waiting for authorization... (press Ctrl+C to cancel)\n");
|
|
8713
|
-
const
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
await new Promise((r) => setTimeout(r, pollInterval));
|
|
8724
|
-
const remaining = Math.max(1, deadline - Date.now());
|
|
8725
|
-
const controller = new AbortController();
|
|
8726
|
-
const timeoutHandle = setTimeout(() => controller.abort(), remaining);
|
|
8727
|
-
let tokenResponse;
|
|
8728
|
-
try {
|
|
8729
|
-
tokenResponse = await f(`${appUrl}/api/auth/device/token`, {
|
|
8730
|
-
method: "POST",
|
|
8731
|
-
headers: { "Content-Type": "application/json" },
|
|
8732
|
-
body: JSON.stringify({ deviceCode, hostname: hostname() }),
|
|
8733
|
-
signal: controller.signal
|
|
8734
|
-
});
|
|
8735
|
-
} catch (err) {
|
|
8736
|
-
clearTimeout(timeoutHandle);
|
|
8737
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
8738
|
-
break;
|
|
8739
|
-
}
|
|
8740
|
-
throw err;
|
|
8741
|
-
} finally {
|
|
8742
|
-
clearTimeout(timeoutHandle);
|
|
8743
|
-
}
|
|
8744
|
-
const data = await safeJsonParse(tokenResponse);
|
|
8745
|
-
if (data === MALFORMED) {
|
|
8746
|
-
return {
|
|
8747
|
-
success: false,
|
|
8748
|
-
error: "Server returned malformed response"
|
|
8749
|
-
};
|
|
8750
|
-
}
|
|
8751
|
-
if (tokenResponse.ok) {
|
|
8752
|
-
if (data.token === void 0) {
|
|
8753
|
-
continue;
|
|
8754
|
-
}
|
|
8755
|
-
const tokenParsed = TokenResponseSchema.safeParse(data);
|
|
8756
|
-
if (!tokenParsed.success) {
|
|
8757
|
-
return {
|
|
8758
|
-
success: false,
|
|
8759
|
-
error: "Server returned malformed token response"
|
|
8760
|
-
};
|
|
8761
|
-
}
|
|
8762
|
-
const { token, email } = tokenParsed.data;
|
|
8763
|
-
writeConfig({ token, email, appUrl });
|
|
8764
|
-
const configPath = getConfigPath();
|
|
8765
|
-
return { success: true, email, configPath };
|
|
8766
|
-
}
|
|
8767
|
-
if (data.error === "authorization_pending") continue;
|
|
8768
|
-
if (data.error === "slow_down") {
|
|
8769
|
-
pollInterval += 5e3;
|
|
8770
|
-
continue;
|
|
8771
|
-
}
|
|
8772
|
-
const errField = data.error;
|
|
8773
|
-
const errorMsg = typeof errField === "string" ? errField : "Authorization failed";
|
|
8774
|
-
return { success: false, error: errorMsg };
|
|
8775
|
-
}
|
|
8776
|
-
return {
|
|
8777
|
-
success: false,
|
|
8778
|
-
error: "Authorization timed out. Please try again."
|
|
8779
|
-
};
|
|
8780
|
-
}
|
|
8781
|
-
const pollResult = await pollForToken(deviceCode, {
|
|
8782
|
-
url: urlOption,
|
|
8783
|
-
fetch: fetchOption,
|
|
8784
|
-
timeoutMs,
|
|
8785
|
-
intervalMs
|
|
8978
|
+
const outcome = await completeDeviceLogin(authorization.deviceCode, {
|
|
8979
|
+
url: appUrl,
|
|
8980
|
+
fetch: fetchFn,
|
|
8981
|
+
timeoutMs: authorization.expiresIn * 1e3 + POLL_TIMEOUT_BUFFER_MS,
|
|
8982
|
+
// Clamped here, at the one place a server's number enters the loop. The
|
|
8983
|
+
// helper takes its caller's interval as stated, which is what keeps a
|
|
8984
|
+
// stated 0 from becoming a poll flood without making the helper's own
|
|
8985
|
+
// option untestably slow.
|
|
8986
|
+
intervalMs: options.pollIntervalMs ?? Math.max(MIN_SERVER_POLL_INTERVAL_MS, authorization.interval * 1e3),
|
|
8987
|
+
...options.maxPollAttempts !== void 0 ? { maxPollAttempts: options.maxPollAttempts } : {}
|
|
8786
8988
|
});
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
|
|
8790
|
-
|
|
8791
|
-
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
|
|
8795
|
-
|
|
8989
|
+
switch (outcome.status) {
|
|
8990
|
+
case "ok": {
|
|
8991
|
+
const email = readConfig()?.email;
|
|
8992
|
+
return {
|
|
8993
|
+
success: true,
|
|
8994
|
+
...email ? { email } : {},
|
|
8995
|
+
configPath: getConfigPath()
|
|
8996
|
+
};
|
|
8997
|
+
}
|
|
8998
|
+
case "denied":
|
|
8999
|
+
return { success: false, error: "Authorization was denied." };
|
|
9000
|
+
case "error":
|
|
9001
|
+
return { success: false, error: outcome.error };
|
|
9002
|
+
default:
|
|
9003
|
+
return { success: false, error: TIMED_OUT };
|
|
8796
9004
|
}
|
|
8797
|
-
return {
|
|
8798
|
-
success: false,
|
|
8799
|
-
error: "Authorization timed out. Please try again."
|
|
8800
|
-
};
|
|
8801
9005
|
}
|
|
8802
9006
|
|
|
8803
9007
|
// src/commands/logout/index.ts
|
|
8804
9008
|
init_cli_logger();
|
|
9009
|
+
init_oauth_client();
|
|
8805
9010
|
init_config_file();
|
|
8806
9011
|
async function logoutCommand(options) {
|
|
8807
9012
|
const logger = createCLILogger(options);
|
|
8808
|
-
const deleted =
|
|
9013
|
+
const { deleted } = await logout();
|
|
8809
9014
|
const configPath = getConfigPath();
|
|
8810
9015
|
if (options.json) {
|
|
8811
9016
|
logger.json({ success: true, deleted });
|
|
8812
9017
|
} else if (deleted) {
|
|
8813
|
-
logger.info(`Logged out.
|
|
9018
|
+
logger.info(`Logged out. Session removed from ${configPath}`);
|
|
8814
9019
|
} else {
|
|
8815
9020
|
logger.info("No stored credentials found.");
|
|
8816
9021
|
}
|
|
8817
9022
|
process.exit(0);
|
|
8818
9023
|
}
|
|
9024
|
+
async function logout() {
|
|
9025
|
+
const config = readConfig();
|
|
9026
|
+
const appUrl = resolveAppUrl();
|
|
9027
|
+
if (config?.refreshToken) {
|
|
9028
|
+
await revokeRefreshToken(appUrl, config.refreshToken);
|
|
9029
|
+
}
|
|
9030
|
+
return { deleted: deleteConfig() };
|
|
9031
|
+
}
|
|
8819
9032
|
|
|
8820
9033
|
// src/core/api-client.ts
|
|
8821
9034
|
init_auth();
|
|
@@ -8827,8 +9040,8 @@ import createClient from "openapi-fetch";
|
|
|
8827
9040
|
init_config_file();
|
|
8828
9041
|
import { createHash } from "crypto";
|
|
8829
9042
|
import semver4 from "semver";
|
|
8830
|
-
var bakedContractVersion = true ? "4.
|
|
8831
|
-
var bakedContractHash = true ? "
|
|
9043
|
+
var bakedContractVersion = true ? "4.5.1" : PLACEHOLDER;
|
|
9044
|
+
var bakedContractHash = true ? "335b9bd11acaf7c516e3fcd47c74b4ab212032375e00f2b58b8459f4cb30e3a6" : "";
|
|
8832
9045
|
function isRecord3(value) {
|
|
8833
9046
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
8834
9047
|
}
|
|
@@ -8939,17 +9152,26 @@ function emitDriftWarning(responseHeaders) {
|
|
|
8939
9152
|
);
|
|
8940
9153
|
}
|
|
8941
9154
|
function createApiClient() {
|
|
8942
|
-
const token = getToken();
|
|
8943
|
-
if (!token) throw new Error("WALKEROS_TOKEN not set.");
|
|
8944
9155
|
const client = createClient({
|
|
8945
9156
|
baseUrl: resolveAppUrl(),
|
|
8946
9157
|
headers: {
|
|
8947
|
-
Authorization: `Bearer ${token}`,
|
|
8948
9158
|
"Content-Type": "application/json",
|
|
8949
9159
|
...clientContextHeaders()
|
|
8950
9160
|
}
|
|
8951
9161
|
});
|
|
8952
9162
|
client.use({
|
|
9163
|
+
// Authorization is attached per request, not at construction: the stdio
|
|
9164
|
+
// MCP server builds one client and keeps it for hours, so a token captured
|
|
9165
|
+
// here would go stale and never pick up a refresh.
|
|
9166
|
+
async onRequest({ request }) {
|
|
9167
|
+
const token = await resolveAccessToken();
|
|
9168
|
+
if (!token)
|
|
9169
|
+
throw new Error("Not authenticated. Run `walkeros login` first.");
|
|
9170
|
+
request.headers.set("Authorization", `Bearer ${token}`);
|
|
9171
|
+
return request;
|
|
9172
|
+
},
|
|
9173
|
+
// Surface contract drift once per process from any response's version
|
|
9174
|
+
// headers. openapi-fetch ^0.17 supports `use({ onResponse })`.
|
|
8953
9175
|
onResponse({ response }) {
|
|
8954
9176
|
emitDriftWarning(response.headers);
|
|
8955
9177
|
return void 0;
|
|
@@ -10212,6 +10434,7 @@ async function wrapSkeleton(options) {
|
|
|
10212
10434
|
|
|
10213
10435
|
// src/index.ts
|
|
10214
10436
|
init_auth();
|
|
10437
|
+
init_oauth_client();
|
|
10215
10438
|
init_http();
|
|
10216
10439
|
init_client_context();
|
|
10217
10440
|
|
|
@@ -10361,7 +10584,7 @@ async function listJourneys(options) {
|
|
|
10361
10584
|
init_auth();
|
|
10362
10585
|
init_http();
|
|
10363
10586
|
init_output();
|
|
10364
|
-
|
|
10587
|
+
init_auth();
|
|
10365
10588
|
async function startObserveSession(options) {
|
|
10366
10589
|
const pid = options.projectId ?? requireProjectId();
|
|
10367
10590
|
const body = {
|
|
@@ -10413,6 +10636,149 @@ async function endObserveSession(options) {
|
|
|
10413
10636
|
}
|
|
10414
10637
|
}
|
|
10415
10638
|
|
|
10639
|
+
// src/commands/hub/index.ts
|
|
10640
|
+
init_auth();
|
|
10641
|
+
init_http();
|
|
10642
|
+
async function readJson2(response, fallback) {
|
|
10643
|
+
if (!response.ok) {
|
|
10644
|
+
const body = await response.json().catch(() => ({}));
|
|
10645
|
+
throwApiResponseError(response, body, fallback);
|
|
10646
|
+
}
|
|
10647
|
+
return response.json();
|
|
10648
|
+
}
|
|
10649
|
+
async function listReleases(options) {
|
|
10650
|
+
const pid = options.projectId ?? requireProjectId();
|
|
10651
|
+
const params = new URLSearchParams({ rationale: "true" });
|
|
10652
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
10653
|
+
if (options.offset !== void 0)
|
|
10654
|
+
params.set("offset", String(options.offset));
|
|
10655
|
+
const response = await apiFetch(
|
|
10656
|
+
`/api/projects/${pid}/flows/${options.flowId}/releases?${params.toString()}`
|
|
10657
|
+
);
|
|
10658
|
+
return readJson2(response, "Failed to list releases");
|
|
10659
|
+
}
|
|
10660
|
+
async function getRelease(options) {
|
|
10661
|
+
const pid = options.projectId ?? requireProjectId();
|
|
10662
|
+
const segment = "versionId" in options.ref ? options.ref.versionId : String(options.ref.versionNumber);
|
|
10663
|
+
const response = await apiFetch(
|
|
10664
|
+
`/api/projects/${pid}/flows/${options.flowId}/releases/${encodeURIComponent(segment)}`
|
|
10665
|
+
);
|
|
10666
|
+
return readJson2(response, "Failed to read release");
|
|
10667
|
+
}
|
|
10668
|
+
async function listStepHistory(options) {
|
|
10669
|
+
const pid = options.projectId ?? requireProjectId();
|
|
10670
|
+
const params = new URLSearchParams({ step: options.step });
|
|
10671
|
+
if (options.flow !== void 0) params.set("flow", options.flow);
|
|
10672
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
10673
|
+
const response = await apiFetch(
|
|
10674
|
+
`/api/projects/${pid}/flows/${options.flowId}/releases/step-history?${params.toString()}`
|
|
10675
|
+
);
|
|
10676
|
+
return readJson2(response, "Failed to read step history");
|
|
10677
|
+
}
|
|
10678
|
+
async function setReleaseRationale(options) {
|
|
10679
|
+
const pid = options.projectId ?? requireProjectId();
|
|
10680
|
+
const response = await apiFetch(
|
|
10681
|
+
`/api/projects/${pid}/flows/${options.flowId}/releases/annotations`,
|
|
10682
|
+
{
|
|
10683
|
+
method: "PUT",
|
|
10684
|
+
headers: { "Content-Type": "application/json" },
|
|
10685
|
+
body: JSON.stringify({
|
|
10686
|
+
versionId: options.versionId,
|
|
10687
|
+
humanText: options.text
|
|
10688
|
+
})
|
|
10689
|
+
}
|
|
10690
|
+
);
|
|
10691
|
+
return readJson2(response, "Failed to write release rationale");
|
|
10692
|
+
}
|
|
10693
|
+
async function listThreads(options) {
|
|
10694
|
+
const pid = options.projectId ?? requireProjectId();
|
|
10695
|
+
const params = new URLSearchParams();
|
|
10696
|
+
if (options.anchorType !== void 0)
|
|
10697
|
+
params.set("anchorType", options.anchorType);
|
|
10698
|
+
if (options.anchorKey !== void 0)
|
|
10699
|
+
params.set("anchorKey", options.anchorKey);
|
|
10700
|
+
if (options.status !== void 0) params.set("status", options.status);
|
|
10701
|
+
params.set("includeMessages", options.includeMessages ? "true" : "false");
|
|
10702
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
10703
|
+
const response = await apiFetch(
|
|
10704
|
+
`/api/projects/${pid}/flows/${options.flowId}/threads?${params.toString()}`
|
|
10705
|
+
);
|
|
10706
|
+
return readJson2(response, "Failed to list threads");
|
|
10707
|
+
}
|
|
10708
|
+
async function createThread(options) {
|
|
10709
|
+
const pid = options.projectId ?? requireProjectId();
|
|
10710
|
+
const response = await apiFetch(
|
|
10711
|
+
`/api/projects/${pid}/flows/${options.flowId}/threads`,
|
|
10712
|
+
{
|
|
10713
|
+
method: "POST",
|
|
10714
|
+
headers: { "Content-Type": "application/json" },
|
|
10715
|
+
body: JSON.stringify({
|
|
10716
|
+
anchorType: options.anchorType,
|
|
10717
|
+
anchorKey: options.anchorKey,
|
|
10718
|
+
...options.anchorLabel !== void 0 ? { anchorLabel: options.anchorLabel } : {},
|
|
10719
|
+
text: options.text
|
|
10720
|
+
})
|
|
10721
|
+
}
|
|
10722
|
+
);
|
|
10723
|
+
return readJson2(response, "Failed to open thread");
|
|
10724
|
+
}
|
|
10725
|
+
async function addThreadMessage(options) {
|
|
10726
|
+
const pid = options.projectId ?? requireProjectId();
|
|
10727
|
+
const response = await apiFetch(
|
|
10728
|
+
`/api/projects/${pid}/flows/${options.flowId}/threads/${encodeURIComponent(options.threadId)}/messages`,
|
|
10729
|
+
{
|
|
10730
|
+
method: "POST",
|
|
10731
|
+
headers: { "Content-Type": "application/json" },
|
|
10732
|
+
body: JSON.stringify({ text: options.text })
|
|
10733
|
+
}
|
|
10734
|
+
);
|
|
10735
|
+
return readJson2(response, "Failed to add message");
|
|
10736
|
+
}
|
|
10737
|
+
async function listKnowledge(options) {
|
|
10738
|
+
const pid = options.projectId ?? requireProjectId();
|
|
10739
|
+
const params = new URLSearchParams();
|
|
10740
|
+
if (options.pageKey !== void 0) params.set("pageKey", options.pageKey);
|
|
10741
|
+
if (options.frameId !== void 0) params.set("frameId", options.frameId);
|
|
10742
|
+
if (options.markId !== void 0) params.set("markId", options.markId);
|
|
10743
|
+
params.set("includeMessages", options.includeMessages ? "true" : "false");
|
|
10744
|
+
if (options.limit !== void 0) params.set("limit", String(options.limit));
|
|
10745
|
+
const response = await apiFetch(
|
|
10746
|
+
`/api/projects/${pid}/knowledge?${params.toString()}`
|
|
10747
|
+
);
|
|
10748
|
+
return readJson2(response, "Failed to read knowledge");
|
|
10749
|
+
}
|
|
10750
|
+
|
|
10751
|
+
// src/commands/frames/index.ts
|
|
10752
|
+
init_auth();
|
|
10753
|
+
init_http();
|
|
10754
|
+
async function readJson3(response, fallback) {
|
|
10755
|
+
if (!response.ok) {
|
|
10756
|
+
const body = await response.json().catch(() => ({}));
|
|
10757
|
+
throwApiResponseError(response, body, fallback);
|
|
10758
|
+
}
|
|
10759
|
+
return response.json();
|
|
10760
|
+
}
|
|
10761
|
+
async function listFrames(options = {}) {
|
|
10762
|
+
const pid = options.projectId ?? requireProjectId();
|
|
10763
|
+
const response = await apiFetch(`/api/projects/${pid}/frames`);
|
|
10764
|
+
return readJson3(response, "Failed to list frames");
|
|
10765
|
+
}
|
|
10766
|
+
async function listPageFrames(options) {
|
|
10767
|
+
const pid = options.projectId ?? requireProjectId();
|
|
10768
|
+
const params = new URLSearchParams({ pageKey: options.pageKey });
|
|
10769
|
+
const response = await apiFetch(
|
|
10770
|
+
`/api/projects/${pid}/frames?${params.toString()}`
|
|
10771
|
+
);
|
|
10772
|
+
return readJson3(response, "Failed to list page frames");
|
|
10773
|
+
}
|
|
10774
|
+
async function getFrame(options) {
|
|
10775
|
+
const pid = options.projectId ?? requireProjectId();
|
|
10776
|
+
const response = await apiFetch(
|
|
10777
|
+
`/api/projects/${pid}/frames/${encodeURIComponent(options.frameId)}`
|
|
10778
|
+
);
|
|
10779
|
+
return readJson3(response, "Failed to read frame");
|
|
10780
|
+
}
|
|
10781
|
+
|
|
10416
10782
|
// src/commands/secrets/index.ts
|
|
10417
10783
|
init_auth();
|
|
10418
10784
|
init_http();
|
|
@@ -10784,6 +11150,7 @@ export {
|
|
|
10784
11150
|
ApiError,
|
|
10785
11151
|
DeploymentAmbiguityError,
|
|
10786
11152
|
VERSION,
|
|
11153
|
+
addThreadMessage,
|
|
10787
11154
|
annotateErrorWithDrift,
|
|
10788
11155
|
apiFetch,
|
|
10789
11156
|
bakedContractHash,
|
|
@@ -10793,9 +11160,11 @@ export {
|
|
|
10793
11160
|
bundleCommand,
|
|
10794
11161
|
canonicalContractHash,
|
|
10795
11162
|
classifyStepProperties,
|
|
11163
|
+
clearAuthFields,
|
|
10796
11164
|
clientContextHeaders,
|
|
10797
11165
|
compareContract,
|
|
10798
11166
|
compareOutput,
|
|
11167
|
+
completeDeviceLogin,
|
|
10799
11168
|
containsCodeMarkers,
|
|
10800
11169
|
createApiClient,
|
|
10801
11170
|
createDeployCommand,
|
|
@@ -10807,6 +11176,8 @@ export {
|
|
|
10807
11176
|
createProject,
|
|
10808
11177
|
createProjectCommand,
|
|
10809
11178
|
createSecret,
|
|
11179
|
+
createThread,
|
|
11180
|
+
credentialSource,
|
|
10810
11181
|
deleteConfig,
|
|
10811
11182
|
deleteDeployment,
|
|
10812
11183
|
deleteDeploymentByFlowId,
|
|
@@ -10837,36 +11208,44 @@ export {
|
|
|
10837
11208
|
getFeedbackPreference,
|
|
10838
11209
|
getFlow,
|
|
10839
11210
|
getFlowCommand,
|
|
11211
|
+
getFrame,
|
|
10840
11212
|
getObserveSession,
|
|
10841
11213
|
getPreview,
|
|
10842
11214
|
getProject,
|
|
10843
11215
|
getProjectCommand,
|
|
10844
|
-
|
|
11216
|
+
getRelease,
|
|
10845
11217
|
listAllFlows,
|
|
10846
11218
|
listDeployments,
|
|
10847
11219
|
listDeploymentsCommand,
|
|
10848
11220
|
listFlows,
|
|
10849
11221
|
listFlowsCommand,
|
|
11222
|
+
listFrames,
|
|
10850
11223
|
listJourneys,
|
|
11224
|
+
listKnowledge,
|
|
11225
|
+
listPageFrames,
|
|
10851
11226
|
listPreviews,
|
|
10852
11227
|
listProjects,
|
|
10853
11228
|
listProjectsCommand,
|
|
11229
|
+
listReleases,
|
|
10854
11230
|
listSecrets,
|
|
11231
|
+
listStepHistory,
|
|
11232
|
+
listThreads,
|
|
10855
11233
|
loadConfig,
|
|
10856
11234
|
loadJsonConfig,
|
|
11235
|
+
login,
|
|
10857
11236
|
loginCommand,
|
|
11237
|
+
logout,
|
|
10858
11238
|
logoutCommand,
|
|
10859
11239
|
mergeAuthHeaders,
|
|
10860
11240
|
parseSSEEvents,
|
|
10861
|
-
pollForToken,
|
|
10862
11241
|
publicFetch,
|
|
10863
11242
|
push,
|
|
10864
11243
|
pushCommand,
|
|
10865
11244
|
readConfig,
|
|
10866
11245
|
regrantPreview,
|
|
10867
|
-
requestDeviceCode,
|
|
10868
11246
|
requireProjectId,
|
|
10869
11247
|
resetClientContext,
|
|
11248
|
+
resolveAccessToken,
|
|
10870
11249
|
resolveAppUrl,
|
|
10871
11250
|
resolveToken,
|
|
10872
11251
|
run,
|
|
@@ -10874,10 +11253,12 @@ export {
|
|
|
10874
11253
|
setClientContext,
|
|
10875
11254
|
setDefaultProject,
|
|
10876
11255
|
setFeedbackPreference,
|
|
11256
|
+
setReleaseRationale,
|
|
10877
11257
|
simulateCollector,
|
|
10878
11258
|
simulateDestination,
|
|
10879
11259
|
simulateSource,
|
|
10880
11260
|
simulateTransformer,
|
|
11261
|
+
startDeviceAuthorization,
|
|
10881
11262
|
startObserveSession,
|
|
10882
11263
|
telemetry_exports as telemetry,
|
|
10883
11264
|
telemetryDisableCommand,
|