u1s1-cli 1.14.4 → 1.14.5
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/dist/api.d.ts +2 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/device-auth.d.ts +2 -1
- package/dist/device-auth.js +29 -3
- package/dist/site.d.ts +7 -0
- package/dist/site.js +20 -1
- package/dist/usage.d.ts +5 -3
- package/dist/usage.js +7 -3
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export interface MeResponse {
|
|
|
26
26
|
free_claim?: "first" | "renew" | null;
|
|
27
27
|
/** 支付通道是否开放;老网关没有该字段,按开放处理(保留充值入口) */
|
|
28
28
|
pay_enabled?: boolean;
|
|
29
|
+
/** 拉新收口:false = 收口后注册的账号,没有打卡等活动;老网关没有该字段,按可参与处理 */
|
|
30
|
+
incentives_eligible?: boolean;
|
|
29
31
|
}
|
|
30
32
|
export interface MePackage {
|
|
31
33
|
id: number;
|
package/dist/config.d.ts
CHANGED
|
@@ -94,7 +94,7 @@ export interface ModelDef {
|
|
|
94
94
|
* 而 deepseek-flash 的窗口是 1M,会话逼近 100 万 token 才压缩——每轮 2 MB 请求体对渠道、
|
|
95
95
|
* 时延、成本都是负担(近 7 天 >200K 的请求占 28% 却吃掉 54% 采购)。所以把注册给 pi 的
|
|
96
96
|
* contextWindow 钉在 min(模型窗口, 预算),压缩、/context 百分比、溢出判定都随之按预算算。
|
|
97
|
-
*
|
|
97
|
+
* 只影响自动压缩时机,不改模型能力。
|
|
98
98
|
*/
|
|
99
99
|
export declare const DEFAULT_COMPACTION_BUDGET_TOKENS = 200000;
|
|
100
100
|
/**
|
package/dist/config.js
CHANGED
|
@@ -100,7 +100,7 @@ export const UNKNOWN_MODEL_COST = { input: 0, output: 0, cacheRead: 0, cacheWrit
|
|
|
100
100
|
* 而 deepseek-flash 的窗口是 1M,会话逼近 100 万 token 才压缩——每轮 2 MB 请求体对渠道、
|
|
101
101
|
* 时延、成本都是负担(近 7 天 >200K 的请求占 28% 却吃掉 54% 采购)。所以把注册给 pi 的
|
|
102
102
|
* contextWindow 钉在 min(模型窗口, 预算),压缩、/context 百分比、溢出判定都随之按预算算。
|
|
103
|
-
*
|
|
103
|
+
* 只影响自动压缩时机,不改模型能力。
|
|
104
104
|
*/
|
|
105
105
|
export const DEFAULT_COMPACTION_BUDGET_TOKENS = 200_000;
|
|
106
106
|
/**
|
package/dist/device-auth.d.ts
CHANGED
|
@@ -53,7 +53,7 @@ interface SigningProxy {
|
|
|
53
53
|
}
|
|
54
54
|
/** Attach a fresh (self-healing) attestation header to an outbound proxy request. */
|
|
55
55
|
export declare function attachAttestationHeader(holder: AttestationHolder, headers: Headers): Promise<void>;
|
|
56
|
-
export type ClientSurface = "terminal" | "web" | "desktop"
|
|
56
|
+
export type ClientSurface = "terminal" | "web" | "desktop";
|
|
57
57
|
/** What a failed gateway fetch looked like at the socket level; never carries request content. */
|
|
58
58
|
export interface GatewayFetchFailure {
|
|
59
59
|
/** Node/undici error code such as ECONNRESET or UND_ERR_CONNECT_TIMEOUT; "unknown" when absent. */
|
|
@@ -68,6 +68,7 @@ export interface GatewayFetchFailure {
|
|
|
68
68
|
* agent's retry patterns still match.
|
|
69
69
|
*/
|
|
70
70
|
export declare function describeFetchFailure(error: unknown): GatewayFetchFailure;
|
|
71
|
+
export declare function isConnectPhaseFailure(failure: GatewayFetchFailure): boolean;
|
|
71
72
|
/** One listener per process (telemetry); failures are reported only when the local caller is still waiting. */
|
|
72
73
|
export declare function onGatewayFetchFailure(listener: ((failure: GatewayFetchFailure) => void) | undefined): void;
|
|
73
74
|
/**
|
package/dist/device-auth.js
CHANGED
|
@@ -2,6 +2,7 @@ import { createHash, randomBytes, randomUUID, webcrypto } from "node:crypto";
|
|
|
2
2
|
import { createServer } from "node:http";
|
|
3
3
|
import { VERSION } from "./config.js";
|
|
4
4
|
import { tr } from "./i18n.js";
|
|
5
|
+
import { edgeFallbackOrigin } from "./site.js";
|
|
5
6
|
const enc = new TextEncoder();
|
|
6
7
|
const SIGNING_PROXY_REQUEST_LIMIT_BYTES = 32 * 1024 * 1024;
|
|
7
8
|
let cachedPrivate;
|
|
@@ -204,7 +205,7 @@ export async function attachAttestationHeader(holder, headers) {
|
|
|
204
205
|
}
|
|
205
206
|
function clientSurface(fallback) {
|
|
206
207
|
const explicit = process.env["U1S1_CLIENT"];
|
|
207
|
-
if (explicit === "terminal" || explicit === "web" || explicit === "desktop"
|
|
208
|
+
if (explicit === "terminal" || explicit === "web" || explicit === "desktop") {
|
|
208
209
|
return explicit;
|
|
209
210
|
}
|
|
210
211
|
return process.versions.electron ? "desktop" : fallback;
|
|
@@ -234,6 +235,16 @@ export function describeFetchFailure(error) {
|
|
|
234
235
|
: causeMessage || code;
|
|
235
236
|
return { code, detail: `${message} (${reason})` };
|
|
236
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* 只认建连阶段的失败(请求还没发出去,换个入口重发不会重复扣费)。ECONNRESET / 读超时这类
|
|
240
|
+
* 可能发生在请求已送达之后,不重试,照旧报给用户。
|
|
241
|
+
*/
|
|
242
|
+
const CONNECT_PHASE_CODES = new Set([
|
|
243
|
+
"ECONNREFUSED", "ENOTFOUND", "EAI_AGAIN", "ENETUNREACH", "EHOSTUNREACH", "ETIMEDOUT", "UND_ERR_CONNECT_TIMEOUT",
|
|
244
|
+
]);
|
|
245
|
+
export function isConnectPhaseFailure(failure) {
|
|
246
|
+
return CONNECT_PHASE_CODES.has(failure.code);
|
|
247
|
+
}
|
|
237
248
|
let gatewayFetchFailureListener;
|
|
238
249
|
/** One listener per process (telemetry); failures are reported only when the local caller is still waiting. */
|
|
239
250
|
export function onGatewayFetchFailure(listener) {
|
|
@@ -256,6 +267,9 @@ export async function ensureSigningProxy(cfg, fallbackClient = "terminal", attes
|
|
|
256
267
|
updateAttestationHolder(attestation, attestationSource);
|
|
257
268
|
const localKey = `local-${randomBytes(32).toString("hex")}`;
|
|
258
269
|
const upstreamOrigin = new URL(cfg.baseUrl).origin;
|
|
270
|
+
// 中国站主域建连失败时换到大陆加速入口重试一次,本进程之后都走它(site.ts edgeFallbackOrigin)
|
|
271
|
+
const fallbackOrigin = edgeFallbackOrigin(upstreamOrigin);
|
|
272
|
+
let activeOrigin = upstreamOrigin;
|
|
259
273
|
const server = createServer(async (req, res) => {
|
|
260
274
|
try {
|
|
261
275
|
if (req.headers.authorization !== `Bearer ${localKey}` || !req.url) {
|
|
@@ -278,7 +292,7 @@ export async function ensureSigningProxy(cfg, fallbackClient = "terminal", attes
|
|
|
278
292
|
}
|
|
279
293
|
};
|
|
280
294
|
res.once("close", abortUpstream);
|
|
281
|
-
const
|
|
295
|
+
const pathAndQuery = `${localUrl.pathname}${localUrl.search}`;
|
|
282
296
|
try {
|
|
283
297
|
const body = await readSigningProxyRequestBody(req);
|
|
284
298
|
const outboundHeaders = requestHeaders(req.headers);
|
|
@@ -288,12 +302,24 @@ export async function ensureSigningProxy(cfg, fallbackClient = "terminal", attes
|
|
|
288
302
|
outboundHeaders.set("x-u1s1-version", VERSION);
|
|
289
303
|
outboundHeaders.set("x-u1s1-platform", `${process.platform}-${process.arch}`);
|
|
290
304
|
await attachAttestationHeader(attestation, outboundHeaders);
|
|
291
|
-
const
|
|
305
|
+
const send = (origin) => authorizedFetch(cfg, new URL(pathAndQuery, origin).toString(), {
|
|
292
306
|
method: req.method ?? "GET",
|
|
293
307
|
headers: outboundHeaders,
|
|
294
308
|
body,
|
|
295
309
|
signal: upstreamAbort.signal,
|
|
296
310
|
});
|
|
311
|
+
const origin = activeOrigin;
|
|
312
|
+
let upstream;
|
|
313
|
+
try {
|
|
314
|
+
upstream = await send(origin);
|
|
315
|
+
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
if (!fallbackOrigin || origin === fallbackOrigin || upstreamAbort.signal.aborted
|
|
318
|
+
|| !isConnectPhaseFailure(describeFetchFailure(error)))
|
|
319
|
+
throw error;
|
|
320
|
+
upstream = await send(fallbackOrigin);
|
|
321
|
+
activeOrigin = fallbackOrigin;
|
|
322
|
+
}
|
|
297
323
|
res.writeHead(upstream.status, forwardedResponseHeaders(upstream.headers));
|
|
298
324
|
if (upstream.body) {
|
|
299
325
|
for await (const chunk of upstream.body)
|
package/dist/site.d.ts
CHANGED
|
@@ -27,6 +27,13 @@ export interface Site {
|
|
|
27
27
|
* api.u1s1.io 由 migrateStoredBaseUrl 在下次保存时改写到新 apiBase。
|
|
28
28
|
*/
|
|
29
29
|
export declare const CN_ORIGIN = "https://u1s1app.com";
|
|
30
|
+
/**
|
|
31
|
+
* 中国站的大陆加速入口(EdgeOne → 同一个网关)。直连 api 主域在建连阶段就失败时,签名代理
|
|
32
|
+
* 换到这里重试一次,本进程之后都走它(device-auth.ts)。只在大陆有解析,海外解析不到也无妨。
|
|
33
|
+
*/
|
|
34
|
+
export declare const CN_EDGE_API_HOST = "api-cn.u1s1app.com";
|
|
35
|
+
/** 这个网关 origin 连不上时可以换到的备用 origin;不是中国站官方 API 域名就没有备用。 */
|
|
36
|
+
export declare function edgeFallbackOrigin(origin: string): string | null;
|
|
30
37
|
/** origin → https://api.<host>/v1 */
|
|
31
38
|
export declare function apiBaseForOrigin(origin: string): string;
|
|
32
39
|
export declare const SITES: Readonly<Record<SiteId, Site>>;
|
package/dist/site.js
CHANGED
|
@@ -14,6 +14,25 @@
|
|
|
14
14
|
*/
|
|
15
15
|
export const CN_ORIGIN = "https://u1s1app.com";
|
|
16
16
|
const INTL_ORIGIN = "https://u1s1.dev";
|
|
17
|
+
/**
|
|
18
|
+
* 中国站的大陆加速入口(EdgeOne → 同一个网关)。直连 api 主域在建连阶段就失败时,签名代理
|
|
19
|
+
* 换到这里重试一次,本进程之后都走它(device-auth.ts)。只在大陆有解析,海外解析不到也无妨。
|
|
20
|
+
*/
|
|
21
|
+
export const CN_EDGE_API_HOST = "api-cn.u1s1app.com";
|
|
22
|
+
const CN_EDGE_FALLBACK_FROM = ["api.u1s1app.com", "api.u1s1.io"];
|
|
23
|
+
/** 这个网关 origin 连不上时可以换到的备用 origin;不是中国站官方 API 域名就没有备用。 */
|
|
24
|
+
export function edgeFallbackOrigin(origin) {
|
|
25
|
+
let url;
|
|
26
|
+
try {
|
|
27
|
+
url = new URL(origin);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (url.protocol !== "https:" || url.port || !CN_EDGE_FALLBACK_FROM.includes(url.hostname.toLowerCase()))
|
|
33
|
+
return null;
|
|
34
|
+
return `https://${CN_EDGE_API_HOST}`;
|
|
35
|
+
}
|
|
17
36
|
/** origin → https://api.<host>/v1 */
|
|
18
37
|
export function apiBaseForOrigin(origin) {
|
|
19
38
|
const url = new URL(origin);
|
|
@@ -27,7 +46,7 @@ export const SITES = {
|
|
|
27
46
|
releaseOrigin: CN_ORIGIN,
|
|
28
47
|
// 邮件域已切到 u1s1app.com(2026-09-30);contact@u1s1.io 仍能收信,老版本照旧可用
|
|
29
48
|
contactEmail: "contact@u1s1app.com",
|
|
30
|
-
hosts: ["u1s1.io", "www.u1s1.io", "api.u1s1.io", "u1s1app.com", "www.u1s1app.com", "api.u1s1app.com"],
|
|
49
|
+
hosts: ["u1s1.io", "www.u1s1.io", "api.u1s1.io", "u1s1app.com", "www.u1s1app.com", "api.u1s1app.com", CN_EDGE_API_HOST],
|
|
31
50
|
},
|
|
32
51
|
intl: {
|
|
33
52
|
id: "intl",
|
package/dist/usage.d.ts
CHANGED
|
@@ -3,12 +3,14 @@ import { type Site } from "./site.js";
|
|
|
3
3
|
/** 当前站点的充值深链(仪表盘充值卡片)。 */
|
|
4
4
|
export declare function topupUrl(site?: Site): string;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
* 08-25
|
|
6
|
+
* 报告尾巴的两条行动入口:打卡领包与充值(撞线用户的直接出口,运营清单 A2)。
|
|
7
|
+
* 08-25 起没有「每天自动恢复」的免费池,打卡包有有效期,别再写「永久加量」。
|
|
8
|
+
* 2026-10-26 起邀请不再带来新奖励,不再提邀请;拉新收口后注册的账号(incentives_eligible=false)
|
|
9
|
+
* 也没有打卡,第一行只指仪表盘。
|
|
8
10
|
* 支付通道关闭时充值是死路(仪表盘会报「支付通道未开放」),改说即将上线并指向
|
|
9
11
|
* 仪表盘的加量包/打卡入口;老网关没有 pay_enabled 字段,按开放处理。
|
|
10
12
|
*/
|
|
11
|
-
export declare function usageCtaLines(me?: Pick<MeResponse, "pay_enabled">, site?: Site): string[];
|
|
13
|
+
export declare function usageCtaLines(me?: Pick<MeResponse, "pay_enabled" | "incentives_eligible">, site?: Site): string[];
|
|
12
14
|
/** 额度报告正文(不含首尾空行),终端 `u1s1 usage` 和会话内 /usage 共用。 */
|
|
13
15
|
export declare function usageReportLines(me: MeResponse, site?: Site): string[];
|
|
14
16
|
/** 会话内 /usage 用:拉取额度并打包成 entry data,错误转成提示文字而不是抛出。 */
|
package/dist/usage.js
CHANGED
|
@@ -179,8 +179,10 @@ export function topupUrl(site = activeSite()) {
|
|
|
179
179
|
return siteLinks(site).topup;
|
|
180
180
|
}
|
|
181
181
|
/**
|
|
182
|
-
*
|
|
183
|
-
* 08-25
|
|
182
|
+
* 报告尾巴的两条行动入口:打卡领包与充值(撞线用户的直接出口,运营清单 A2)。
|
|
183
|
+
* 08-25 起没有「每天自动恢复」的免费池,打卡包有有效期,别再写「永久加量」。
|
|
184
|
+
* 2026-10-26 起邀请不再带来新奖励,不再提邀请;拉新收口后注册的账号(incentives_eligible=false)
|
|
185
|
+
* 也没有打卡,第一行只指仪表盘。
|
|
184
186
|
* 支付通道关闭时充值是死路(仪表盘会报「支付通道未开放」),改说即将上线并指向
|
|
185
187
|
* 仪表盘的加量包/打卡入口;老网关没有 pay_enabled 字段,按开放处理。
|
|
186
188
|
*/
|
|
@@ -188,7 +190,9 @@ export function usageCtaLines(me, site = activeSite()) {
|
|
|
188
190
|
const payClosed = me?.pay_enabled === false;
|
|
189
191
|
const { dashboard, topup } = siteLinks(site);
|
|
190
192
|
return [
|
|
191
|
-
|
|
193
|
+
me?.incentives_eligible === false
|
|
194
|
+
? tr(` 用量包与充值记录在仪表盘 → ${dashboard}`, ` Packs and top-up history are on the dashboard → ${dashboard}`)
|
|
195
|
+
: tr(` 每天到仪表盘打卡领免费包 → ${dashboard}`, ` Check in daily on the dashboard for free packs → ${dashboard}`),
|
|
192
196
|
payClosed
|
|
193
197
|
? tr(` 充值通道即将开放;额度不够先到仪表盘领加量包、每日打卡 → ${dashboard}`, ` Top-ups are coming soon; meanwhile grab extra packs and check in on the dashboard → ${dashboard}`)
|
|
194
198
|
: tr(` 额度不够用?充值 → ${topup}`, ` Need more? Top up → ${topup}`),
|