dsh-opendesign-corouter 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/SECURITY.md +3 -2
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/lib/adapter.d.ts +1 -1
- package/lib/auth.d.ts +18 -3
- package/lib/client.d.ts +12 -4
- package/lib/client.js +224 -117
- package/lib/device-auth.d.ts +34 -0
- package/lib/generated/typert.host.js +77 -57
- package/lib/generated/typert.remote-client.js +77 -57
- package/lib/index.d.ts +5 -1
- package/lib/index.js +628 -389
- package/lib/index.js.map +4 -4
- package/lib/login.d.ts +21 -131
- package/lib/model-settings.d.ts +3 -3
- package/lib/quota.d.ts +6 -0
- package/lib/remote.d.ts +4 -0
- package/package.json +2 -2
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface DeviceTokens {
|
|
2
|
+
controlKey: string;
|
|
3
|
+
runtimeKey: string;
|
|
4
|
+
}
|
|
5
|
+
export declare const DEVICE_AUTH_ENDPOINT = "https://amr-api.open-design.ai/api/v1/cli/device-authorizations";
|
|
6
|
+
export declare const DEVICE_AUTH_PLUGIN_VERSION = "0.1.4";
|
|
7
|
+
export declare const DEVICE_REQUEST_TIMEOUT_MS = 20000;
|
|
8
|
+
export declare const DEVICE_RESPONSE_MAX_BYTES = 65536;
|
|
9
|
+
export declare const DEVICE_POLL_MIN_MS = 1000;
|
|
10
|
+
export declare const DEVICE_POLL_MAX_MS = 300000;
|
|
11
|
+
export declare class DeviceAuthError extends Error {
|
|
12
|
+
readonly code: string;
|
|
13
|
+
constructor(code: string);
|
|
14
|
+
}
|
|
15
|
+
/** Strict public-link allowlist: only an optional, single, non-secret code is allowed. */
|
|
16
|
+
export declare function validateActivationUrl(value: unknown, userCode?: string): string | null;
|
|
17
|
+
export interface DeviceAuthorization {
|
|
18
|
+
deviceId: string;
|
|
19
|
+
deviceSecret: string;
|
|
20
|
+
userCode: string;
|
|
21
|
+
activationUrl: string;
|
|
22
|
+
pollMs: number;
|
|
23
|
+
expiresAt: number;
|
|
24
|
+
}
|
|
25
|
+
export declare function parseDeviceAuthorization(value: unknown): DeviceAuthorization;
|
|
26
|
+
export type DevicePollResult = {
|
|
27
|
+
state: 'pending';
|
|
28
|
+
} | {
|
|
29
|
+
state: 'success';
|
|
30
|
+
tokens: DeviceTokens;
|
|
31
|
+
};
|
|
32
|
+
export declare function parseDevicePoll(value: unknown): DevicePollResult;
|
|
33
|
+
/** Bound fetch *and body consumption*, even if an injected transport ignores abort. */
|
|
34
|
+
export declare function postDeviceJson(fetcher: typeof fetch, url: string, body: unknown, signal: AbortSignal, timeoutMs?: number): Promise<unknown>;
|
|
@@ -7,60 +7,70 @@ function record(value) {
|
|
|
7
7
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
// src/device-auth.ts
|
|
11
|
+
function validateActivationUrl(value, userCode) {
|
|
12
|
+
if (typeof value !== "string" || value.length > 512 || !/^https:\/\/open-design\.ai\/cloud\/cli\/activate(?:\?[^#]*)?$/u.test(value) || /[\s\\]/u.test(value)) return null;
|
|
13
|
+
try {
|
|
14
|
+
const url = new URL(value);
|
|
15
|
+
if (url.origin !== "https://open-design.ai" || url.pathname !== "/cloud/cli/activate" || url.username || url.password || url.hash) return null;
|
|
16
|
+
const entries = [...url.searchParams];
|
|
17
|
+
if (entries.length > 1) return null;
|
|
18
|
+
if (entries.length) {
|
|
19
|
+
const entry = entries[0];
|
|
20
|
+
if (!["code", "user_code"].includes(entry[0]) || !validUserCode(entry[1]) || userCode !== void 0 && entry[1] !== userCode) return null;
|
|
21
|
+
}
|
|
22
|
+
return url.href;
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function validUserCode(value) {
|
|
28
|
+
return typeof value === "string" && /^[a-z0-9][a-z0-9-]{3,31}$/iu.test(value);
|
|
29
|
+
}
|
|
30
|
+
|
|
10
31
|
// src/protocol-options.ts
|
|
11
32
|
var API_PROTOCOL_IDS = ["chat-completions", "responses", "messages"];
|
|
12
33
|
|
|
13
34
|
// src/model-settings.ts
|
|
14
|
-
var MAX_ENTRIES = 512;
|
|
15
|
-
var MAX_MODEL_ID_LENGTH = 128;
|
|
16
|
-
var MODEL_ID = /^[A-Za-z0-9._:/-]{1,128}$/u;
|
|
17
|
-
var MAX_TEMPERATURE = 2;
|
|
18
|
-
var MAX_TOP_P = 1;
|
|
19
|
-
var MAX_TOKENS = 1e7;
|
|
20
|
-
var MAX_CONTEXT_WINDOW = 1e8;
|
|
21
|
-
var REASONING_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"];
|
|
22
|
-
var RESERVED_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
23
|
-
var SETTINGS_FIELDS = /* @__PURE__ */ new Set(["enabled", "temperature", "topP", "maxTokens", "contextWindow", "reasoningEffort"]);
|
|
24
|
-
function flag(value) {
|
|
25
|
-
if (typeof value !== "boolean") throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C");
|
|
26
|
-
return value;
|
|
27
|
-
}
|
|
28
|
-
function bounded(value, max, label) {
|
|
29
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${label} \u5FC5\u987B\u662F 0 \u5230 ${max} \u4E4B\u95F4\u7684\u6709\u9650\u6570\u5B57`);
|
|
30
|
-
return value;
|
|
31
|
-
}
|
|
32
|
-
function capacity(value, max, label) {
|
|
33
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${label} \u5FC5\u987B\u662F 1 \u5230 ${max} \u4E4B\u95F4\u7684\u6574\u6570`);
|
|
34
|
-
return value;
|
|
35
|
-
}
|
|
36
|
-
function effort(value) {
|
|
37
|
-
const hit = REASONING_EFFORTS.find((candidate) => candidate === value);
|
|
38
|
-
if (hit === void 0) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 reasoningEffort \u4E0D\u5728\u5141\u8BB8\u7684\u53D6\u503C\u5185");
|
|
39
|
-
return hit;
|
|
40
|
-
}
|
|
41
|
-
function settingsOf(value) {
|
|
42
|
-
if (!record(value)) throw new Error("\u6BCF\u4E2A\u6A21\u578B\u7684\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
43
|
-
for (const field of Object.keys(value)) {
|
|
44
|
-
if (!SETTINGS_FIELDS.has(field)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u542B\u6709\u4E0D\u652F\u6301\u7684\u5B57\u6BB5");
|
|
45
|
-
}
|
|
46
|
-
const out = {};
|
|
47
|
-
if (value.enabled !== void 0) out.enabled = flag(value.enabled);
|
|
48
|
-
if (value.temperature !== void 0) out.temperature = bounded(value.temperature, MAX_TEMPERATURE, "temperature");
|
|
49
|
-
if (value.topP !== void 0) out.topP = bounded(value.topP, MAX_TOP_P, "topP");
|
|
50
|
-
if (value.maxTokens !== void 0) out.maxTokens = capacity(value.maxTokens, MAX_TOKENS, "maxTokens");
|
|
51
|
-
if (value.contextWindow !== void 0) out.contextWindow = capacity(value.contextWindow, MAX_CONTEXT_WINDOW, "contextWindow");
|
|
52
|
-
if (value.reasoningEffort !== void 0) out.reasoningEffort = effort(value.reasoningEffort);
|
|
53
|
-
return out;
|
|
54
|
-
}
|
|
55
35
|
function parseModelSettingsMap(value) {
|
|
56
|
-
if (
|
|
36
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
57
37
|
const keys = Object.keys(value);
|
|
58
|
-
if (keys.length >
|
|
38
|
+
if (keys.length > 512) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u6700\u591A\u5141\u8BB8 512 \u4E2A\u6A21\u578B");
|
|
39
|
+
const fields = /* @__PURE__ */ new Set(["enabled", "temperature", "topP", "maxTokens", "contextWindow", "reasoningEffort"]);
|
|
40
|
+
const efforts = ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"];
|
|
59
41
|
const out = {};
|
|
60
42
|
for (const id of keys) {
|
|
61
|
-
if (
|
|
62
|
-
if (
|
|
63
|
-
|
|
43
|
+
if (["__proto__", "constructor", "prototype"].includes(id)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u4E0D\u5141\u8BB8\u4FDD\u7559\u5B57\u6BB5\u540D");
|
|
44
|
+
if (!/^[A-Za-z0-9._:/-]{1,128}$/u.test(id)) throw new Error("\u6A21\u578B ID \u5FC5\u987B\u662F 1\u2013128 \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u6216 . _ : / -");
|
|
45
|
+
const entry = value[id];
|
|
46
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) throw new Error("\u6BCF\u4E2A\u6A21\u578B\u7684\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
47
|
+
const settings = entry;
|
|
48
|
+
for (const field of Object.keys(settings)) {
|
|
49
|
+
if (!fields.has(field)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u542B\u6709\u4E0D\u652F\u6301\u7684\u5B57\u6BB5");
|
|
50
|
+
}
|
|
51
|
+
const parsed = {};
|
|
52
|
+
if (settings.enabled !== void 0) {
|
|
53
|
+
if (typeof settings.enabled !== "boolean") throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C");
|
|
54
|
+
parsed.enabled = settings.enabled;
|
|
55
|
+
}
|
|
56
|
+
for (const [field, max] of [["temperature", 2], ["topP", 1]]) {
|
|
57
|
+
const item = settings[field];
|
|
58
|
+
if (item === void 0) continue;
|
|
59
|
+
if (typeof item !== "number" || !Number.isFinite(item) || item < 0 || item > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${field} \u5FC5\u987B\u662F 0 \u5230 ${max} \u4E4B\u95F4\u7684\u6709\u9650\u6570\u5B57`);
|
|
60
|
+
parsed[field] = item;
|
|
61
|
+
}
|
|
62
|
+
for (const [field, max] of [["maxTokens", 1e7], ["contextWindow", 1e8]]) {
|
|
63
|
+
const item = settings[field];
|
|
64
|
+
if (item === void 0) continue;
|
|
65
|
+
if (typeof item !== "number" || !Number.isSafeInteger(item) || item < 1 || item > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${field} \u5FC5\u987B\u662F 1 \u5230 ${max} \u4E4B\u95F4\u7684\u6574\u6570`);
|
|
66
|
+
parsed[field] = item;
|
|
67
|
+
}
|
|
68
|
+
if (settings.reasoningEffort !== void 0) {
|
|
69
|
+
if (typeof settings.reasoningEffort !== "string" || !efforts.includes(settings.reasoningEffort)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 reasoningEffort \u4E0D\u5728\u5141\u8BB8\u7684\u53D6\u503C\u5185");
|
|
70
|
+
parsed.reasoningEffort = settings.reasoningEffort;
|
|
71
|
+
}
|
|
72
|
+
if (parsed.maxTokens !== void 0 && parsed.contextWindow !== void 0 && parsed.maxTokens >= parsed.contextWindow) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 maxTokens \u5FC5\u987B\u5C0F\u4E8E contextWindow");
|
|
73
|
+
out[id] = parsed;
|
|
64
74
|
}
|
|
65
75
|
return out;
|
|
66
76
|
}
|
|
@@ -78,7 +88,7 @@ var MAX_WINDOWS = 64;
|
|
|
78
88
|
var MAX_API_KEY = 16384;
|
|
79
89
|
var HTTP_ASCII = /^[\x21-\x7e]+$/u;
|
|
80
90
|
var ENV_REF = /^[A-Za-z_][A-Za-z0-9_]*$/u;
|
|
81
|
-
var
|
|
91
|
+
var MODEL_ID = /^[A-Za-z0-9._:/-]{1,128}$/u;
|
|
82
92
|
var LOGIN_PHASES = ["idle", "launching", "waiting", "verifying", "success", "cancelled", "error"];
|
|
83
93
|
var QUOTA_STATES = ["ok", "partial", "need-login", "error"];
|
|
84
94
|
var SESSION_SOURCES = ["desktop", "login", "environment"];
|
|
@@ -92,7 +102,7 @@ function isoTime(value, label) {
|
|
|
92
102
|
if (!Number.isFinite(Date.parse(time))) throw new Error(`${label} \u5FC5\u987B\u662F ISO \u65F6\u95F4\u5B57\u7B26\u4E32`);
|
|
93
103
|
return time;
|
|
94
104
|
}
|
|
95
|
-
function
|
|
105
|
+
function flag(value, label) {
|
|
96
106
|
if (typeof value !== "boolean") throw new Error(`${label} \u5FC5\u987B\u662F\u5E03\u5C14\u503C`);
|
|
97
107
|
return value;
|
|
98
108
|
}
|
|
@@ -148,11 +158,11 @@ function parseQuotaSnapshot(value) {
|
|
|
148
158
|
...value.subscriptionPeriodStart === void 0 ? {} : { subscriptionPeriodStart: isoTime(value.subscriptionPeriodStart, "\u8BA2\u9605\u5468\u671F\u5F00\u59CB\u65F6\u95F4") },
|
|
149
159
|
...value.subscriptionPeriodEnd === void 0 ? {} : { subscriptionPeriodEnd: isoTime(value.subscriptionPeriodEnd, "\u8BA2\u9605\u5468\u671F\u7ED3\u675F\u65F6\u95F4") },
|
|
150
160
|
...value.nextRefreshAt === void 0 ? {} : { nextRefreshAt: isoTime(value.nextRefreshAt, "\u4E0B\u6B21\u81EA\u52A8\u5237\u65B0\u65F6\u95F4") },
|
|
151
|
-
...value.stale === void 0 ? {} : { stale:
|
|
161
|
+
...value.stale === void 0 ? {} : { stale: flag(value.stale, "\u5386\u53F2\u989D\u5EA6\u8BFB\u6570") },
|
|
152
162
|
...value.refreshFailures === void 0 ? {} : { refreshFailures: count(value.refreshFailures, "\u8FDE\u7EED\u5237\u65B0\u5931\u8D25\u6B21\u6570") },
|
|
153
|
-
...value.autoRefreshPaused === void 0 ? {} : { autoRefreshPaused:
|
|
163
|
+
...value.autoRefreshPaused === void 0 ? {} : { autoRefreshPaused: flag(value.autoRefreshPaused, "\u81EA\u52A8\u5237\u65B0\u6682\u505C\u72B6\u6001") },
|
|
154
164
|
...value.tier === void 0 ? {} : { tier: text(value.tier, "\u5957\u9910\u540D", MAX_TIER) },
|
|
155
|
-
...value.eligible === void 0 ? {} : { eligible:
|
|
165
|
+
...value.eligible === void 0 ? {} : { eligible: flag(value.eligible, "\u5957\u9910\u8D44\u683C") },
|
|
156
166
|
windows: windows.map(parseQuotaWindow),
|
|
157
167
|
balances: {
|
|
158
168
|
...balances.subscriptionUsd === void 0 ? {} : { subscriptionUsd: amount(balances.subscriptionUsd, "\u8BA2\u9605\u4F59\u989D") },
|
|
@@ -166,9 +176,19 @@ function parseLoginState(value) {
|
|
|
166
176
|
if (!record(value)) throw new Error("\u767B\u5F55\u72B6\u6001\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
167
177
|
const jobId = value.jobId;
|
|
168
178
|
if (jobId !== null && jobId !== void 0 && typeof jobId !== "string") throw new Error("\u767B\u5F55\u4EFB\u52A1 id \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216 null");
|
|
179
|
+
const state = member(value.state, LOGIN_PHASES, "\u767B\u5F55\u9636\u6BB5");
|
|
180
|
+
let approval = {};
|
|
181
|
+
if (state === "waiting" && (value.activationUrl !== void 0 || value.userCode !== void 0 || value.expiresAt !== void 0)) {
|
|
182
|
+
const userCode = text(value.userCode, "\u8BBE\u5907\u6388\u6743\u7801", 64);
|
|
183
|
+
if (!/^[A-Za-z0-9-]+$/u.test(userCode)) throw new Error("\u8BBE\u5907\u6388\u6743\u7801\u683C\u5F0F\u65E0\u6548");
|
|
184
|
+
const activationUrl = validateActivationUrl(value.activationUrl, userCode);
|
|
185
|
+
if (activationUrl === null) throw new Error("\u8BBE\u5907\u6388\u6743\u94FE\u63A5\u65E0\u6548");
|
|
186
|
+
approval = { activationUrl, userCode, expiresAt: isoTime(value.expiresAt, "\u8BBE\u5907\u6388\u6743\u5230\u671F\u65F6\u95F4") };
|
|
187
|
+
}
|
|
169
188
|
return {
|
|
170
189
|
jobId: typeof jobId === "string" && jobId.length > 0 ? text(jobId, "\u767B\u5F55\u4EFB\u52A1 id", MAX_JOB_ID) : null,
|
|
171
|
-
state
|
|
190
|
+
state,
|
|
191
|
+
...approval,
|
|
172
192
|
...value.message === void 0 ? {} : { message: text(value.message, "\u767B\u5F55\u8BF4\u660E", MAX_MESSAGE) },
|
|
173
193
|
...value.startedAt === void 0 ? {} : { startedAt: isoTime(value.startedAt, "\u767B\u5F55\u5F00\u59CB\u65F6\u95F4") },
|
|
174
194
|
...value.finishedAt === void 0 ? {} : { finishedAt: isoTime(value.finishedAt, "\u767B\u5F55\u7ED3\u675F\u65F6\u95F4") }
|
|
@@ -177,12 +197,12 @@ function parseLoginState(value) {
|
|
|
177
197
|
function parseStatusModel(value) {
|
|
178
198
|
if (!record(value)) throw new Error("\u6A21\u578B\u6761\u76EE\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
179
199
|
const id = text(value.id, "\u6A21\u578B id", 128);
|
|
180
|
-
if (!
|
|
200
|
+
if (!MODEL_ID.test(id)) throw new Error("\u6A21\u578B id \u542B\u4E0D\u5141\u8BB8\u7684\u5B57\u7B26");
|
|
181
201
|
return {
|
|
182
202
|
id,
|
|
183
203
|
name: text(value.name, "\u6A21\u578B\u540D", 128),
|
|
184
204
|
group: member(value.group, MODEL_GROUPS, "\u6A21\u578B\u5206\u7EC4"),
|
|
185
|
-
...value.enabled === void 0 ? {} : { enabled:
|
|
205
|
+
...value.enabled === void 0 ? {} : { enabled: flag(value.enabled, "\u6A21\u578B\u542F\u7528\u72B6\u6001") },
|
|
186
206
|
...value.contextWindow === void 0 ? {} : { contextWindow: positiveInteger(value.contextWindow, "\u4E0A\u4E0B\u6587\u9884\u7B97", 1e8) },
|
|
187
207
|
...value.maxOutputTokens === void 0 ? {} : { maxOutputTokens: positiveInteger(value.maxOutputTokens, "\u6700\u5927\u8F93\u51FA", 1e7) },
|
|
188
208
|
...value.reasoningEfforts === void 0 ? {} : { reasoningEfforts: parseEfforts(value.reasoningEfforts) }
|
|
@@ -193,8 +213,8 @@ function parseStatusConfig(value) {
|
|
|
193
213
|
const apiKeyEnv = text(value.apiKeyEnv, "\u51ED\u636E\u5F15\u7528\u540D", MAX_ENV_REF);
|
|
194
214
|
if (!ENV_REF.test(apiKeyEnv)) throw new Error("\u51ED\u636E\u5F15\u7528\u540D\u5FC5\u987B\u662F\u5408\u6CD5\u6807\u8BC6\u7B26");
|
|
195
215
|
return {
|
|
196
|
-
emptyTurnGuard:
|
|
197
|
-
useDesktopCredential:
|
|
216
|
+
emptyTurnGuard: flag(value.emptyTurnGuard, "\u7A7A\u8F6E\u4FDD\u62A4\u5F00\u5173"),
|
|
217
|
+
useDesktopCredential: flag(value.useDesktopCredential, "\u684C\u9762\u767B\u5F55\u6001\u5F00\u5173"),
|
|
198
218
|
baseURL: text(value.baseURL, "\u63A8\u7406\u5730\u5740", MAX_BASE_URL),
|
|
199
219
|
apiKeyEnv,
|
|
200
220
|
...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
|
|
@@ -216,7 +236,7 @@ function parseStatus(value) {
|
|
|
216
236
|
}
|
|
217
237
|
return {
|
|
218
238
|
revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
|
|
219
|
-
apiKeyConfigured:
|
|
239
|
+
apiKeyConfigured: flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
|
|
220
240
|
...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
|
|
221
241
|
quota: parseQuotaSnapshot(value.quota),
|
|
222
242
|
login: parseLoginState(value.login),
|
|
@@ -7,60 +7,70 @@ function record(value) {
|
|
|
7
7
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
// src/device-auth.ts
|
|
11
|
+
function validateActivationUrl(value, userCode) {
|
|
12
|
+
if (typeof value !== "string" || value.length > 512 || !/^https:\/\/open-design\.ai\/cloud\/cli\/activate(?:\?[^#]*)?$/u.test(value) || /[\s\\]/u.test(value)) return null;
|
|
13
|
+
try {
|
|
14
|
+
const url = new URL(value);
|
|
15
|
+
if (url.origin !== "https://open-design.ai" || url.pathname !== "/cloud/cli/activate" || url.username || url.password || url.hash) return null;
|
|
16
|
+
const entries = [...url.searchParams];
|
|
17
|
+
if (entries.length > 1) return null;
|
|
18
|
+
if (entries.length) {
|
|
19
|
+
const entry = entries[0];
|
|
20
|
+
if (!["code", "user_code"].includes(entry[0]) || !validUserCode(entry[1]) || userCode !== void 0 && entry[1] !== userCode) return null;
|
|
21
|
+
}
|
|
22
|
+
return url.href;
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function validUserCode(value) {
|
|
28
|
+
return typeof value === "string" && /^[a-z0-9][a-z0-9-]{3,31}$/iu.test(value);
|
|
29
|
+
}
|
|
30
|
+
|
|
10
31
|
// src/protocol-options.ts
|
|
11
32
|
var API_PROTOCOL_IDS = ["chat-completions", "responses", "messages"];
|
|
12
33
|
|
|
13
34
|
// src/model-settings.ts
|
|
14
|
-
var MAX_ENTRIES = 512;
|
|
15
|
-
var MAX_MODEL_ID_LENGTH = 128;
|
|
16
|
-
var MODEL_ID = /^[A-Za-z0-9._:/-]{1,128}$/u;
|
|
17
|
-
var MAX_TEMPERATURE = 2;
|
|
18
|
-
var MAX_TOP_P = 1;
|
|
19
|
-
var MAX_TOKENS = 1e7;
|
|
20
|
-
var MAX_CONTEXT_WINDOW = 1e8;
|
|
21
|
-
var REASONING_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"];
|
|
22
|
-
var RESERVED_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
23
|
-
var SETTINGS_FIELDS = /* @__PURE__ */ new Set(["enabled", "temperature", "topP", "maxTokens", "contextWindow", "reasoningEffort"]);
|
|
24
|
-
function flag(value) {
|
|
25
|
-
if (typeof value !== "boolean") throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C");
|
|
26
|
-
return value;
|
|
27
|
-
}
|
|
28
|
-
function bounded(value, max, label) {
|
|
29
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${label} \u5FC5\u987B\u662F 0 \u5230 ${max} \u4E4B\u95F4\u7684\u6709\u9650\u6570\u5B57`);
|
|
30
|
-
return value;
|
|
31
|
-
}
|
|
32
|
-
function capacity(value, max, label) {
|
|
33
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${label} \u5FC5\u987B\u662F 1 \u5230 ${max} \u4E4B\u95F4\u7684\u6574\u6570`);
|
|
34
|
-
return value;
|
|
35
|
-
}
|
|
36
|
-
function effort(value) {
|
|
37
|
-
const hit = REASONING_EFFORTS.find((candidate) => candidate === value);
|
|
38
|
-
if (hit === void 0) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 reasoningEffort \u4E0D\u5728\u5141\u8BB8\u7684\u53D6\u503C\u5185");
|
|
39
|
-
return hit;
|
|
40
|
-
}
|
|
41
|
-
function settingsOf(value) {
|
|
42
|
-
if (!record(value)) throw new Error("\u6BCF\u4E2A\u6A21\u578B\u7684\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
43
|
-
for (const field of Object.keys(value)) {
|
|
44
|
-
if (!SETTINGS_FIELDS.has(field)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u542B\u6709\u4E0D\u652F\u6301\u7684\u5B57\u6BB5");
|
|
45
|
-
}
|
|
46
|
-
const out = {};
|
|
47
|
-
if (value.enabled !== void 0) out.enabled = flag(value.enabled);
|
|
48
|
-
if (value.temperature !== void 0) out.temperature = bounded(value.temperature, MAX_TEMPERATURE, "temperature");
|
|
49
|
-
if (value.topP !== void 0) out.topP = bounded(value.topP, MAX_TOP_P, "topP");
|
|
50
|
-
if (value.maxTokens !== void 0) out.maxTokens = capacity(value.maxTokens, MAX_TOKENS, "maxTokens");
|
|
51
|
-
if (value.contextWindow !== void 0) out.contextWindow = capacity(value.contextWindow, MAX_CONTEXT_WINDOW, "contextWindow");
|
|
52
|
-
if (value.reasoningEffort !== void 0) out.reasoningEffort = effort(value.reasoningEffort);
|
|
53
|
-
return out;
|
|
54
|
-
}
|
|
55
35
|
function parseModelSettingsMap(value) {
|
|
56
|
-
if (
|
|
36
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
57
37
|
const keys = Object.keys(value);
|
|
58
|
-
if (keys.length >
|
|
38
|
+
if (keys.length > 512) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u6700\u591A\u5141\u8BB8 512 \u4E2A\u6A21\u578B");
|
|
39
|
+
const fields = /* @__PURE__ */ new Set(["enabled", "temperature", "topP", "maxTokens", "contextWindow", "reasoningEffort"]);
|
|
40
|
+
const efforts = ["none", "minimal", "low", "medium", "high", "xhigh", "ultra", "max"];
|
|
59
41
|
const out = {};
|
|
60
42
|
for (const id of keys) {
|
|
61
|
-
if (
|
|
62
|
-
if (
|
|
63
|
-
|
|
43
|
+
if (["__proto__", "constructor", "prototype"].includes(id)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u4E0D\u5141\u8BB8\u4FDD\u7559\u5B57\u6BB5\u540D");
|
|
44
|
+
if (!/^[A-Za-z0-9._:/-]{1,128}$/u.test(id)) throw new Error("\u6A21\u578B ID \u5FC5\u987B\u662F 1\u2013128 \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u6216 . _ : / -");
|
|
45
|
+
const entry = value[id];
|
|
46
|
+
if (entry === null || typeof entry !== "object" || Array.isArray(entry)) throw new Error("\u6BCF\u4E2A\u6A21\u578B\u7684\u8BBE\u7F6E\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
47
|
+
const settings = entry;
|
|
48
|
+
for (const field of Object.keys(settings)) {
|
|
49
|
+
if (!fields.has(field)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u542B\u6709\u4E0D\u652F\u6301\u7684\u5B57\u6BB5");
|
|
50
|
+
}
|
|
51
|
+
const parsed = {};
|
|
52
|
+
if (settings.enabled !== void 0) {
|
|
53
|
+
if (typeof settings.enabled !== "boolean") throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C");
|
|
54
|
+
parsed.enabled = settings.enabled;
|
|
55
|
+
}
|
|
56
|
+
for (const [field, max] of [["temperature", 2], ["topP", 1]]) {
|
|
57
|
+
const item = settings[field];
|
|
58
|
+
if (item === void 0) continue;
|
|
59
|
+
if (typeof item !== "number" || !Number.isFinite(item) || item < 0 || item > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${field} \u5FC5\u987B\u662F 0 \u5230 ${max} \u4E4B\u95F4\u7684\u6709\u9650\u6570\u5B57`);
|
|
60
|
+
parsed[field] = item;
|
|
61
|
+
}
|
|
62
|
+
for (const [field, max] of [["maxTokens", 1e7], ["contextWindow", 1e8]]) {
|
|
63
|
+
const item = settings[field];
|
|
64
|
+
if (item === void 0) continue;
|
|
65
|
+
if (typeof item !== "number" || !Number.isSafeInteger(item) || item < 1 || item > max) throw new Error(`\u6A21\u578B\u8BBE\u7F6E\u7684 ${field} \u5FC5\u987B\u662F 1 \u5230 ${max} \u4E4B\u95F4\u7684\u6574\u6570`);
|
|
66
|
+
parsed[field] = item;
|
|
67
|
+
}
|
|
68
|
+
if (settings.reasoningEffort !== void 0) {
|
|
69
|
+
if (typeof settings.reasoningEffort !== "string" || !efforts.includes(settings.reasoningEffort)) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 reasoningEffort \u4E0D\u5728\u5141\u8BB8\u7684\u53D6\u503C\u5185");
|
|
70
|
+
parsed.reasoningEffort = settings.reasoningEffort;
|
|
71
|
+
}
|
|
72
|
+
if (parsed.maxTokens !== void 0 && parsed.contextWindow !== void 0 && parsed.maxTokens >= parsed.contextWindow) throw new Error("\u6A21\u578B\u8BBE\u7F6E\u7684 maxTokens \u5FC5\u987B\u5C0F\u4E8E contextWindow");
|
|
73
|
+
out[id] = parsed;
|
|
64
74
|
}
|
|
65
75
|
return out;
|
|
66
76
|
}
|
|
@@ -78,7 +88,7 @@ var MAX_WINDOWS = 64;
|
|
|
78
88
|
var MAX_API_KEY = 16384;
|
|
79
89
|
var HTTP_ASCII = /^[\x21-\x7e]+$/u;
|
|
80
90
|
var ENV_REF = /^[A-Za-z_][A-Za-z0-9_]*$/u;
|
|
81
|
-
var
|
|
91
|
+
var MODEL_ID = /^[A-Za-z0-9._:/-]{1,128}$/u;
|
|
82
92
|
var LOGIN_PHASES = ["idle", "launching", "waiting", "verifying", "success", "cancelled", "error"];
|
|
83
93
|
var QUOTA_STATES = ["ok", "partial", "need-login", "error"];
|
|
84
94
|
var SESSION_SOURCES = ["desktop", "login", "environment"];
|
|
@@ -92,7 +102,7 @@ function isoTime(value, label) {
|
|
|
92
102
|
if (!Number.isFinite(Date.parse(time))) throw new Error(`${label} \u5FC5\u987B\u662F ISO \u65F6\u95F4\u5B57\u7B26\u4E32`);
|
|
93
103
|
return time;
|
|
94
104
|
}
|
|
95
|
-
function
|
|
105
|
+
function flag(value, label) {
|
|
96
106
|
if (typeof value !== "boolean") throw new Error(`${label} \u5FC5\u987B\u662F\u5E03\u5C14\u503C`);
|
|
97
107
|
return value;
|
|
98
108
|
}
|
|
@@ -148,11 +158,11 @@ function parseQuotaSnapshot(value) {
|
|
|
148
158
|
...value.subscriptionPeriodStart === void 0 ? {} : { subscriptionPeriodStart: isoTime(value.subscriptionPeriodStart, "\u8BA2\u9605\u5468\u671F\u5F00\u59CB\u65F6\u95F4") },
|
|
149
159
|
...value.subscriptionPeriodEnd === void 0 ? {} : { subscriptionPeriodEnd: isoTime(value.subscriptionPeriodEnd, "\u8BA2\u9605\u5468\u671F\u7ED3\u675F\u65F6\u95F4") },
|
|
150
160
|
...value.nextRefreshAt === void 0 ? {} : { nextRefreshAt: isoTime(value.nextRefreshAt, "\u4E0B\u6B21\u81EA\u52A8\u5237\u65B0\u65F6\u95F4") },
|
|
151
|
-
...value.stale === void 0 ? {} : { stale:
|
|
161
|
+
...value.stale === void 0 ? {} : { stale: flag(value.stale, "\u5386\u53F2\u989D\u5EA6\u8BFB\u6570") },
|
|
152
162
|
...value.refreshFailures === void 0 ? {} : { refreshFailures: count(value.refreshFailures, "\u8FDE\u7EED\u5237\u65B0\u5931\u8D25\u6B21\u6570") },
|
|
153
|
-
...value.autoRefreshPaused === void 0 ? {} : { autoRefreshPaused:
|
|
163
|
+
...value.autoRefreshPaused === void 0 ? {} : { autoRefreshPaused: flag(value.autoRefreshPaused, "\u81EA\u52A8\u5237\u65B0\u6682\u505C\u72B6\u6001") },
|
|
154
164
|
...value.tier === void 0 ? {} : { tier: text(value.tier, "\u5957\u9910\u540D", MAX_TIER) },
|
|
155
|
-
...value.eligible === void 0 ? {} : { eligible:
|
|
165
|
+
...value.eligible === void 0 ? {} : { eligible: flag(value.eligible, "\u5957\u9910\u8D44\u683C") },
|
|
156
166
|
windows: windows.map(parseQuotaWindow),
|
|
157
167
|
balances: {
|
|
158
168
|
...balances.subscriptionUsd === void 0 ? {} : { subscriptionUsd: amount(balances.subscriptionUsd, "\u8BA2\u9605\u4F59\u989D") },
|
|
@@ -166,9 +176,19 @@ function parseLoginState(value) {
|
|
|
166
176
|
if (!record(value)) throw new Error("\u767B\u5F55\u72B6\u6001\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
167
177
|
const jobId = value.jobId;
|
|
168
178
|
if (jobId !== null && jobId !== void 0 && typeof jobId !== "string") throw new Error("\u767B\u5F55\u4EFB\u52A1 id \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6216 null");
|
|
179
|
+
const state = member(value.state, LOGIN_PHASES, "\u767B\u5F55\u9636\u6BB5");
|
|
180
|
+
let approval = {};
|
|
181
|
+
if (state === "waiting" && (value.activationUrl !== void 0 || value.userCode !== void 0 || value.expiresAt !== void 0)) {
|
|
182
|
+
const userCode = text(value.userCode, "\u8BBE\u5907\u6388\u6743\u7801", 64);
|
|
183
|
+
if (!/^[A-Za-z0-9-]+$/u.test(userCode)) throw new Error("\u8BBE\u5907\u6388\u6743\u7801\u683C\u5F0F\u65E0\u6548");
|
|
184
|
+
const activationUrl = validateActivationUrl(value.activationUrl, userCode);
|
|
185
|
+
if (activationUrl === null) throw new Error("\u8BBE\u5907\u6388\u6743\u94FE\u63A5\u65E0\u6548");
|
|
186
|
+
approval = { activationUrl, userCode, expiresAt: isoTime(value.expiresAt, "\u8BBE\u5907\u6388\u6743\u5230\u671F\u65F6\u95F4") };
|
|
187
|
+
}
|
|
169
188
|
return {
|
|
170
189
|
jobId: typeof jobId === "string" && jobId.length > 0 ? text(jobId, "\u767B\u5F55\u4EFB\u52A1 id", MAX_JOB_ID) : null,
|
|
171
|
-
state
|
|
190
|
+
state,
|
|
191
|
+
...approval,
|
|
172
192
|
...value.message === void 0 ? {} : { message: text(value.message, "\u767B\u5F55\u8BF4\u660E", MAX_MESSAGE) },
|
|
173
193
|
...value.startedAt === void 0 ? {} : { startedAt: isoTime(value.startedAt, "\u767B\u5F55\u5F00\u59CB\u65F6\u95F4") },
|
|
174
194
|
...value.finishedAt === void 0 ? {} : { finishedAt: isoTime(value.finishedAt, "\u767B\u5F55\u7ED3\u675F\u65F6\u95F4") }
|
|
@@ -177,12 +197,12 @@ function parseLoginState(value) {
|
|
|
177
197
|
function parseStatusModel(value) {
|
|
178
198
|
if (!record(value)) throw new Error("\u6A21\u578B\u6761\u76EE\u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
179
199
|
const id = text(value.id, "\u6A21\u578B id", 128);
|
|
180
|
-
if (!
|
|
200
|
+
if (!MODEL_ID.test(id)) throw new Error("\u6A21\u578B id \u542B\u4E0D\u5141\u8BB8\u7684\u5B57\u7B26");
|
|
181
201
|
return {
|
|
182
202
|
id,
|
|
183
203
|
name: text(value.name, "\u6A21\u578B\u540D", 128),
|
|
184
204
|
group: member(value.group, MODEL_GROUPS, "\u6A21\u578B\u5206\u7EC4"),
|
|
185
|
-
...value.enabled === void 0 ? {} : { enabled:
|
|
205
|
+
...value.enabled === void 0 ? {} : { enabled: flag(value.enabled, "\u6A21\u578B\u542F\u7528\u72B6\u6001") },
|
|
186
206
|
...value.contextWindow === void 0 ? {} : { contextWindow: positiveInteger(value.contextWindow, "\u4E0A\u4E0B\u6587\u9884\u7B97", 1e8) },
|
|
187
207
|
...value.maxOutputTokens === void 0 ? {} : { maxOutputTokens: positiveInteger(value.maxOutputTokens, "\u6700\u5927\u8F93\u51FA", 1e7) },
|
|
188
208
|
...value.reasoningEfforts === void 0 ? {} : { reasoningEfforts: parseEfforts(value.reasoningEfforts) }
|
|
@@ -193,8 +213,8 @@ function parseStatusConfig(value) {
|
|
|
193
213
|
const apiKeyEnv = text(value.apiKeyEnv, "\u51ED\u636E\u5F15\u7528\u540D", MAX_ENV_REF);
|
|
194
214
|
if (!ENV_REF.test(apiKeyEnv)) throw new Error("\u51ED\u636E\u5F15\u7528\u540D\u5FC5\u987B\u662F\u5408\u6CD5\u6807\u8BC6\u7B26");
|
|
195
215
|
return {
|
|
196
|
-
emptyTurnGuard:
|
|
197
|
-
useDesktopCredential:
|
|
216
|
+
emptyTurnGuard: flag(value.emptyTurnGuard, "\u7A7A\u8F6E\u4FDD\u62A4\u5F00\u5173"),
|
|
217
|
+
useDesktopCredential: flag(value.useDesktopCredential, "\u684C\u9762\u767B\u5F55\u6001\u5F00\u5173"),
|
|
198
218
|
baseURL: text(value.baseURL, "\u63A8\u7406\u5730\u5740", MAX_BASE_URL),
|
|
199
219
|
apiKeyEnv,
|
|
200
220
|
...value.apiProtocol === void 0 ? {} : { apiProtocol: member(value.apiProtocol, API_PROTOCOL_IDS, "\u63A8\u7406\u534F\u8BAE") },
|
|
@@ -216,7 +236,7 @@ function parseStatus(value) {
|
|
|
216
236
|
}
|
|
217
237
|
return {
|
|
218
238
|
revision: text(value.revision, "\u914D\u7F6E\u7248\u672C", MAX_REVISION),
|
|
219
|
-
apiKeyConfigured:
|
|
239
|
+
apiKeyConfigured: flag(value.apiKeyConfigured, "\u51ED\u636E\u662F\u5426\u5C31\u7EEA"),
|
|
220
240
|
...value.sessionSource === void 0 ? {} : { sessionSource: member(value.sessionSource, SESSION_SOURCES, "\u767B\u5F55\u6001\u6765\u6E90") },
|
|
221
241
|
quota: parseQuotaSnapshot(value.quota),
|
|
222
242
|
login: parseLoginState(value.login),
|
package/lib/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { fetchModelCatalog } from './model-discovery.js';
|
|
|
4
4
|
import type { CatalogModel } from './catalog.js';
|
|
5
5
|
import { readConfig, type LiveConfig } from './config.js';
|
|
6
6
|
import { resolveSession } from './auth.js';
|
|
7
|
+
import { type LoginOptions } from './login.js';
|
|
7
8
|
import { readQuota, type QuotaSnapshot } from './quota.js';
|
|
8
9
|
import { readDesktopQuota } from './desktop-quota.js';
|
|
9
10
|
import { type Status, type LoginState, type StartLoginRequest, type CancelLoginRequest, type SaveApiKeyRequest } from './remote.js';
|
|
@@ -18,6 +19,7 @@ export interface HostDependencies {
|
|
|
18
19
|
readDesktopQuota: typeof readDesktopQuota;
|
|
19
20
|
fetchModels?: typeof fetchModelCatalog;
|
|
20
21
|
modelsChanged?: () => void;
|
|
22
|
+
loginOptions?: LoginOptions;
|
|
21
23
|
}
|
|
22
24
|
export declare class OpenDesignCoRouterService extends TypertRemoteService {
|
|
23
25
|
readonly dependencies: HostDependencies;
|
|
@@ -44,7 +46,9 @@ export declare class OpenDesignCoRouterService extends TypertRemoteService {
|
|
|
44
46
|
modelCatalog(): readonly CatalogModel[];
|
|
45
47
|
constructor(ctx: Context, config: () => ReturnType<typeof readConfig>, dependencies?: HostDependencies);
|
|
46
48
|
private _credentials;
|
|
47
|
-
|
|
49
|
+
private _key;
|
|
50
|
+
resolveApiKey(ref: string, baseURL?: string): Promise<string | undefined>;
|
|
51
|
+
private _invalidateModels;
|
|
48
52
|
private _state;
|
|
49
53
|
private _conflict;
|
|
50
54
|
private _expect;
|