@hypersoniclabs/helix-cli 0.1.25-helix3.465 → 0.1.25-helix3.466
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/api.d.ts +4 -0
- package/dist/api.js +39 -2
- package/dist/api.js.map +1 -1
- package/dist/assetGenerationDriver.d.ts +24 -1
- package/dist/assetGenerationDriver.js +43 -5
- package/dist/assetGenerationDriver.js.map +1 -1
- package/dist/authRefresh.d.ts +9 -0
- package/dist/authRefresh.js +61 -0
- package/dist/authRefresh.js.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +47 -9
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_abs.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_audio.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_engine.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_expression.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_jbeam.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_materials.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/beamng_stock_events.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/fmod_studio.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/fsb5.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/sim_audio.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/sim_audio_ac.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/sim_audio_beamng.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/sim_audio_fixtures.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/test_beamng_engine.cpython-312.pyc +0 -0
- package/plugins/beamng-vehicle/bin/__pycache__/test_sim_audio.cpython-312.pyc +0 -0
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ The token is stored in `~/.helix/credentials.json` (mode `600`). It's sent as
|
|
|
47
47
|
|---|---|
|
|
48
48
|
| `helix bridge detect\|inspect\|plan\|import\|validate\|doctor` | Universal plugin-driven intake for assets, characters, animations, scenes, and engine projects. Produces deterministic plans, HELIX-native outputs, and checksummed provenance. See [`docs/bridge.md`](docs/bridge.md). |
|
|
49
49
|
| `helix bridge plugins create\|test\|list\|inspect\|install\|remove` | Build and manage local/community Bridge Plugins using the versioned capability and permission contract. |
|
|
50
|
-
| `helix login [--api-url <url>] [--web-url <url>] [--token <t>] [--no-browser]` | Sign in via the browser (`/cli-login`), or `--token` for CI/headless. Stores the client token. |
|
|
50
|
+
| `helix login [--api-url <url>] [--web-url <url>] [--token <t> [--refresh-token <r>]] [--no-browser]` | Sign in via the browser (`/cli-login`), or `--token` for CI/headless. Stores the client token. `--refresh-token` (or `HELIX_REFRESH_TOKEN`) pairs a short-lived access token with its refresh token so a long command (`assets resume`) renews it when it expires. |
|
|
51
51
|
| `helix logout` | Remove the stored token. |
|
|
52
52
|
| `helix whoami` | Show current login status. |
|
|
53
53
|
| `helix init <dir> [--kind character\|multiplayer\|scene]` | Scaffold a complete, build-ready Vite + TypeScript world. `--kind scene` emits a multiplayer world whose ENVIRONMENT is a sealed HELIX Scene v2 document — the starter document is compiled offline into `public/scene/mall/`, pinned in `public/helix.json`'s `scene` field, kept out of the bundle by `public/.helixignore`, and lit by `public/helix.visuals.json` through the `scene` + `visual` system pins. |
|
|
@@ -86,8 +86,8 @@ The token is stored in `~/.helix/credentials.json` (mode `600`). It's sent as
|
|
|
86
86
|
| `helix assets start\|status\|generate\|resume` | Start or poll generation without duplicates. Props/characters use the Asset Generation job lane; standalone assets use the shared broker and report the auto-published `vaultAssetId`. `generate` and `resume` block waiting for the job (see `--timeout`/`--poll-interval` below). |
|
|
87
87
|
| `helix assets voices [--search <text>] [--category premade\|professional] [--page-size <n>] [--page-token <token>] [--json]` | Discover safe text-to-speech voices through the authenticated HELIX catalog, including language, labels, preview, default/recommended selection, and pagination. |
|
|
88
88
|
| `helix assets generate-image\|generate-material\|generate-audio\|generate-environment` | Run the supported standalone generation adapters. Material is a validated PBR bundle (1K default, explicit 2K); splats declare object/environment scope. Animation remains an explicit unavailable boundary. |
|
|
89
|
-
| `helix assets start character "<prompt>" [--title t] [--visibility v] [--max-lix n]` | Starts a character on the server-side Asset Generation job driver (`POST /api/v1/asset-generation/jobs`, `mode: deterministic`) and returns at once; stdout is the driver job JSON (`id`). `--visibility` is sent only when you pass it; the server owns the default and every other policy (reference review, redraws, retries, visual QA wait, WARN/BLOCK, refunds). |
|
|
90
|
-
| `helix assets resume <id> [--timeout <ms>] [--poll-interval <ms>]` (driver job) | Waits for `succeeded`, `held`, `failed` or `handoff` (default **80 min**, poll **3 s**), one progress line per change on stderr (stage, reference gate, scheduled retry, policy events, cost). Final stdout is the driver job JSON plus top-level `publishedItemId` (= `result.itemId`). Exit 0 for succeeded, held (the item exists but is not released; `result.qa` says why; `helix assets refund <id>` is offered) and handoff; exit 1 for `failed` (JSON on stdout, message with `escalate`/`retriable` on stderr) and for a client-side timeout (nothing on stdout). `--visibility` must match the job's (it is fixed at start) or the command exits 1. An id the driver does not know (props, older characters) resumes through the previous loop below. `helix assets generate character` is `start` + `resume`. |
|
|
89
|
+
| `helix assets start character "<prompt>" [--title t] [--visibility v] [--idempotency-key k] [--max-lix n]` | Starts a character on the server-side Asset Generation job driver (`POST /api/v1/asset-generation/jobs`, `mode: deterministic`) and returns at once; stdout is the driver job JSON (`id`). `--visibility` is sent only when you pass it; the server owns the default and every other policy (reference review, redraws, retries, visual QA wait, WARN/BLOCK, refunds). The create is retry-safe: the CLI picks one idempotency key (a UUID, or your `--idempotency-key`, 8-96 chars), sends the same key on every try (3 tries on a timeout, dropped connection or 5xx), and the backend returns the existing job for the same owner and key, so a timeout after the server created the job never duplicates or double charges. The key is printed on stderr and in the stdout JSON as `idempotencyKey`; if a run's answer was lost, re-run the same command with `--idempotency-key <key>`. |
|
|
90
|
+
| `helix assets resume <id> [--timeout <ms>] [--poll-interval <ms>]` (driver job) | Waits for `succeeded`, `held`, `failed` or `handoff` (default **80 min**, poll **3 s**), one progress line per change on stderr (stage, reference gate, scheduled retry, policy events, cost). Final stdout is the driver job JSON plus top-level `publishedItemId` (= `result.itemId`). Exit 0 for succeeded, held (the item exists but is not released; `result.qa` says why; `helix assets refund <id>` is offered) and handoff; exit 1 for `failed` (JSON on stdout, message with `escalate`/`retriable` on stderr) and for a client-side timeout (nothing on stdout). `--visibility` must match the job's (it is fixed at start) or the command exits 1. An access token that expires during the wait is renewed (see Login below: `helix login --token <access> --refresh-token <refresh>` or `HELIX_REFRESH_TOKEN`; otherwise another process's fresh `helix login` is picked up); a login that cannot be renewed ends the wait with `helix login` + `helix assets resume <id>`, and the job keeps running. An id the driver does not know (props, older characters) resumes through the previous loop below. `helix assets generate character` is `start` + `resume`. |
|
|
91
91
|
| `helix assets act <id> approve\|revise ["guidance"]`, `helix assets refund <id>`, `helix assets status <id> --pipeline driver` | Decide at the open reference gate, get the LIX back for a held avatar, or read the raw driver job. |
|
|
92
92
|
| `helix assets start-reference\|generate-reference` | Start or fully drive a character job from a local four-view PNG/JPEG/WebP. The backend validates and reuses the exact sheet; it skips image generation while preserving mesh, texture, rig, LOD, thumbnail, billing, and Vault publication. `generate-reference` blocks waiting for the job (see `--timeout`/`--poll-interval` below). |
|
|
93
93
|
| `helix assets generate\|generate-reference\|resume [--timeout <ms>] [--poll-interval <ms>]` | These three drive an Asset Generation prop/character job to completion (concept → mesh → texture → rig → publish) and block until it finishes. `--timeout` bounds how long the CLI process waits before giving up (default **1200000ms / 20min**, unchanged if omitted); `--poll-interval` sets how often it checks job status while waiting (default **2000ms**). A timeout is a CLIENT-SIDE giveup, not a job failure — the job keeps running server-side. The error prints the exact `helix assets resume <job-id>` command to check on or continue it; on a genuinely slow stage (e.g. mesh generation), rerun with a larger `--timeout`, or just poll separately with `helix assets status <job-id> --pipeline dreamer`. |
|
package/dist/api.d.ts
CHANGED
|
@@ -17,6 +17,10 @@ export declare class HelixApi {
|
|
|
17
17
|
private token;
|
|
18
18
|
constructor(baseUrl: string, token?: string | null);
|
|
19
19
|
setToken(token: string): void;
|
|
20
|
+
private refresher;
|
|
21
|
+
private inflightRefresh;
|
|
22
|
+
setRefresher(refresher: (() => Promise<string | null>) | null): void;
|
|
23
|
+
private renewToken;
|
|
20
24
|
/**
|
|
21
25
|
* A stable, non-reversible scope for durable client state (for example the
|
|
22
26
|
* resumable large-upload checkpoint). It binds that state to this API origin
|
package/dist/api.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.HelixApi = exports.ApiError = exports.API_FETCH_TIMEOUT_MS = void 0;
|
|
4
4
|
exports.uploadToTicket = uploadToTicket;
|
|
5
5
|
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
const authRefresh_1 = require("./authRefresh");
|
|
6
7
|
exports.API_FETCH_TIMEOUT_MS = 30_000;
|
|
7
8
|
function withTimeout(init, timeoutMs = exports.API_FETCH_TIMEOUT_MS) {
|
|
8
9
|
return { ...init, signal: AbortSignal.timeout(timeoutMs) };
|
|
@@ -42,6 +43,28 @@ class HelixApi {
|
|
|
42
43
|
setToken(token) {
|
|
43
44
|
this.token = token;
|
|
44
45
|
}
|
|
46
|
+
// Asked for a newer token after a 401; resolves to it or null. Installed by forCredentials.
|
|
47
|
+
refresher = null;
|
|
48
|
+
inflightRefresh = null;
|
|
49
|
+
setRefresher(refresher) {
|
|
50
|
+
this.refresher = refresher;
|
|
51
|
+
}
|
|
52
|
+
// One shared refresh for concurrent 401s.
|
|
53
|
+
async renewToken(staleToken) {
|
|
54
|
+
if (!this.refresher)
|
|
55
|
+
return false;
|
|
56
|
+
// Another call already renewed while this one was in flight.
|
|
57
|
+
if (this.token && this.token !== staleToken)
|
|
58
|
+
return true;
|
|
59
|
+
this.inflightRefresh ??= this.refresher().finally(() => {
|
|
60
|
+
this.inflightRefresh = null;
|
|
61
|
+
});
|
|
62
|
+
const next = await this.inflightRefresh;
|
|
63
|
+
if (!next)
|
|
64
|
+
return false;
|
|
65
|
+
this.token = next;
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
45
68
|
/**
|
|
46
69
|
* A stable, non-reversible scope for durable client state (for example the
|
|
47
70
|
* resumable large-upload checkpoint). It binds that state to this API origin
|
|
@@ -63,7 +86,7 @@ class HelixApi {
|
|
|
63
86
|
.slice(0, 32);
|
|
64
87
|
}
|
|
65
88
|
async request(method, path, body) {
|
|
66
|
-
const
|
|
89
|
+
const send = () => fetch(`${this.baseUrl}${path}`, withTimeout({
|
|
67
90
|
method,
|
|
68
91
|
headers: {
|
|
69
92
|
'content-type': 'application/json',
|
|
@@ -71,6 +94,11 @@ class HelixApi {
|
|
|
71
94
|
},
|
|
72
95
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
73
96
|
}));
|
|
97
|
+
const sentWith = this.token;
|
|
98
|
+
let res = await send();
|
|
99
|
+
// A 401 means nothing was done: renew the token once and replay the identical request.
|
|
100
|
+
if (res.status === 401 && (await this.renewToken(sentWith)))
|
|
101
|
+
res = await send();
|
|
74
102
|
if (!res.ok) {
|
|
75
103
|
const problem = (await res.json().catch(() => ({})));
|
|
76
104
|
throw new ApiError(res.status, problem);
|
|
@@ -128,7 +156,16 @@ class HelixApi {
|
|
|
128
156
|
return (await res.json());
|
|
129
157
|
}
|
|
130
158
|
static forCredentials(creds) {
|
|
131
|
-
|
|
159
|
+
const api = new HelixApi(creds.apiUrl, creds.token);
|
|
160
|
+
let current = creds;
|
|
161
|
+
api.setRefresher(async () => {
|
|
162
|
+
const next = await (0, authRefresh_1.refreshCredentials)(current);
|
|
163
|
+
if (!next)
|
|
164
|
+
return null;
|
|
165
|
+
current = next;
|
|
166
|
+
return next.token;
|
|
167
|
+
});
|
|
168
|
+
return api;
|
|
132
169
|
}
|
|
133
170
|
}
|
|
134
171
|
exports.HelixApi = HelixApi;
|
package/dist/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -64,8 +64,29 @@ export interface StartDriverAvatarInput {
|
|
|
64
64
|
title?: string;
|
|
65
65
|
/** Sent ONLY when the user chose one; the server owns the default. */
|
|
66
66
|
visibility?: DriverVisibility;
|
|
67
|
+
/** The caller's own key (8-96 chars). Default: a fresh UUID. */
|
|
68
|
+
idempotencyKey?: string;
|
|
67
69
|
}
|
|
68
|
-
export
|
|
70
|
+
export interface StartRetryOptions {
|
|
71
|
+
/** Total tries of the create call (default 3). Every try carries the SAME idempotency key. */
|
|
72
|
+
attempts?: number;
|
|
73
|
+
/** Backoff before try n+1 (default 1s, 3s). */
|
|
74
|
+
backoffMs?: (attempt: number) => number;
|
|
75
|
+
sleep?: (ms: number) => Promise<void>;
|
|
76
|
+
/** One human line per retry (the caller sends it to stderr). */
|
|
77
|
+
onRetry?: (line: string) => void;
|
|
78
|
+
}
|
|
79
|
+
/** A create that may have reached the server: no answer (timeout, dropped connection) or a gateway/server error. */
|
|
80
|
+
export declare function isAmbiguousCreateFailure(err: unknown): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Create the avatar job. The idempotency key is chosen ONCE and sent on every try, so a timeout after the server had
|
|
83
|
+
* already created the job re-attaches to that job on the next try (the backend returns the existing job for the same
|
|
84
|
+
* owner and key) instead of creating and charging a second one. The key is returned so a caller whose own process
|
|
85
|
+
* died can re-run the start with it.
|
|
86
|
+
*/
|
|
87
|
+
export declare function startDriverAvatarJob(api: DriverApi, input: StartDriverAvatarInput, newKey?: () => string, retry?: StartRetryOptions): Promise<DriverJobView & {
|
|
88
|
+
idempotencyKey: string;
|
|
89
|
+
}>;
|
|
69
90
|
/** The driver job, or null when the id is not a driver job (a legacy generation job id, a prop). */
|
|
70
91
|
export declare function getDriverJob(api: DriverApi, id: string): Promise<DriverJobView | null>;
|
|
71
92
|
export declare class DriverVisibilityError extends Error {
|
|
@@ -86,6 +107,8 @@ export interface ResumeDriverOptions {
|
|
|
86
107
|
progress?: (line: string) => void;
|
|
87
108
|
sleep?: (ms: number) => Promise<void>;
|
|
88
109
|
now?: () => number;
|
|
110
|
+
/** Echoed into the printed job JSON as `idempotencyKey`, so a `generate` run records the key its start used. */
|
|
111
|
+
idempotencyKey?: string;
|
|
89
112
|
}
|
|
90
113
|
/**
|
|
91
114
|
* Wait for a driver job to reach a terminal status. Returns null when `id` is not a driver job (the caller falls
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DriverTimeoutError = exports.DriverVisibilityError = exports.DRIVER_DEFAULT_POLL_MS = exports.DRIVER_DEFAULT_TIMEOUT_MS = exports.DRIVER_BASE = exports.DRIVER_TERMINAL = void 0;
|
|
4
|
+
exports.isAmbiguousCreateFailure = isAmbiguousCreateFailure;
|
|
4
5
|
exports.startDriverAvatarJob = startDriverAvatarJob;
|
|
5
6
|
exports.getDriverJob = getDriverJob;
|
|
6
7
|
exports.describeDriverEvent = describeDriverEvent;
|
|
@@ -27,15 +28,47 @@ exports.DRIVER_BASE = '/api/v1/asset-generation';
|
|
|
27
28
|
exports.DRIVER_DEFAULT_TIMEOUT_MS = 80 * 60_000;
|
|
28
29
|
exports.DRIVER_DEFAULT_POLL_MS = 3_000;
|
|
29
30
|
const MAX_CONSECUTIVE_POLL_ERRORS = 5;
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
/** A create that may have reached the server: no answer (timeout, dropped connection) or a gateway/server error. */
|
|
32
|
+
function isAmbiguousCreateFailure(err) {
|
|
33
|
+
if (err instanceof api_1.ApiError)
|
|
34
|
+
return [408, 425, 500, 502, 503, 504].includes(err.status);
|
|
35
|
+
if (err instanceof Error) {
|
|
36
|
+
// fetch() timeouts (AbortSignal.timeout -> TimeoutError / AbortError) and network failures (TypeError: fetch failed).
|
|
37
|
+
return err.name === 'TimeoutError' || err.name === 'AbortError' || err instanceof TypeError;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create the avatar job. The idempotency key is chosen ONCE and sent on every try, so a timeout after the server had
|
|
43
|
+
* already created the job re-attaches to that job on the next try (the backend returns the existing job for the same
|
|
44
|
+
* owner and key) instead of creating and charging a second one. The key is returned so a caller whose own process
|
|
45
|
+
* died can re-run the start with it.
|
|
46
|
+
*/
|
|
47
|
+
async function startDriverAvatarJob(api, input, newKey = node_crypto_1.randomUUID, retry = {}) {
|
|
48
|
+
const idempotencyKey = input.idempotencyKey ?? newKey();
|
|
49
|
+
const attempts = Math.max(1, retry.attempts ?? 3);
|
|
50
|
+
const backoff = retry.backoffMs ?? ((n) => (n === 1 ? 1_000 : 3_000));
|
|
51
|
+
const sleep = retry.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
52
|
+
const body = {
|
|
32
53
|
kind: 'avatar',
|
|
33
54
|
prompt: input.prompt,
|
|
34
55
|
...(input.title ? { title: input.title } : {}),
|
|
35
56
|
mode: 'deterministic',
|
|
36
57
|
...(input.visibility ? { visibility: input.visibility } : {}),
|
|
37
|
-
idempotencyKey
|
|
38
|
-
}
|
|
58
|
+
idempotencyKey,
|
|
59
|
+
};
|
|
60
|
+
for (let attempt = 1;; attempt++) {
|
|
61
|
+
try {
|
|
62
|
+
const job = await api.request('POST', `${exports.DRIVER_BASE}/jobs`, body);
|
|
63
|
+
return { ...job, idempotencyKey };
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
if (attempt >= attempts || !isAmbiguousCreateFailure(err))
|
|
67
|
+
throw err;
|
|
68
|
+
retry.onRetry?.(`create did not answer (${err instanceof Error ? err.message : String(err)}); retrying with the same idempotency key ${idempotencyKey} (try ${attempt + 1} of ${attempts})`);
|
|
69
|
+
await sleep(backoff(attempt));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
39
72
|
}
|
|
40
73
|
/** The driver job, or null when the id is not a driver job (a legacy generation job id, a prop). */
|
|
41
74
|
async function getDriverJob(api, id) {
|
|
@@ -157,6 +190,11 @@ async function waitForDriverJob(api, id, options = {}) {
|
|
|
157
190
|
errors = 0;
|
|
158
191
|
}
|
|
159
192
|
catch (err) {
|
|
193
|
+
// The session ended and could not be renewed (HelixApi already tried): retrying cannot help.
|
|
194
|
+
if (err instanceof api_1.ApiError && err.status === 401) {
|
|
195
|
+
throw new Error(`Your login expired and could not be renewed. The job ${id} keeps running on the server. ` +
|
|
196
|
+
`Run \`helix login\`, then \`helix assets resume ${id}\`.`);
|
|
197
|
+
}
|
|
160
198
|
// A transport blip on a poll is not a verdict about the job; a persistent one is real.
|
|
161
199
|
if (++errors >= MAX_CONSECUTIVE_POLL_ERRORS)
|
|
162
200
|
throw err;
|
|
@@ -197,7 +235,7 @@ async function runDriverResume(api, id, options, io) {
|
|
|
197
235
|
}
|
|
198
236
|
if (!job)
|
|
199
237
|
return null;
|
|
200
|
-
io.stdout(JSON.stringify(driverOutput(job), null, 2));
|
|
238
|
+
io.stdout(JSON.stringify(options.idempotencyKey ? { ...driverOutput(job), idempotencyKey: options.idempotencyKey } : driverOutput(job), null, 2));
|
|
201
239
|
if (job.status === 'failed') {
|
|
202
240
|
io.stderr(renderDriverFailure(job));
|
|
203
241
|
return 1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assetGenerationDriver.js","sourceRoot":"","sources":["../src/assetGenerationDriver.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"assetGenerationDriver.js","sourceRoot":"","sources":["../src/assetGenerationDriver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type CliCredentials } from './config';
|
|
2
|
+
export interface RefreshDeps {
|
|
3
|
+
readStored?: () => CliCredentials | null;
|
|
4
|
+
save?: (creds: CliCredentials) => void;
|
|
5
|
+
fetchImpl?: typeof fetch;
|
|
6
|
+
now?: () => number;
|
|
7
|
+
}
|
|
8
|
+
/** A newer token for `current`, persisted when it was renewed here, or null when none can be had. */
|
|
9
|
+
export declare function refreshCredentials(current: CliCredentials, deps?: RefreshDeps): Promise<CliCredentials | null>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.refreshCredentials = refreshCredentials;
|
|
4
|
+
// The CLI's one token-renewal path. Every `HelixApi.forCredentials(creds)` client uses it: on a 401 the api asks
|
|
5
|
+
// `refreshCredentials` for a newer token and retries the request once, so a long command (`assets resume` waits up
|
|
6
|
+
// to 80 minutes; a 1 hour access token can expire inside it) survives expiry without a restart.
|
|
7
|
+
//
|
|
8
|
+
// Order of attempts:
|
|
9
|
+
// 1. Another process may already have renewed it (a concurrent `helix login`, or a parallel command that refreshed
|
|
10
|
+
// first). If credentials.json now holds a different, unexpired token for the SAME account and API, adopt it.
|
|
11
|
+
// 2. If the stored login carries a refresh token, exchange it at POST /auth/refresh and persist the new access token.
|
|
12
|
+
// 3. Otherwise there is nothing to renew with: return null and the caller surfaces the 401 ("run helix login").
|
|
13
|
+
//
|
|
14
|
+
// This is deliberately not the visual-QA bot login (visualQa/hosted.ts botLogin): that signs a *bot account* in with
|
|
15
|
+
// a password and is only meant for the hosted QA runner.
|
|
16
|
+
const config_1 = require("./config");
|
|
17
|
+
function unexpired(creds, now) {
|
|
18
|
+
return !creds.expiresAt || new Date(creds.expiresAt).getTime() > now;
|
|
19
|
+
}
|
|
20
|
+
/** A newer token for `current`, persisted when it was renewed here, or null when none can be had. */
|
|
21
|
+
async function refreshCredentials(current, deps = {}) {
|
|
22
|
+
const readStored = deps.readStored ?? config_1.readStoredCredentials;
|
|
23
|
+
const save = deps.save ?? config_1.saveCredentials;
|
|
24
|
+
const doFetch = deps.fetchImpl ?? fetch;
|
|
25
|
+
const now = (deps.now ?? Date.now)();
|
|
26
|
+
const stored = readStored();
|
|
27
|
+
const sameAccount = stored && stored.apiUrl === current.apiUrl && stored.username === current.username;
|
|
28
|
+
if (sameAccount && stored.token !== current.token && unexpired(stored, now))
|
|
29
|
+
return stored;
|
|
30
|
+
const refreshToken = (sameAccount ? stored.refreshToken : undefined) ?? current.refreshToken;
|
|
31
|
+
if (!refreshToken)
|
|
32
|
+
return null;
|
|
33
|
+
let res;
|
|
34
|
+
try {
|
|
35
|
+
res = await doFetch(`${current.apiUrl}/auth/refresh`, {
|
|
36
|
+
method: 'POST',
|
|
37
|
+
headers: { 'content-type': 'application/json' },
|
|
38
|
+
body: JSON.stringify({ refresh_token: refreshToken }),
|
|
39
|
+
signal: AbortSignal.timeout(30_000),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
if (!res.ok)
|
|
46
|
+
return null;
|
|
47
|
+
const body = (await res.json().catch(() => ({})));
|
|
48
|
+
if (typeof body.access_token !== 'string' || !body.access_token)
|
|
49
|
+
return null;
|
|
50
|
+
const expiresAt = (0, config_1.jwtExpiresAtIso)(body.access_token) ||
|
|
51
|
+
(typeof body.expires_in === 'number' ? new Date(now + body.expires_in * 1000).toISOString() : '');
|
|
52
|
+
const renewed = { ...current, token: body.access_token, expiresAt, refreshToken };
|
|
53
|
+
try {
|
|
54
|
+
save(renewed);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// A read-only home must not stop the running command; the new token still works in memory.
|
|
58
|
+
}
|
|
59
|
+
return renewed;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=authRefresh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authRefresh.js","sourceRoot":"","sources":["../src/authRefresh.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export type CliCredentials = {
|
|
|
3
3
|
token: string;
|
|
4
4
|
expiresAt: string;
|
|
5
5
|
username: string;
|
|
6
|
+
refreshToken?: string;
|
|
6
7
|
};
|
|
7
8
|
export declare const CONFIG_DIR: string;
|
|
8
9
|
type HelixEnvName = 'staging' | 'production';
|
|
@@ -30,6 +31,7 @@ export declare function credsEnvMismatchWarning(credsApiUrl: string, env?: {
|
|
|
30
31
|
}): string | null;
|
|
31
32
|
export declare function saveCredentials(creds: CliCredentials): void;
|
|
32
33
|
export declare function loadCredentials(): CliCredentials | null;
|
|
34
|
+
export declare function readStoredCredentials(): CliCredentials | null;
|
|
33
35
|
export declare function clearCredentials(): void;
|
|
34
36
|
export declare function jwtExpiresAtIso(token: string): string;
|
|
35
37
|
export declare function jwtSubject(token: string): string | null;
|
package/dist/config.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.apiUrlMatchesEnv = apiUrlMatchesEnv;
|
|
|
7
7
|
exports.credsEnvMismatchWarning = credsEnvMismatchWarning;
|
|
8
8
|
exports.saveCredentials = saveCredentials;
|
|
9
9
|
exports.loadCredentials = loadCredentials;
|
|
10
|
+
exports.readStoredCredentials = readStoredCredentials;
|
|
10
11
|
exports.clearCredentials = clearCredentials;
|
|
11
12
|
exports.jwtExpiresAtIso = jwtExpiresAtIso;
|
|
12
13
|
exports.jwtSubject = jwtSubject;
|
|
@@ -140,6 +141,18 @@ function loadCredentials() {
|
|
|
140
141
|
return null;
|
|
141
142
|
}
|
|
142
143
|
}
|
|
144
|
+
// The stored credentials exactly as written, with NO expiry check. loadCredentials() hides an expired login so a
|
|
145
|
+
// command fails fast with "run helix login"; the token-refresh path needs the expired record because its refresh
|
|
146
|
+
// token is what renews it.
|
|
147
|
+
function readStoredCredentials() {
|
|
148
|
+
try {
|
|
149
|
+
const creds = JSON.parse((0, node_fs_1.readFileSync)(CREDENTIALS_FILE, 'utf8'));
|
|
150
|
+
return creds && typeof creds.token === 'string' && typeof creds.apiUrl === 'string' ? creds : null;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
143
156
|
function clearCredentials() {
|
|
144
157
|
try {
|
|
145
158
|
(0, node_fs_1.writeFileSync)(CREDENTIALS_FILE, '{}', { mode: 0o600 });
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -69,6 +69,7 @@ const ability_1 = require("./ability");
|
|
|
69
69
|
const initAbility_1 = require("./initAbility");
|
|
70
70
|
const config_1 = require("./config");
|
|
71
71
|
const enginePins_1 = require("./enginePins");
|
|
72
|
+
const authRefresh_1 = require("./authRefresh");
|
|
72
73
|
const init_1 = require("./init");
|
|
73
74
|
const prompt_1 = require("./prompt");
|
|
74
75
|
const browserLogin_1 = require("./browserLogin");
|
|
@@ -108,6 +109,21 @@ function requireAuth() {
|
|
|
108
109
|
fail('Not logged in (or token expired). Run: helix login');
|
|
109
110
|
return creds;
|
|
110
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* requireAuth for commands that can outlive an access token (`assets start|generate|resume`). An expired stored login
|
|
114
|
+
* that carries a refresh token is renewed here instead of failing "Not logged in"; everything after that renews itself
|
|
115
|
+
* on a 401 (HelixApi.forCredentials -> src/authRefresh.ts).
|
|
116
|
+
*/
|
|
117
|
+
async function requireAuthRenewable() {
|
|
118
|
+
const creds = (0, config_1.loadCredentials)();
|
|
119
|
+
if (creds)
|
|
120
|
+
return creds;
|
|
121
|
+
const stored = (0, config_1.readStoredCredentials)();
|
|
122
|
+
const renewed = stored?.refreshToken ? await (0, authRefresh_1.refreshCredentials)(stored) : null;
|
|
123
|
+
if (!renewed)
|
|
124
|
+
fail('Not logged in (or token expired). Run: helix login');
|
|
125
|
+
return renewed;
|
|
126
|
+
}
|
|
111
127
|
function bridgeType(value) {
|
|
112
128
|
if (!types_1.BRIDGE_CONTENT_TYPES.includes(value)) {
|
|
113
129
|
fail(`✖ --type must be one of ${types_1.BRIDGE_CONTENT_TYPES.join(', ')}, got '${bridgeTerminalText(value)}'`);
|
|
@@ -1249,11 +1265,11 @@ vehicleAddOnCommand
|
|
|
1249
1265
|
});
|
|
1250
1266
|
// Validate a token against the API, then persist it. Shared by the browser
|
|
1251
1267
|
// flow and the --token (CI/headless) path.
|
|
1252
|
-
async function finishLogin(apiUrl, token) {
|
|
1268
|
+
async function finishLogin(apiUrl, token, refreshToken) {
|
|
1253
1269
|
const api = new lib_1.HelixApi(apiUrl, token);
|
|
1254
1270
|
const user = await (0, lib_1.whoAmI)(api); // validates the token
|
|
1255
1271
|
const expiresAt = (0, config_1.jwtExpiresAtIso)(token);
|
|
1256
|
-
(0, config_1.saveCredentials)({ apiUrl, token, expiresAt, username: user.username });
|
|
1272
|
+
(0, config_1.saveCredentials)({ apiUrl, token, expiresAt, username: user.username, ...(refreshToken ? { refreshToken } : {}) });
|
|
1257
1273
|
const until = expiresAt ? ` (valid until ${expiresAt.slice(0, 10)})` : '';
|
|
1258
1274
|
console.log(`✔ Logged in as ${user.username}${until}`);
|
|
1259
1275
|
}
|
|
@@ -1263,6 +1279,7 @@ program
|
|
|
1263
1279
|
.option('--api-url <url>', 'platform API base URL', config_1.DEFAULT_API_URL)
|
|
1264
1280
|
.option('--web-url <url>', 'HELIX website base URL (default: HELIX_WEB_URL, else the environment default; set for local dev)')
|
|
1265
1281
|
.option('--token <token>', 'client token — non-interactive login for CI/headless')
|
|
1282
|
+
.option('--refresh-token <token>', 'with --token: the refresh token paired with a short-lived access token (or HELIX_REFRESH_TOKEN). A long command then renews an expired access token itself; a long-lived client token needs none')
|
|
1266
1283
|
.option('--no-browser', "don't open a browser automatically; print the URL to open manually")
|
|
1267
1284
|
.action(async (opts) => {
|
|
1268
1285
|
try {
|
|
@@ -1271,7 +1288,7 @@ program
|
|
|
1271
1288
|
const token = opts.token || (await (0, prompt_1.askHidden)('Client token: '));
|
|
1272
1289
|
if (!token)
|
|
1273
1290
|
fail('✖ No token provided.');
|
|
1274
|
-
await finishLogin(opts.apiUrl, token);
|
|
1291
|
+
await finishLogin(opts.apiUrl, token, opts.refreshToken ?? process.env.HELIX_REFRESH_TOKEN ?? undefined);
|
|
1275
1292
|
return;
|
|
1276
1293
|
}
|
|
1277
1294
|
// Interactive: open the browser, let the website mint + hand back a token.
|
|
@@ -3295,8 +3312,20 @@ function driverStartInput(prompt, opts) {
|
|
|
3295
3312
|
prompt: opts.additionalPrompt ? `${prompt}\n${opts.additionalPrompt}` : prompt,
|
|
3296
3313
|
title: opts.title,
|
|
3297
3314
|
visibility: parseDriverVisibility(opts.visibility),
|
|
3315
|
+
idempotencyKey: parseIdempotencyKey(opts.idempotencyKey),
|
|
3298
3316
|
};
|
|
3299
3317
|
}
|
|
3318
|
+
function parseIdempotencyKey(value) {
|
|
3319
|
+
if (value === undefined)
|
|
3320
|
+
return undefined;
|
|
3321
|
+
if (value.length < 8 || value.length > 96 || value.trim() !== value) {
|
|
3322
|
+
fail('✖ --idempotency-key must be 8-96 characters with no leading or trailing spaces');
|
|
3323
|
+
}
|
|
3324
|
+
return value;
|
|
3325
|
+
}
|
|
3326
|
+
function driverKeyNote(key) {
|
|
3327
|
+
return ` idempotency key: ${key} (if this run's answer was lost, re-run the same command with --idempotency-key ${key} to re-attach to the same job; nothing is created or charged twice)`;
|
|
3328
|
+
}
|
|
3300
3329
|
const driverIo = {
|
|
3301
3330
|
stdout: (text) => console.log(text),
|
|
3302
3331
|
stderr: (text) => note(text),
|
|
@@ -3787,6 +3816,7 @@ const assetsStart = assets
|
|
|
3787
3816
|
.option('--repeat-per-meter <n>', 'material physical scale: tile repeats per metre')
|
|
3788
3817
|
.option('--splat-scope <scope>', 'Gaussian-splat scope: object or environment', 'environment')
|
|
3789
3818
|
.option('--visibility <visibility>', 'character: public, unlisted, or private. Sent only when you pass it; otherwise the Asset Generation job driver applies its own default')
|
|
3819
|
+
.option('--idempotency-key <key>', 'character: re-attach to the job a previous start created instead of creating a second (8-96 characters). Default: a fresh key, printed so a start whose answer was lost can be re-run safely')
|
|
3790
3820
|
.option('--max-lix <n>', 'refuse to start if the estimate exceeds this many LIX')
|
|
3791
3821
|
.option('--no-estimate', 'skip the up-front cost estimate');
|
|
3792
3822
|
// The audio surface, attached from the SAME definition `generate-audio` uses (minus the flags
|
|
@@ -3836,7 +3866,7 @@ const assetsStart = assets
|
|
|
3836
3866
|
...(0, audioCommand_1.buildAudioInput)(prompt, opts, fail),
|
|
3837
3867
|
};
|
|
3838
3868
|
}
|
|
3839
|
-
const creds =
|
|
3869
|
+
const creds = await requireAuthRenewable();
|
|
3840
3870
|
// A voice id that is not in the catalog fails HERE, before the quote and before any LIX
|
|
3841
3871
|
// moves. A lookup that cannot run only warns — an advisory check must not become a new way
|
|
3842
3872
|
// to block a valid job.
|
|
@@ -3874,7 +3904,11 @@ const assetsStart = assets
|
|
|
3874
3904
|
if (kind === 'character') {
|
|
3875
3905
|
// A character from a prompt is a thin client of the Asset Generation job driver: it owns every policy.
|
|
3876
3906
|
const input = driverStartInput(promptText, opts);
|
|
3877
|
-
|
|
3907
|
+
const started = await (0, assetGenerationDriver_1.startDriverAvatarJob)(lib_1.HelixApi.forCredentials(creds), input, undefined, {
|
|
3908
|
+
onRetry: (line) => note(` ${line}`),
|
|
3909
|
+
});
|
|
3910
|
+
note(driverKeyNote(started.idempotencyKey));
|
|
3911
|
+
printJson(started);
|
|
3878
3912
|
return;
|
|
3879
3913
|
}
|
|
3880
3914
|
if (kind === 'prop') {
|
|
@@ -4158,6 +4192,7 @@ assets
|
|
|
4158
4192
|
.option('--visibility <visibility>', 'public, unlisted, or private (default public for a prop; a character uses the Asset Generation job driver default unless you pass it)')
|
|
4159
4193
|
.option('--timeout <ms>', 'how long to wait for the job to finish before giving up (client-side only — the job keeps running; default 20min for a prop, 80min for a character)')
|
|
4160
4194
|
.option('--poll-interval <ms>', 'how often to poll job status while waiting (default 2000ms prop, 3000ms character)')
|
|
4195
|
+
.option('--idempotency-key <key>', 'character: re-attach to the job a previous start created instead of creating a second (8-96 characters). Default: a fresh key, printed so a start whose answer was lost can be re-run safely')
|
|
4161
4196
|
.option('--max-lix <n>', 'refuse to start if the estimate exceeds this many LIX')
|
|
4162
4197
|
.option('--no-estimate', 'skip the up-front cost estimate')
|
|
4163
4198
|
.action(async (kind, prompt, opts) => {
|
|
@@ -4167,14 +4202,17 @@ assets
|
|
|
4167
4202
|
const requestedVisibility = parseDriverVisibility(opts.visibility);
|
|
4168
4203
|
const timeoutMs = optionalPositiveMs(opts.timeout, '--timeout');
|
|
4169
4204
|
const pollIntervalMs = optionalPositiveMs(opts.pollInterval, '--poll-interval');
|
|
4170
|
-
const creds =
|
|
4205
|
+
const creds = await requireAuthRenewable();
|
|
4171
4206
|
await showEstimateBeforeSpending(creds, buildQuoteInput(kind, prompt, opts), opts);
|
|
4172
4207
|
if (kind === 'character') {
|
|
4173
4208
|
const api = lib_1.HelixApi.forCredentials(creds);
|
|
4174
4209
|
try {
|
|
4175
|
-
const started = await (0, assetGenerationDriver_1.startDriverAvatarJob)(api, driverStartInput(prompt, opts)
|
|
4210
|
+
const started = await (0, assetGenerationDriver_1.startDriverAvatarJob)(api, driverStartInput(prompt, opts), undefined, {
|
|
4211
|
+
onRetry: (line) => note(` ${line}`),
|
|
4212
|
+
});
|
|
4176
4213
|
note(`Started Asset Generation job ${started.id}. Waiting (resume later with: helix assets resume ${started.id})`);
|
|
4177
|
-
|
|
4214
|
+
note(driverKeyNote(started.idempotencyKey));
|
|
4215
|
+
const code = await (0, assetGenerationDriver_1.runDriverResume)(api, started.id, { timeoutMs, pollIntervalMs, idempotencyKey: started.idempotencyKey }, driverIo);
|
|
4178
4216
|
process.exitCode = code ?? 1;
|
|
4179
4217
|
}
|
|
4180
4218
|
catch (err) {
|
|
@@ -4248,7 +4286,7 @@ assets
|
|
|
4248
4286
|
}
|
|
4249
4287
|
const timeoutMs = optionalPositiveMs(opts.timeout, '--timeout');
|
|
4250
4288
|
const pollIntervalMs = optionalPositiveMs(opts.pollInterval, '--poll-interval');
|
|
4251
|
-
const creds =
|
|
4289
|
+
const creds = await requireAuthRenewable();
|
|
4252
4290
|
try {
|
|
4253
4291
|
const code = await (0, assetGenerationDriver_1.runDriverResume)(lib_1.HelixApi.forCredentials(creds), jobId, {
|
|
4254
4292
|
visibility: opts.visibility,
|