@mars-sea/dsh-commandcode-provider 0.11.10 → 0.11.11
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 +8 -0
- package/README.md +4 -4
- package/README.zh-CN.md +4 -4
- package/lib/client.js +166 -62
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +14 -9
- package/lib/index.js +111 -42
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -259,7 +259,7 @@ interface CommandCodePlan {
|
|
|
259
259
|
* at all, so the degraded per-endpoint view would hide the root cause behind
|
|
260
260
|
* a generic "partial data" note). Undefined for partial failures.
|
|
261
261
|
*/
|
|
262
|
-
type UsageBlockReason = 'invalid-key' | 'service-unavailable' | 'network';
|
|
262
|
+
type UsageBlockReason = 'invalid-key' | 'service-unavailable' | 'invalid-response' | 'network';
|
|
263
263
|
/** Everything the usage endpoints report, fetched together. */
|
|
264
264
|
interface CommandCodeUsageReport {
|
|
265
265
|
account?: CommandCodeAccount;
|
|
@@ -271,8 +271,9 @@ interface CommandCodeUsageReport {
|
|
|
271
271
|
/**
|
|
272
272
|
* The single reason every endpoint failed, when they all did: `invalid-key`
|
|
273
273
|
* (every call rejected with 401 — the stored key is wrong or expired),
|
|
274
|
-
* `service-unavailable` (every call answered 5xx),
|
|
275
|
-
*
|
|
274
|
+
* `service-unavailable` (every call answered 5xx), `invalid-response`
|
|
275
|
+
* (every call answered but its body was not usable JSON), or `network`
|
|
276
|
+
* (no HTTP response at all). Undefined when any endpoint succeeded.
|
|
276
277
|
*/
|
|
277
278
|
blocked?: UsageBlockReason;
|
|
278
279
|
}
|
|
@@ -348,8 +349,8 @@ declare class CommandCodeAdapter<C extends CommandCodeConnectionOptions = Comman
|
|
|
348
349
|
* Fetch one account endpoint and parse its JSON body. Returns the HTTP
|
|
349
350
|
* status alongside the parsed record so each caller applies its own
|
|
350
351
|
* failure accounting: the billing probe fails open silently, the usage
|
|
351
|
-
* report books failures per endpoint. Non-2xx and
|
|
352
|
-
* back without a record; only a
|
|
352
|
+
* report books failures per endpoint. Non-2xx and invalid JSON bodies come
|
|
353
|
+
* back without a record; only a fetch failure propagates to the caller.
|
|
353
354
|
*
|
|
354
355
|
* `timeoutMs` is the caller's budget for this one request. The default is the
|
|
355
356
|
* CATALOG probe's short cap, which fits the picker's fail-open reads; the
|
|
@@ -1284,7 +1285,7 @@ declare const loginStatusSchema: TypertSchema<CommandCodeLoginStatus>;
|
|
|
1284
1285
|
*/
|
|
1285
1286
|
interface LoginFlowFacade {
|
|
1286
1287
|
/** Start (or rejoin) an attempt; rejects when it cannot start at all. */
|
|
1287
|
-
begin(): Promise<CommandCodeLoginStatus>;
|
|
1288
|
+
begin(targetRef?: string): Promise<CommandCodeLoginStatus>;
|
|
1288
1289
|
/** The current attempt's status. */
|
|
1289
1290
|
status(): CommandCodeLoginStatus;
|
|
1290
1291
|
/** Cancel a waiting attempt. */
|
|
@@ -1361,7 +1362,7 @@ declare class CommandCodeUsageService<C extends CommandCodeConnectionOptions = C
|
|
|
1361
1362
|
* (no free loopback port, disposed plugin); the Gateway folds the throw
|
|
1362
1363
|
* into the failure branch the page renders.
|
|
1363
1364
|
*/
|
|
1364
|
-
loginBegin(): Promise<CommandCodeLoginStatus>;
|
|
1365
|
+
loginBegin(targetRef?: string): Promise<CommandCodeLoginStatus>;
|
|
1365
1366
|
/** Poll a login attempt's status. */
|
|
1366
1367
|
loginStatus(): Promise<CommandCodeLoginStatus>;
|
|
1367
1368
|
/** Cancel a waiting attempt; returns the post-cancel status. */
|
|
@@ -1422,7 +1423,9 @@ interface CommandCodeLoginFlowDeps {
|
|
|
1422
1423
|
* Receives the validated credentials after a successful login. Rejecting
|
|
1423
1424
|
* fails the attempt with `unavailable`.
|
|
1424
1425
|
*/
|
|
1425
|
-
storeKey(credentials: CommandCodeLoginCredentials): Promise<void>;
|
|
1426
|
+
storeKey(credentials: CommandCodeLoginCredentials, targetRef?: string): Promise<void>;
|
|
1427
|
+
/** Reject an account target that is not a saved slot before opening Studio. */
|
|
1428
|
+
validateTargetRef?(targetRef: string | undefined): void;
|
|
1426
1429
|
}
|
|
1427
1430
|
/** Compose the Studio authorization URL (pure, exported for tests). */
|
|
1428
1431
|
declare function buildCommandAuthUrl(options: {
|
|
@@ -1471,6 +1474,8 @@ declare class CommandCodeLoginFlow {
|
|
|
1471
1474
|
* the port window so browser login dies until the Host restarts.
|
|
1472
1475
|
*/
|
|
1473
1476
|
private starting;
|
|
1477
|
+
/** A live attempt's destination; different rows may not rejoin it. */
|
|
1478
|
+
private targetRef;
|
|
1474
1479
|
/** A `cancel()` that arrived while a start was still binding (see {@link CommandCodeLoginFlow.cancel}). */
|
|
1475
1480
|
private cancelPending;
|
|
1476
1481
|
private disposed;
|
|
@@ -1484,7 +1489,7 @@ declare class CommandCodeLoginFlow {
|
|
|
1484
1489
|
* `waiting` carrying the Studio URL once the loopback server is up.
|
|
1485
1490
|
* Rejects only when the flow cannot start at all (no free port, disposed).
|
|
1486
1491
|
*/
|
|
1487
|
-
begin(): Promise<CommandCodeLoginStatus>;
|
|
1492
|
+
begin(targetRef?: string): Promise<CommandCodeLoginStatus>;
|
|
1488
1493
|
/**
|
|
1489
1494
|
* The binding half of {@link CommandCodeLoginFlow.begin}: one attempt, one
|
|
1490
1495
|
* server, one published `waiting` status. Callers reach it only through
|
package/lib/index.js
CHANGED
|
@@ -2135,6 +2135,14 @@ function installCostProjection(ctx) {
|
|
|
2135
2135
|
});
|
|
2136
2136
|
}
|
|
2137
2137
|
//#endregion
|
|
2138
|
+
//#region src/response-encoding.ts
|
|
2139
|
+
/**
|
|
2140
|
+
* Ask Command Code for plain response bodies. A DSH host using an incompatible
|
|
2141
|
+
* undici global dispatcher can lose response headers and leave compressed
|
|
2142
|
+
* JSON, SSE, and pre-stream error bodies undecoded.
|
|
2143
|
+
*/
|
|
2144
|
+
const IDENTITY_ENCODING_HEADER = { "accept-encoding": "identity" };
|
|
2145
|
+
//#endregion
|
|
2138
2146
|
//#region src/accounts.ts
|
|
2139
2147
|
/**
|
|
2140
2148
|
* Multi-account pool for the Command Code provider (host side).
|
|
@@ -3993,17 +4001,12 @@ function parseAccountIdentity(whoami) {
|
|
|
3993
4001
|
orgId: orgData === void 0 ? void 0 : stringValue(orgData.id)
|
|
3994
4002
|
};
|
|
3995
4003
|
}
|
|
3996
|
-
|
|
3997
|
-
* Classify a TOTAL failure: when every endpoint failed with one class of
|
|
3998
|
-
* error, the degraded per-endpoint view would hide the root cause behind
|
|
3999
|
-
* a generic "partial data" note — name it instead.
|
|
4000
|
-
*/
|
|
4001
|
-
function classifyTotalFailure(failures, failedStatuses) {
|
|
4004
|
+
function classifyTotalFailure(failures, failed) {
|
|
4002
4005
|
if (failures.length !== USAGE_ENDPOINT_COUNT) return void 0;
|
|
4003
|
-
|
|
4004
|
-
if (
|
|
4005
|
-
if (
|
|
4006
|
-
if (
|
|
4006
|
+
if (failed.every((item) => item.kind === "http" && item.status === 401)) return "invalid-key";
|
|
4007
|
+
if (failed.every((item) => item.kind === "http" && item.status >= 500)) return "service-unavailable";
|
|
4008
|
+
if (failed.every((item) => item.kind === "invalid-response")) return "invalid-response";
|
|
4009
|
+
if (failed.every((item) => item.kind === "transport")) return "network";
|
|
4007
4010
|
}
|
|
4008
4011
|
/** Build the legacy CLI (`/alpha/generate`) request body for one call. */
|
|
4009
4012
|
async function buildCliBody(options, connection, facts) {
|
|
@@ -4097,6 +4100,7 @@ async function connectGenerate(deps, key, protocol, body) {
|
|
|
4097
4100
|
const zdr = connection.zdr === true;
|
|
4098
4101
|
const headers = protocol === "cli" ? {
|
|
4099
4102
|
"Content-Type": "application/json",
|
|
4103
|
+
...IDENTITY_ENCODING_HEADER,
|
|
4100
4104
|
Authorization: `Bearer ${key}`,
|
|
4101
4105
|
"x-command-code-version": COMMAND_CODE_CLI_VERSION,
|
|
4102
4106
|
"x-cli-environment": "production",
|
|
@@ -4107,6 +4111,7 @@ async function connectGenerate(deps, key, protocol, body) {
|
|
|
4107
4111
|
...attributionHeaders()
|
|
4108
4112
|
} : {
|
|
4109
4113
|
"Content-Type": "application/json",
|
|
4114
|
+
...IDENTITY_ENCODING_HEADER,
|
|
4110
4115
|
Authorization: `Bearer ${key}`,
|
|
4111
4116
|
Accept: "text/event-stream",
|
|
4112
4117
|
...zdr ? { "x-cmd-zdr": "1" } : {},
|
|
@@ -4314,6 +4319,7 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
4314
4319
|
const response = await this.fetchImpl(`${apiBase}/provider/v1/models`, {
|
|
4315
4320
|
headers: {
|
|
4316
4321
|
accept: "application/json",
|
|
4322
|
+
...IDENTITY_ENCODING_HEADER,
|
|
4317
4323
|
...attributionHeaders()
|
|
4318
4324
|
},
|
|
4319
4325
|
signal: signal ?? AbortSignal.timeout(1e4)
|
|
@@ -4377,6 +4383,7 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
4377
4383
|
const named = connection.apiKeyEnv;
|
|
4378
4384
|
return {
|
|
4379
4385
|
Authorization: `Bearer ${assertUsableApiKey(raw, "llm-commandcode", typeof named === "string" && named !== "" ? named : "the stored credential")}`,
|
|
4386
|
+
...IDENTITY_ENCODING_HEADER,
|
|
4380
4387
|
"x-command-code-version": COMMAND_CODE_CLI_VERSION,
|
|
4381
4388
|
"x-cli-environment": "production",
|
|
4382
4389
|
...attributionHeaders()
|
|
@@ -4386,8 +4393,8 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
4386
4393
|
* Fetch one account endpoint and parse its JSON body. Returns the HTTP
|
|
4387
4394
|
* status alongside the parsed record so each caller applies its own
|
|
4388
4395
|
* failure accounting: the billing probe fails open silently, the usage
|
|
4389
|
-
* report books failures per endpoint. Non-2xx and
|
|
4390
|
-
* back without a record; only a
|
|
4396
|
+
* report books failures per endpoint. Non-2xx and invalid JSON bodies come
|
|
4397
|
+
* back without a record; only a fetch failure propagates to the caller.
|
|
4391
4398
|
*
|
|
4392
4399
|
* `timeoutMs` is the caller's budget for this one request. The default is the
|
|
4393
4400
|
* CATALOG probe's short cap, which fits the picker's fail-open reads; the
|
|
@@ -4400,10 +4407,21 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
4400
4407
|
signal: AbortSignal.timeout(timeoutMs)
|
|
4401
4408
|
});
|
|
4402
4409
|
if (!response.ok) return { status: response.status };
|
|
4403
|
-
|
|
4404
|
-
|
|
4410
|
+
let parsed;
|
|
4411
|
+
try {
|
|
4412
|
+
parsed = await response.json();
|
|
4413
|
+
} catch {
|
|
4414
|
+
return {
|
|
4415
|
+
status: response.status,
|
|
4416
|
+
invalidResponse: true
|
|
4417
|
+
};
|
|
4418
|
+
}
|
|
4419
|
+
return isRecord(parsed) ? {
|
|
4420
|
+
status: response.status,
|
|
4421
|
+
record: parsed
|
|
4422
|
+
} : {
|
|
4405
4423
|
status: response.status,
|
|
4406
|
-
|
|
4424
|
+
invalidResponse: true
|
|
4407
4425
|
};
|
|
4408
4426
|
}
|
|
4409
4427
|
/**
|
|
@@ -4584,19 +4602,25 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
4584
4602
|
throw error;
|
|
4585
4603
|
}
|
|
4586
4604
|
const failures = [];
|
|
4587
|
-
const
|
|
4605
|
+
const failed = [];
|
|
4588
4606
|
const getJson = async (path) => {
|
|
4589
4607
|
try {
|
|
4590
|
-
const { status, record } = await this.fetchEndpointJson(`${base}${path}`, headers, connection.requestTimeoutMs);
|
|
4608
|
+
const { status, record, invalidResponse } = await this.fetchEndpointJson(`${base}${path}`, headers, connection.requestTimeoutMs);
|
|
4591
4609
|
if (record === void 0) {
|
|
4592
|
-
failures.push(`${path}: HTTP ${status}`);
|
|
4593
|
-
|
|
4610
|
+
failures.push(`${path}: HTTP ${status}${invalidResponse ? " returned an unreadable or invalid JSON body" : ""}`);
|
|
4611
|
+
failed.push(invalidResponse ? {
|
|
4612
|
+
kind: "invalid-response",
|
|
4613
|
+
status
|
|
4614
|
+
} : {
|
|
4615
|
+
kind: "http",
|
|
4616
|
+
status
|
|
4617
|
+
});
|
|
4594
4618
|
return;
|
|
4595
4619
|
}
|
|
4596
4620
|
return record;
|
|
4597
4621
|
} catch (error) {
|
|
4598
4622
|
failures.push(`${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
4599
|
-
|
|
4623
|
+
failed.push({ kind: "transport" });
|
|
4600
4624
|
return;
|
|
4601
4625
|
}
|
|
4602
4626
|
};
|
|
@@ -4625,7 +4649,7 @@ var CommandCodeAdapter = class extends LlmAdapter {
|
|
|
4625
4649
|
currentPeriodEnd: periodEndValue(subData?.currentPeriodEnd)
|
|
4626
4650
|
};
|
|
4627
4651
|
}
|
|
4628
|
-
const blocked = classifyTotalFailure(failures,
|
|
4652
|
+
const blocked = classifyTotalFailure(failures, failed);
|
|
4629
4653
|
if (blocked !== void 0) report.blocked = blocked;
|
|
4630
4654
|
return report;
|
|
4631
4655
|
}
|
|
@@ -5438,6 +5462,7 @@ const commandcodeCommand = {
|
|
|
5438
5462
|
unconfigured: " (未配置 API 密钥)",
|
|
5439
5463
|
blockedInvalidKey: "⛔ API 密钥无效或已过期 — 服务端拒绝了全部请求(401),请检查该账户的密钥配置",
|
|
5440
5464
|
blockedServiceUnavailable: "⚠️ Command Code 服务暂时不可用(5xx),稍后重试",
|
|
5465
|
+
blockedInvalidResponse: "⚠️ Command Code 返回了无法读取的响应 — 请检查宿主的 HTTP 代理或响应解压配置",
|
|
5441
5466
|
blockedNetwork: "⚠️ 无法连接 Command Code 服务 — 请检查网络或 API 地址",
|
|
5442
5467
|
planLine: " 📦 套餐 {name}{status}{period}",
|
|
5443
5468
|
planPeriodSuffix: " · 账期截止 {date}",
|
|
@@ -5469,6 +5494,7 @@ const commandcodeCommand = {
|
|
|
5469
5494
|
unconfigured: " (no API key configured)",
|
|
5470
5495
|
blockedInvalidKey: "⛔ API key invalid or expired — the server rejected every request (401); check the key configured for this account",
|
|
5471
5496
|
blockedServiceUnavailable: "⚠️ Command Code service temporarily unavailable (5xx); try again later",
|
|
5497
|
+
blockedInvalidResponse: "⚠️ Command Code returned an unreadable response — check the host HTTP proxy or response decoding",
|
|
5472
5498
|
blockedNetwork: "⚠️ could not reach the Command Code service — check your network or the API base setting",
|
|
5473
5499
|
planLine: " 📦 Plan {name}{status}{period}",
|
|
5474
5500
|
planPeriodSuffix: " · period ends {date}",
|
|
@@ -5567,6 +5593,7 @@ function renderReport(report, locale, title) {
|
|
|
5567
5593
|
lines.push(title ?? commandCopy(locale, "title").replace("{account}", account), "");
|
|
5568
5594
|
if (report.blocked === "invalid-key") lines.push(commandCopy(locale, "blockedInvalidKey"), "");
|
|
5569
5595
|
else if (report.blocked === "service-unavailable") lines.push(commandCopy(locale, "blockedServiceUnavailable"), "");
|
|
5596
|
+
else if (report.blocked === "invalid-response") lines.push(commandCopy(locale, "blockedInvalidResponse"), "");
|
|
5570
5597
|
else if (report.blocked === "network") lines.push(commandCopy(locale, "blockedNetwork"), "");
|
|
5571
5598
|
if (report.plan && report.plan.name !== "") {
|
|
5572
5599
|
const p = report.plan;
|
|
@@ -5668,6 +5695,15 @@ function makeBoundaryValidator(prefix) {
|
|
|
5668
5695
|
booleanField
|
|
5669
5696
|
};
|
|
5670
5697
|
}
|
|
5698
|
+
/** Use the same strict-codec shape for invocation parameters and results. */
|
|
5699
|
+
function makeStrictCodec(typeSymbol, schema) {
|
|
5700
|
+
return {
|
|
5701
|
+
mode: "strict",
|
|
5702
|
+
typeSymbol,
|
|
5703
|
+
schema,
|
|
5704
|
+
create: () => schema
|
|
5705
|
+
};
|
|
5706
|
+
}
|
|
5671
5707
|
/**
|
|
5672
5708
|
* Build one strict invocation descriptor. Every Command Code Remote shares the
|
|
5673
5709
|
* `commandcode` namespace, the `commandcodeUsage` service, and a strict
|
|
@@ -5676,12 +5712,7 @@ function makeBoundaryValidator(prefix) {
|
|
|
5676
5712
|
* only its own facts.
|
|
5677
5713
|
*/
|
|
5678
5714
|
function makeRemoteDescriptor(endpoint, method, typeSymbol, schema) {
|
|
5679
|
-
const result =
|
|
5680
|
-
mode: "strict",
|
|
5681
|
-
typeSymbol,
|
|
5682
|
-
schema,
|
|
5683
|
-
create: () => schema
|
|
5684
|
-
};
|
|
5715
|
+
const result = makeStrictCodec(typeSymbol, schema);
|
|
5685
5716
|
return {
|
|
5686
5717
|
id: `${REMOTE_PACKAGE}#${endpoint}`,
|
|
5687
5718
|
service: REMOTE_SERVICE,
|
|
@@ -5734,7 +5765,7 @@ function parseUsageReport(value) {
|
|
|
5734
5765
|
const report = { failures };
|
|
5735
5766
|
if (source.blocked !== void 0) {
|
|
5736
5767
|
const blocked = source.blocked;
|
|
5737
|
-
if (blocked === "invalid-key" || blocked === "service-unavailable" || blocked === "network") report.blocked = blocked;
|
|
5768
|
+
if (blocked === "invalid-key" || blocked === "service-unavailable" || blocked === "invalid-response" || blocked === "network") report.blocked = blocked;
|
|
5738
5769
|
else reject$1("blocked");
|
|
5739
5770
|
}
|
|
5740
5771
|
if (source.account !== void 0) {
|
|
@@ -5963,9 +5994,24 @@ function parseLoginStatus(value) {
|
|
|
5963
5994
|
}
|
|
5964
5995
|
/** The strict result codec shared by all three login endpoints. */
|
|
5965
5996
|
const loginStatusSchema = { parse: parseLoginStatus };
|
|
5966
|
-
/**
|
|
5997
|
+
/** Optional account target; the Host still checks it against saved slots. */
|
|
5998
|
+
const loginTargetSchema = { parse(value) {
|
|
5999
|
+
if (value === void 0 || typeof value === "string") return value;
|
|
6000
|
+
return reject("targetRef");
|
|
6001
|
+
} };
|
|
6002
|
+
/** Build one login invocation descriptor. Only begin accepts an account ref. */
|
|
5967
6003
|
function loginDescriptor(endpoint, method) {
|
|
5968
|
-
|
|
6004
|
+
const descriptor = makeRemoteDescriptor(endpoint, method, `${REMOTE_PACKAGE}#CommandCodeLoginStatus`, loginStatusSchema);
|
|
6005
|
+
return method === "loginBegin" ? {
|
|
6006
|
+
...descriptor,
|
|
6007
|
+
parameters: [{
|
|
6008
|
+
name: "targetRef",
|
|
6009
|
+
wire: "targetRef",
|
|
6010
|
+
source: "json",
|
|
6011
|
+
codec: makeStrictCodec(`${REMOTE_PACKAGE}#CommandCodeLoginTargetRef`, loginTargetSchema),
|
|
6012
|
+
acceptsUndefined: true
|
|
6013
|
+
}]
|
|
6014
|
+
} : descriptor;
|
|
5969
6015
|
}
|
|
5970
6016
|
/** The three login descriptors, shared verbatim by Host registration and Client mount. */
|
|
5971
6017
|
const LOGIN_DESCRIPTORS = [
|
|
@@ -6033,8 +6079,8 @@ var CommandCodeUsageService = class extends TypertRemoteService {
|
|
|
6033
6079
|
* (no free loopback port, disposed plugin); the Gateway folds the throw
|
|
6034
6080
|
* into the failure branch the page renders.
|
|
6035
6081
|
*/
|
|
6036
|
-
async loginBegin() {
|
|
6037
|
-
return this.requireLogin().begin();
|
|
6082
|
+
async loginBegin(targetRef) {
|
|
6083
|
+
return this.requireLogin().begin(targetRef);
|
|
6038
6084
|
}
|
|
6039
6085
|
/** Poll a login attempt's status. */
|
|
6040
6086
|
async loginStatus() {
|
|
@@ -6121,6 +6167,12 @@ const LOGIN_ALLOWED_ORIGINS = [
|
|
|
6121
6167
|
];
|
|
6122
6168
|
/** The Studio route that performs the browser-side login. */
|
|
6123
6169
|
const STUDIO_AUTH_PATH = "/studio/auth/cli";
|
|
6170
|
+
/** Resolve a browser-login destination without allowing arbitrary credential writes. */
|
|
6171
|
+
function loginCredentialRef(targetRef, defaultRef, accounts) {
|
|
6172
|
+
if (targetRef === void 0) return defaultRef;
|
|
6173
|
+
if (targetRef === defaultRef || !accounts.some((account) => account.apiKeyEnv === targetRef)) throw new Error("the target account must be saved before browser sign-in");
|
|
6174
|
+
return targetRef;
|
|
6175
|
+
}
|
|
6124
6176
|
/** Compose the Studio authorization URL (pure, exported for tests). */
|
|
6125
6177
|
function buildCommandAuthUrl(options) {
|
|
6126
6178
|
const callback = `http://localhost:${options.port}/callback`;
|
|
@@ -6143,6 +6195,7 @@ async function validateCommandApiKey(fetchImpl, apiBase, apiKey) {
|
|
|
6143
6195
|
method: "GET",
|
|
6144
6196
|
headers: {
|
|
6145
6197
|
"Content-Type": "application/json",
|
|
6198
|
+
...IDENTITY_ENCODING_HEADER,
|
|
6146
6199
|
Authorization: `Bearer ${apiKey}`
|
|
6147
6200
|
}
|
|
6148
6201
|
});
|
|
@@ -6210,6 +6263,8 @@ var CommandCodeLoginFlow = class {
|
|
|
6210
6263
|
* the port window so browser login dies until the Host restarts.
|
|
6211
6264
|
*/
|
|
6212
6265
|
starting;
|
|
6266
|
+
/** A live attempt's destination; different rows may not rejoin it. */
|
|
6267
|
+
targetRef;
|
|
6213
6268
|
/** A `cancel()` that arrived while a start was still binding (see {@link CommandCodeLoginFlow.cancel}). */
|
|
6214
6269
|
cancelPending = false;
|
|
6215
6270
|
disposed = false;
|
|
@@ -6230,12 +6285,20 @@ var CommandCodeLoginFlow = class {
|
|
|
6230
6285
|
* `waiting` carrying the Studio URL once the loopback server is up.
|
|
6231
6286
|
* Rejects only when the flow cannot start at all (no free port, disposed).
|
|
6232
6287
|
*/
|
|
6233
|
-
async begin() {
|
|
6288
|
+
async begin(targetRef) {
|
|
6234
6289
|
if (this.disposed) throw new Error("login flow has been disposed");
|
|
6235
|
-
|
|
6236
|
-
if (this.
|
|
6290
|
+
this.deps.validateTargetRef?.(targetRef);
|
|
6291
|
+
if (this.statusValue.state === "waiting" && this.server !== void 0) {
|
|
6292
|
+
if (this.targetRef !== targetRef) throw new Error("another account login is already in progress");
|
|
6293
|
+
return this.statusValue;
|
|
6294
|
+
}
|
|
6295
|
+
if (this.starting !== void 0) {
|
|
6296
|
+
if (this.targetRef !== targetRef) throw new Error("another account login is already in progress");
|
|
6297
|
+
return this.starting;
|
|
6298
|
+
}
|
|
6237
6299
|
this.cancelPending = false;
|
|
6238
|
-
|
|
6300
|
+
this.targetRef = targetRef;
|
|
6301
|
+
const starting = this.startAttempt(targetRef);
|
|
6239
6302
|
this.starting = starting;
|
|
6240
6303
|
try {
|
|
6241
6304
|
return await starting;
|
|
@@ -6248,7 +6311,7 @@ var CommandCodeLoginFlow = class {
|
|
|
6248
6311
|
* server, one published `waiting` status. Callers reach it only through
|
|
6249
6312
|
* `begin()`'s single-flight fence.
|
|
6250
6313
|
*/
|
|
6251
|
-
async startAttempt() {
|
|
6314
|
+
async startAttempt(targetRef) {
|
|
6252
6315
|
this.teardown();
|
|
6253
6316
|
const attempt = ++this.attemptSeq;
|
|
6254
6317
|
const port = await this.findPort();
|
|
@@ -6288,7 +6351,7 @@ var CommandCodeLoginFlow = class {
|
|
|
6288
6351
|
});
|
|
6289
6352
|
}, this.deps.timeoutMs ?? 12e4);
|
|
6290
6353
|
this.timer.unref?.();
|
|
6291
|
-
settled.then((credentials) => this.complete(attempt, credentials), (failure) => this.failFrom(attempt, failure));
|
|
6354
|
+
settled.then((credentials) => this.complete(attempt, credentials, targetRef), (failure) => this.failFrom(attempt, failure));
|
|
6292
6355
|
return this.statusValue;
|
|
6293
6356
|
}
|
|
6294
6357
|
/**
|
|
@@ -6467,7 +6530,7 @@ var CommandCodeLoginFlow = class {
|
|
|
6467
6530
|
* would report "cancelled" while the credential landed anyway, and the page
|
|
6468
6531
|
* would silently flip to success.
|
|
6469
6532
|
*/
|
|
6470
|
-
async complete(attempt, credentials) {
|
|
6533
|
+
async complete(attempt, credentials, targetRef) {
|
|
6471
6534
|
if (!this.ownsAttempt(attempt)) return;
|
|
6472
6535
|
const validation = await validateCommandApiKey(this.deps.fetchImpl ?? fetch, this.readApiBase(), credentials.apiKey);
|
|
6473
6536
|
if (!this.ownsAttempt(attempt)) return;
|
|
@@ -6482,7 +6545,8 @@ var CommandCodeLoginFlow = class {
|
|
|
6482
6545
|
}
|
|
6483
6546
|
if (!this.ownsAttempt(attempt)) return;
|
|
6484
6547
|
try {
|
|
6485
|
-
|
|
6548
|
+
this.deps.validateTargetRef?.(targetRef);
|
|
6549
|
+
await this.deps.storeKey(credentials, targetRef);
|
|
6486
6550
|
} catch (error) {
|
|
6487
6551
|
if (!this.ownsAttempt(attempt)) return;
|
|
6488
6552
|
this.setStatus({
|
|
@@ -6732,6 +6796,7 @@ var CommandCodeSearchProvider = class {
|
|
|
6732
6796
|
method: "POST",
|
|
6733
6797
|
headers: {
|
|
6734
6798
|
"Content-Type": "application/json",
|
|
6799
|
+
...IDENTITY_ENCODING_HEADER,
|
|
6735
6800
|
Authorization: `Bearer ${key}`,
|
|
6736
6801
|
"x-command-code-version": COMMAND_CODE_CLI_VERSION,
|
|
6737
6802
|
"x-cli-environment": "production",
|
|
@@ -7572,6 +7637,7 @@ async function runSystemOne(deps, request, options = {}) {
|
|
|
7572
7637
|
method: "POST",
|
|
7573
7638
|
headers: {
|
|
7574
7639
|
"Content-Type": "application/json",
|
|
7640
|
+
...IDENTITY_ENCODING_HEADER,
|
|
7575
7641
|
Authorization: `Bearer ${key}`,
|
|
7576
7642
|
"x-command-code-version": COMMAND_CODE_CLI_VERSION,
|
|
7577
7643
|
...attributionHeaders()
|
|
@@ -8398,8 +8464,11 @@ function apply(ctx, config) {
|
|
|
8398
8464
|
});
|
|
8399
8465
|
const loginFlow = new CommandCodeLoginFlow({
|
|
8400
8466
|
apiBase: () => options().apiBase,
|
|
8401
|
-
|
|
8402
|
-
|
|
8467
|
+
validateTargetRef: (targetRef) => {
|
|
8468
|
+
loginCredentialRef(targetRef, current().apiKeyEnv ?? DEFAULT_API_KEY_ENV, current().accounts ?? []);
|
|
8469
|
+
},
|
|
8470
|
+
storeKey: async ({ apiKey }, targetRef) => {
|
|
8471
|
+
const ref = credentialRef(loginCredentialRef(targetRef, current().apiKeyEnv ?? DEFAULT_API_KEY_ENV, current().accounts ?? []));
|
|
8403
8472
|
const credentials = ctx.get("credentials");
|
|
8404
8473
|
if (credentials === void 0) throw new Error("the credentials service is unavailable in this profile; paste the key manually");
|
|
8405
8474
|
await credentials.set(ref, apiKey);
|