@acosmi/sdk-ts 2.18.0 → 2.19.1
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 +28 -0
- package/README.md +30 -2
- package/dist/browser/index.mjs +1228 -171
- package/dist/browser/index.mjs.map +1 -1
- package/dist/index.mjs +1228 -171
- package/dist/index.mjs.map +1 -1
- package/dist/node/adapters/anthropic.cjs.map +1 -1
- package/dist/node/adapters/anthropic.mjs.map +1 -1
- package/dist/node/adapters/openai.cjs +110 -45
- package/dist/node/adapters/openai.cjs.map +1 -1
- package/dist/node/adapters/openai.d.cts +1 -1
- package/dist/node/adapters/openai.d.ts +1 -1
- package/dist/node/adapters/openai.mjs +110 -45
- package/dist/node/adapters/openai.mjs.map +1 -1
- package/dist/node/index.cjs +1230 -170
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.d.cts +376 -153
- package/dist/node/index.d.ts +376 -153
- package/dist/node/index.mjs +1228 -171
- package/dist/node/index.mjs.map +1 -1
- package/dist/node/{openai-Cyvi8g6B.d.ts → openai-BbCQOMNY.d.ts} +28 -1
- package/dist/node/{openai-DR_KhEdM.d.cts → openai-CMrvATF_.d.cts} +28 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -147,6 +147,55 @@ var init_types = __esm({
|
|
|
147
147
|
});
|
|
148
148
|
|
|
149
149
|
// src/shared/errors.ts
|
|
150
|
+
function nullableID(value) {
|
|
151
|
+
return value === null || typeof value === "string";
|
|
152
|
+
}
|
|
153
|
+
function decodeGatewayErrorContract(value) {
|
|
154
|
+
if (value == null || typeof value !== "object") return null;
|
|
155
|
+
const v = value;
|
|
156
|
+
const version = v.errorContractVersion;
|
|
157
|
+
const domain = v.faultDomain;
|
|
158
|
+
const disposition = v.requestDisposition;
|
|
159
|
+
const errorCode = v.errorCode;
|
|
160
|
+
if (version !== 1 || typeof domain !== "string" || !gatewayFaultDomains.includes(domain)) return null;
|
|
161
|
+
if (typeof errorCode !== "string" || errorCode.length === 0) return null;
|
|
162
|
+
if (disposition !== "not_accepted" && disposition !== "accepted" && disposition !== "unknown") return null;
|
|
163
|
+
if (!nullableID(v.transportRequestId) || !nullableID(v.consumeRequestId) || !nullableID(v.providerRequestId)) return null;
|
|
164
|
+
if (typeof v.retryable !== "boolean") return null;
|
|
165
|
+
return {
|
|
166
|
+
errorContractVersion: 1,
|
|
167
|
+
faultDomain: domain,
|
|
168
|
+
errorCode,
|
|
169
|
+
transportRequestId: v.transportRequestId,
|
|
170
|
+
consumeRequestId: v.consumeRequestId,
|
|
171
|
+
providerRequestId: v.providerRequestId,
|
|
172
|
+
requestDisposition: disposition,
|
|
173
|
+
retryable: v.retryable
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function readGatewayErrorContract(error) {
|
|
177
|
+
const direct = decodeGatewayErrorContract(error);
|
|
178
|
+
if (direct) return direct;
|
|
179
|
+
if (error == null || typeof error !== "object") return null;
|
|
180
|
+
const e = error;
|
|
181
|
+
const axios = decodeGatewayErrorContract(e.response?.data);
|
|
182
|
+
if (axios) return axios;
|
|
183
|
+
if (typeof e.body === "string") {
|
|
184
|
+
try {
|
|
185
|
+
return decodeGatewayErrorContract(JSON.parse(e.body));
|
|
186
|
+
} catch {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
function isUserAccessTokenRejected(error) {
|
|
193
|
+
if (error == null || typeof error !== "object") return false;
|
|
194
|
+
const e = error;
|
|
195
|
+
const status = e.statusCode ?? e.response?.status;
|
|
196
|
+
const contract = readGatewayErrorContract(error);
|
|
197
|
+
return status === 401 && contract?.faultDomain === "user_auth" && contract.errorCode === "USER_ACCESS_TOKEN_INVALID" && contract.requestDisposition === "not_accepted";
|
|
198
|
+
}
|
|
150
199
|
function isWindowLimitError(err) {
|
|
151
200
|
if (!(err instanceof HTTPError)) return false;
|
|
152
201
|
if (err.errorCode === windowLimitErrorCode) return true;
|
|
@@ -174,7 +223,7 @@ function getWindowLimitStreamDetails(err) {
|
|
|
174
223
|
windowOverridable: typeof e.windowOverridable === "boolean" ? e.windowOverridable : void 0
|
|
175
224
|
};
|
|
176
225
|
}
|
|
177
|
-
var RateLimitError, BusinessError, OrderTerminalError, ModelNotFoundError, HTTPError, NetworkError, StreamError, windowLimitErrorCode, windowLimitStreamCode;
|
|
226
|
+
var RateLimitError, BusinessError, OrderTerminalError, ModelNotFoundError, HTTPError, NetworkError, StreamError, gatewayFaultDomains, windowLimitErrorCode, windowLimitStreamCode;
|
|
178
227
|
var init_errors = __esm({
|
|
179
228
|
"src/shared/errors.ts"() {
|
|
180
229
|
RateLimitError = class extends Error {
|
|
@@ -233,6 +282,13 @@ var init_errors = __esm({
|
|
|
233
282
|
* false/缺失 = 周窗/显式禁止/灰度关 (硬等待, 无豁免路径, 老网关不返回时为 undefined)。
|
|
234
283
|
*/
|
|
235
284
|
windowOverridable;
|
|
285
|
+
errorContractVersion;
|
|
286
|
+
faultDomain;
|
|
287
|
+
requestDisposition;
|
|
288
|
+
transportRequestId;
|
|
289
|
+
consumeRequestId;
|
|
290
|
+
providerRequestId;
|
|
291
|
+
retryable;
|
|
236
292
|
constructor(statusCode, opts = {}) {
|
|
237
293
|
let msg;
|
|
238
294
|
if (opts.type) {
|
|
@@ -254,6 +310,13 @@ var init_errors = __esm({
|
|
|
254
310
|
this.windowKind = opts.windowKind;
|
|
255
311
|
this.windowResetAt = opts.windowResetAt;
|
|
256
312
|
this.windowOverridable = opts.windowOverridable;
|
|
313
|
+
this.errorContractVersion = opts.errorContractVersion;
|
|
314
|
+
this.faultDomain = opts.faultDomain;
|
|
315
|
+
this.requestDisposition = opts.requestDisposition;
|
|
316
|
+
this.transportRequestId = opts.transportRequestId;
|
|
317
|
+
this.consumeRequestId = opts.consumeRequestId;
|
|
318
|
+
this.providerRequestId = opts.providerRequestId;
|
|
319
|
+
this.retryable = opts.retryable === true && opts.requestDisposition === "not_accepted";
|
|
257
320
|
}
|
|
258
321
|
};
|
|
259
322
|
NetworkError = class extends Error {
|
|
@@ -264,6 +327,7 @@ var init_errors = __esm({
|
|
|
264
327
|
cause;
|
|
265
328
|
timeout;
|
|
266
329
|
eof;
|
|
330
|
+
requestDisposition = "unknown";
|
|
267
331
|
constructor(op, url, cause, opts = {}) {
|
|
268
332
|
const causeMsg = cause instanceof Error ? cause.message : cause != null ? String(cause) : "network error";
|
|
269
333
|
super(`${op} ${url}: ${causeMsg}`);
|
|
@@ -284,6 +348,8 @@ var init_errors = __esm({
|
|
|
284
348
|
StreamError = class extends Error {
|
|
285
349
|
/** 例: "empty_response" / "rate_limit" / "overloaded" / "" */
|
|
286
350
|
code;
|
|
351
|
+
/** D23 gateway machine code; mirrors the legacy `code` field. */
|
|
352
|
+
errorCode;
|
|
287
353
|
/** 例: "provider" / "settlement" */
|
|
288
354
|
stage;
|
|
289
355
|
/** 用户友好提示 (中文); 历史字段, 与 rawError 区分 */
|
|
@@ -292,23 +358,47 @@ var init_errors = __esm({
|
|
|
292
358
|
rawError;
|
|
293
359
|
/** 客户端是否值得重试 */
|
|
294
360
|
retryable;
|
|
361
|
+
errorContractVersion;
|
|
362
|
+
faultDomain;
|
|
363
|
+
requestDisposition;
|
|
364
|
+
transportRequestId;
|
|
365
|
+
consumeRequestId;
|
|
366
|
+
providerRequestId;
|
|
295
367
|
constructor(opts = {}) {
|
|
296
368
|
const code = opts.code ?? "";
|
|
297
369
|
const stage = opts.stage ?? "";
|
|
298
370
|
const userMessage = opts.message ?? "";
|
|
299
371
|
const rawError = opts.rawError ?? "";
|
|
300
|
-
const retryable = opts.retryable
|
|
372
|
+
const retryable = opts.retryable === true && opts.requestDisposition === "not_accepted";
|
|
301
373
|
const body = rawError !== "" ? rawError : userMessage;
|
|
302
374
|
const msg = stage !== "" ? `stream failed: ${stage}: ${body}` : `stream failed: ${body}`;
|
|
303
375
|
super(msg);
|
|
304
376
|
this.name = "StreamError";
|
|
305
377
|
this.code = code;
|
|
378
|
+
this.errorCode = code;
|
|
306
379
|
this.stage = stage;
|
|
307
380
|
this.userMessage = userMessage;
|
|
308
381
|
this.rawError = rawError;
|
|
309
382
|
this.retryable = retryable;
|
|
383
|
+
this.errorContractVersion = opts.errorContractVersion;
|
|
384
|
+
this.faultDomain = opts.faultDomain;
|
|
385
|
+
this.requestDisposition = opts.requestDisposition;
|
|
386
|
+
this.transportRequestId = opts.transportRequestId;
|
|
387
|
+
this.consumeRequestId = opts.consumeRequestId;
|
|
388
|
+
this.providerRequestId = opts.providerRequestId;
|
|
310
389
|
}
|
|
311
390
|
};
|
|
391
|
+
gatewayFaultDomains = [
|
|
392
|
+
"user_auth",
|
|
393
|
+
"caller_credentials",
|
|
394
|
+
"account_quota",
|
|
395
|
+
"account_permission",
|
|
396
|
+
"provider",
|
|
397
|
+
"gateway",
|
|
398
|
+
"transport",
|
|
399
|
+
"stream_ticket",
|
|
400
|
+
"protocol"
|
|
401
|
+
];
|
|
312
402
|
windowLimitErrorCode = "WINDOW_LIMIT_EXCEEDED";
|
|
313
403
|
windowLimitStreamCode = "window_limit_exceeded";
|
|
314
404
|
}
|
|
@@ -891,16 +981,90 @@ var init_openai = __esm({
|
|
|
891
981
|
* 可能已被 text/tool 推进的 this.blockIndex (否则 content_block_stop 索引错配)。 */
|
|
892
982
|
thinkingBlockIndex = 0;
|
|
893
983
|
textStarted = false;
|
|
894
|
-
/** OpenAI tool_call
|
|
984
|
+
/** OpenAI tool_call 键 → Anthropic block index。键正常是 `tc.index`;上游省略
|
|
985
|
+
* index 时退化为 `id:<tool_call_id>`,两者都没有时沿用上一个键(见
|
|
986
|
+
* {@link resolveToolKey})。 */
|
|
895
987
|
toolBlockIndex = /* @__PURE__ */ new Map();
|
|
896
988
|
blockIndex = 0;
|
|
989
|
+
/** 每个 tool block 已发出的 `partial_json` 累积,用于识别「每片重发全量参数」
|
|
990
|
+
* 的上游(见 tool_calls 分支的累计判别)。 */
|
|
991
|
+
toolArgsAccum = /* @__PURE__ */ new Map();
|
|
992
|
+
/** 上一次解析出的 tool 键,供缺 index 且缺 id 的后续增量沿用。 */
|
|
993
|
+
lastToolKey = null;
|
|
994
|
+
/** 已发出 message_delta/message_stop,避免 finish_reason 与 `[DONE]` 各收一次。 */
|
|
995
|
+
messageClosed = false;
|
|
996
|
+
/**
|
|
997
|
+
* 解析一条 tool_call delta 归属的块键。
|
|
998
|
+
*
|
|
999
|
+
* OpenAI 流式规范里 `index` 是必填,但兼容实现常有省略。此前这里直接用
|
|
1000
|
+
* `tc.index` 做 Map 键:两个都省略 index 的 tool_call 会共用键 `undefined`,
|
|
1001
|
+
* 于是只开一个块、两段参数拼进同一条 `partial_json` 流,产出 `{…}{…}` 这种
|
|
1002
|
+
* 必然非法的 JSON。这里按「index → id → 沿用上一个」三级降级,让至少一种
|
|
1003
|
+
* 稳定标识生效。
|
|
1004
|
+
*/
|
|
1005
|
+
resolveToolKey(tc) {
|
|
1006
|
+
if (typeof tc.index === "number" && Number.isFinite(tc.index)) {
|
|
1007
|
+
this.lastToolKey = tc.index;
|
|
1008
|
+
return tc.index;
|
|
1009
|
+
}
|
|
1010
|
+
if (typeof tc.id === "string" && tc.id !== "") {
|
|
1011
|
+
const key = `id:${tc.id}`;
|
|
1012
|
+
this.lastToolKey = key;
|
|
1013
|
+
return key;
|
|
1014
|
+
}
|
|
1015
|
+
if (this.lastToolKey !== null) return this.lastToolKey;
|
|
1016
|
+
this.lastToolKey = 0;
|
|
1017
|
+
return 0;
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* 关闭仍打开的 text / thinking / tool 块,并收口 message。
|
|
1021
|
+
*
|
|
1022
|
+
* 由 `finish_reason` 分支与 `[DONE]` 分支共用:上游断流或只发 `[DONE]` 而不发
|
|
1023
|
+
* `finish_reason` 时,此前一个 `content_block_stop` 都不会发,下游拿到的是一个
|
|
1024
|
+
* 永不闭合的 tool_use 块。
|
|
1025
|
+
*/
|
|
1026
|
+
closeOpenBlocks(events, stopReason) {
|
|
1027
|
+
if (this.messageClosed) return;
|
|
1028
|
+
this.messageClosed = true;
|
|
1029
|
+
if (this.textStarted) {
|
|
1030
|
+
events.push({
|
|
1031
|
+
event: "content_block_stop",
|
|
1032
|
+
data: JSON.stringify({ type: "content_block_stop", index: this.blockIndex })
|
|
1033
|
+
});
|
|
1034
|
+
this.textStarted = false;
|
|
1035
|
+
} else if (this.thinkingStarted && !this.thinkingStopped) {
|
|
1036
|
+
this.thinkingStopped = true;
|
|
1037
|
+
events.push({
|
|
1038
|
+
event: "content_block_stop",
|
|
1039
|
+
data: JSON.stringify({ type: "content_block_stop", index: this.thinkingBlockIndex })
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
for (const idx of this.toolBlockIndex.values()) {
|
|
1043
|
+
events.push({
|
|
1044
|
+
event: "content_block_stop",
|
|
1045
|
+
data: JSON.stringify({ type: "content_block_stop", index: idx })
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
events.push({
|
|
1049
|
+
event: "message_delta",
|
|
1050
|
+
data: JSON.stringify({ type: "message_delta", delta: { stop_reason: stopReason } })
|
|
1051
|
+
});
|
|
1052
|
+
events.push({
|
|
1053
|
+
event: "message_stop",
|
|
1054
|
+
data: JSON.stringify({ type: "message_stop" })
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
897
1057
|
/**
|
|
898
1058
|
* 将一行 OpenAI SSE data 转换为零或多个 Anthropic 格式 StreamEvent
|
|
899
1059
|
* 返回 { events, done }
|
|
900
1060
|
*/
|
|
901
1061
|
convert(data) {
|
|
902
1062
|
if (data === "[DONE]") {
|
|
903
|
-
|
|
1063
|
+
const events2 = [];
|
|
1064
|
+
if (this.messageStarted) {
|
|
1065
|
+
this.closeOpenBlocks(events2, "end_turn");
|
|
1066
|
+
}
|
|
1067
|
+
return { events: events2, done: true };
|
|
904
1068
|
}
|
|
905
1069
|
let chunk;
|
|
906
1070
|
try {
|
|
@@ -972,7 +1136,9 @@ var init_openai = __esm({
|
|
|
972
1136
|
events.push({ event: "content_block_delta", data: deltaJSON });
|
|
973
1137
|
}
|
|
974
1138
|
for (const tc of choice.delta.tool_calls ?? []) {
|
|
975
|
-
|
|
1139
|
+
const fn = tc.function;
|
|
1140
|
+
const toolKey = this.resolveToolKey(tc);
|
|
1141
|
+
if (!this.toolBlockIndex.has(toolKey)) {
|
|
976
1142
|
if (this.thinkingStarted && !this.thinkingStopped) {
|
|
977
1143
|
this.thinkingStopped = true;
|
|
978
1144
|
const stopJSON = JSON.stringify({
|
|
@@ -991,56 +1157,46 @@ var init_openai = __esm({
|
|
|
991
1157
|
this.blockIndex++;
|
|
992
1158
|
this.textStarted = false;
|
|
993
1159
|
}
|
|
994
|
-
this.toolBlockIndex.set(
|
|
1160
|
+
this.toolBlockIndex.set(toolKey, this.blockIndex);
|
|
995
1161
|
const blockJSON = JSON.stringify({
|
|
996
1162
|
type: "content_block_start",
|
|
997
1163
|
index: this.blockIndex,
|
|
998
1164
|
content_block: {
|
|
999
1165
|
type: "tool_use",
|
|
1000
1166
|
id: tc.id,
|
|
1001
|
-
name:
|
|
1167
|
+
name: fn?.name,
|
|
1002
1168
|
input: {}
|
|
1003
1169
|
}
|
|
1004
1170
|
});
|
|
1005
1171
|
events.push({ event: "content_block_start", data: blockJSON });
|
|
1006
1172
|
this.blockIndex++;
|
|
1007
1173
|
}
|
|
1008
|
-
if (
|
|
1009
|
-
const
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1174
|
+
if (fn?.arguments !== void 0 && fn.arguments !== null && fn.arguments !== "") {
|
|
1175
|
+
const rawArgs = typeof fn.arguments === "string" ? fn.arguments : JSON.stringify(fn.arguments);
|
|
1176
|
+
const accum = this.toolArgsAccum.get(toolKey) ?? "";
|
|
1177
|
+
let emit = rawArgs;
|
|
1178
|
+
if (accum !== "" && rawArgs.length > accum.length && rawArgs.startsWith(accum)) {
|
|
1179
|
+
emit = rawArgs.slice(accum.length);
|
|
1180
|
+
this.toolArgsAccum.set(toolKey, rawArgs);
|
|
1181
|
+
} else {
|
|
1182
|
+
this.toolArgsAccum.set(toolKey, accum + rawArgs);
|
|
1183
|
+
}
|
|
1184
|
+
if (emit !== "") {
|
|
1185
|
+
const idx = this.toolBlockIndex.get(toolKey);
|
|
1186
|
+
const deltaJSON = JSON.stringify({
|
|
1187
|
+
type: "content_block_delta",
|
|
1188
|
+
index: idx,
|
|
1189
|
+
delta: {
|
|
1190
|
+
type: "input_json_delta",
|
|
1191
|
+
partial_json: emit
|
|
1192
|
+
}
|
|
1193
|
+
});
|
|
1194
|
+
events.push({ event: "content_block_delta", data: deltaJSON });
|
|
1195
|
+
}
|
|
1019
1196
|
}
|
|
1020
1197
|
}
|
|
1021
1198
|
if (choice.finish_reason != null && choice.finish_reason !== "") {
|
|
1022
|
-
|
|
1023
|
-
const stopJSON2 = JSON.stringify({
|
|
1024
|
-
type: "content_block_stop",
|
|
1025
|
-
index: this.blockIndex
|
|
1026
|
-
});
|
|
1027
|
-
events.push({ event: "content_block_stop", data: stopJSON2 });
|
|
1028
|
-
} else if (this.thinkingStarted && !this.thinkingStopped) {
|
|
1029
|
-
this.thinkingStopped = true;
|
|
1030
|
-
const stopJSON2 = JSON.stringify({
|
|
1031
|
-
type: "content_block_stop",
|
|
1032
|
-
index: this.thinkingBlockIndex
|
|
1033
|
-
});
|
|
1034
|
-
events.push({ event: "content_block_stop", data: stopJSON2 });
|
|
1035
|
-
}
|
|
1036
|
-
for (const idx of this.toolBlockIndex.values()) {
|
|
1037
|
-
const stopJSON2 = JSON.stringify({
|
|
1038
|
-
type: "content_block_stop",
|
|
1039
|
-
index: idx
|
|
1040
|
-
});
|
|
1041
|
-
events.push({ event: "content_block_stop", data: stopJSON2 });
|
|
1042
|
-
}
|
|
1043
|
-
let stopReason = "end_turn";
|
|
1199
|
+
let stopReason;
|
|
1044
1200
|
switch (choice.finish_reason) {
|
|
1045
1201
|
case "tool_calls":
|
|
1046
1202
|
stopReason = "tool_use";
|
|
@@ -1048,14 +1204,13 @@ var init_openai = __esm({
|
|
|
1048
1204
|
case "length":
|
|
1049
1205
|
stopReason = "max_tokens";
|
|
1050
1206
|
break;
|
|
1207
|
+
case "stop":
|
|
1208
|
+
stopReason = "end_turn";
|
|
1209
|
+
break;
|
|
1210
|
+
default:
|
|
1211
|
+
stopReason = choice.finish_reason;
|
|
1051
1212
|
}
|
|
1052
|
-
|
|
1053
|
-
type: "message_delta",
|
|
1054
|
-
delta: { stop_reason: stopReason }
|
|
1055
|
-
});
|
|
1056
|
-
events.push({ event: "message_delta", data: deltaJSON });
|
|
1057
|
-
const stopJSON = JSON.stringify({ type: "message_stop" });
|
|
1058
|
-
events.push({ event: "message_stop", data: stopJSON });
|
|
1213
|
+
this.closeOpenBlocks(events, stopReason);
|
|
1059
1214
|
}
|
|
1060
1215
|
return { events, done: false };
|
|
1061
1216
|
}
|
|
@@ -1116,6 +1271,560 @@ var init_adapters = __esm({
|
|
|
1116
1271
|
}
|
|
1117
1272
|
});
|
|
1118
1273
|
|
|
1274
|
+
// src/core/credentials.ts
|
|
1275
|
+
var uuid = () => globalThis.crypto.randomUUID();
|
|
1276
|
+
var pause = () => new Promise((resolve) => setTimeout(resolve, 25));
|
|
1277
|
+
var abort = (signal) => {
|
|
1278
|
+
if (signal?.aborted) throw new Error("aborted");
|
|
1279
|
+
};
|
|
1280
|
+
var sameRequestOwner = (snapshot, expected) => snapshot.storeInstanceId === expected.storeInstanceId && snapshot.authSessionId === expected.authSessionId && snapshot.principal?.issuer === expected.principal?.issuer && snapshot.principal?.subject === expected.principal?.subject && snapshot.principal?.organizationId === expected.principal?.organizationId;
|
|
1281
|
+
var CredentialLifecycle = class {
|
|
1282
|
+
constructor(store, protocol) {
|
|
1283
|
+
this.store = store;
|
|
1284
|
+
this.protocol = protocol;
|
|
1285
|
+
}
|
|
1286
|
+
store;
|
|
1287
|
+
protocol;
|
|
1288
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1289
|
+
notificationKey = "";
|
|
1290
|
+
observations = /* @__PURE__ */ new Map();
|
|
1291
|
+
read(signal) {
|
|
1292
|
+
return this.store.readSnapshot(signal);
|
|
1293
|
+
}
|
|
1294
|
+
subscribe(listener) {
|
|
1295
|
+
this.listeners.add(listener);
|
|
1296
|
+
return () => {
|
|
1297
|
+
this.listeners.delete(listener);
|
|
1298
|
+
};
|
|
1299
|
+
}
|
|
1300
|
+
async notify(snapshot) {
|
|
1301
|
+
let current;
|
|
1302
|
+
try {
|
|
1303
|
+
current = await this.read();
|
|
1304
|
+
} catch {
|
|
1305
|
+
return;
|
|
1306
|
+
}
|
|
1307
|
+
if (current.storeInstanceId !== snapshot.storeInstanceId || current.revision !== snapshot.revision)
|
|
1308
|
+
return;
|
|
1309
|
+
const projection = {
|
|
1310
|
+
storeInstanceId: snapshot.storeInstanceId,
|
|
1311
|
+
authorityConfig: snapshot.authorityConfig && {
|
|
1312
|
+
serverURL: snapshot.authorityConfig.serverURL,
|
|
1313
|
+
issuer: snapshot.authorityConfig.issuer,
|
|
1314
|
+
oauthProfile: "desktop",
|
|
1315
|
+
authContractVersion: 2,
|
|
1316
|
+
errorContractVersion: 1
|
|
1317
|
+
},
|
|
1318
|
+
revision: snapshot.revision,
|
|
1319
|
+
authSessionId: snapshot.authSessionId,
|
|
1320
|
+
credentialState: snapshot.credentialState,
|
|
1321
|
+
reason: snapshot.reason,
|
|
1322
|
+
principal: snapshot.principal && {
|
|
1323
|
+
issuer: snapshot.principal.issuer,
|
|
1324
|
+
subject: snapshot.principal.subject,
|
|
1325
|
+
organizationId: snapshot.principal.organizationId
|
|
1326
|
+
},
|
|
1327
|
+
refreshOperation: snapshot.refreshOperation && {
|
|
1328
|
+
operationId: snapshot.refreshOperation.operationId,
|
|
1329
|
+
sessionId: snapshot.refreshOperation.sessionId,
|
|
1330
|
+
baseRevision: snapshot.refreshOperation.baseRevision,
|
|
1331
|
+
phase: snapshot.refreshOperation.phase,
|
|
1332
|
+
returnState: snapshot.refreshOperation.returnState,
|
|
1333
|
+
startedAt: snapshot.refreshOperation.startedAt,
|
|
1334
|
+
dispatchedAt: snapshot.refreshOperation.dispatchedAt,
|
|
1335
|
+
deadlineAt: snapshot.refreshOperation.deadlineAt
|
|
1336
|
+
},
|
|
1337
|
+
loginAttempt: snapshot.loginAttempt && {
|
|
1338
|
+
attemptId: snapshot.loginAttempt.attemptId,
|
|
1339
|
+
baseSessionId: snapshot.loginAttempt.baseSessionId,
|
|
1340
|
+
startedAt: snapshot.loginAttempt.startedAt
|
|
1341
|
+
},
|
|
1342
|
+
lastMutation: snapshot.lastMutation && {
|
|
1343
|
+
mutationId: snapshot.lastMutation.mutationId,
|
|
1344
|
+
operationId: snapshot.lastMutation.operationId,
|
|
1345
|
+
resultRevision: snapshot.lastMutation.resultRevision
|
|
1346
|
+
},
|
|
1347
|
+
lastLoginAttemptId: snapshot.lastLoginAttemptId,
|
|
1348
|
+
verifiedIdentity: snapshot.verifiedIdentity && {
|
|
1349
|
+
authSessionId: snapshot.verifiedIdentity.authSessionId,
|
|
1350
|
+
principal: {
|
|
1351
|
+
issuer: snapshot.verifiedIdentity.principal.issuer,
|
|
1352
|
+
subject: snapshot.verifiedIdentity.principal.subject,
|
|
1353
|
+
organizationId: snapshot.verifiedIdentity.principal.organizationId
|
|
1354
|
+
},
|
|
1355
|
+
displayName: snapshot.verifiedIdentity.displayName,
|
|
1356
|
+
avatarUrl: snapshot.verifiedIdentity.avatarUrl,
|
|
1357
|
+
email: snapshot.verifiedIdentity.email,
|
|
1358
|
+
imageUrl: snapshot.verifiedIdentity.imageUrl,
|
|
1359
|
+
accountCreatedAt: snapshot.verifiedIdentity.accountCreatedAt,
|
|
1360
|
+
requiresPhoneBinding: snapshot.verifiedIdentity.requiresPhoneBinding,
|
|
1361
|
+
hasExtraUsageEnabled: snapshot.verifiedIdentity.hasExtraUsageEnabled,
|
|
1362
|
+
billingType: snapshot.verifiedIdentity.billingType,
|
|
1363
|
+
subscriptionCreatedAt: snapshot.verifiedIdentity.subscriptionCreatedAt,
|
|
1364
|
+
rateLimitTier: snapshot.verifiedIdentity.rateLimitTier,
|
|
1365
|
+
organizationName: snapshot.verifiedIdentity.organizationName,
|
|
1366
|
+
verifiedAt: snapshot.verifiedIdentity.verifiedAt
|
|
1367
|
+
}
|
|
1368
|
+
};
|
|
1369
|
+
const key = JSON.stringify({ ...projection, revision: void 0, lastMutation: void 0 });
|
|
1370
|
+
if (key === this.notificationKey) return;
|
|
1371
|
+
this.notificationKey = key;
|
|
1372
|
+
for (const listener of this.listeners) {
|
|
1373
|
+
try {
|
|
1374
|
+
listener(structuredClone(projection));
|
|
1375
|
+
} catch {
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
async reconcile(signal) {
|
|
1380
|
+
const s = await this.read(signal);
|
|
1381
|
+
await this.notify(s);
|
|
1382
|
+
return s;
|
|
1383
|
+
}
|
|
1384
|
+
cas(s, changes, mutationId = uuid(), signal) {
|
|
1385
|
+
return this.store.compareAndSwap(
|
|
1386
|
+
{
|
|
1387
|
+
storeInstanceId: s.storeInstanceId,
|
|
1388
|
+
revision: s.revision,
|
|
1389
|
+
authSessionId: s.authSessionId,
|
|
1390
|
+
state: s.credentialState,
|
|
1391
|
+
operationId: s.refreshOperation?.operationId ?? s.loginAttempt?.attemptId ?? null
|
|
1392
|
+
},
|
|
1393
|
+
{ ...s, ...changes },
|
|
1394
|
+
mutationId,
|
|
1395
|
+
signal
|
|
1396
|
+
);
|
|
1397
|
+
}
|
|
1398
|
+
async commit(s, changes, signal) {
|
|
1399
|
+
const r = await this.cas(s, changes, uuid(), signal);
|
|
1400
|
+
if (r.status === "storage_error") throw new Error("storage_unavailable");
|
|
1401
|
+
if (r.status === "committed") await this.notify(r.snapshot);
|
|
1402
|
+
return r;
|
|
1403
|
+
}
|
|
1404
|
+
async metadata(s, signal) {
|
|
1405
|
+
const m = await this.protocol.metadata(signal);
|
|
1406
|
+
if (m.crabcode_auth_contract_version !== 2 || m.gateway_error_contract_version !== 1 || !m.issuer)
|
|
1407
|
+
throw new Error("auth_contract_unsupported");
|
|
1408
|
+
if (s.authorityConfig && (s.authorityConfig.serverURL !== this.protocol.serverURL || s.authorityConfig.issuer !== m.issuer || s.authorityConfig.oauthProfile !== "desktop" || s.authorityConfig.authContractVersion !== 2 || s.authorityConfig.errorContractVersion !== 1))
|
|
1409
|
+
throw new Error("auth_contract_unsupported");
|
|
1410
|
+
return m;
|
|
1411
|
+
}
|
|
1412
|
+
async reserveLogin(signal) {
|
|
1413
|
+
const attemptId = uuid();
|
|
1414
|
+
let reserved;
|
|
1415
|
+
for (; ; ) {
|
|
1416
|
+
abort(signal);
|
|
1417
|
+
const s = await this.read(signal);
|
|
1418
|
+
if (s.credentialState !== "signed_out") throw new Error("local_logout_required");
|
|
1419
|
+
const r = await this.commit(s, { loginAttempt: { attemptId, baseSessionId: s.authSessionId, startedAt: (/* @__PURE__ */ new Date()).toISOString() } }, signal);
|
|
1420
|
+
if (r.status === "committed") {
|
|
1421
|
+
reserved = r.snapshot;
|
|
1422
|
+
break;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
try {
|
|
1426
|
+
const m = await this.metadata(reserved, signal);
|
|
1427
|
+
for (; ; ) {
|
|
1428
|
+
abort(signal);
|
|
1429
|
+
const current = await this.read(signal);
|
|
1430
|
+
if (current.storeInstanceId !== reserved.storeInstanceId || current.loginAttempt?.attemptId !== attemptId) throw new Error("superseded");
|
|
1431
|
+
if (current.authorityConfig) return { attemptId, metadata: m };
|
|
1432
|
+
const r = await this.commit(current, { authorityConfig: { serverURL: this.protocol.serverURL, issuer: m.issuer, oauthProfile: "desktop", authContractVersion: 2, errorContractVersion: 1 } }, signal);
|
|
1433
|
+
if (r.status === "committed") return { attemptId, metadata: m };
|
|
1434
|
+
}
|
|
1435
|
+
} catch (error) {
|
|
1436
|
+
await this.cancelLogin(attemptId);
|
|
1437
|
+
throw error;
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
async installLogin(attemptId, tokens, signal) {
|
|
1441
|
+
this.validateTokens(tokens);
|
|
1442
|
+
for (; ; ) {
|
|
1443
|
+
abort(signal);
|
|
1444
|
+
const s = await this.read(signal);
|
|
1445
|
+
if (s.loginAttempt?.attemptId !== attemptId || s.loginAttempt.baseSessionId !== s.authSessionId)
|
|
1446
|
+
throw new Error("superseded");
|
|
1447
|
+
const r = await this.commit(
|
|
1448
|
+
s,
|
|
1449
|
+
{
|
|
1450
|
+
authSessionId: uuid(),
|
|
1451
|
+
tokenSet: tokens,
|
|
1452
|
+
credentialState: "pending_identity",
|
|
1453
|
+
principal: null,
|
|
1454
|
+
verifiedIdentity: null,
|
|
1455
|
+
loginAttempt: null,
|
|
1456
|
+
lastLoginAttemptId: attemptId,
|
|
1457
|
+
reason: "identity_unavailable"
|
|
1458
|
+
},
|
|
1459
|
+
signal
|
|
1460
|
+
);
|
|
1461
|
+
if (r.status === "committed") return this.bindIdentity(r.snapshot.authSessionId, signal);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
async assertLogin(attemptId, signal) {
|
|
1465
|
+
abort(signal);
|
|
1466
|
+
const s = await this.read(signal);
|
|
1467
|
+
if (s.loginAttempt?.attemptId !== attemptId) throw new Error("superseded");
|
|
1468
|
+
}
|
|
1469
|
+
async cancelLogin(attemptId) {
|
|
1470
|
+
const s = await this.read();
|
|
1471
|
+
if (s.loginAttempt?.attemptId === attemptId) await this.commit(s, { loginAttempt: null });
|
|
1472
|
+
}
|
|
1473
|
+
validateTokens(t) {
|
|
1474
|
+
if (!t.access_token?.trim() || !t.refresh_token?.trim() || !t.client_id?.trim() || t.server_url !== this.protocol.serverURL || !Number.isFinite(Date.parse(t.expires_at)) || Date.parse(t.expires_at) <= Date.now())
|
|
1475
|
+
throw new Error("invalid_response");
|
|
1476
|
+
}
|
|
1477
|
+
usable(s) {
|
|
1478
|
+
return !!s.tokenSet && Date.parse(s.tokenSet.expires_at) > Date.now() + 3e5;
|
|
1479
|
+
}
|
|
1480
|
+
async bindIdentity(sessionId, signal) {
|
|
1481
|
+
const s = await this.ensureSnapshot(signal, void 0, true);
|
|
1482
|
+
if (s.authSessionId !== sessionId) throw new Error("superseded");
|
|
1483
|
+
if (s.credentialState === "ready") return s;
|
|
1484
|
+
await this.metadata(s, signal);
|
|
1485
|
+
const beforeProfile = await this.read(signal);
|
|
1486
|
+
if (beforeProfile.storeInstanceId !== s.storeInstanceId || beforeProfile.authSessionId !== sessionId || beforeProfile.revision !== s.revision || beforeProfile.credentialState !== "pending_identity")
|
|
1487
|
+
throw new Error("superseded");
|
|
1488
|
+
let identity;
|
|
1489
|
+
try {
|
|
1490
|
+
identity = await this.protocol.profile(s.tokenSet, signal);
|
|
1491
|
+
} catch (error) {
|
|
1492
|
+
const message = error instanceof Error ? error.message : "";
|
|
1493
|
+
if (message === "invalid_scope" || message === "auth_contract_unsupported")
|
|
1494
|
+
await this.commit(s, { credentialState: "configuration_error", reason: message });
|
|
1495
|
+
throw error;
|
|
1496
|
+
}
|
|
1497
|
+
abort(signal);
|
|
1498
|
+
const current = await this.read(signal);
|
|
1499
|
+
if (current.storeInstanceId !== s.storeInstanceId || current.authSessionId !== sessionId || current.revision !== s.revision)
|
|
1500
|
+
throw new Error("superseded");
|
|
1501
|
+
if (!identity.subject) throw new Error("invalid_response");
|
|
1502
|
+
const principal = {
|
|
1503
|
+
issuer: s.authorityConfig.issuer,
|
|
1504
|
+
subject: identity.subject,
|
|
1505
|
+
organizationId: identity.organizationId
|
|
1506
|
+
};
|
|
1507
|
+
const r = await this.commit(
|
|
1508
|
+
s,
|
|
1509
|
+
{
|
|
1510
|
+
principal,
|
|
1511
|
+
verifiedIdentity: {
|
|
1512
|
+
authSessionId: sessionId,
|
|
1513
|
+
principal,
|
|
1514
|
+
displayName: identity.displayName,
|
|
1515
|
+
avatarUrl: identity.avatarUrl,
|
|
1516
|
+
email: identity.email,
|
|
1517
|
+
imageUrl: identity.imageUrl,
|
|
1518
|
+
accountCreatedAt: identity.accountCreatedAt,
|
|
1519
|
+
requiresPhoneBinding: identity.requiresPhoneBinding,
|
|
1520
|
+
hasExtraUsageEnabled: identity.hasExtraUsageEnabled,
|
|
1521
|
+
billingType: identity.billingType,
|
|
1522
|
+
subscriptionCreatedAt: identity.subscriptionCreatedAt,
|
|
1523
|
+
rateLimitTier: identity.rateLimitTier,
|
|
1524
|
+
organizationName: identity.organizationName,
|
|
1525
|
+
verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1526
|
+
},
|
|
1527
|
+
credentialState: "ready",
|
|
1528
|
+
reason: null
|
|
1529
|
+
},
|
|
1530
|
+
signal
|
|
1531
|
+
);
|
|
1532
|
+
if (r.status !== "committed") throw new Error("superseded");
|
|
1533
|
+
return r.snapshot;
|
|
1534
|
+
}
|
|
1535
|
+
async ensure(signal, rejected, expected) {
|
|
1536
|
+
const snapshot = await this.ensureSnapshot(signal, rejected, false, expected);
|
|
1537
|
+
this.observations.set(snapshot.tokenSet.access_token, snapshot);
|
|
1538
|
+
if (this.observations.size > 128)
|
|
1539
|
+
this.observations.delete(this.observations.keys().next().value);
|
|
1540
|
+
return snapshot.tokenSet.access_token;
|
|
1541
|
+
}
|
|
1542
|
+
async forceRefresh(signal, rejectedToken, expected) {
|
|
1543
|
+
const rejected = rejectedToken ? this.observations.get(rejectedToken) : await this.read(signal);
|
|
1544
|
+
if (rejectedToken && !rejected) throw new Error("credential_observation_unavailable");
|
|
1545
|
+
return this.ensure(signal, rejected, expected);
|
|
1546
|
+
}
|
|
1547
|
+
async ensureSnapshot(signal, rejected, pending = false, expected) {
|
|
1548
|
+
let session;
|
|
1549
|
+
let instance;
|
|
1550
|
+
let initialRevision;
|
|
1551
|
+
let refreshed = false;
|
|
1552
|
+
let initialAccess;
|
|
1553
|
+
for (; ; ) {
|
|
1554
|
+
abort(signal);
|
|
1555
|
+
const s = await this.read(signal);
|
|
1556
|
+
if (expected && !sameRequestOwner(s, expected)) throw new Error("superseded");
|
|
1557
|
+
if (s.authorityConfig && s.authorityConfig.serverURL !== this.protocol.serverURL)
|
|
1558
|
+
throw new Error("auth_contract_unsupported");
|
|
1559
|
+
if (session === void 0) {
|
|
1560
|
+
session = s.authSessionId;
|
|
1561
|
+
instance = s.storeInstanceId;
|
|
1562
|
+
initialRevision = s.revision;
|
|
1563
|
+
initialAccess = s.tokenSet?.access_token;
|
|
1564
|
+
}
|
|
1565
|
+
if (s.storeInstanceId !== instance || s.authSessionId !== session || rejected && (s.authSessionId !== rejected.authSessionId || s.storeInstanceId !== rejected.storeInstanceId))
|
|
1566
|
+
throw new Error("superseded");
|
|
1567
|
+
if (s.credentialState === "refresh_dispatched") {
|
|
1568
|
+
if (Date.now() >= Date.parse(s.refreshOperation.deadlineAt))
|
|
1569
|
+
await this.commit(s, {
|
|
1570
|
+
credentialState: "reauth_required",
|
|
1571
|
+
tokenSet: null,
|
|
1572
|
+
refreshOperation: null,
|
|
1573
|
+
reason: "refresh_outcome_unknown"
|
|
1574
|
+
});
|
|
1575
|
+
else await pause();
|
|
1576
|
+
continue;
|
|
1577
|
+
}
|
|
1578
|
+
if (s.credentialState === "refresh_reserved") {
|
|
1579
|
+
if (Date.now() >= Date.parse(s.refreshOperation.startedAt) + 3e4)
|
|
1580
|
+
await this.commit(s, {
|
|
1581
|
+
credentialState: s.refreshOperation.returnState,
|
|
1582
|
+
refreshOperation: null
|
|
1583
|
+
});
|
|
1584
|
+
else await pause();
|
|
1585
|
+
continue;
|
|
1586
|
+
}
|
|
1587
|
+
if (s.credentialState !== "ready" && !(pending && s.credentialState === "pending_identity"))
|
|
1588
|
+
throw new Error(`credential_unavailable:${s.credentialState}:${s.reason ?? ""}`);
|
|
1589
|
+
const live = !!s.tokenSet && Date.parse(s.tokenSet.expires_at) > Date.now();
|
|
1590
|
+
if (live && (refreshed || s.revision !== (rejected?.revision ?? initialRevision) && (rejected !== void 0 || s.tokenSet.access_token !== initialAccess)))
|
|
1591
|
+
return s;
|
|
1592
|
+
if (this.usable(s) && !rejected) return s;
|
|
1593
|
+
const metadata = await this.metadata(s, signal);
|
|
1594
|
+
abort(signal);
|
|
1595
|
+
const operationId = uuid();
|
|
1596
|
+
const r = await this.commit(
|
|
1597
|
+
s,
|
|
1598
|
+
{
|
|
1599
|
+
credentialState: "refresh_reserved",
|
|
1600
|
+
refreshOperation: {
|
|
1601
|
+
operationId,
|
|
1602
|
+
sessionId: s.authSessionId,
|
|
1603
|
+
baseRevision: s.revision,
|
|
1604
|
+
phase: "reserved",
|
|
1605
|
+
returnState: s.credentialState,
|
|
1606
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1607
|
+
dispatchedAt: null,
|
|
1608
|
+
deadlineAt: null
|
|
1609
|
+
}
|
|
1610
|
+
},
|
|
1611
|
+
signal
|
|
1612
|
+
);
|
|
1613
|
+
if (r.status !== "committed") continue;
|
|
1614
|
+
const owner = this.refresh(r.snapshot, metadata);
|
|
1615
|
+
await this.wait(owner, signal);
|
|
1616
|
+
refreshed = true;
|
|
1617
|
+
rejected = void 0;
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
wait(promise, signal) {
|
|
1621
|
+
if (!signal) return promise;
|
|
1622
|
+
return new Promise((resolve, reject) => {
|
|
1623
|
+
const onAbort = () => {
|
|
1624
|
+
signal.removeEventListener("abort", onAbort);
|
|
1625
|
+
reject(new Error("aborted"));
|
|
1626
|
+
};
|
|
1627
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1628
|
+
promise.then(
|
|
1629
|
+
(value) => {
|
|
1630
|
+
signal.removeEventListener("abort", onAbort);
|
|
1631
|
+
resolve(value);
|
|
1632
|
+
},
|
|
1633
|
+
(error) => {
|
|
1634
|
+
signal.removeEventListener("abort", onAbort);
|
|
1635
|
+
reject(error);
|
|
1636
|
+
}
|
|
1637
|
+
);
|
|
1638
|
+
if (signal.aborted) onAbort();
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
async refresh(reserved, metadata) {
|
|
1642
|
+
const dispatchedAt = Date.now();
|
|
1643
|
+
const r = await this.commit(reserved, {
|
|
1644
|
+
credentialState: "refresh_dispatched",
|
|
1645
|
+
refreshOperation: {
|
|
1646
|
+
...reserved.refreshOperation,
|
|
1647
|
+
phase: "dispatched",
|
|
1648
|
+
dispatchedAt: new Date(dispatchedAt).toISOString(),
|
|
1649
|
+
deadlineAt: new Date(dispatchedAt + 3e4).toISOString()
|
|
1650
|
+
}
|
|
1651
|
+
});
|
|
1652
|
+
if (r.status !== "committed") return;
|
|
1653
|
+
const s = r.snapshot;
|
|
1654
|
+
const ctl = new AbortController();
|
|
1655
|
+
const timeout = setTimeout(() => ctl.abort(), 3e4);
|
|
1656
|
+
let tokens;
|
|
1657
|
+
try {
|
|
1658
|
+
const result = await this.wait(
|
|
1659
|
+
(async () => {
|
|
1660
|
+
const response = await this.protocol.fetch(metadata.token_endpoint, {
|
|
1661
|
+
method: "POST",
|
|
1662
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1663
|
+
body: new URLSearchParams({
|
|
1664
|
+
grant_type: "refresh_token",
|
|
1665
|
+
client_id: s.tokenSet.client_id,
|
|
1666
|
+
refresh_token: s.tokenSet.refresh_token
|
|
1667
|
+
}),
|
|
1668
|
+
signal: ctl.signal
|
|
1669
|
+
});
|
|
1670
|
+
const body2 = await response.json();
|
|
1671
|
+
return { response, body: body2 };
|
|
1672
|
+
})(),
|
|
1673
|
+
ctl.signal
|
|
1674
|
+
);
|
|
1675
|
+
if (!result.response.ok) {
|
|
1676
|
+
const code = result.body.error;
|
|
1677
|
+
let reason = "refresh_outcome_unknown";
|
|
1678
|
+
let state = "reauth_required";
|
|
1679
|
+
if (code === "invalid_grant") reason = code;
|
|
1680
|
+
else if (["invalid_client", "invalid_scope", "unsupported_grant_type"].includes(code)) {
|
|
1681
|
+
reason = code;
|
|
1682
|
+
state = "configuration_error";
|
|
1683
|
+
} else if (result.body.rotationOutcome === "not_committed" && ["temporarily_unavailable", "server_error"].includes(code)) {
|
|
1684
|
+
await this.commit(s, {
|
|
1685
|
+
credentialState: s.refreshOperation.returnState,
|
|
1686
|
+
refreshOperation: null
|
|
1687
|
+
});
|
|
1688
|
+
throw new Error("refresh_temporarily_unavailable");
|
|
1689
|
+
}
|
|
1690
|
+
await this.commit(s, {
|
|
1691
|
+
credentialState: state,
|
|
1692
|
+
tokenSet: null,
|
|
1693
|
+
refreshOperation: null,
|
|
1694
|
+
reason
|
|
1695
|
+
});
|
|
1696
|
+
throw new Error(reason);
|
|
1697
|
+
}
|
|
1698
|
+
const body = result.body;
|
|
1699
|
+
if (!Number.isFinite(body.expires_in) || body.expires_in <= 0)
|
|
1700
|
+
throw new Error("invalid_response");
|
|
1701
|
+
tokens = {
|
|
1702
|
+
...s.tokenSet,
|
|
1703
|
+
access_token: body.access_token,
|
|
1704
|
+
refresh_token: body.refresh_token,
|
|
1705
|
+
expires_at: new Date(Date.now() + body.expires_in * 1e3).toISOString(),
|
|
1706
|
+
scope: body.scope ?? s.tokenSet.scope
|
|
1707
|
+
};
|
|
1708
|
+
this.validateTokens(tokens);
|
|
1709
|
+
} catch (error) {
|
|
1710
|
+
await this.commit(s, {
|
|
1711
|
+
credentialState: "reauth_required",
|
|
1712
|
+
tokenSet: null,
|
|
1713
|
+
refreshOperation: null,
|
|
1714
|
+
reason: "refresh_outcome_unknown"
|
|
1715
|
+
});
|
|
1716
|
+
throw error;
|
|
1717
|
+
} finally {
|
|
1718
|
+
clearTimeout(timeout);
|
|
1719
|
+
}
|
|
1720
|
+
const started = performance.now(), mutationId = uuid();
|
|
1721
|
+
for (; ; ) {
|
|
1722
|
+
if (Date.now() >= Date.parse(s.refreshOperation.deadlineAt)) {
|
|
1723
|
+
await this.commit(s, {
|
|
1724
|
+
credentialState: "reauth_required",
|
|
1725
|
+
tokenSet: null,
|
|
1726
|
+
refreshOperation: null,
|
|
1727
|
+
reason: "refresh_outcome_unknown"
|
|
1728
|
+
});
|
|
1729
|
+
void this.revoke(tokens, metadata);
|
|
1730
|
+
throw new Error("refresh_outcome_unknown");
|
|
1731
|
+
}
|
|
1732
|
+
const result = await this.cas(
|
|
1733
|
+
s,
|
|
1734
|
+
{
|
|
1735
|
+
tokenSet: tokens,
|
|
1736
|
+
credentialState: s.refreshOperation.returnState,
|
|
1737
|
+
refreshOperation: null
|
|
1738
|
+
},
|
|
1739
|
+
mutationId
|
|
1740
|
+
);
|
|
1741
|
+
if (result.status === "committed") {
|
|
1742
|
+
await this.notify(result.snapshot);
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1745
|
+
if (result.status === "superseded") {
|
|
1746
|
+
void this.revoke(tokens, metadata);
|
|
1747
|
+
return;
|
|
1748
|
+
}
|
|
1749
|
+
if (performance.now() - started >= 2e3) throw new Error("credential_persist_failed");
|
|
1750
|
+
await pause();
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
async revoke(tokens, metadata, authority) {
|
|
1754
|
+
const ctl = new AbortController();
|
|
1755
|
+
const timer = setTimeout(() => ctl.abort(), 3e4);
|
|
1756
|
+
try {
|
|
1757
|
+
const m = metadata ?? await this.wait(authority ? this.metadata(authority, ctl.signal) : this.protocol.metadata(ctl.signal), ctl.signal);
|
|
1758
|
+
if (!m.revocation_endpoint) return "unsupported";
|
|
1759
|
+
const response = await this.wait(this.protocol.fetch(m.revocation_endpoint, {
|
|
1760
|
+
method: "POST",
|
|
1761
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1762
|
+
body: new URLSearchParams({ token: tokens.refresh_token, token_type_hint: "refresh_token" }),
|
|
1763
|
+
signal: ctl.signal
|
|
1764
|
+
}), ctl.signal);
|
|
1765
|
+
return response.ok ? "confirmed" : "failed";
|
|
1766
|
+
} catch {
|
|
1767
|
+
return "failed";
|
|
1768
|
+
} finally {
|
|
1769
|
+
clearTimeout(timer);
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
async logout(signal, expected) {
|
|
1773
|
+
let s = await this.read(signal);
|
|
1774
|
+
if (expected && (s.storeInstanceId !== expected.storeInstanceId || s.authSessionId !== expected.authSessionId)) {
|
|
1775
|
+
return {
|
|
1776
|
+
logoutOperationId: uuid(),
|
|
1777
|
+
expectedAuthSessionId: expected.authSessionId,
|
|
1778
|
+
storeInstanceId: expected.storeInstanceId,
|
|
1779
|
+
revision: s.revision,
|
|
1780
|
+
status: "superseded"
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1783
|
+
const session = s.authSessionId, instance = s.storeInstanceId, started = performance.now(), logoutOperationId = uuid();
|
|
1784
|
+
const receipt = () => ({
|
|
1785
|
+
logoutOperationId,
|
|
1786
|
+
expectedAuthSessionId: session,
|
|
1787
|
+
storeInstanceId: instance,
|
|
1788
|
+
revision: s.revision
|
|
1789
|
+
});
|
|
1790
|
+
for (; ; ) {
|
|
1791
|
+
abort(signal);
|
|
1792
|
+
if (s.storeInstanceId !== instance || s.authSessionId !== session)
|
|
1793
|
+
return { ...receipt(), status: "superseded" };
|
|
1794
|
+
if (s.credentialState === "signed_out" && !s.loginAttempt)
|
|
1795
|
+
return { ...receipt(), status: "already_signed_out" };
|
|
1796
|
+
const r = await this.cas(
|
|
1797
|
+
s,
|
|
1798
|
+
{
|
|
1799
|
+
credentialState: "signed_out",
|
|
1800
|
+
authSessionId: null,
|
|
1801
|
+
principal: null,
|
|
1802
|
+
tokenSet: null,
|
|
1803
|
+
refreshOperation: null,
|
|
1804
|
+
loginAttempt: null,
|
|
1805
|
+
lastLoginAttemptId: null,
|
|
1806
|
+
verifiedIdentity: null,
|
|
1807
|
+
reason: null
|
|
1808
|
+
},
|
|
1809
|
+
logoutOperationId,
|
|
1810
|
+
signal
|
|
1811
|
+
);
|
|
1812
|
+
if (r.status === "committed") {
|
|
1813
|
+
await this.notify(r.snapshot);
|
|
1814
|
+
return {
|
|
1815
|
+
...receipt(),
|
|
1816
|
+
revision: r.snapshot.revision,
|
|
1817
|
+
status: "committed",
|
|
1818
|
+
revocation: s.tokenSet ? this.revoke(s.tokenSet, void 0, s) : Promise.resolve("unsupported")
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
if (performance.now() - started >= 2e3) throw new Error("storage_busy");
|
|
1822
|
+
await pause();
|
|
1823
|
+
s = await this.read(signal);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
};
|
|
1827
|
+
|
|
1119
1828
|
// src/core/client.ts
|
|
1120
1829
|
init_types();
|
|
1121
1830
|
|
|
@@ -1555,33 +2264,35 @@ async function revokeToken(meta, token, signal, fetchImpl = globalThis.fetch) {
|
|
|
1555
2264
|
}
|
|
1556
2265
|
async function postToken(endpoint, data, signal, fetchImpl = globalThis.fetch) {
|
|
1557
2266
|
const ctl = withTimeout(authTimeoutMs, signal);
|
|
1558
|
-
let resp;
|
|
1559
2267
|
try {
|
|
1560
|
-
resp
|
|
1561
|
-
method: "POST",
|
|
1562
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1563
|
-
body: data,
|
|
1564
|
-
signal: ctl.signal
|
|
1565
|
-
});
|
|
1566
|
-
} catch (e) {
|
|
1567
|
-
throw new Error(`token request: ${e instanceof Error ? e.message : String(e)}`);
|
|
1568
|
-
} finally {
|
|
1569
|
-
ctl.dispose();
|
|
1570
|
-
}
|
|
1571
|
-
if (!resp.ok) {
|
|
1572
|
-
let errBody = {};
|
|
2268
|
+
let resp;
|
|
1573
2269
|
try {
|
|
1574
|
-
|
|
1575
|
-
|
|
2270
|
+
resp = await fetchImpl(endpoint, {
|
|
2271
|
+
method: "POST",
|
|
2272
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
2273
|
+
body: data,
|
|
2274
|
+
signal: ctl.signal
|
|
2275
|
+
});
|
|
2276
|
+
} catch (e) {
|
|
2277
|
+
throw new Error(`token request: ${e instanceof Error ? e.message : String(e)}`);
|
|
1576
2278
|
}
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
2279
|
+
if (!resp.ok) {
|
|
2280
|
+
let errBody = {};
|
|
2281
|
+
try {
|
|
2282
|
+
errBody = await resp.json();
|
|
2283
|
+
} catch {
|
|
2284
|
+
}
|
|
2285
|
+
const oauthError = typeof errBody.error === "string" ? errBody.error : "";
|
|
2286
|
+
const errorDescription = typeof errBody.error_description === "string" ? errBody.error_description : "";
|
|
2287
|
+
throw new OAuthTokenEndpointError(resp.status, oauthError, errorDescription);
|
|
2288
|
+
}
|
|
2289
|
+
try {
|
|
2290
|
+
return await resp.json();
|
|
2291
|
+
} catch (e) {
|
|
2292
|
+
throw new Error(`token: decode: ${e instanceof Error ? e.message : String(e)}`);
|
|
2293
|
+
}
|
|
2294
|
+
} finally {
|
|
2295
|
+
ctl.dispose();
|
|
1585
2296
|
}
|
|
1586
2297
|
}
|
|
1587
2298
|
function newTokenSet(resp, clientID, serverURL) {
|
|
@@ -2064,10 +2775,31 @@ function parseHTTPErrorWithHeader(statusCode, body, header) {
|
|
|
2064
2775
|
} else if (typeof top.message === "string") {
|
|
2065
2776
|
message = top.message;
|
|
2066
2777
|
}
|
|
2778
|
+
const contractSource = errObj && typeof errObj === "object" ? errObj : top;
|
|
2067
2779
|
if (typeof top.errorCode === "string") errorCode = top.errorCode;
|
|
2780
|
+
else if (typeof contractSource.errorCode === "string") errorCode = contractSource.errorCode;
|
|
2068
2781
|
if (top.windowKind === "FIVE_HOUR" || top.windowKind === "WEEKLY") windowKind = top.windowKind;
|
|
2069
2782
|
if (typeof top.windowResetAt === "string") windowResetAt = top.windowResetAt;
|
|
2070
2783
|
if (typeof top.windowOverridable === "boolean") windowOverridable = top.windowOverridable;
|
|
2784
|
+
const disposition = contractSource.requestDisposition === "not_accepted" || contractSource.requestDisposition === "accepted" || contractSource.requestDisposition === "unknown" ? contractSource.requestDisposition : void 0;
|
|
2785
|
+
const domains = ["user_auth", "caller_credentials", "account_quota", "account_permission", "provider", "gateway", "transport", "stream_ticket", "protocol"];
|
|
2786
|
+
return new HTTPError(statusCode, {
|
|
2787
|
+
type,
|
|
2788
|
+
message,
|
|
2789
|
+
retryAfter,
|
|
2790
|
+
body: bodyStr,
|
|
2791
|
+
errorCode,
|
|
2792
|
+
windowKind,
|
|
2793
|
+
windowResetAt,
|
|
2794
|
+
windowOverridable,
|
|
2795
|
+
errorContractVersion: contractSource.errorContractVersion === 1 ? 1 : void 0,
|
|
2796
|
+
faultDomain: typeof contractSource.faultDomain === "string" && domains.includes(contractSource.faultDomain) ? contractSource.faultDomain : void 0,
|
|
2797
|
+
requestDisposition: disposition,
|
|
2798
|
+
transportRequestId: typeof contractSource.transportRequestId === "string" ? contractSource.transportRequestId : null,
|
|
2799
|
+
consumeRequestId: typeof contractSource.consumeRequestId === "string" ? contractSource.consumeRequestId : null,
|
|
2800
|
+
providerRequestId: typeof contractSource.providerRequestId === "string" ? contractSource.providerRequestId : null,
|
|
2801
|
+
retryable: contractSource.retryable === true
|
|
2802
|
+
});
|
|
2071
2803
|
}
|
|
2072
2804
|
} catch {
|
|
2073
2805
|
}
|
|
@@ -2129,7 +2861,19 @@ function parseStreamError(data) {
|
|
|
2129
2861
|
if (code === "" && errObj.type) code = errObj.type;
|
|
2130
2862
|
}
|
|
2131
2863
|
}
|
|
2132
|
-
return new StreamError({
|
|
2864
|
+
return new StreamError({
|
|
2865
|
+
code,
|
|
2866
|
+
stage,
|
|
2867
|
+
message,
|
|
2868
|
+
rawError,
|
|
2869
|
+
retryable,
|
|
2870
|
+
errorContractVersion: payload.errorContractVersion,
|
|
2871
|
+
faultDomain: payload.faultDomain,
|
|
2872
|
+
requestDisposition: payload.requestDisposition,
|
|
2873
|
+
transportRequestId: payload.transportRequestId,
|
|
2874
|
+
consumeRequestId: payload.consumeRequestId,
|
|
2875
|
+
providerRequestId: payload.providerRequestId
|
|
2876
|
+
});
|
|
2133
2877
|
}
|
|
2134
2878
|
function isOrderSuccess(status) {
|
|
2135
2879
|
switch (status) {
|
|
@@ -2317,6 +3061,22 @@ function notifyUpstreamActivity(cb) {
|
|
|
2317
3061
|
} catch {
|
|
2318
3062
|
}
|
|
2319
3063
|
}
|
|
3064
|
+
var GATEWAY_REQUEST_ID_HEADER = "X-Acosmi-Request-Id";
|
|
3065
|
+
function readGatewayRequestID(headers) {
|
|
3066
|
+
const raw = headers.get(GATEWAY_REQUEST_ID_HEADER);
|
|
3067
|
+
if (!raw) return void 0;
|
|
3068
|
+
const trimmed = raw.trim();
|
|
3069
|
+
return trimmed === "" ? void 0 : trimmed;
|
|
3070
|
+
}
|
|
3071
|
+
function notifyGatewayRequestID(cb, headers) {
|
|
3072
|
+
if (!cb) return;
|
|
3073
|
+
const id = readGatewayRequestID(headers);
|
|
3074
|
+
if (id === void 0) return;
|
|
3075
|
+
try {
|
|
3076
|
+
cb(id);
|
|
3077
|
+
} catch {
|
|
3078
|
+
}
|
|
3079
|
+
}
|
|
2320
3080
|
var DEFAULT_API_TIMEOUT_MS = 6e4;
|
|
2321
3081
|
function newDeferred() {
|
|
2322
3082
|
let resolve;
|
|
@@ -2347,6 +3107,13 @@ var Client = class _Client {
|
|
|
2347
3107
|
tokens = null;
|
|
2348
3108
|
/** token 持久化 */
|
|
2349
3109
|
store;
|
|
3110
|
+
credentialMode;
|
|
3111
|
+
versionedCredentialStore;
|
|
3112
|
+
accessTokenProvider;
|
|
3113
|
+
beforeCredentialInstall;
|
|
3114
|
+
credentialAuthority;
|
|
3115
|
+
credentialRequestOwner;
|
|
3116
|
+
lifecycle = null;
|
|
2350
3117
|
/** fetch 实现 (默认 globalThis.fetch) */
|
|
2351
3118
|
fetchImpl;
|
|
2352
3119
|
/** 互斥锁 (TS 用 Promise chain 替代 sync.Mutex) */
|
|
@@ -2377,6 +3144,7 @@ var Client = class _Client {
|
|
|
2377
3144
|
/** V29 系数缓存 (TTL 8s, listCoefficients 内部用) */
|
|
2378
3145
|
coefCacheData = null;
|
|
2379
3146
|
coefCacheTimeMs = 0;
|
|
3147
|
+
credentialOwnerKey = null;
|
|
2380
3148
|
/** 串行化锁 (替代 Go sync.Mutex) */
|
|
2381
3149
|
coefMu = Promise.resolve();
|
|
2382
3150
|
constructor(cfg = {}) {
|
|
@@ -2387,8 +3155,92 @@ var Client = class _Client {
|
|
|
2387
3155
|
this.oauthMetadataProfile = cfg.oauthMetadataProfile ?? "desktop";
|
|
2388
3156
|
this.browserRefreshMode = cfg.browserRefreshMode ?? "direct";
|
|
2389
3157
|
this.refreshProxyURL = cfg.refreshProxyURL ?? null;
|
|
2390
|
-
this.
|
|
3158
|
+
this.credentialMode = cfg.credentialMode ?? "legacy";
|
|
3159
|
+
this.credentialAuthority = new URL(this.serverURL).origin;
|
|
3160
|
+
if (this.credentialMode === "versioned" && !cfg.versionedCredentialStore) {
|
|
3161
|
+
throw new Error("versionedCredentialStore is required for credentialMode=versioned");
|
|
3162
|
+
}
|
|
3163
|
+
if (cfg.credentialRequestOwner && this.credentialMode !== "versioned") {
|
|
3164
|
+
throw new Error("credentialRequestOwner requires credentialMode=versioned");
|
|
3165
|
+
}
|
|
3166
|
+
if (this.credentialMode === "legacy" && cfg.versionedCredentialStore) {
|
|
3167
|
+
throw new Error("credentialMode=versioned is required when versionedCredentialStore is provided");
|
|
3168
|
+
}
|
|
3169
|
+
if (this.credentialMode === "external" && cfg.versionedCredentialStore) {
|
|
3170
|
+
throw new Error("versionedCredentialStore is incompatible with credentialMode=external");
|
|
3171
|
+
}
|
|
3172
|
+
if (this.credentialMode !== "external" && cfg.accessTokenProvider) {
|
|
3173
|
+
throw new Error("accessTokenProvider requires credentialMode=external");
|
|
3174
|
+
}
|
|
3175
|
+
if (this.credentialMode === "external" && !cfg.accessTokenProvider) {
|
|
3176
|
+
throw new Error("accessTokenProvider is required for credentialMode=external");
|
|
3177
|
+
}
|
|
3178
|
+
if (this.credentialMode !== "versioned" && cfg.beforeCredentialInstall) {
|
|
3179
|
+
throw new Error("beforeCredentialInstall requires credentialMode=versioned");
|
|
3180
|
+
}
|
|
3181
|
+
if (this.credentialMode !== "legacy") {
|
|
3182
|
+
const authority = new URL(this.serverURL).origin;
|
|
3183
|
+
for (const [name, override] of [["apiBaseURL", this.apiBaseURL], ["complianceBaseURL", this.complianceBaseURL]]) {
|
|
3184
|
+
if (override && new URL(override).origin !== authority) {
|
|
3185
|
+
throw new Error(`${name} must use the credential authority ${authority}`);
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
this.accessTokenProvider = cfg.accessTokenProvider;
|
|
3190
|
+
this.beforeCredentialInstall = cfg.beforeCredentialInstall;
|
|
3191
|
+
this.credentialRequestOwner = cfg.credentialRequestOwner ? {
|
|
3192
|
+
storeInstanceId: cfg.credentialRequestOwner.storeInstanceId,
|
|
3193
|
+
authSessionId: cfg.credentialRequestOwner.authSessionId,
|
|
3194
|
+
principal: cfg.credentialRequestOwner.principal ? {
|
|
3195
|
+
issuer: cfg.credentialRequestOwner.principal.issuer,
|
|
3196
|
+
subject: cfg.credentialRequestOwner.principal.subject,
|
|
3197
|
+
organizationId: cfg.credentialRequestOwner.principal.organizationId
|
|
3198
|
+
} : null
|
|
3199
|
+
} : null;
|
|
2391
3200
|
this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
3201
|
+
this.versionedCredentialStore = cfg.versionedCredentialStore ?? null;
|
|
3202
|
+
if (this.versionedCredentialStore) this.lifecycle = new CredentialLifecycle(this.versionedCredentialStore, {
|
|
3203
|
+
serverURL: this.serverURL,
|
|
3204
|
+
fetch: this.fetchImpl,
|
|
3205
|
+
metadata: (signal) => discoverWithProfile(this.serverURL, "desktop", signal, this.fetchImpl),
|
|
3206
|
+
profile: async (tokens, signal) => {
|
|
3207
|
+
const gatewayRoot = this.serverURL.replace(/\/api\/v4$/, "");
|
|
3208
|
+
const profileURL = `${gatewayRoot}/api/oauth/profile`;
|
|
3209
|
+
this.assertCredentialURL(profileURL);
|
|
3210
|
+
const response = await this.fetchImpl(profileURL, { headers: { Authorization: `Bearer ${tokens.access_token}` }, signal });
|
|
3211
|
+
if (!response.ok) {
|
|
3212
|
+
const bodyBytes = response.body ? await readLimited(response.body, maxErrorBodySize) : new Uint8Array();
|
|
3213
|
+
const failure = parseHTTPErrorWithHeader(response.status, bodyBytes, response.headers);
|
|
3214
|
+
const contract = readGatewayErrorContract(failure);
|
|
3215
|
+
const code = contract?.errorCode ?? null;
|
|
3216
|
+
if (code === "INVALID_SCOPE") throw new Error("invalid_scope");
|
|
3217
|
+
if (code === "AUTH_CONTRACT_UNSUPPORTED") throw new Error("auth_contract_unsupported");
|
|
3218
|
+
if (code === "ACCOUNT_NOT_FOUND") throw new Error("account_permission");
|
|
3219
|
+
throw new Error("identity_unavailable");
|
|
3220
|
+
}
|
|
3221
|
+
const body = await response.json();
|
|
3222
|
+
const subject = body.account?.uuid;
|
|
3223
|
+
if (typeof subject !== "string" || !subject) throw new Error("invalid_response");
|
|
3224
|
+
const account = body.account;
|
|
3225
|
+
const organization = body.organization;
|
|
3226
|
+
return {
|
|
3227
|
+
subject,
|
|
3228
|
+
organizationId: organization?.uuid || null,
|
|
3229
|
+
...typeof account.display_name === "string" ? { displayName: account.display_name } : {},
|
|
3230
|
+
...[account.avatar_url, account.picture, account.image, body.avatar_url, body.picture, body.image].find((value) => typeof value === "string") !== void 0 ? { avatarUrl: [account.avatar_url, account.picture, account.image, body.avatar_url, body.picture, body.image].find((value) => typeof value === "string") } : {},
|
|
3231
|
+
...typeof account.email === "string" ? { email: account.email } : {},
|
|
3232
|
+
...typeof account.image_url === "string" ? { imageUrl: account.image_url } : {},
|
|
3233
|
+
...typeof account.created_at === "string" ? { accountCreatedAt: account.created_at } : {},
|
|
3234
|
+
...typeof account.requires_phone_binding === "boolean" ? { requiresPhoneBinding: account.requires_phone_binding } : {},
|
|
3235
|
+
...typeof organization?.has_extra_usage_enabled === "boolean" ? { hasExtraUsageEnabled: organization.has_extra_usage_enabled } : {},
|
|
3236
|
+
...typeof organization?.billing_type === "string" ? { billingType: organization.billing_type } : {},
|
|
3237
|
+
...typeof organization?.subscription_created_at === "string" ? { subscriptionCreatedAt: organization.subscription_created_at } : {},
|
|
3238
|
+
...typeof organization?.rate_limit_tier === "string" ? { rateLimitTier: organization.rate_limit_tier } : {},
|
|
3239
|
+
...typeof organization?.name === "string" ? { organizationName: organization.name } : {}
|
|
3240
|
+
};
|
|
3241
|
+
}
|
|
3242
|
+
});
|
|
3243
|
+
this.store = cfg.store ?? defaultTokenStore();
|
|
2392
3244
|
this.retryPolicy = effectivePolicy(cfg.retryPolicy ?? null);
|
|
2393
3245
|
}
|
|
2394
3246
|
/**
|
|
@@ -2397,6 +3249,11 @@ var Client = class _Client {
|
|
|
2397
3249
|
*/
|
|
2398
3250
|
static async create(cfg = {}) {
|
|
2399
3251
|
const c = new _Client(cfg);
|
|
3252
|
+
if (c.credentialMode === "external") return c;
|
|
3253
|
+
if (c.credentialMode === "versioned") {
|
|
3254
|
+
await c.reconcileCredentials();
|
|
3255
|
+
return c;
|
|
3256
|
+
}
|
|
2400
3257
|
try {
|
|
2401
3258
|
const tokens = await c.store.load();
|
|
2402
3259
|
if (tokens) {
|
|
@@ -2410,6 +3267,63 @@ var Client = class _Client {
|
|
|
2410
3267
|
}
|
|
2411
3268
|
return c;
|
|
2412
3269
|
}
|
|
3270
|
+
/** Read the durable authority. Available only in explicit versioned mode. */
|
|
3271
|
+
async getCredentialSnapshot(signal) {
|
|
3272
|
+
if (!this.versionedCredentialStore) {
|
|
3273
|
+
throw new Error("getCredentialSnapshot requires credentialMode=versioned");
|
|
3274
|
+
}
|
|
3275
|
+
return this.versionedCredentialStore.readSnapshot(signal);
|
|
3276
|
+
}
|
|
3277
|
+
/** Reconcile memory from durable state; storage errors never clear confirmed memory. */
|
|
3278
|
+
async reconcileCredentials(signal) {
|
|
3279
|
+
const snapshot = await this.lifecycle.reconcile(signal);
|
|
3280
|
+
this.adoptCredentialOwner(snapshot);
|
|
3281
|
+
this.tokens = snapshot.credentialState === "ready" ? snapshot.tokenSet : null;
|
|
3282
|
+
return snapshot;
|
|
3283
|
+
}
|
|
3284
|
+
ownerKey(snapshot) {
|
|
3285
|
+
return `${snapshot.storeInstanceId}\0${snapshot.authSessionId ?? ""}\0${snapshot.principal?.issuer ?? ""}\0${snapshot.principal?.subject ?? ""}\0${snapshot.principal?.organizationId ?? ""}`;
|
|
3286
|
+
}
|
|
3287
|
+
adoptCredentialOwner(snapshot) {
|
|
3288
|
+
const next = this.ownerKey(snapshot);
|
|
3289
|
+
if (this.credentialOwnerKey !== null && this.credentialOwnerKey !== next) {
|
|
3290
|
+
this.modelCache = [];
|
|
3291
|
+
this.modelCacheTimeMs = 0;
|
|
3292
|
+
this.coefCacheData = null;
|
|
3293
|
+
this.coefCacheTimeMs = 0;
|
|
3294
|
+
}
|
|
3295
|
+
this.credentialOwnerKey = next;
|
|
3296
|
+
}
|
|
3297
|
+
async ensureCredential(signal) {
|
|
3298
|
+
if (!this.lifecycle) return this.ensureToken(signal);
|
|
3299
|
+
const token = await this.lifecycle.ensure(signal, void 0, this.credentialRequestOwner ?? void 0);
|
|
3300
|
+
const snapshot = await this.lifecycle.read(signal);
|
|
3301
|
+
this.adoptCredentialOwner(snapshot);
|
|
3302
|
+
this.tokens = snapshot.credentialState === "ready" ? snapshot.tokenSet : null;
|
|
3303
|
+
return token;
|
|
3304
|
+
}
|
|
3305
|
+
subscribeCredentialState(listener) {
|
|
3306
|
+
if (!this.lifecycle) throw new Error("subscribeCredentialState requires credentialMode=versioned");
|
|
3307
|
+
return this.lifecycle.subscribe(listener);
|
|
3308
|
+
}
|
|
3309
|
+
async retryCredentialIdentity(signal) {
|
|
3310
|
+
const snapshot = await this.getCredentialSnapshot(signal);
|
|
3311
|
+
if (!snapshot.authSessionId) throw new Error("not authorized");
|
|
3312
|
+
const ready = await this.lifecycle.bindIdentity(snapshot.authSessionId, signal);
|
|
3313
|
+
this.adoptCredentialOwner(ready);
|
|
3314
|
+
this.tokens = ready.credentialState === "ready" ? ready.tokenSet : null;
|
|
3315
|
+
return ready;
|
|
3316
|
+
}
|
|
3317
|
+
async logoutCredential(signal, expected) {
|
|
3318
|
+
if (!this.lifecycle) throw new Error("logoutCredential requires credentialMode=versioned");
|
|
3319
|
+
const result = await this.lifecycle.logout(signal, expected);
|
|
3320
|
+
if (result.status === "committed" || result.status === "already_signed_out") {
|
|
3321
|
+
const current = await this.lifecycle.read(signal);
|
|
3322
|
+
this.adoptCredentialOwner(current);
|
|
3323
|
+
this.tokens = null;
|
|
3324
|
+
}
|
|
3325
|
+
return result;
|
|
3326
|
+
}
|
|
2413
3327
|
// ===========================================================================
|
|
2414
3328
|
// 授权生命周期
|
|
2415
3329
|
// ===========================================================================
|
|
@@ -2460,6 +3374,44 @@ var Client = class _Client {
|
|
|
2460
3374
|
return this.loginInternal(appName, scopes, { handler, ...opts }, signal);
|
|
2461
3375
|
}
|
|
2462
3376
|
async loginInternal(appName, scopes, opts, signal) {
|
|
3377
|
+
if (this.lifecycle) {
|
|
3378
|
+
const attempt = await this.lifecycle.reserveLogin(signal);
|
|
3379
|
+
let installHookRejected = false;
|
|
3380
|
+
try {
|
|
3381
|
+
const registration = await register(attempt.metadata, appName, signal, this.fetchImpl);
|
|
3382
|
+
await this.lifecycle.assertLogin(attempt.attemptId, signal);
|
|
3383
|
+
const authorization = await authorize(attempt.metadata, registration.client_id, scopes, { ...opts, handler: opts?.handler ?? void 0, signal });
|
|
3384
|
+
await this.lifecycle.assertLogin(attempt.attemptId, signal);
|
|
3385
|
+
const response = await exchangeCode(attempt.metadata, registration.client_id, authorization.result.code, authorization.result.redirectURI, authorization.verifier, signal, this.fetchImpl);
|
|
3386
|
+
if (!Number.isFinite(response.expires_in) || response.expires_in <= 0) throw new Error("invalid_response");
|
|
3387
|
+
await this.lifecycle.assertLogin(attempt.attemptId, signal);
|
|
3388
|
+
try {
|
|
3389
|
+
await this.beforeCredentialInstall?.({
|
|
3390
|
+
accessToken: response.access_token,
|
|
3391
|
+
attemptId: attempt.attemptId,
|
|
3392
|
+
serverURL: this.serverURL,
|
|
3393
|
+
clientId: registration.client_id
|
|
3394
|
+
}, signal);
|
|
3395
|
+
} catch (error) {
|
|
3396
|
+
installHookRejected = true;
|
|
3397
|
+
throw error;
|
|
3398
|
+
}
|
|
3399
|
+
await this.lifecycle.assertLogin(attempt.attemptId, signal);
|
|
3400
|
+
const ready = await this.lifecycle.installLogin(attempt.attemptId, newTokenSet(response, registration.client_id, this.serverURL), signal);
|
|
3401
|
+
const current = await this.getCredentialSnapshot(signal);
|
|
3402
|
+
if (current.revision !== ready.revision || current.authSessionId !== ready.authSessionId) throw new Error("superseded");
|
|
3403
|
+
this.tokens = ready.tokenSet;
|
|
3404
|
+
opts?.handler?.({ type: EventComplete, attemptId: attempt.attemptId });
|
|
3405
|
+
} catch (error) {
|
|
3406
|
+
const current = await this.getCredentialSnapshot();
|
|
3407
|
+
if (current.loginAttempt?.attemptId === attempt.attemptId || current.lastLoginAttemptId === attempt.attemptId) {
|
|
3408
|
+
opts?.handler?.(installHookRejected ? { type: EventError, attemptId: attempt.attemptId, err_code: "credential_install_rejected", error: "credential_install_rejected" } : { type: EventError, attemptId: attempt.attemptId, error: "credential_login_failed" });
|
|
3409
|
+
}
|
|
3410
|
+
await this.lifecycle.cancelLogin(attempt.attemptId);
|
|
3411
|
+
throw error;
|
|
3412
|
+
}
|
|
3413
|
+
return;
|
|
3414
|
+
}
|
|
2463
3415
|
const handler = opts?.handler ?? void 0;
|
|
2464
3416
|
const emit = (e) => {
|
|
2465
3417
|
if (handler) handler(e);
|
|
@@ -2568,6 +3520,11 @@ var Client = class _Client {
|
|
|
2568
3520
|
}
|
|
2569
3521
|
/** 吊销 token 并清除本地存储 */
|
|
2570
3522
|
async logout(signal) {
|
|
3523
|
+
if (this.lifecycle) {
|
|
3524
|
+
await this.logoutCredential(signal);
|
|
3525
|
+
await this.reconcileCredentials(signal);
|
|
3526
|
+
return;
|
|
3527
|
+
}
|
|
2571
3528
|
const tokens = this.tokens;
|
|
2572
3529
|
let meta = this.meta;
|
|
2573
3530
|
this.tokens = null;
|
|
@@ -2605,6 +3562,13 @@ var Client = class _Client {
|
|
|
2605
3562
|
* 避免应用启动期 "login + 多个 API 调用" 并发场景下 4+ 条 "not authorized" 误报.
|
|
2606
3563
|
*/
|
|
2607
3564
|
async ensureToken(signal) {
|
|
3565
|
+
if (this.credentialMode === "external") {
|
|
3566
|
+
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
3567
|
+
const token = await this.accessTokenProvider(signal);
|
|
3568
|
+
if (typeof token !== "string" || token.length === 0) throw new Error("external access token unavailable");
|
|
3569
|
+
return token;
|
|
3570
|
+
}
|
|
3571
|
+
if (this.lifecycle) return this.lifecycle.ensure(signal, void 0, this.credentialRequestOwner ?? void 0);
|
|
2608
3572
|
let tokens = this.tokens;
|
|
2609
3573
|
const ready = this.tokenReady.promise;
|
|
2610
3574
|
const inFlight = this.loginInFlight;
|
|
@@ -2652,7 +3616,14 @@ var Client = class _Client {
|
|
|
2652
3616
|
);
|
|
2653
3617
|
}
|
|
2654
3618
|
/** 强制刷新 token (用于 401 重试) */
|
|
2655
|
-
async forceRefresh(signal) {
|
|
3619
|
+
async forceRefresh(signal, rejectedToken) {
|
|
3620
|
+
if (this.credentialMode === "external") throw new Error("external credentials cannot be refreshed by the SDK");
|
|
3621
|
+
if (this.lifecycle) {
|
|
3622
|
+
await this.lifecycle.forceRefresh(signal, rejectedToken, this.credentialRequestOwner ?? void 0);
|
|
3623
|
+
const snapshot = await this.lifecycle.read(signal);
|
|
3624
|
+
this.tokens = snapshot.credentialState === "ready" ? snapshot.tokenSet : null;
|
|
3625
|
+
return;
|
|
3626
|
+
}
|
|
2656
3627
|
return this.withMu(
|
|
2657
3628
|
() => this.storeWithLock(async () => {
|
|
2658
3629
|
await this.syncFromDisk();
|
|
@@ -2847,6 +3818,7 @@ var Client = class _Client {
|
|
|
2847
3818
|
*/
|
|
2848
3819
|
async listModelsWithStatus(signal, opts) {
|
|
2849
3820
|
const includeLocked = opts?.includeLocked === true;
|
|
3821
|
+
const requestOwner = this.lifecycle ? this.ownerKey(await this.getCredentialSnapshot(signal)) : null;
|
|
2850
3822
|
const path = includeLocked ? "/managed-models?picker=1" : "/managed-models";
|
|
2851
3823
|
const { result, headers } = await this.doJSONFull(
|
|
2852
3824
|
"GET",
|
|
@@ -2855,6 +3827,11 @@ var Client = class _Client {
|
|
|
2855
3827
|
signal
|
|
2856
3828
|
);
|
|
2857
3829
|
const normalized = normalizeInputModalities(result.data);
|
|
3830
|
+
if (requestOwner !== null) {
|
|
3831
|
+
const current = await this.getCredentialSnapshot(signal);
|
|
3832
|
+
if (this.ownerKey(current) !== requestOwner) throw new Error("superseded");
|
|
3833
|
+
this.adoptCredentialOwner(current);
|
|
3834
|
+
}
|
|
2858
3835
|
if (!includeLocked) {
|
|
2859
3836
|
this.modelCache = normalized;
|
|
2860
3837
|
this.modelCacheTimeMs = Date.now();
|
|
@@ -3024,7 +4001,7 @@ var Client = class _Client {
|
|
|
3024
4001
|
* 响应的 tokenRemaining / callRemaining 字段来自服务端 Header, 反映结算后余额
|
|
3025
4002
|
* v0.5.0: 根据 provider 自动路由到 /anthropic 或 /chat 端点
|
|
3026
4003
|
*/
|
|
3027
|
-
async chat(modelID, req, signal) {
|
|
4004
|
+
async chat(modelID, req, signal, onGatewayRequestID) {
|
|
3028
4005
|
const r = { ...req, stream: false };
|
|
3029
4006
|
const ctl = withRequestTimeout(CHAT_REQUEST_TIMEOUT_MS, signal);
|
|
3030
4007
|
try {
|
|
@@ -3037,6 +4014,7 @@ var Client = class _Client {
|
|
|
3037
4014
|
ctl.signal,
|
|
3038
4015
|
CHAT_REQUEST_TIMEOUT_MS
|
|
3039
4016
|
);
|
|
4017
|
+
notifyGatewayRequestID(onGatewayRequestID, headers);
|
|
3040
4018
|
const resp = adapter.parseResponse(result);
|
|
3041
4019
|
const v1 = headers.get("X-Token-Remaining");
|
|
3042
4020
|
if (v1) {
|
|
@@ -3157,28 +4135,29 @@ var Client = class _Client {
|
|
|
3157
4135
|
* Anthropic → chatMessagesAnthropic (现有路径, POST /anthropic)
|
|
3158
4136
|
* 其他厂商 → chatMessagesOpenAI (POST /chat, 响应转换为 AnthropicResponse)
|
|
3159
4137
|
*/
|
|
3160
|
-
async chatMessages(modelID, req, signal) {
|
|
4138
|
+
async chatMessages(modelID, req, signal, onGatewayRequestID) {
|
|
3161
4139
|
const m = await this.ensureModelCached(modelID, signal);
|
|
3162
4140
|
const adapter = getAdapterForModel(m);
|
|
3163
4141
|
if (adapter.format() === 0 /* Anthropic */) {
|
|
3164
|
-
return this.chatMessagesAnthropic(modelID, req, adapter, signal);
|
|
4142
|
+
return this.chatMessagesAnthropic(modelID, req, adapter, signal, onGatewayRequestID);
|
|
3165
4143
|
}
|
|
3166
|
-
return this.chatMessagesOpenAI(modelID, req, adapter, signal);
|
|
4144
|
+
return this.chatMessagesOpenAI(modelID, req, adapter, signal, onGatewayRequestID);
|
|
3167
4145
|
}
|
|
3168
|
-
async chatMessagesAnthropic(modelID, req, adapter, signal) {
|
|
4146
|
+
async chatMessagesAnthropic(modelID, req, adapter, signal, onGatewayRequestID) {
|
|
3169
4147
|
const r = { ...req, stream: false };
|
|
3170
4148
|
const ctl = withRequestTimeout(CHAT_REQUEST_TIMEOUT_MS, signal);
|
|
3171
4149
|
try {
|
|
3172
4150
|
const caps = this.getCachedCapabilities(modelID) ?? zeroModelCapabilities();
|
|
3173
4151
|
const body = adapter.buildRequestBody(caps, r);
|
|
3174
4152
|
const data = JSON.stringify(body);
|
|
3175
|
-
const { result } = await this.doJSONFullRaw(
|
|
4153
|
+
const { result, headers } = await this.doJSONFullRaw(
|
|
3176
4154
|
"POST",
|
|
3177
4155
|
`/managed-models/${encodeURIComponent(modelID)}/anthropic`,
|
|
3178
4156
|
data,
|
|
3179
4157
|
ctl.signal,
|
|
3180
4158
|
CHAT_REQUEST_TIMEOUT_MS
|
|
3181
4159
|
);
|
|
4160
|
+
notifyGatewayRequestID(onGatewayRequestID, headers);
|
|
3182
4161
|
const rawStr = new TextDecoder().decode(result);
|
|
3183
4162
|
try {
|
|
3184
4163
|
const wrapper = JSON.parse(rawStr);
|
|
@@ -3203,7 +4182,7 @@ var Client = class _Client {
|
|
|
3203
4182
|
ctl.dispose();
|
|
3204
4183
|
}
|
|
3205
4184
|
}
|
|
3206
|
-
async chatMessagesOpenAI(modelID, req, adapter, signal) {
|
|
4185
|
+
async chatMessagesOpenAI(modelID, req, adapter, signal, onGatewayRequestID) {
|
|
3207
4186
|
const r = { ...req, stream: false };
|
|
3208
4187
|
const ctl = withRequestTimeout(CHAT_REQUEST_TIMEOUT_MS, signal);
|
|
3209
4188
|
try {
|
|
@@ -3211,13 +4190,14 @@ var Client = class _Client {
|
|
|
3211
4190
|
const body = adapter.buildRequestBody(caps, r);
|
|
3212
4191
|
const data = JSON.stringify(body);
|
|
3213
4192
|
const endpoint = `/managed-models/${encodeURIComponent(modelID)}${adapter.endpointSuffix()}`;
|
|
3214
|
-
const { result } = await this.doJSONFullRaw(
|
|
4193
|
+
const { result, headers } = await this.doJSONFullRaw(
|
|
3215
4194
|
"POST",
|
|
3216
4195
|
endpoint,
|
|
3217
4196
|
data,
|
|
3218
4197
|
ctl.signal,
|
|
3219
4198
|
CHAT_REQUEST_TIMEOUT_MS
|
|
3220
4199
|
);
|
|
4200
|
+
notifyGatewayRequestID(onGatewayRequestID, headers);
|
|
3221
4201
|
const { parseOpenAIResponseToAnthropic: parseOpenAIResponseToAnthropic2 } = await Promise.resolve().then(() => (init_openai(), openai_exports));
|
|
3222
4202
|
return parseOpenAIResponseToAnthropic2(result);
|
|
3223
4203
|
} finally {
|
|
@@ -3229,10 +4209,11 @@ var Client = class _Client {
|
|
|
3229
4209
|
* v0.5.0: 根据 adapter 路由端点
|
|
3230
4210
|
*
|
|
3231
4211
|
* @param onUpstreamActivity 见 {@link UpstreamActivityCallback}
|
|
4212
|
+
* @param onGatewayRequestID 见 {@link GatewayRequestIDCallback}
|
|
3232
4213
|
*/
|
|
3233
|
-
chatStream(modelID, req, signal, onUpstreamActivity) {
|
|
4214
|
+
chatStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID) {
|
|
3234
4215
|
return {
|
|
3235
|
-
[Symbol.asyncIterator]: () => this.chatStreamGen(modelID, req, signal, false, onUpstreamActivity)
|
|
4216
|
+
[Symbol.asyncIterator]: () => this.chatStreamGen(modelID, req, signal, false, onUpstreamActivity, onGatewayRequestID)
|
|
3236
4217
|
};
|
|
3237
4218
|
}
|
|
3238
4219
|
/**
|
|
@@ -3241,13 +4222,14 @@ var Client = class _Client {
|
|
|
3241
4222
|
* 无 started/settled/failed 自定义事件, 无 data: [DONE], message_stop 为自然结束
|
|
3242
4223
|
*
|
|
3243
4224
|
* @param onUpstreamActivity 见 {@link UpstreamActivityCallback}
|
|
4225
|
+
* @param onGatewayRequestID 见 {@link GatewayRequestIDCallback}
|
|
3244
4226
|
*/
|
|
3245
|
-
chatMessagesStream(modelID, req, signal, onUpstreamActivity) {
|
|
4227
|
+
chatMessagesStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID) {
|
|
3246
4228
|
return {
|
|
3247
|
-
[Symbol.asyncIterator]: () => this.chatMessagesStreamGen(modelID, req, signal, false, onUpstreamActivity)
|
|
4229
|
+
[Symbol.asyncIterator]: () => this.chatMessagesStreamGen(modelID, req, signal, false, onUpstreamActivity, onGatewayRequestID)
|
|
3248
4230
|
};
|
|
3249
4231
|
}
|
|
3250
|
-
async *chatStreamGen(modelID, req, signal, retried, onUpstreamActivity) {
|
|
4232
|
+
async *chatStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID) {
|
|
3251
4233
|
const r = { ...req, stream: true };
|
|
3252
4234
|
const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
|
|
3253
4235
|
const token = await this.ensureToken(signal);
|
|
@@ -3269,20 +4251,20 @@ var Client = class _Client {
|
|
|
3269
4251
|
throw classifyTransport("POST " + endpoint, url, e);
|
|
3270
4252
|
}
|
|
3271
4253
|
if (resp.status === 401 && !retried) {
|
|
4254
|
+
const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
|
|
4255
|
+
const authError = parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
|
|
4256
|
+
if (!isUserAccessTokenRejected(authError)) throw authError;
|
|
3272
4257
|
try {
|
|
3273
|
-
await
|
|
3274
|
-
} catch {
|
|
3275
|
-
}
|
|
3276
|
-
try {
|
|
3277
|
-
await this.forceRefresh(signal);
|
|
4258
|
+
await this.forceRefresh(signal, token);
|
|
3278
4259
|
} catch (refreshErr) {
|
|
3279
4260
|
throw new Error(
|
|
3280
4261
|
`stream: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
|
|
3281
4262
|
);
|
|
3282
4263
|
}
|
|
3283
|
-
yield* this.chatStreamGen(modelID, req, signal, true, onUpstreamActivity);
|
|
4264
|
+
yield* this.chatStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID);
|
|
3284
4265
|
return;
|
|
3285
4266
|
}
|
|
4267
|
+
notifyGatewayRequestID(onGatewayRequestID, resp.headers);
|
|
3286
4268
|
if (!resp.ok) {
|
|
3287
4269
|
const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
|
|
3288
4270
|
throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
|
|
@@ -3317,7 +4299,7 @@ var Client = class _Client {
|
|
|
3317
4299
|
}
|
|
3318
4300
|
}
|
|
3319
4301
|
}
|
|
3320
|
-
async *chatMessagesStreamGen(modelID, req, signal, retried, onUpstreamActivity) {
|
|
4302
|
+
async *chatMessagesStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID) {
|
|
3321
4303
|
const r = { ...req, stream: true };
|
|
3322
4304
|
const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
|
|
3323
4305
|
const token = await this.ensureToken(signal);
|
|
@@ -3339,20 +4321,20 @@ var Client = class _Client {
|
|
|
3339
4321
|
throw classifyTransport("POST " + endpoint, url, e);
|
|
3340
4322
|
}
|
|
3341
4323
|
if (resp.status === 401 && !retried) {
|
|
4324
|
+
const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
|
|
4325
|
+
const authError = parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
|
|
4326
|
+
if (!isUserAccessTokenRejected(authError)) throw authError;
|
|
3342
4327
|
try {
|
|
3343
|
-
await
|
|
3344
|
-
} catch {
|
|
3345
|
-
}
|
|
3346
|
-
try {
|
|
3347
|
-
await this.forceRefresh(signal);
|
|
4328
|
+
await this.forceRefresh(signal, token);
|
|
3348
4329
|
} catch (refreshErr) {
|
|
3349
4330
|
throw new Error(
|
|
3350
4331
|
`messages stream: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
|
|
3351
4332
|
);
|
|
3352
4333
|
}
|
|
3353
|
-
yield* this.chatMessagesStreamGen(modelID, req, signal, true, onUpstreamActivity);
|
|
4334
|
+
yield* this.chatMessagesStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID);
|
|
3354
4335
|
return;
|
|
3355
4336
|
}
|
|
4337
|
+
notifyGatewayRequestID(onGatewayRequestID, resp.headers);
|
|
3356
4338
|
if (!resp.ok) {
|
|
3357
4339
|
const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
|
|
3358
4340
|
throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
|
|
@@ -3433,7 +4415,9 @@ var Client = class _Client {
|
|
|
3433
4415
|
if (!base.endsWith("/api/v4")) {
|
|
3434
4416
|
base += "/api/v4";
|
|
3435
4417
|
}
|
|
3436
|
-
|
|
4418
|
+
const url = base + path;
|
|
4419
|
+
this.assertCredentialURL(url);
|
|
4420
|
+
return url;
|
|
3437
4421
|
}
|
|
3438
4422
|
/**
|
|
3439
4423
|
* Compliance API URL 拼接。
|
|
@@ -3446,7 +4430,14 @@ var Client = class _Client {
|
|
|
3446
4430
|
*/
|
|
3447
4431
|
complianceURL(path) {
|
|
3448
4432
|
const base = this.complianceBaseURL ?? this.serverURL + "/admin-api";
|
|
3449
|
-
|
|
4433
|
+
const url = base + path;
|
|
4434
|
+
this.assertCredentialURL(url);
|
|
4435
|
+
return url;
|
|
4436
|
+
}
|
|
4437
|
+
assertCredentialURL(url) {
|
|
4438
|
+
if (this.credentialMode !== "legacy" && new URL(url).origin !== this.credentialAuthority) {
|
|
4439
|
+
throw new Error("credential request authority changed");
|
|
4440
|
+
}
|
|
3450
4441
|
}
|
|
3451
4442
|
/** GET/POST/... 通用 JSON 调用 (返回 result 已 typed) */
|
|
3452
4443
|
async doJSON(method, path, body, signal) {
|
|
@@ -3475,12 +4466,11 @@ var Client = class _Client {
|
|
|
3475
4466
|
ctl.signal
|
|
3476
4467
|
);
|
|
3477
4468
|
if (resp.status === 401 && !retried) {
|
|
4469
|
+
const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
|
|
4470
|
+
const authError = parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
|
|
4471
|
+
if (!isUserAccessTokenRejected(authError)) throw authError;
|
|
3478
4472
|
try {
|
|
3479
|
-
await
|
|
3480
|
-
} catch {
|
|
3481
|
-
}
|
|
3482
|
-
try {
|
|
3483
|
-
await this.forceRefresh(ctl.signal);
|
|
4473
|
+
await this.forceRefresh(ctl.signal, token);
|
|
3484
4474
|
} catch (refreshErr) {
|
|
3485
4475
|
throw new Error(
|
|
3486
4476
|
`unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
|
|
@@ -3545,12 +4535,11 @@ var Client = class _Client {
|
|
|
3545
4535
|
ctl.signal
|
|
3546
4536
|
);
|
|
3547
4537
|
if (resp.status === 401 && !retried) {
|
|
4538
|
+
const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
|
|
4539
|
+
const authError = parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
|
|
4540
|
+
if (!isUserAccessTokenRejected(authError)) throw authError;
|
|
3548
4541
|
try {
|
|
3549
|
-
await
|
|
3550
|
-
} catch {
|
|
3551
|
-
}
|
|
3552
|
-
try {
|
|
3553
|
-
await this.forceRefresh(ctl.signal);
|
|
4542
|
+
await this.forceRefresh(ctl.signal, token);
|
|
3554
4543
|
} catch (refreshErr) {
|
|
3555
4544
|
throw new Error(
|
|
3556
4545
|
`unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
|
|
@@ -3625,6 +4614,7 @@ var Client = class _Client {
|
|
|
3625
4614
|
* 6 处原始 fetch() 全部走此 helper
|
|
3626
4615
|
*/
|
|
3627
4616
|
async doRequest(req, signal) {
|
|
4617
|
+
if (new Headers(req.headers).has("Authorization")) this.assertCredentialURL(req.url);
|
|
3628
4618
|
try {
|
|
3629
4619
|
return await this.fetchImpl(req.url, {
|
|
3630
4620
|
method: req.method,
|
|
@@ -4622,12 +5612,11 @@ async function uploadSkillInternal(c, zipData, scope, intent, retried, signal) {
|
|
|
4622
5612
|
throw classifyTransport("POST /skill-store/upload", url, e);
|
|
4623
5613
|
}
|
|
4624
5614
|
if (resp.status === 401 && !retried) {
|
|
5615
|
+
const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
|
|
5616
|
+
const authError = parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
|
|
5617
|
+
if (!isUserAccessTokenRejected(authError)) throw authError;
|
|
4625
5618
|
try {
|
|
4626
|
-
await
|
|
4627
|
-
} catch {
|
|
4628
|
-
}
|
|
4629
|
-
try {
|
|
4630
|
-
await c.forceRefresh(ctl.signal);
|
|
5619
|
+
await c.forceRefresh(ctl.signal, token);
|
|
4631
5620
|
} catch (refreshErr) {
|
|
4632
5621
|
throw new Error(
|
|
4633
5622
|
`upload: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
|
|
@@ -4798,9 +5787,7 @@ Client.prototype.updateNotificationPreference = async function(typeCode, pref, s
|
|
|
4798
5787
|
|
|
4799
5788
|
// src/notifications/ws.ts
|
|
4800
5789
|
Client.prototype.connect = async function(cfg, signal) {
|
|
4801
|
-
|
|
4802
|
-
await this.disconnect();
|
|
4803
|
-
}
|
|
5790
|
+
const oldDisconnect = this.ws ? this.disconnect() : Promise.resolve();
|
|
4804
5791
|
const noop = () => {
|
|
4805
5792
|
};
|
|
4806
5793
|
const filledCfg = {
|
|
@@ -4816,21 +5803,31 @@ Client.prototype.connect = async function(cfg, signal) {
|
|
|
4816
5803
|
const done = new Promise((r) => {
|
|
4817
5804
|
resolveDone = r;
|
|
4818
5805
|
});
|
|
4819
|
-
const
|
|
5806
|
+
const abort2 = new AbortController();
|
|
4820
5807
|
if (signal) {
|
|
4821
|
-
if (signal.aborted)
|
|
4822
|
-
else signal.addEventListener("abort", () =>
|
|
5808
|
+
if (signal.aborted) abort2.abort();
|
|
5809
|
+
else signal.addEventListener("abort", () => abort2.abort());
|
|
4823
5810
|
}
|
|
4824
5811
|
const ws = {
|
|
4825
5812
|
conn: null,
|
|
4826
5813
|
cfg: filledCfg,
|
|
4827
|
-
abort,
|
|
5814
|
+
abort: abort2,
|
|
4828
5815
|
done,
|
|
4829
5816
|
doneResolve: resolveDone,
|
|
4830
|
-
connected: false
|
|
5817
|
+
connected: false,
|
|
5818
|
+
owner: null
|
|
4831
5819
|
};
|
|
4832
|
-
await wsConnectOnce(this, ws);
|
|
4833
5820
|
this.ws = ws;
|
|
5821
|
+
try {
|
|
5822
|
+
await oldDisconnect;
|
|
5823
|
+
await assertCurrent(this, ws);
|
|
5824
|
+
await wsConnectOnce(this, ws);
|
|
5825
|
+
} catch (error) {
|
|
5826
|
+
ws.abort.abort();
|
|
5827
|
+
if (this.ws === ws) this.ws = null;
|
|
5828
|
+
ws.doneResolve();
|
|
5829
|
+
throw error;
|
|
5830
|
+
}
|
|
4834
5831
|
void wsLoop(this, ws);
|
|
4835
5832
|
};
|
|
4836
5833
|
Client.prototype.disconnect = async function() {
|
|
@@ -4868,15 +5865,47 @@ function getWebSocketCtor() {
|
|
|
4868
5865
|
}
|
|
4869
5866
|
return WSCtor;
|
|
4870
5867
|
}
|
|
5868
|
+
function sameOwner(a, b) {
|
|
5869
|
+
return a?.storeInstanceId === b?.storeInstanceId && a?.authSessionId === b?.authSessionId && a?.principal?.issuer === b?.principal?.issuer && a?.principal?.subject === b?.principal?.subject && a?.principal?.organizationId === b?.principal?.organizationId;
|
|
5870
|
+
}
|
|
5871
|
+
async function readOwner(c, signal) {
|
|
5872
|
+
if (c.credentialMode !== "versioned") return null;
|
|
5873
|
+
const snapshot = await c.getCredentialSnapshot(signal);
|
|
5874
|
+
return {
|
|
5875
|
+
storeInstanceId: snapshot.storeInstanceId,
|
|
5876
|
+
authSessionId: snapshot.authSessionId,
|
|
5877
|
+
principal: snapshot.principal
|
|
5878
|
+
};
|
|
5879
|
+
}
|
|
5880
|
+
async function assertCurrent(c, ws) {
|
|
5881
|
+
if (ws.abort.signal.aborted || c.ws !== ws) throw new Error("websocket connection superseded");
|
|
5882
|
+
if (ws.owner !== null && !sameOwner(ws.owner, await readOwner(c, ws.abort.signal))) {
|
|
5883
|
+
ws.abort.abort();
|
|
5884
|
+
throw new Error("websocket credential owner changed");
|
|
5885
|
+
}
|
|
5886
|
+
}
|
|
4871
5887
|
async function wsConnectOnce(c, ws) {
|
|
5888
|
+
const observedOwner = await readOwner(c, ws.abort.signal);
|
|
5889
|
+
if (ws.owner === null) ws.owner = observedOwner;
|
|
5890
|
+
else if (!sameOwner(ws.owner, observedOwner)) throw new Error("websocket credential owner changed");
|
|
5891
|
+
await assertCurrent(c, ws);
|
|
4872
5892
|
const url = wsURL(c);
|
|
4873
5893
|
const WSCtor = getWebSocketCtor();
|
|
4874
|
-
const
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
5894
|
+
const token = await c.ensureToken(ws.abort.signal);
|
|
5895
|
+
await assertCurrent(c, ws);
|
|
5896
|
+
const ticketURL = c.apiURL("/ws/stream-ticket");
|
|
5897
|
+
await assertCurrent(c, ws);
|
|
5898
|
+
const ticketHTTP = await c.doRequest({
|
|
5899
|
+
method: "POST",
|
|
5900
|
+
url: ticketURL,
|
|
5901
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
5902
|
+
}, ws.abort.signal);
|
|
5903
|
+
if (!ticketHTTP.ok) {
|
|
5904
|
+
const body = ticketHTTP.body ? await readLimited(ticketHTTP.body, maxErrorBodySize) : new Uint8Array();
|
|
5905
|
+
throw parseHTTPErrorWithHeader(ticketHTTP.status, body, ticketHTTP.headers);
|
|
5906
|
+
}
|
|
5907
|
+
const ticketResp = await ticketHTTP.json();
|
|
5908
|
+
await assertCurrent(c, ws);
|
|
4880
5909
|
const ticket = ticketResp.data.ticket;
|
|
4881
5910
|
const u = new URL(url);
|
|
4882
5911
|
u.searchParams.set("ticket", ticket);
|
|
@@ -4897,11 +5926,28 @@ async function wsConnectOnce(c, ws) {
|
|
|
4897
5926
|
reject(new Error("dial: handshake timeout"));
|
|
4898
5927
|
}
|
|
4899
5928
|
}, 3e4);
|
|
5929
|
+
const abortHandshake = () => {
|
|
5930
|
+
clearTimeout(handshakeTimer);
|
|
5931
|
+
try {
|
|
5932
|
+
conn.close();
|
|
5933
|
+
} catch {
|
|
5934
|
+
}
|
|
5935
|
+
reject(new Error("websocket connection aborted"));
|
|
5936
|
+
};
|
|
5937
|
+
ws.abort.signal.addEventListener("abort", abortHandshake, { once: true });
|
|
4900
5938
|
conn.addEventListener("open", () => {
|
|
5939
|
+
if (ws.abort.signal.aborted || c.ws !== ws) {
|
|
5940
|
+
try {
|
|
5941
|
+
conn.close();
|
|
5942
|
+
} catch {
|
|
5943
|
+
}
|
|
5944
|
+
return;
|
|
5945
|
+
}
|
|
4901
5946
|
opened = true;
|
|
4902
5947
|
});
|
|
4903
5948
|
conn.addEventListener("error", (e) => {
|
|
4904
5949
|
clearTimeout(handshakeTimer);
|
|
5950
|
+
ws.abort.signal.removeEventListener("abort", abortHandshake);
|
|
4905
5951
|
reject(new Error(`dial: ${e.message ?? "connection error"}`));
|
|
4906
5952
|
});
|
|
4907
5953
|
conn.addEventListener("message", (e) => {
|
|
@@ -4910,6 +5956,7 @@ async function wsConnectOnce(c, ws) {
|
|
|
4910
5956
|
const welcome = JSON.parse(msg);
|
|
4911
5957
|
if (welcome.type !== "welcome") {
|
|
4912
5958
|
clearTimeout(handshakeTimer);
|
|
5959
|
+
ws.abort.signal.removeEventListener("abort", abortHandshake);
|
|
4913
5960
|
try {
|
|
4914
5961
|
conn.close();
|
|
4915
5962
|
} catch {
|
|
@@ -4917,31 +5964,34 @@ async function wsConnectOnce(c, ws) {
|
|
|
4917
5964
|
reject(new Error(`unexpected first message: ${welcome.type}`));
|
|
4918
5965
|
return;
|
|
4919
5966
|
}
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
JSON.stringify({
|
|
4927
|
-
type: "subscribe",
|
|
4928
|
-
topics: ws.cfg.topics
|
|
4929
|
-
})
|
|
4930
|
-
);
|
|
4931
|
-
} catch (sendErr) {
|
|
4932
|
-
ws.conn = null;
|
|
4933
|
-
ws.connected = false;
|
|
5967
|
+
void assertCurrent(c, ws).then(() => {
|
|
5968
|
+
clearTimeout(handshakeTimer);
|
|
5969
|
+
ws.abort.signal.removeEventListener("abort", abortHandshake);
|
|
5970
|
+
ws.conn = conn;
|
|
5971
|
+
ws.connected = true;
|
|
5972
|
+
if (ws.cfg.topics.length > 0) {
|
|
4934
5973
|
try {
|
|
4935
|
-
conn.
|
|
4936
|
-
|
|
5974
|
+
conn.send(
|
|
5975
|
+
JSON.stringify({
|
|
5976
|
+
type: "subscribe",
|
|
5977
|
+
topics: ws.cfg.topics
|
|
5978
|
+
})
|
|
5979
|
+
);
|
|
5980
|
+
} catch (sendErr) {
|
|
5981
|
+
ws.conn = null;
|
|
5982
|
+
ws.connected = false;
|
|
5983
|
+
try {
|
|
5984
|
+
conn.close();
|
|
5985
|
+
} catch {
|
|
5986
|
+
}
|
|
5987
|
+
reject(new Error(`send subscribe: ${sendErr instanceof Error ? sendErr.message : String(sendErr)}`));
|
|
5988
|
+
return;
|
|
4937
5989
|
}
|
|
4938
|
-
reject(new Error(`send subscribe: ${sendErr instanceof Error ? sendErr.message : String(sendErr)}`));
|
|
4939
|
-
return;
|
|
4940
5990
|
}
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
5991
|
+
ws.cfg.onConnect();
|
|
5992
|
+
console.log(`[acosmi-sdk] websocket connected, connId=${welcome.connId ?? ""}`);
|
|
5993
|
+
resolve();
|
|
5994
|
+
}).catch(reject);
|
|
4945
5995
|
} catch (parseErr) {
|
|
4946
5996
|
clearTimeout(handshakeTimer);
|
|
4947
5997
|
try {
|
|
@@ -4956,7 +6006,7 @@ async function wsConnectOnce(c, ws) {
|
|
|
4956
6006
|
async function wsLoop(c, ws) {
|
|
4957
6007
|
try {
|
|
4958
6008
|
while (true) {
|
|
4959
|
-
await wsReadLoop(ws);
|
|
6009
|
+
await wsReadLoop(c, ws);
|
|
4960
6010
|
if (ws.abort.signal.aborted) return;
|
|
4961
6011
|
if (ws.conn) {
|
|
4962
6012
|
try {
|
|
@@ -4987,7 +6037,7 @@ async function wsLoop(c, ws) {
|
|
|
4987
6037
|
ws.doneResolve();
|
|
4988
6038
|
}
|
|
4989
6039
|
}
|
|
4990
|
-
async function wsReadLoop(ws) {
|
|
6040
|
+
async function wsReadLoop(c, ws) {
|
|
4991
6041
|
const conn = ws.conn;
|
|
4992
6042
|
if (!conn) return;
|
|
4993
6043
|
return new Promise((resolve) => {
|
|
@@ -4995,10 +6045,17 @@ async function wsReadLoop(ws) {
|
|
|
4995
6045
|
try {
|
|
4996
6046
|
const data = e.data;
|
|
4997
6047
|
const event = JSON.parse(data);
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
6048
|
+
void assertCurrent(c, ws).then(() => {
|
|
6049
|
+
try {
|
|
6050
|
+
ws.cfg.onEvent(event);
|
|
6051
|
+
} catch {
|
|
6052
|
+
}
|
|
6053
|
+
}).catch(() => {
|
|
6054
|
+
try {
|
|
6055
|
+
conn.close();
|
|
6056
|
+
} catch {
|
|
6057
|
+
}
|
|
6058
|
+
});
|
|
5002
6059
|
} catch {
|
|
5003
6060
|
}
|
|
5004
6061
|
};
|
|
@@ -5211,6 +6268,7 @@ function isTerminalRemoteEvent(ev) {
|
|
|
5211
6268
|
}
|
|
5212
6269
|
|
|
5213
6270
|
// src/agent-runs/client.ts
|
|
6271
|
+
init_errors();
|
|
5214
6272
|
var agentRunsByClient = /* @__PURE__ */ new WeakMap();
|
|
5215
6273
|
Object.defineProperty(Client.prototype, "agentRuns", {
|
|
5216
6274
|
configurable: true,
|
|
@@ -5590,11 +6648,10 @@ var AgentRunsClient = class {
|
|
|
5590
6648
|
}
|
|
5591
6649
|
const resp = await this.client.doRequest({ method, url, headers, body: bodyStr }, signal);
|
|
5592
6650
|
if (resp.status === 401 && opts.retryOn401 && !retried) {
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
await this.client.forceRefresh(signal);
|
|
6651
|
+
const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
|
|
6652
|
+
const authError = parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
|
|
6653
|
+
if (!isUserAccessTokenRejected(authError)) throw authError;
|
|
6654
|
+
await this.client.forceRefresh(signal, token);
|
|
5598
6655
|
return this.requestRawInner(method, path, body, signal, opts, true);
|
|
5599
6656
|
}
|
|
5600
6657
|
if (resp.status < 200 || resp.status >= 300) {
|
|
@@ -6221,6 +7278,7 @@ function isComplianceBusinessError(err) {
|
|
|
6221
7278
|
}
|
|
6222
7279
|
|
|
6223
7280
|
// src/compliance/client.ts
|
|
7281
|
+
init_errors();
|
|
6224
7282
|
var cache = /* @__PURE__ */ new WeakMap();
|
|
6225
7283
|
Object.defineProperty(Client.prototype, "compliance", {
|
|
6226
7284
|
configurable: true,
|
|
@@ -7037,11 +8095,10 @@ var ComplianceClient = class {
|
|
|
7037
8095
|
}
|
|
7038
8096
|
const resp = await this.client.doRequest({ method, url, headers, body: bodyStr }, signal);
|
|
7039
8097
|
if (resp.status === 401 && opts.retryOn401 && !retried) {
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
await this.client.forceRefresh(signal);
|
|
8098
|
+
const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
|
|
8099
|
+
const authError = parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
|
|
8100
|
+
if (!isUserAccessTokenRejected(authError)) throw authError;
|
|
8101
|
+
await this.client.forceRefresh(signal, token);
|
|
7045
8102
|
return this.executeJsonInner(method, path, body, signal, opts, true);
|
|
7046
8103
|
}
|
|
7047
8104
|
if (resp.status < 200 || resp.status >= 300) {
|
|
@@ -7812,6 +8869,6 @@ function brandCredential(c) {
|
|
|
7812
8869
|
return c;
|
|
7813
8870
|
}
|
|
7814
8871
|
|
|
7815
|
-
export { AGENT_RUN_META_TITLE, AGENT_RUN_META_WORKSPACE, ALL_INTEGRATION_STATUS, ALL_PLATFORMS, ALL_REGIONS, AgentRunStreamError, AgentRunsClient, AnthropicAdapter, AudienceEnum, BillingModeEnum, BucketClassCommercial, BucketClassGeneric, BusinessError, CHAT_REQUEST_TIMEOUT_MS, ChatBridgeClient, Client, ComplianceClient, CompliancePollError, CrabCodeByokClient, DEFAULT_API_TIMEOUT_MS, DEFAULT_GATEWAY_BASE_URL, DefaultRetryPolicy, ErrAuthDenied, ErrBillingCallbackCannotCommit, ErrBillingCommitRequiresLocalVerify, ErrBillingS2sForbidden, ErrBrowserOpen, ErrComplianceStepUpRequired, ErrDiscovery, ErrEnvelopeGateClosed, ErrOAuthCORSBlocked, ErrProviderNotConfigured, ErrProviderUnknownNoRetry, ErrRefreshProxyFailed, ErrRegistration, ErrSSLProxy, ErrSealApprovalContractHashMismatch, ErrSealApprovalExpired, ErrSealApprovalLocationMismatch, ErrSealApprovalNonceUsed, ErrSealApprovalNotApproved, ErrSealApprovalSealMismatch, ErrSealApprovalTransactorMismatch, ErrSealUseAlreadyConsumed, ErrStateMismatch, ErrTimeout, ErrTokenExchange, ErrTokenExpired, EventAuthURL, EventComplete, EventError, FileTokenStore, FilterStatusAdminBypass, FilterStatusDisabledByFlag, FilterStatusFallbackMissingUser, FilterStatusFallbackNoBuckets, FilterStatusFallbackTkdistError, FilterStatusFallbackTkdistSkew, FilterStatusInternalBypass, FilterStatusOK, FilterStatusUnknown, HTTPError, IdempotencyKeyHeader, InMemoryTokenStore, LocalStorageTokenStore, ModelNotFoundError, NetworkError, OAuthTokenEndpointError, OpenAIAdapter, OrderTerminalError, ProductFamilyEnum, ProviderFormat, RETRY_ADVICE_REASONS, RateLimitError, RegionScopeEnum, ScopeAI, ScopeAccount, ScopeAgentAccessManage, ScopeChatBridge, ScopeChatBridgeRead, ScopeChatBridgeRotate, ScopeChatBridgeWrite, ScopeComplianceContractSigningRead, ScopeComplianceContractSigningWrite, ScopeComplianceContractTemplateRead, ScopeComplianceContractTemplateWrite, ScopeComplianceEvidenceRead, ScopeComplianceEvidenceWrite, ScopeComplianceReportsPublish, ScopeComplianceReportsRead, ScopeComplianceReportsWrite, ScopeComplianceSealApprovalApprove, ScopeComplianceSealApprovalRequest, ScopeComplianceSealManage, ScopeComplianceSealUseExecute, ScopeComplianceTimestampIssue, ScopeComplianceTimestampVerify, ScopeEntitlements, ScopeModels, ScopeModelsChat, ScopeProfile, ScopeRemoteControl, ScopeRemoteControlAgentRun, ScopeRemoteControlPermissionResponse, ScopeRemoteControlSessionControl, ScopeSkillStore, ScopeSkills, ScopeTokenPackages, ScopeTools, ScopeToolsExecute, ScopeWallet, ScopeWalletReadonly, ServerToolTypeWebSearch, StreamError, ThinkingHigh, ThinkingHighMinMaxTokens, ThinkingMax, ThinkingMaxFallbackMaxTokens, ThinkingOff, agentAccessScopes, allScopes, anthropicResponseTextContent, anthropicResponseThinkingContent, anthropicResponseToolUseBlocks, apiResponseBusinessError, apiResponseGetMessage, asCredentialRef, authorize, bucketInfoIsCommercial, bucketRowIsCommercial, buildBetas, chatBridgeScopes, classifyComplianceError, classifySourcesEvent, commerceScopes, completeWebAuthorizationRequest, complianceErrorToRetryAdvice, complianceScopes, computeBackoff, createWebAuthorizationRequest, defaultRetryable, defaultSafeToRetry, discover, discoverWebOAuthMetadata, discoverWithProfile, effectivePolicy, exchangeCode, extractAnthropicBlockMeta, fileLockDefaults, findDesktopVisualUnderstandingModel, findFirstModelByInputModality, generateState, getAdapter, getAdapterForModel, getWindowLimitStreamDetails, isBillingConfirmable, isChannelInboundEvent, isComplianceBusinessError, isComplianceTerminalError, isContinuableWindowLimitError, isIntegrationStatus, isInvalidGrantError, isPlatform, isRegion, isSSECommentLine, isSSLError, isTerminalRemoteEvent, isValidTokenSet, isWindowLimitError, isWindowLimitStreamError, maxEndUserIdLength, modelScopes, modelSupportsImageInput, modelSupportsInputModality, newFileTokenStore, newThinkingConfig, newTokenSet, newWebSearchTool, normalizeGatewayBaseURL, normalizeOverrideBaseURL, parseNotificationEvent, parseRemoteControlEvent, parseSettlement, parseSourcesEvent, refreshToken, register, registerWebOAuthClient, remoteControlScopes, retryReasonForComplianceKey, retryReasonForOAuthError, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge, validateEndUserId };
|
|
8872
|
+
export { AGENT_RUN_META_TITLE, AGENT_RUN_META_WORKSPACE, ALL_INTEGRATION_STATUS, ALL_PLATFORMS, ALL_REGIONS, AgentRunStreamError, AgentRunsClient, AnthropicAdapter, AudienceEnum, BillingModeEnum, BucketClassCommercial, BucketClassGeneric, BusinessError, CHAT_REQUEST_TIMEOUT_MS, ChatBridgeClient, Client, ComplianceClient, CompliancePollError, CrabCodeByokClient, DEFAULT_API_TIMEOUT_MS, DEFAULT_GATEWAY_BASE_URL, DefaultRetryPolicy, ErrAuthDenied, ErrBillingCallbackCannotCommit, ErrBillingCommitRequiresLocalVerify, ErrBillingS2sForbidden, ErrBrowserOpen, ErrComplianceStepUpRequired, ErrDiscovery, ErrEnvelopeGateClosed, ErrOAuthCORSBlocked, ErrProviderNotConfigured, ErrProviderUnknownNoRetry, ErrRefreshProxyFailed, ErrRegistration, ErrSSLProxy, ErrSealApprovalContractHashMismatch, ErrSealApprovalExpired, ErrSealApprovalLocationMismatch, ErrSealApprovalNonceUsed, ErrSealApprovalNotApproved, ErrSealApprovalSealMismatch, ErrSealApprovalTransactorMismatch, ErrSealUseAlreadyConsumed, ErrStateMismatch, ErrTimeout, ErrTokenExchange, ErrTokenExpired, EventAuthURL, EventComplete, EventError, FileTokenStore, FilterStatusAdminBypass, FilterStatusDisabledByFlag, FilterStatusFallbackMissingUser, FilterStatusFallbackNoBuckets, FilterStatusFallbackTkdistError, FilterStatusFallbackTkdistSkew, FilterStatusInternalBypass, FilterStatusOK, FilterStatusUnknown, GATEWAY_REQUEST_ID_HEADER, HTTPError, IdempotencyKeyHeader, InMemoryTokenStore, LocalStorageTokenStore, ModelNotFoundError, NetworkError, OAuthTokenEndpointError, OpenAIAdapter, OrderTerminalError, ProductFamilyEnum, ProviderFormat, RETRY_ADVICE_REASONS, RateLimitError, RegionScopeEnum, ScopeAI, ScopeAccount, ScopeAgentAccessManage, ScopeChatBridge, ScopeChatBridgeRead, ScopeChatBridgeRotate, ScopeChatBridgeWrite, ScopeComplianceContractSigningRead, ScopeComplianceContractSigningWrite, ScopeComplianceContractTemplateRead, ScopeComplianceContractTemplateWrite, ScopeComplianceEvidenceRead, ScopeComplianceEvidenceWrite, ScopeComplianceReportsPublish, ScopeComplianceReportsRead, ScopeComplianceReportsWrite, ScopeComplianceSealApprovalApprove, ScopeComplianceSealApprovalRequest, ScopeComplianceSealManage, ScopeComplianceSealUseExecute, ScopeComplianceTimestampIssue, ScopeComplianceTimestampVerify, ScopeEntitlements, ScopeModels, ScopeModelsChat, ScopeProfile, ScopeRemoteControl, ScopeRemoteControlAgentRun, ScopeRemoteControlPermissionResponse, ScopeRemoteControlSessionControl, ScopeSkillStore, ScopeSkills, ScopeTokenPackages, ScopeTools, ScopeToolsExecute, ScopeWallet, ScopeWalletReadonly, ServerToolTypeWebSearch, StreamError, ThinkingHigh, ThinkingHighMinMaxTokens, ThinkingMax, ThinkingMaxFallbackMaxTokens, ThinkingOff, agentAccessScopes, allScopes, anthropicResponseTextContent, anthropicResponseThinkingContent, anthropicResponseToolUseBlocks, apiResponseBusinessError, apiResponseGetMessage, asCredentialRef, authorize, bucketInfoIsCommercial, bucketRowIsCommercial, buildBetas, chatBridgeScopes, classifyComplianceError, classifySourcesEvent, commerceScopes, completeWebAuthorizationRequest, complianceErrorToRetryAdvice, complianceScopes, computeBackoff, createWebAuthorizationRequest, defaultRetryable, defaultSafeToRetry, discover, discoverWebOAuthMetadata, discoverWithProfile, effectivePolicy, exchangeCode, extractAnthropicBlockMeta, fileLockDefaults, findDesktopVisualUnderstandingModel, findFirstModelByInputModality, generateState, getAdapter, getAdapterForModel, getWindowLimitStreamDetails, isBillingConfirmable, isChannelInboundEvent, isComplianceBusinessError, isComplianceTerminalError, isContinuableWindowLimitError, isIntegrationStatus, isInvalidGrantError, isPlatform, isRegion, isSSECommentLine, isSSLError, isTerminalRemoteEvent, isUserAccessTokenRejected, isValidTokenSet, isWindowLimitError, isWindowLimitStreamError, maxEndUserIdLength, modelScopes, modelSupportsImageInput, modelSupportsInputModality, newFileTokenStore, newThinkingConfig, newTokenSet, newWebSearchTool, normalizeGatewayBaseURL, normalizeOverrideBaseURL, parseNotificationEvent, parseRemoteControlEvent, parseSettlement, parseSourcesEvent, readGatewayErrorContract, refreshToken, register, registerWebOAuthClient, remoteControlScopes, retryReasonForComplianceKey, retryReasonForOAuthError, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge, validateEndUserId };
|
|
7816
8873
|
//# sourceMappingURL=index.mjs.map
|
|
7817
8874
|
//# sourceMappingURL=index.mjs.map
|