@walkeros/cli 3.4.1-next-1776790594143 → 3.4.2
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 +32 -3
- package/dist/cli.js +353 -126
- package/dist/index.d.ts +429 -332
- package/dist/index.js +293 -36
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
# @walkeros/cli
|
|
2
2
|
|
|
3
|
-
## 3.4.
|
|
3
|
+
## 3.4.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2d25eda: Replace `api` mega-tool with four focused management tools: `auth`
|
|
8
|
+
(device code login), `project_manage`, `flow_manage`, and `deploy_manage`.
|
|
9
|
+
Enforce strict CLI/MCP separation of concern — MCP no longer reads config
|
|
10
|
+
files or checks env vars directly. All tools are always registered regardless
|
|
11
|
+
of auth state.
|
|
12
|
+
|
|
13
|
+
CLI exports new functions: `requestDeviceCode`, `pollForToken`,
|
|
14
|
+
`setDefaultProject`, `getDefaultProject`, `listAllFlows`,
|
|
15
|
+
`setFeedbackPreference`, `getFeedbackPreference`, `resolveToken`,
|
|
16
|
+
`deleteConfig`.
|
|
17
|
+
|
|
18
|
+
Preview CRUD (`preview_list`, `preview_get`, `preview_create`,
|
|
19
|
+
`preview_delete`) is now part of `flow_manage` — previews are a flow-scoped
|
|
20
|
+
concern and belong alongside the flow lifecycle actions rather than in a
|
|
21
|
+
separate tool.
|
|
22
|
+
|
|
23
|
+
- cb4c069: Runtime fetchers (`fetchConfig`, `fetchSecrets`) now classify 401/403
|
|
24
|
+
responses from the app as a typed `RunnerAuthError` with a structured `reason`
|
|
25
|
+
(`'unauthorised' | 'flow' | 'scope' | 'forbidden'`) and the app's error `code`
|
|
26
|
+
(`FORBIDDEN_FLOW` / `FORBIDDEN_SCOPE`). Callers can log a specific reason
|
|
27
|
+
instead of a generic "token may have expired" message, and exit cleanly rather
|
|
28
|
+
than retry on scope/flow mismatches.
|
|
29
|
+
- @walkeros/core@3.4.2
|
|
30
|
+
- @walkeros/server-core@3.4.2
|
|
31
|
+
|
|
32
|
+
## 3.4.1
|
|
4
33
|
|
|
5
34
|
### Patch Changes
|
|
6
35
|
|
|
@@ -16,8 +45,8 @@
|
|
|
16
45
|
silent analytics breakage.
|
|
17
46
|
- Updated dependencies [12adf24]
|
|
18
47
|
- Updated dependencies [75aa26b]
|
|
19
|
-
- @walkeros/core@3.4.1
|
|
20
|
-
- @walkeros/server-core@3.4.1
|
|
48
|
+
- @walkeros/core@3.4.1
|
|
49
|
+
- @walkeros/server-core@3.4.1
|
|
21
50
|
|
|
22
51
|
## 3.4.0
|
|
23
52
|
|
package/dist/cli.js
CHANGED
|
@@ -665,6 +665,10 @@ function deleteConfig() {
|
|
|
665
665
|
}
|
|
666
666
|
return false;
|
|
667
667
|
}
|
|
668
|
+
function getDefaultProject() {
|
|
669
|
+
const config2 = readConfig();
|
|
670
|
+
return config2?.defaultProjectId ?? null;
|
|
671
|
+
}
|
|
668
672
|
function resolveToken() {
|
|
669
673
|
const envToken = process.env.WALKEROS_TOKEN;
|
|
670
674
|
if (envToken) return { token: envToken, source: "env" };
|
|
@@ -1030,8 +1034,11 @@ function resolveRunToken() {
|
|
|
1030
1034
|
return resolveDeployToken() ?? resolveToken()?.token ?? null;
|
|
1031
1035
|
}
|
|
1032
1036
|
function requireProjectId() {
|
|
1033
|
-
const projectId = process.env.WALKEROS_PROJECT_ID;
|
|
1034
|
-
if (!projectId)
|
|
1037
|
+
const projectId = process.env.WALKEROS_PROJECT_ID || getDefaultProject();
|
|
1038
|
+
if (!projectId)
|
|
1039
|
+
throw new Error(
|
|
1040
|
+
"No project selected. Set WALKEROS_PROJECT_ID or configure a default project."
|
|
1041
|
+
);
|
|
1035
1042
|
return projectId;
|
|
1036
1043
|
}
|
|
1037
1044
|
var init_auth = __esm({
|
|
@@ -18301,6 +18308,101 @@ var init_utils3 = __esm({
|
|
|
18301
18308
|
}
|
|
18302
18309
|
});
|
|
18303
18310
|
|
|
18311
|
+
// src/commands/projects/index.ts
|
|
18312
|
+
async function listProjects() {
|
|
18313
|
+
const client = createApiClient();
|
|
18314
|
+
const { data, error: error48 } = await client.GET("/api/projects");
|
|
18315
|
+
if (error48) throw new Error(error48.error?.message || "Failed to list projects");
|
|
18316
|
+
return data;
|
|
18317
|
+
}
|
|
18318
|
+
async function getProject(options = {}) {
|
|
18319
|
+
const id = options.projectId ?? requireProjectId();
|
|
18320
|
+
const client = createApiClient();
|
|
18321
|
+
const { data, error: error48 } = await client.GET("/api/projects/{projectId}", {
|
|
18322
|
+
params: { path: { projectId: id } }
|
|
18323
|
+
});
|
|
18324
|
+
if (error48) throw new Error(error48.error?.message || "Failed to get project");
|
|
18325
|
+
return data;
|
|
18326
|
+
}
|
|
18327
|
+
async function createProject(options) {
|
|
18328
|
+
const client = createApiClient();
|
|
18329
|
+
const { data, error: error48 } = await client.POST("/api/projects", {
|
|
18330
|
+
body: { name: options.name }
|
|
18331
|
+
});
|
|
18332
|
+
if (error48)
|
|
18333
|
+
throw new Error(error48.error?.message || "Failed to create project");
|
|
18334
|
+
return data;
|
|
18335
|
+
}
|
|
18336
|
+
async function updateProject(options) {
|
|
18337
|
+
const id = options.projectId ?? requireProjectId();
|
|
18338
|
+
const client = createApiClient();
|
|
18339
|
+
const { data, error: error48 } = await client.PATCH("/api/projects/{projectId}", {
|
|
18340
|
+
params: { path: { projectId: id } },
|
|
18341
|
+
body: { name: options.name }
|
|
18342
|
+
});
|
|
18343
|
+
if (error48)
|
|
18344
|
+
throw new Error(error48.error?.message || "Failed to update project");
|
|
18345
|
+
return data;
|
|
18346
|
+
}
|
|
18347
|
+
async function deleteProject(options = {}) {
|
|
18348
|
+
const id = options.projectId ?? requireProjectId();
|
|
18349
|
+
const client = createApiClient();
|
|
18350
|
+
const { data, error: error48 } = await client.DELETE("/api/projects/{projectId}", {
|
|
18351
|
+
params: { path: { projectId: id } }
|
|
18352
|
+
});
|
|
18353
|
+
if (error48)
|
|
18354
|
+
throw new Error(error48.error?.message || "Failed to delete project");
|
|
18355
|
+
return data ?? { success: true };
|
|
18356
|
+
}
|
|
18357
|
+
async function handleResult(fn2, options) {
|
|
18358
|
+
try {
|
|
18359
|
+
const result = await fn2();
|
|
18360
|
+
await writeResult(JSON.stringify(result, null, 2), options);
|
|
18361
|
+
} catch (error48) {
|
|
18362
|
+
handleCliError(error48);
|
|
18363
|
+
}
|
|
18364
|
+
}
|
|
18365
|
+
async function listProjectsCommand(options) {
|
|
18366
|
+
await handleResult(() => listProjects(), options);
|
|
18367
|
+
}
|
|
18368
|
+
async function getProjectCommand(projectId, options) {
|
|
18369
|
+
await handleResult(
|
|
18370
|
+
() => getProject({ projectId: projectId ?? options.project }),
|
|
18371
|
+
options
|
|
18372
|
+
);
|
|
18373
|
+
}
|
|
18374
|
+
async function createProjectCommand(name, options) {
|
|
18375
|
+
await handleResult(() => createProject({ name }), options);
|
|
18376
|
+
}
|
|
18377
|
+
async function updateProjectCommand(projectId, options) {
|
|
18378
|
+
const name = options.name;
|
|
18379
|
+
if (!name) {
|
|
18380
|
+
throw new Error("Missing required option: --name <name>");
|
|
18381
|
+
}
|
|
18382
|
+
await handleResult(
|
|
18383
|
+
() => updateProject({
|
|
18384
|
+
projectId: projectId ?? options.project,
|
|
18385
|
+
name
|
|
18386
|
+
}),
|
|
18387
|
+
options
|
|
18388
|
+
);
|
|
18389
|
+
}
|
|
18390
|
+
async function deleteProjectCommand(projectId, options) {
|
|
18391
|
+
await handleResult(
|
|
18392
|
+
() => deleteProject({ projectId: projectId ?? options.project }),
|
|
18393
|
+
options
|
|
18394
|
+
);
|
|
18395
|
+
}
|
|
18396
|
+
var init_projects = __esm({
|
|
18397
|
+
"src/commands/projects/index.ts"() {
|
|
18398
|
+
"use strict";
|
|
18399
|
+
init_api_client();
|
|
18400
|
+
init_api_error();
|
|
18401
|
+
init_auth();
|
|
18402
|
+
init_output();
|
|
18403
|
+
}
|
|
18404
|
+
});
|
|
18405
|
+
|
|
18304
18406
|
// src/commands/flows/index.ts
|
|
18305
18407
|
async function listFlows(options = {}) {
|
|
18306
18408
|
const id = options.projectId ?? requireProjectId();
|
|
@@ -18459,6 +18561,7 @@ var init_flows = __esm({
|
|
|
18459
18561
|
init_auth();
|
|
18460
18562
|
init_output();
|
|
18461
18563
|
init_stdin();
|
|
18564
|
+
init_projects();
|
|
18462
18565
|
}
|
|
18463
18566
|
});
|
|
18464
18567
|
|
|
@@ -20039,6 +20142,37 @@ async function resolveBundle(bundleEnv) {
|
|
|
20039
20142
|
|
|
20040
20143
|
// src/runtime/config-fetcher.ts
|
|
20041
20144
|
init_http();
|
|
20145
|
+
|
|
20146
|
+
// src/runtime/runner-auth-error.ts
|
|
20147
|
+
var RunnerAuthError = class extends Error {
|
|
20148
|
+
constructor(status, reason, code, message) {
|
|
20149
|
+
super(message);
|
|
20150
|
+
this.status = status;
|
|
20151
|
+
this.reason = reason;
|
|
20152
|
+
this.code = code;
|
|
20153
|
+
this.name = "RunnerAuthError";
|
|
20154
|
+
}
|
|
20155
|
+
};
|
|
20156
|
+
function isAppErrorBody(value) {
|
|
20157
|
+
return typeof value === "object" && value !== null && "error" in value && typeof value.error === "object";
|
|
20158
|
+
}
|
|
20159
|
+
async function throwIfRunnerAuthFailure(res) {
|
|
20160
|
+
if (res.status !== 401 && res.status !== 403) return;
|
|
20161
|
+
let code = null;
|
|
20162
|
+
let message = res.statusText;
|
|
20163
|
+
try {
|
|
20164
|
+
const body = await res.clone().json();
|
|
20165
|
+
if (isAppErrorBody(body) && body.error) {
|
|
20166
|
+
if (typeof body.error.code === "string") code = body.error.code;
|
|
20167
|
+
if (typeof body.error.message === "string") message = body.error.message;
|
|
20168
|
+
}
|
|
20169
|
+
} catch {
|
|
20170
|
+
}
|
|
20171
|
+
const reason = res.status === 401 ? "unauthorised" : code === "FORBIDDEN_FLOW" ? "flow" : code === "FORBIDDEN_SCOPE" ? "scope" : "forbidden";
|
|
20172
|
+
throw new RunnerAuthError(res.status, reason, code, message);
|
|
20173
|
+
}
|
|
20174
|
+
|
|
20175
|
+
// src/runtime/config-fetcher.ts
|
|
20042
20176
|
async function fetchConfig(options) {
|
|
20043
20177
|
const url2 = `${options.appUrl}/api/projects/${options.projectId}/flows/${options.flowId}`;
|
|
20044
20178
|
const headers = mergeAuthHeaders(
|
|
@@ -20052,12 +20186,8 @@ async function fetchConfig(options) {
|
|
|
20052
20186
|
if (response.status === 304) {
|
|
20053
20187
|
return { changed: false };
|
|
20054
20188
|
}
|
|
20189
|
+
await throwIfRunnerAuthFailure(response);
|
|
20055
20190
|
if (!response.ok) {
|
|
20056
|
-
if (response.status === 401 || response.status === 403) {
|
|
20057
|
-
throw new Error(
|
|
20058
|
-
`Config fetch failed (${response.status}): token may have expired \u2014 redeploy to rotate`
|
|
20059
|
-
);
|
|
20060
|
-
}
|
|
20061
20191
|
throw new Error(
|
|
20062
20192
|
`Config fetch failed: ${response.status} ${response.statusText}`
|
|
20063
20193
|
);
|
|
@@ -20488,6 +20618,7 @@ async function fetchSecrets(options) {
|
|
|
20488
20618
|
const res = await fetch(url2, {
|
|
20489
20619
|
headers: mergeAuthHeaders(token, { "Content-Type": "application/json" })
|
|
20490
20620
|
});
|
|
20621
|
+
await throwIfRunnerAuthFailure(res);
|
|
20491
20622
|
if (!res.ok) {
|
|
20492
20623
|
throw new SecretsHttpError(res.status, res.statusText);
|
|
20493
20624
|
}
|
|
@@ -21611,6 +21742,8 @@ init_cli_logger();
|
|
|
21611
21742
|
init_config_file();
|
|
21612
21743
|
import { hostname as hostname3 } from "os";
|
|
21613
21744
|
var POLL_TIMEOUT_BUFFER_MS = 5e3;
|
|
21745
|
+
var DEFAULT_POLL_TIMEOUT_MS = 6e4;
|
|
21746
|
+
var DEFAULT_POLL_INTERVAL_MS = 5e3;
|
|
21614
21747
|
async function openInBrowser(url2) {
|
|
21615
21748
|
const { default: open } = await import("open");
|
|
21616
21749
|
await open(url2);
|
|
@@ -21636,25 +21769,143 @@ async function loginCommand(options) {
|
|
|
21636
21769
|
process.exit(1);
|
|
21637
21770
|
}
|
|
21638
21771
|
}
|
|
21639
|
-
async function
|
|
21772
|
+
async function requestDeviceCode(options = {}) {
|
|
21640
21773
|
const appUrl = options.url || resolveAppUrl();
|
|
21641
21774
|
const f2 = options.fetch ?? globalThis.fetch;
|
|
21642
|
-
const
|
|
21775
|
+
const response = await f2(`${appUrl}/api/auth/device/code`, {
|
|
21643
21776
|
method: "POST",
|
|
21644
21777
|
headers: { "Content-Type": "application/json" },
|
|
21645
21778
|
body: JSON.stringify({})
|
|
21646
21779
|
});
|
|
21647
|
-
if (!
|
|
21780
|
+
if (!response.ok) {
|
|
21781
|
+
throw new Error("Failed to request device code");
|
|
21782
|
+
}
|
|
21783
|
+
const data = await response.json();
|
|
21784
|
+
return {
|
|
21785
|
+
deviceCode: data.deviceCode,
|
|
21786
|
+
userCode: data.userCode,
|
|
21787
|
+
verificationUri: data.verificationUri,
|
|
21788
|
+
verificationUriComplete: data.verificationUriComplete,
|
|
21789
|
+
expiresIn: data.expiresIn,
|
|
21790
|
+
interval: data.interval
|
|
21791
|
+
};
|
|
21792
|
+
}
|
|
21793
|
+
async function pollForToken(deviceCode, options = {}) {
|
|
21794
|
+
const appUrl = options.url || resolveAppUrl();
|
|
21795
|
+
const f2 = options.fetch ?? globalThis.fetch;
|
|
21796
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;
|
|
21797
|
+
let intervalMs = options.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
21798
|
+
const deadline = Date.now() + timeoutMs;
|
|
21799
|
+
while (Date.now() < deadline) {
|
|
21800
|
+
await new Promise((r2) => setTimeout(r2, intervalMs));
|
|
21801
|
+
if (Date.now() >= deadline) break;
|
|
21802
|
+
const remaining = Math.max(1, deadline - Date.now());
|
|
21803
|
+
const controller = new AbortController();
|
|
21804
|
+
const timeoutHandle = setTimeout(() => controller.abort(), remaining);
|
|
21805
|
+
let tokenResponse;
|
|
21806
|
+
try {
|
|
21807
|
+
tokenResponse = await f2(`${appUrl}/api/auth/device/token`, {
|
|
21808
|
+
method: "POST",
|
|
21809
|
+
headers: { "Content-Type": "application/json" },
|
|
21810
|
+
body: JSON.stringify({ deviceCode, hostname: hostname3() }),
|
|
21811
|
+
signal: controller.signal
|
|
21812
|
+
});
|
|
21813
|
+
} catch (err) {
|
|
21814
|
+
clearTimeout(timeoutHandle);
|
|
21815
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
21816
|
+
break;
|
|
21817
|
+
}
|
|
21818
|
+
throw err;
|
|
21819
|
+
} finally {
|
|
21820
|
+
clearTimeout(timeoutHandle);
|
|
21821
|
+
}
|
|
21822
|
+
const data = await safeJsonParse(tokenResponse);
|
|
21823
|
+
if (data === MALFORMED) {
|
|
21824
|
+
return {
|
|
21825
|
+
success: false,
|
|
21826
|
+
status: "error",
|
|
21827
|
+
error: "Server returned malformed response"
|
|
21828
|
+
};
|
|
21829
|
+
}
|
|
21830
|
+
if (tokenResponse.ok) {
|
|
21831
|
+
const token = data.token;
|
|
21832
|
+
const email3 = data.email;
|
|
21833
|
+
if (typeof token === "string" && token.length > 0) {
|
|
21834
|
+
if (typeof email3 !== "string" || email3.length === 0) {
|
|
21835
|
+
return {
|
|
21836
|
+
success: false,
|
|
21837
|
+
status: "error",
|
|
21838
|
+
error: "Server returned malformed response (missing email)"
|
|
21839
|
+
};
|
|
21840
|
+
}
|
|
21841
|
+
writeConfig({ token, email: email3, appUrl });
|
|
21842
|
+
const configPath = getConfigPath();
|
|
21843
|
+
return {
|
|
21844
|
+
success: true,
|
|
21845
|
+
status: "authenticated",
|
|
21846
|
+
email: email3,
|
|
21847
|
+
configPath
|
|
21848
|
+
};
|
|
21849
|
+
}
|
|
21850
|
+
if (token !== void 0) {
|
|
21851
|
+
return {
|
|
21852
|
+
success: false,
|
|
21853
|
+
status: "error",
|
|
21854
|
+
error: "Server returned malformed response (invalid token type)"
|
|
21855
|
+
};
|
|
21856
|
+
}
|
|
21857
|
+
continue;
|
|
21858
|
+
}
|
|
21859
|
+
if (data.error === "authorization_pending") continue;
|
|
21860
|
+
if (data.error === "slow_down") {
|
|
21861
|
+
intervalMs += 5e3;
|
|
21862
|
+
continue;
|
|
21863
|
+
}
|
|
21864
|
+
const errField = data.error;
|
|
21865
|
+
let errorMsg;
|
|
21866
|
+
if (typeof errField === "string") {
|
|
21867
|
+
errorMsg = errField;
|
|
21868
|
+
} else if (errField && typeof errField === "object" && "message" in errField && typeof errField.message === "string") {
|
|
21869
|
+
errorMsg = errField.message;
|
|
21870
|
+
} else {
|
|
21871
|
+
errorMsg = "Authorization failed";
|
|
21872
|
+
}
|
|
21873
|
+
return { success: false, status: "error", error: errorMsg };
|
|
21874
|
+
}
|
|
21875
|
+
return { success: false, status: "pending" };
|
|
21876
|
+
}
|
|
21877
|
+
var MALFORMED = /* @__PURE__ */ Symbol("malformed-json");
|
|
21878
|
+
async function safeJsonParse(response) {
|
|
21879
|
+
try {
|
|
21880
|
+
const parsed = await response.json();
|
|
21881
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
21882
|
+
return parsed;
|
|
21883
|
+
}
|
|
21884
|
+
return MALFORMED;
|
|
21885
|
+
} catch {
|
|
21886
|
+
return MALFORMED;
|
|
21887
|
+
}
|
|
21888
|
+
}
|
|
21889
|
+
async function login(options = {}) {
|
|
21890
|
+
const fetchOption = options.fetch ?? globalThis.fetch;
|
|
21891
|
+
const urlOption = options.url;
|
|
21892
|
+
let codeResult;
|
|
21893
|
+
try {
|
|
21894
|
+
codeResult = await requestDeviceCode({
|
|
21895
|
+
url: urlOption,
|
|
21896
|
+
fetch: fetchOption
|
|
21897
|
+
});
|
|
21898
|
+
} catch {
|
|
21648
21899
|
return { success: false, error: "Failed to request device code" };
|
|
21649
21900
|
}
|
|
21650
21901
|
const {
|
|
21651
|
-
deviceCode,
|
|
21652
21902
|
userCode,
|
|
21653
21903
|
verificationUri,
|
|
21654
21904
|
verificationUriComplete,
|
|
21655
21905
|
expiresIn,
|
|
21656
|
-
interval
|
|
21657
|
-
|
|
21906
|
+
interval,
|
|
21907
|
+
deviceCode
|
|
21908
|
+
} = codeResult;
|
|
21658
21909
|
const prompt = (msg) => process.stderr.write(msg + "\n");
|
|
21659
21910
|
prompt(`
|
|
21660
21911
|
! Your one-time code: ${userCode}`);
|
|
@@ -21668,30 +21919,95 @@ async function login(options = {}) {
|
|
|
21668
21919
|
prompt(" Could not open browser. Visit the URL manually.");
|
|
21669
21920
|
}
|
|
21670
21921
|
prompt(" Waiting for authorization... (press Ctrl+C to cancel)\n");
|
|
21671
|
-
const
|
|
21672
|
-
|
|
21673
|
-
|
|
21674
|
-
|
|
21675
|
-
|
|
21676
|
-
|
|
21677
|
-
|
|
21678
|
-
const
|
|
21679
|
-
|
|
21680
|
-
|
|
21681
|
-
|
|
21682
|
-
|
|
21683
|
-
|
|
21684
|
-
|
|
21685
|
-
|
|
21686
|
-
|
|
21687
|
-
|
|
21688
|
-
|
|
21689
|
-
|
|
21690
|
-
|
|
21691
|
-
|
|
21692
|
-
|
|
21922
|
+
const timeoutMs = expiresIn * 1e3 + POLL_TIMEOUT_BUFFER_MS;
|
|
21923
|
+
const intervalMs = (interval ?? 5) * 1e3;
|
|
21924
|
+
if (options.maxPollAttempts !== void 0) {
|
|
21925
|
+
const appUrl = urlOption || resolveAppUrl();
|
|
21926
|
+
const f2 = fetchOption;
|
|
21927
|
+
let pollInterval = intervalMs;
|
|
21928
|
+
let attempts = 0;
|
|
21929
|
+
const deadline = Date.now() + timeoutMs;
|
|
21930
|
+
while (Date.now() < deadline && attempts < options.maxPollAttempts) {
|
|
21931
|
+
attempts++;
|
|
21932
|
+
await new Promise((r2) => setTimeout(r2, pollInterval));
|
|
21933
|
+
const remaining = Math.max(1, deadline - Date.now());
|
|
21934
|
+
const controller = new AbortController();
|
|
21935
|
+
const timeoutHandle = setTimeout(() => controller.abort(), remaining);
|
|
21936
|
+
let tokenResponse;
|
|
21937
|
+
try {
|
|
21938
|
+
tokenResponse = await f2(`${appUrl}/api/auth/device/token`, {
|
|
21939
|
+
method: "POST",
|
|
21940
|
+
headers: { "Content-Type": "application/json" },
|
|
21941
|
+
body: JSON.stringify({ deviceCode, hostname: hostname3() }),
|
|
21942
|
+
signal: controller.signal
|
|
21943
|
+
});
|
|
21944
|
+
} catch (err) {
|
|
21945
|
+
clearTimeout(timeoutHandle);
|
|
21946
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
21947
|
+
break;
|
|
21948
|
+
}
|
|
21949
|
+
throw err;
|
|
21950
|
+
} finally {
|
|
21951
|
+
clearTimeout(timeoutHandle);
|
|
21952
|
+
}
|
|
21953
|
+
const data = await safeJsonParse(tokenResponse);
|
|
21954
|
+
if (data === MALFORMED) {
|
|
21955
|
+
return {
|
|
21956
|
+
success: false,
|
|
21957
|
+
error: "Server returned malformed response"
|
|
21958
|
+
};
|
|
21959
|
+
}
|
|
21960
|
+
if (tokenResponse.ok) {
|
|
21961
|
+
const token = data.token;
|
|
21962
|
+
const email3 = data.email;
|
|
21963
|
+
if (typeof token === "string" && token.length > 0) {
|
|
21964
|
+
if (typeof email3 !== "string" || email3.length === 0) {
|
|
21965
|
+
return {
|
|
21966
|
+
success: false,
|
|
21967
|
+
error: "Server returned malformed response (missing email)"
|
|
21968
|
+
};
|
|
21969
|
+
}
|
|
21970
|
+
writeConfig({ token, email: email3, appUrl });
|
|
21971
|
+
const configPath = getConfigPath();
|
|
21972
|
+
return { success: true, email: email3, configPath };
|
|
21973
|
+
}
|
|
21974
|
+
if (token !== void 0) {
|
|
21975
|
+
return {
|
|
21976
|
+
success: false,
|
|
21977
|
+
error: "Server returned malformed response (invalid token type)"
|
|
21978
|
+
};
|
|
21979
|
+
}
|
|
21980
|
+
continue;
|
|
21981
|
+
}
|
|
21982
|
+
if (data.error === "authorization_pending") continue;
|
|
21983
|
+
if (data.error === "slow_down") {
|
|
21984
|
+
pollInterval += 5e3;
|
|
21985
|
+
continue;
|
|
21986
|
+
}
|
|
21987
|
+
const errField = data.error;
|
|
21988
|
+
const errorMsg = typeof errField === "string" ? errField : "Authorization failed";
|
|
21989
|
+
return { success: false, error: errorMsg };
|
|
21693
21990
|
}
|
|
21694
|
-
return {
|
|
21991
|
+
return {
|
|
21992
|
+
success: false,
|
|
21993
|
+
error: "Authorization timed out. Please try again."
|
|
21994
|
+
};
|
|
21995
|
+
}
|
|
21996
|
+
const pollResult = await pollForToken(deviceCode, {
|
|
21997
|
+
url: urlOption,
|
|
21998
|
+
fetch: fetchOption,
|
|
21999
|
+
timeoutMs,
|
|
22000
|
+
intervalMs
|
|
22001
|
+
});
|
|
22002
|
+
if (pollResult.success) {
|
|
22003
|
+
return {
|
|
22004
|
+
success: true,
|
|
22005
|
+
email: pollResult.email,
|
|
22006
|
+
configPath: pollResult.configPath
|
|
22007
|
+
};
|
|
22008
|
+
}
|
|
22009
|
+
if (pollResult.status === "error") {
|
|
22010
|
+
return { success: false, error: pollResult.error };
|
|
21695
22011
|
}
|
|
21696
22012
|
return {
|
|
21697
22013
|
success: false,
|
|
@@ -21744,97 +22060,8 @@ async function whoamiCommand(options) {
|
|
|
21744
22060
|
}
|
|
21745
22061
|
}
|
|
21746
22062
|
|
|
21747
|
-
// src/commands/projects/index.ts
|
|
21748
|
-
init_api_client();
|
|
21749
|
-
init_api_error();
|
|
21750
|
-
init_auth();
|
|
21751
|
-
init_output();
|
|
21752
|
-
async function listProjects() {
|
|
21753
|
-
const client = createApiClient();
|
|
21754
|
-
const { data, error: error48 } = await client.GET("/api/projects");
|
|
21755
|
-
if (error48) throw new Error(error48.error?.message || "Failed to list projects");
|
|
21756
|
-
return data;
|
|
21757
|
-
}
|
|
21758
|
-
async function getProject(options = {}) {
|
|
21759
|
-
const id = options.projectId ?? requireProjectId();
|
|
21760
|
-
const client = createApiClient();
|
|
21761
|
-
const { data, error: error48 } = await client.GET("/api/projects/{projectId}", {
|
|
21762
|
-
params: { path: { projectId: id } }
|
|
21763
|
-
});
|
|
21764
|
-
if (error48) throw new Error(error48.error?.message || "Failed to get project");
|
|
21765
|
-
return data;
|
|
21766
|
-
}
|
|
21767
|
-
async function createProject(options) {
|
|
21768
|
-
const client = createApiClient();
|
|
21769
|
-
const { data, error: error48 } = await client.POST("/api/projects", {
|
|
21770
|
-
body: { name: options.name }
|
|
21771
|
-
});
|
|
21772
|
-
if (error48)
|
|
21773
|
-
throw new Error(error48.error?.message || "Failed to create project");
|
|
21774
|
-
return data;
|
|
21775
|
-
}
|
|
21776
|
-
async function updateProject(options) {
|
|
21777
|
-
const id = options.projectId ?? requireProjectId();
|
|
21778
|
-
const client = createApiClient();
|
|
21779
|
-
const { data, error: error48 } = await client.PATCH("/api/projects/{projectId}", {
|
|
21780
|
-
params: { path: { projectId: id } },
|
|
21781
|
-
body: { name: options.name }
|
|
21782
|
-
});
|
|
21783
|
-
if (error48)
|
|
21784
|
-
throw new Error(error48.error?.message || "Failed to update project");
|
|
21785
|
-
return data;
|
|
21786
|
-
}
|
|
21787
|
-
async function deleteProject(options = {}) {
|
|
21788
|
-
const id = options.projectId ?? requireProjectId();
|
|
21789
|
-
const client = createApiClient();
|
|
21790
|
-
const { data, error: error48 } = await client.DELETE("/api/projects/{projectId}", {
|
|
21791
|
-
params: { path: { projectId: id } }
|
|
21792
|
-
});
|
|
21793
|
-
if (error48)
|
|
21794
|
-
throw new Error(error48.error?.message || "Failed to delete project");
|
|
21795
|
-
return data ?? { success: true };
|
|
21796
|
-
}
|
|
21797
|
-
async function handleResult(fn2, options) {
|
|
21798
|
-
try {
|
|
21799
|
-
const result = await fn2();
|
|
21800
|
-
await writeResult(JSON.stringify(result, null, 2), options);
|
|
21801
|
-
} catch (error48) {
|
|
21802
|
-
handleCliError(error48);
|
|
21803
|
-
}
|
|
21804
|
-
}
|
|
21805
|
-
async function listProjectsCommand(options) {
|
|
21806
|
-
await handleResult(() => listProjects(), options);
|
|
21807
|
-
}
|
|
21808
|
-
async function getProjectCommand(projectId, options) {
|
|
21809
|
-
await handleResult(
|
|
21810
|
-
() => getProject({ projectId: projectId ?? options.project }),
|
|
21811
|
-
options
|
|
21812
|
-
);
|
|
21813
|
-
}
|
|
21814
|
-
async function createProjectCommand(name, options) {
|
|
21815
|
-
await handleResult(() => createProject({ name }), options);
|
|
21816
|
-
}
|
|
21817
|
-
async function updateProjectCommand(projectId, options) {
|
|
21818
|
-
const name = options.name;
|
|
21819
|
-
if (!name) {
|
|
21820
|
-
throw new Error("Missing required option: --name <name>");
|
|
21821
|
-
}
|
|
21822
|
-
await handleResult(
|
|
21823
|
-
() => updateProject({
|
|
21824
|
-
projectId: projectId ?? options.project,
|
|
21825
|
-
name
|
|
21826
|
-
}),
|
|
21827
|
-
options
|
|
21828
|
-
);
|
|
21829
|
-
}
|
|
21830
|
-
async function deleteProjectCommand(projectId, options) {
|
|
21831
|
-
await handleResult(
|
|
21832
|
-
() => deleteProject({ projectId: projectId ?? options.project }),
|
|
21833
|
-
options
|
|
21834
|
-
);
|
|
21835
|
-
}
|
|
21836
|
-
|
|
21837
22063
|
// src/cli.ts
|
|
22064
|
+
init_projects();
|
|
21838
22065
|
init_flows();
|
|
21839
22066
|
|
|
21840
22067
|
// src/commands/deploy/index.ts
|