ai-fly 0.5.0-alpha.1 → 0.6.0-alpha.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/dist/ai-fly.js CHANGED
@@ -66,7 +66,7 @@ async function dispatch(command, rest) {
66
66
  const lazy = (load) => {
67
67
  return (argv, ctx) => load().then((m) => m.run([...argv], ctx));
68
68
  };
69
- return match(command).with("serve", () => lazy(() => import("./serve-B7CRdGoy.mjs"))(rest)).with("app", async () => {
69
+ return match(command).with("serve", () => lazy(() => import("./serve-DJ8id2Qo.mjs"))(rest)).with("app", async () => {
70
70
  const { join, dirname } = await import("node:path");
71
71
  const { fileURLToPath } = await import("node:url");
72
72
  const { spawn } = await import("node:child_process");
@@ -81,7 +81,7 @@ async function dispatch(command, rest) {
81
81
  return await new Promise((resolve) => {
82
82
  child.once("exit", (c) => resolve(c ?? 0));
83
83
  });
84
- }).with("daemon", () => lazy(() => import("./daemon-Oh-SQUeo.mjs"))(rest)).with("presets", () => lazy(() => import("./presets-BwkVV7E2.mjs"))(rest)).with("hooks", () => lazy(() => import("./hooks-BztmB61b.mjs"))(rest)).with("secret", () => lazy(() => import("./secret-BrfkuRkP.mjs"))(rest)).with("settings", async () => (await import("./settings-15j9BB6j.mjs")).runAsSettings(rest, {})).with("relay", async () => (await import("./settings-15j9BB6j.mjs")).runAsRelay(rest, {})).with("test", () => lazy(() => import("./test-ChqaPwHA.mjs"))(rest)).with("service", () => lazy(() => import("./service-P-vz61tx.mjs"))(rest)).with("group", () => lazy(() => import("./group-Dh64zhKn.mjs"))(rest)).with("share", () => lazy(() => import("./share-BogH4NQJ.mjs"))(rest)).with("revoke", () => lazy(() => import("./revoke-CQdhajpu.mjs"))(rest)).with("join", () => lazy(() => import("./join-CLD4fdCf.mjs"))(rest)).with("import", () => lazy(() => import("./import-DpW4ignw.mjs"))(rest)).with("run", () => lazy(() => import("./run-nJ_AEsMr.mjs"))(rest)).with("ports", () => lazy(() => import("./ports-DmBKgLSi.mjs"))(rest)).with("forget", () => lazy(() => import("./forget-DGJwF3Gy.mjs"))(rest)).with("services", () => lazy(() => import("./services-Deh7Gxwa.mjs"))(rest)).with("key", () => {
84
+ }).with("daemon", () => lazy(() => import("./daemon-D5J50r7U.mjs"))(rest)).with("presets", () => lazy(() => import("./presets-BwkVV7E2.mjs"))(rest)).with("hooks", () => lazy(() => import("./hooks-BztmB61b.mjs"))(rest)).with("secret", () => lazy(() => import("./secret-BrfkuRkP.mjs"))(rest)).with("settings", async () => (await import("./settings-15j9BB6j.mjs")).runAsSettings(rest, {})).with("relay", async () => (await import("./settings-15j9BB6j.mjs")).runAsRelay(rest, {})).with("test", () => lazy(() => import("./test-ChqaPwHA.mjs"))(rest)).with("service", () => lazy(() => import("./service-P-vz61tx.mjs"))(rest)).with("group", () => lazy(() => import("./group-Dh64zhKn.mjs"))(rest)).with("share", () => lazy(() => import("./share-mozydAfj.mjs"))(rest)).with("revoke", () => lazy(() => import("./revoke-DMx9hZUH.mjs"))(rest)).with("join", () => lazy(() => import("./join-CLD4fdCf.mjs"))(rest)).with("import", () => lazy(() => import("./import-DN8bNBJU.mjs"))(rest)).with("run", () => lazy(() => import("./run-C-CxjlLu.mjs"))(rest)).with("ports", () => lazy(() => import("./ports-DmBKgLSi.mjs"))(rest)).with("forget", () => lazy(() => import("./forget-DGJwF3Gy.mjs"))(rest)).with("services", () => lazy(() => import("./services-Deh7Gxwa.mjs"))(rest)).with("key", () => {
85
85
  if (rest[0] === "add") return lazy(() => import("./key-JLJewbw9.mjs"))(rest);
86
86
  return lazy(() => import("./key-Cpw-HzT4.mjs"))(rest);
87
87
  }).with("status", async () => {
@@ -90,8 +90,8 @@ async function dispatch(command, rest) {
90
90
  const wantConsumer = scope === "consumer" || scope !== "provider" && consumersRootExists();
91
91
  const argv = scope === "provider" || scope === "consumer" ? tail : rest;
92
92
  let code = 0;
93
- if (wantProvider) code = Math.max(code, await lazy(() => import("./status-VCGexKPW.mjs"))(argv));
94
- if (wantConsumer) code = Math.max(code, await lazy(() => import("./status-COzqwi-v.mjs"))(argv));
93
+ if (wantProvider) code = Math.max(code, await lazy(() => import("./status-DsFpGrzC.mjs"))(argv));
94
+ if (wantConsumer) code = Math.max(code, await lazy(() => import("./status-BlvQvxGW.mjs"))(argv));
95
95
  if (!wantProvider && !wantConsumer) process.stdout.write("nothing to report: no provider storage and no imported consumers\n");
96
96
  return code;
97
97
  }).otherwise(() => {
package/dist/app/main.js CHANGED
@@ -3775,6 +3775,7 @@ async function forwardHttp(ctx, plan, t) {
3775
3775
  /** js-backend-fetch 路径:连接期探测 + fetch(fetchImpl 测试注入缝保留于此)。 */
3776
3776
  const nativeResponse = async () => {
3777
3777
  const probe = ctx.probeConnect ?? defaultProbeConnect;
3778
+ if (ctrl.signal.aborted || ctx.signal.aborted) throw new ProbeFailedError();
3778
3779
  try {
3779
3780
  await probe(plan.url, t.connectMs);
3780
3781
  } catch {
@@ -3921,6 +3922,8 @@ async function forwardHttp(ctx, plan, t) {
3921
3922
  }
3922
3923
  //#endregion
3923
3924
  //#region src/provider/engine.ts
3925
+ /** per-peer 并发授权会话容量(LRU 逐出——内核暂无会话终结通知的防泄漏上限)。 */
3926
+ const SESSION_AUTH_CAP = 32;
3924
3927
  /** 错误码 → 载体响应(shared 映射表;null status(本地中止族)→ 504 语义)。 */
3925
3928
  function errorCarrierResponse(code, message) {
3926
3929
  const m = ERROR_HTTP_MAPPING[code] ?? {
@@ -4041,23 +4044,34 @@ var ProviderEngine = class {
4041
4044
  async refreshSession(ps) {
4042
4045
  if (!ps.authed()) return;
4043
4046
  const dir = this.directory();
4044
- const { valid } = evaluateKeyring(ps.keyring, dir);
4045
- if (valid.length === 0) {
4046
- ps.keyring = [];
4047
- ps.grants = [];
4047
+ let anyAlive = false;
4048
+ for (const sessionId of [...ps.sessionAuthIds()]) {
4049
+ const sa = ps.sessionAuthOf(sessionId);
4050
+ if (sa === void 0) continue;
4051
+ const { valid } = evaluateKeyring(sa.keyring, dir);
4052
+ if (valid.length === 0) {
4053
+ ps.dropSessionAuth(sessionId);
4054
+ continue;
4055
+ }
4056
+ anyAlive = true;
4057
+ const header = buildAuthOk(valid, dir, { refresh: true });
4058
+ const json = JSON.stringify(header);
4059
+ if (json === sa.lastView) {
4060
+ sa.grants = valid;
4061
+ continue;
4062
+ }
4063
+ this.catalogSeq++;
4064
+ sa.grants = valid;
4065
+ sa.lastView = json;
4066
+ ps.notifyWatch(sessionId, header);
4067
+ }
4068
+ if (!anyAlive) {
4048
4069
  this.keyIndex.untrack(ps);
4049
4070
  ps.notifyWatchInvalidated();
4050
4071
  this.fabric.disconnect(ps.peerId).catch(() => void 0);
4051
4072
  return;
4052
4073
  }
4053
- const header = buildAuthOk(valid, dir, { refresh: true });
4054
- const json = JSON.stringify(header);
4055
- if (json === ps.lastView) return;
4056
- this.catalogSeq++;
4057
- ps.grants = valid;
4058
- ps.lastView = json;
4059
4074
  this.keyIndex.track(ps);
4060
- ps.notifyWatch(header);
4061
4075
  }
4062
4076
  async addPeer(peerId) {
4063
4077
  if (this.stopped) return;
@@ -4104,12 +4118,14 @@ var ProviderPeerServer = class {
4104
4118
  disposed = false;
4105
4119
  active = /* @__PURE__ */ new Map();
4106
4120
  acquired = /* @__PURE__ */ new Map();
4107
- /** 最近一次 AUTH 呈交的钥环原文(仅内存;撤钥后重算用;MUST NOT 进日志)。 */
4108
- keyring = [];
4109
- grants = [];
4110
- lastView = "";
4111
- /** watch 长轮询等待者(目录变更时唤醒;授权失效以 "invalid" 唤醒 → 401)。 */
4112
- watchWaiters = /* @__PURE__ */ new Set();
4121
+ /**
4122
+ * session_id → 授权态(LRU;上限防泄漏——内核暂无「会话终结」通知,旧
4123
+ * session 条目由容量逐出。恢复轮 sessionId 稳定,逐出只发生在远超活跃
4124
+ * 会话数的场景)。
4125
+ */
4126
+ sessionAuths = /* @__PURE__ */ new Map();
4127
+ /** watch 长轮询等待者(目录变更按各自 session 视图唤醒;失效 → 401)。 */
4128
+ watchWaiters = /* @__PURE__ */ new Map();
4113
4129
  constructor(engine, peerId, fabric) {
4114
4130
  this.engine = engine;
4115
4131
  this.peerId = peerId;
@@ -4118,31 +4134,85 @@ var ProviderPeerServer = class {
4118
4134
  async start(serveHttpImpl) {
4119
4135
  this.server = await serveHttpImpl(this.fabric, this.peerId, (req) => this.handle(req));
4120
4136
  }
4137
+ /** 任一会话持有有效授权(peer 级观测)。 */
4121
4138
  authed() {
4122
- return this.grants.length > 0;
4139
+ for (const sa of this.sessionAuths.values()) if (sa.grants.length > 0) return true;
4140
+ return false;
4141
+ }
4142
+ /** 该会话的授权态(无 → undefined:未 AUTH/已失效/被逐出)。访问即提升
4143
+ * LRU 位次(Map 重插——访问序逐出,非仅插入序)。 */
4144
+ sessionAuthOf(sessionId) {
4145
+ const sa = this.sessionAuths.get(sessionId);
4146
+ if (sa !== void 0) {
4147
+ this.sessionAuths.delete(sessionId);
4148
+ this.sessionAuths.set(sessionId, sa);
4149
+ }
4150
+ return sa;
4151
+ }
4152
+ /** 会话 id 快照(engine.refreshSession 迭代用)。 */
4153
+ sessionAuthIds() {
4154
+ return [...this.sessionAuths.keys()];
4155
+ }
4156
+ /** 摘除会话授权态(refresh 裁剪路径——全钥失效的会话;watch 随之唤醒 401)。 */
4157
+ dropSessionAuth(sessionId) {
4158
+ this.sessionAuths.delete(sessionId);
4159
+ this.invalidateWatch(sessionId);
4160
+ }
4161
+ /** 写入该会话授权态(LRU 容量逐出最旧)。 */
4162
+ putSessionAuth(sessionId, keyring, grants) {
4163
+ this.sessionAuths.delete(sessionId);
4164
+ this.sessionAuths.set(sessionId, {
4165
+ keyring,
4166
+ grants,
4167
+ lastView: ""
4168
+ });
4169
+ while (this.sessionAuths.size > SESSION_AUTH_CAP) {
4170
+ const oldest = this.sessionAuths.keys().next().value;
4171
+ if (oldest === void 0) break;
4172
+ this.sessionAuths.delete(oldest);
4173
+ this.invalidateWatch(oldest);
4174
+ }
4123
4175
  }
4124
4176
  get keys() {
4125
- return this.keyring;
4177
+ const out = /* @__PURE__ */ new Set();
4178
+ for (const sa of this.sessionAuths.values()) for (const k of sa.keyring) out.add(k);
4179
+ return [...out];
4126
4180
  }
4127
4181
  get keyIds() {
4128
- return new Set(this.grants.map((g) => g.keyId));
4182
+ const out = /* @__PURE__ */ new Set();
4183
+ for (const sa of this.sessionAuths.values()) for (const g of sa.grants) out.add(g.keyId);
4184
+ return out;
4129
4185
  }
4130
4186
  /** 撤键/目录变更后的刷新:唤醒 watch 长轮询(全量视图;refresh 语义不变)。 */
4131
4187
  async pushRefresh(header) {
4132
- this.lastView = JSON.stringify(header);
4133
- this.notifyWatch(header);
4188
+ this.notifyWatchAll(header);
4134
4189
  }
4135
4190
  disconnect(reason) {
4136
4191
  this.disposeLocal(reason);
4137
4192
  }
4138
- /** 唤醒全部 watch 等待者(视图变更)。 */
4139
- notifyWatch(view) {
4140
- for (const wake of [...this.watchWaiters]) wake(view);
4193
+ /** 会话授权失效(drop/无效 AUTH/逐出):唤醒该会话全部 watch 等待者以
4194
+ * 401 收敛(5.2-P2——此前删集合不唤醒,在途长轮询干等到 20s 超时)。 */
4195
+ invalidateWatch(sessionId) {
4196
+ const waiters = this.watchWaiters.get(sessionId);
4197
+ if (waiters === void 0) return;
4198
+ for (const wake of [...waiters]) wake("invalid");
4199
+ this.watchWaiters.delete(sessionId);
4200
+ }
4201
+ /** 唤醒指定会话的 watch 等待者(该会话自己的刷新视图)。 */
4202
+ notifyWatch(sessionId, view) {
4203
+ const waiters = this.watchWaiters.get(sessionId);
4204
+ if (waiters === void 0) return;
4205
+ for (const wake of [...waiters]) wake(view);
4206
+ this.watchWaiters.delete(sessionId);
4207
+ }
4208
+ /** 唤醒全部 watch 等待者(键重加等 peer 级推送:并集视图,各会话自行重同步)。 */
4209
+ notifyWatchAll(view) {
4210
+ for (const waiters of [...this.watchWaiters.values()]) for (const wake of [...waiters]) wake(view);
4141
4211
  this.watchWaiters.clear();
4142
4212
  }
4143
4213
  /** 授权失效:唤醒等待者以 401 收敛(watch 循环退出,由 active 转换重启)。 */
4144
4214
  notifyWatchInvalidated() {
4145
- for (const wake of [...this.watchWaiters]) wake("invalid");
4215
+ for (const waiters of [...this.watchWaiters.values()]) for (const wake of [...waiters]) wake("invalid");
4146
4216
  this.watchWaiters.clear();
4147
4217
  }
4148
4218
  /** 本地善后(撤钥/引擎关闭):中止全部在途、释放限额、停 HTTP 引擎、断 fabric 会话。 */
@@ -4163,6 +4233,8 @@ var ProviderPeerServer = class {
4163
4233
  let result;
4164
4234
  if (barePath === "/_aifly/auth" && req.method === "POST") result = await this.handleAuth(req);
4165
4235
  else if (barePath === "/_aifly/catalog-watch" && req.method === "GET") result = await this.handleWatch(req);
4236
+ else if (barePath === "/_aifly/auth" || barePath === "/_aifly/catalog-watch") result = errorCarrierResponse(ERROR_CODE.forbidden_method, `method not allowed on control endpoint: ${req.method} ${barePath}`);
4237
+ else if (barePath.startsWith("/_aifly/")) result = errorCarrierResponse(ERROR_CODE.unauthorized, "unauthorized");
4166
4238
  else result = await this.handleForward(req);
4167
4239
  return result;
4168
4240
  }
@@ -4177,7 +4249,7 @@ var ProviderPeerServer = class {
4177
4249
  });
4178
4250
  return out;
4179
4251
  }
4180
- /** AUTH(重复 AUTH 以最后一次为准:钥环变更 = 重授权)。 */
4252
+ /** AUTH(重复 AUTH 以最后一次为准:钥环变更 = 重授权;授权按 session_id 隔离)。 */
4181
4253
  async handleAuth(req) {
4182
4254
  let parsedBody;
4183
4255
  try {
@@ -4190,18 +4262,16 @@ var ProviderPeerServer = class {
4190
4262
  if (!parsed.success) return errorCarrierResponse(ERROR_CODE.protocol_error, "auth body schema rejected");
4191
4263
  const decision = handleAuthFrame(parsed.data, this.engine.directory());
4192
4264
  if (decision.kind === "err") {
4193
- this.keyring = [];
4194
- this.grants = [];
4195
- this.engine.keySessionIndex().untrack(this);
4265
+ this.sessionAuths.delete(req.sessionId);
4266
+ this.invalidateWatch(req.sessionId);
4267
+ if (!this.authed()) this.engine.keySessionIndex().untrack(this);
4196
4268
  return {
4197
4269
  status: 403,
4198
4270
  headers: this.jsonHeaders(),
4199
4271
  bodyChunks: [Buffer.from(JSON.stringify(decision.header))]
4200
4272
  };
4201
4273
  }
4202
- this.keyring = decision.keys;
4203
- this.grants = decision.valid;
4204
- this.lastView = JSON.stringify(decision.header);
4274
+ this.putSessionAuth(req.sessionId, decision.keys, decision.valid);
4205
4275
  this.engine.keySessionIndex().track(this);
4206
4276
  return {
4207
4277
  status: 200,
@@ -4211,17 +4281,18 @@ var ProviderPeerServer = class {
4211
4281
  }
4212
4282
  /** 目录刷新长轮询:since 落后即时回;未变更挂起至视图变更(200)或超时(204)。 */
4213
4283
  async handleWatch(req) {
4214
- if (!this.authed()) return errorCarrierResponse(ERROR_CODE.unauthorized, "session is not authenticated");
4284
+ const sa = this.sessionAuthOf(req.sessionId);
4285
+ if (sa === void 0 || sa.grants.length === 0) return errorCarrierResponse(ERROR_CODE.unauthorized, "session is not authenticated");
4215
4286
  const query = req.path.split("?", 2)[1] ?? "";
4216
4287
  const sinceRaw = Number(new URLSearchParams(query).get("since") ?? "0");
4217
4288
  const since = Number.isFinite(sinceRaw) && sinceRaw >= 0 ? Math.floor(sinceRaw) : 0;
4218
4289
  const current = this.engine.currentCatalogSeq();
4219
4290
  if (since < current) {
4220
4291
  const dir = this.engine.directory();
4221
- const { valid } = evaluateKeyring(this.keyring, dir);
4292
+ const { valid } = evaluateKeyring(sa.keyring, dir);
4222
4293
  if (valid.length === 0) return errorCarrierResponse(ERROR_CODE.unauthorized, "no valid key remains");
4223
4294
  const header = buildAuthOk(valid, dir, { refresh: true });
4224
- this.grants = valid;
4295
+ sa.grants = valid;
4225
4296
  return {
4226
4297
  status: 200,
4227
4298
  headers: this.jsonHeaders({ "x-aifly-catalog-seq": String(current) }),
@@ -4230,16 +4301,27 @@ var ProviderPeerServer = class {
4230
4301
  }
4231
4302
  const changed = await new Promise((resolve) => {
4232
4303
  const timer = setTimeout(() => {
4233
- this.watchWaiters.delete(wake);
4304
+ let waiters = this.watchWaiters.get(req.sessionId);
4305
+ waiters?.delete(wake);
4306
+ if (waiters !== void 0 && waiters.size === 0) this.watchWaiters.delete(req.sessionId);
4234
4307
  resolve(null);
4235
4308
  }, CATALOG_WATCH_TIMEOUT_MS);
4236
4309
  const wake = (view) => {
4237
4310
  clearTimeout(timer);
4238
4311
  resolve(view);
4239
4312
  };
4240
- this.watchWaiters.add(wake);
4313
+ let waiters = this.watchWaiters.get(req.sessionId);
4314
+ if (waiters === void 0) {
4315
+ waiters = /* @__PURE__ */ new Set();
4316
+ this.watchWaiters.set(req.sessionId, waiters);
4317
+ }
4318
+ waiters.add(wake);
4241
4319
  });
4242
4320
  if (changed === "invalid") return errorCarrierResponse(ERROR_CODE.unauthorized, "authorization invalidated");
4321
+ if (changed !== null) {
4322
+ const saAfter = this.sessionAuthOf(req.sessionId);
4323
+ if (saAfter === void 0 || saAfter.grants.length === 0) return errorCarrierResponse(ERROR_CODE.unauthorized, "session is not authenticated");
4324
+ }
4243
4325
  if (changed === null) return {
4244
4326
  status: 204,
4245
4327
  headers: [{
@@ -4254,13 +4336,15 @@ var ProviderPeerServer = class {
4254
4336
  };
4255
4337
  }
4256
4338
  async handleForward(req) {
4257
- if (!this.authed()) return errorCarrierResponse(ERROR_CODE.unauthorized, "session is not authenticated");
4339
+ const sa = this.sessionAuthOf(req.sessionId);
4340
+ if (sa === void 0 || sa.grants.length === 0) return errorCarrierResponse(ERROR_CODE.unauthorized, "session is not authenticated");
4341
+ if (req.signal.aborted) return errorCarrierResponse(ERROR_CODE.aborted, "request cancelled before dispatch");
4258
4342
  const serviceHeader = req.headers.find((h) => h.name === AIFLY_SERVICE_HEADER)?.value;
4259
4343
  if (serviceHeader === void 0) return errorCarrierResponse(ERROR_CODE.protocol_error, `missing ${AIFLY_SERVICE_HEADER} header`);
4260
4344
  const method = req.method.toUpperCase();
4261
4345
  if (!HTTP_METHODS.includes(method)) return errorCarrierResponse(ERROR_CODE.forbidden_method, `http method not allowed: ${method}`);
4262
4346
  const service = this.engine.store.getService(serviceHeader);
4263
- const grant = service === void 0 ? void 0 : this.grants.find((g) => this.engine.groupHasService(g.group, serviceHeader));
4347
+ const grant = service === void 0 ? void 0 : sa.grants.find((g) => this.engine.groupHasService(g.group, serviceHeader));
4264
4348
  if (service === void 0 || service.enabled === false || grant === void 0) return errorCarrierResponse(ERROR_CODE.unknown_service, "service not available");
4265
4349
  const acquired = this.engine.limits.acquire(grant.keyId, grant.group);
4266
4350
  if (!acquired.ok) return errorCarrierResponse(acquired.code, acquired.code === "rate_limited" ? "group concurrency limit reached" : "daily request quota reached");
@@ -4299,6 +4383,11 @@ var ProviderPeerServer = class {
4299
4383
  };
4300
4384
  const outcome = new CarrierOutcome((status, headers) => req.respondStreaming(status, headers));
4301
4385
  const ctrl = new AbortController();
4386
+ const abortUpstream = () => {
4387
+ ctrl.abort(new UpstreamAbortError(ERROR_CODE.aborted, true));
4388
+ };
4389
+ req.signal.addEventListener("abort", abortUpstream, { once: true });
4390
+ if (req.signal.aborted) abortUpstream();
4302
4391
  const act = {
4303
4392
  ctrl,
4304
4393
  keyId: grant.keyId,
@@ -5144,6 +5233,10 @@ function removeKeyring(root, ref) {
5144
5233
  }
5145
5234
  };
5146
5235
  }
5236
+ //#endregion
5237
+ //#region src/consumer/providers.ts
5238
+ /** fetchHttp head 等待期取消键序号(per 进程单调;abortKey 注册表关联)。 */
5239
+ let fetchAbortKeySeq = 0;
5147
5240
  /**
5148
5241
  * full jitter:delay = random() * min(cap, base * 2^attempt)。
5149
5242
  * attempt 从 0 起(首次重连窗口 [0, base]);封顶后窗口恒为 [0, cap]。
@@ -5314,6 +5407,7 @@ var ProviderConnection = class {
5314
5407
  });
5315
5408
  let aborted = false;
5316
5409
  let tunnel = null;
5410
+ const abortKey = ++fetchAbortKeySeq;
5317
5411
  (async () => {
5318
5412
  try {
5319
5413
  const resp = await session.fetchHttp({
@@ -5321,7 +5415,8 @@ var ProviderConnection = class {
5321
5415
  path: input.path,
5322
5416
  headers,
5323
5417
  ...input.body.length > 0 ? { body: [input.body] } : {},
5324
- ...input.upgrade ? { keepOpen: true } : {}
5418
+ ...input.upgrade ? { keepOpen: true } : {},
5419
+ abortKey
5325
5420
  });
5326
5421
  if (aborted) {
5327
5422
  try {
@@ -5398,6 +5493,9 @@ var ProviderConnection = class {
5398
5493
  id,
5399
5494
  abort: () => {
5400
5495
  aborted = true;
5496
+ try {
5497
+ session.abortFetch?.(abortKey);
5498
+ } catch {}
5401
5499
  try {
5402
5500
  tunnel?.abort?.();
5403
5501
  } catch {}
@@ -99,7 +99,7 @@ async function start(startArgv, home) {
99
99
  process.on("exit", () => {
100
100
  clearPid(home);
101
101
  });
102
- const { run: serveRun } = await import("./serve-B7CRdGoy.mjs");
102
+ const { run: serveRun } = await import("./serve-DJ8id2Qo.mjs");
103
103
  return serveRun([...startArgv], { homedir: home });
104
104
  }
105
105
  /** 后台 pid(活性核验;陈旧 pidfile 就地清理返回 null)。 */
@@ -3,7 +3,7 @@ import { n as parseArgv } from "./args-CSxXW9eD.mjs";
3
3
  import { n as consumersRoot, s as listKeyrings } from "./store-Bu4I1rNj.mjs";
4
4
  import { a as ringsForRun, i as printListeners, n as ctxHomedir, o as waitForSignals, r as ctxOut, t as createSdkFabricFactory } from "./common-9KRvrs5f.mjs";
5
5
  import { a as importLink, i as formatLinkPreview, n as decodeShareLink, r as formatKeyringSummary } from "./join-D5QUz8mh.mjs";
6
- import { n as createFabricSessionFactory, t as startEngine } from "./runtime-D9rSByOO.mjs";
6
+ import { n as createFabricSessionFactory, t as startEngine } from "./runtime-DKmrkfNT.mjs";
7
7
  import { homedir } from "node:os";
8
8
  //#region src/cli/commands/consumer/import.ts
9
9
  async function run(argv, ctx = {}) {
@@ -2,7 +2,7 @@ import { n as UsageError, r as reportCliError } from "./errors-BGtxPkM7.mjs";
2
2
  import { n as parseArgv } from "./args-CSxXW9eD.mjs";
3
3
  import { t as resolveHttpProxy } from "./proxy-D7VMUVEg.mjs";
4
4
  import { d as resolvedRelayUrls, f as str, u as resolveDataDir } from "./common-DqSyhR6F.mjs";
5
- import { t as openExistingFabric } from "./serve-BlWkrYrl.mjs";
5
+ import { t as openExistingFabric } from "./serve-BB6-4Ixd.mjs";
6
6
  import { homedir } from "node:os";
7
7
  //#region src/cli/commands/provider/revoke.ts
8
8
  const SPEC = {
@@ -2,7 +2,7 @@ import { n as UsageError, r as reportCliError, t as CliError } from "./errors-BG
2
2
  import { n as parseArgv } from "./args-CSxXW9eD.mjs";
3
3
  import { c as loadKeyring, n as consumersRoot, o as keyringDir, s as listKeyrings } from "./store-Bu4I1rNj.mjs";
4
4
  import { a as ringsForRun, i as printListeners, n as ctxHomedir, o as waitForSignals, r as ctxOut, t as createSdkFabricFactory } from "./common-9KRvrs5f.mjs";
5
- import { n as createFabricSessionFactory, t as startEngine } from "./runtime-D9rSByOO.mjs";
5
+ import { n as createFabricSessionFactory, t as startEngine } from "./runtime-DKmrkfNT.mjs";
6
6
  import { a as killHard, c as terminateGracefully, i as isAlive, l as writeLastStart, n as daemonDir, o as readLastStart, r as ensureDaemonDir, s as readPid, t as clearPid, u as writePid } from "./daemon-state-CYkiW3SA.mjs";
7
7
  import { openSync, readFileSync, watch } from "node:fs";
8
8
  import { resolve } from "node:path";
@@ -5,6 +5,9 @@ import { n as desiredPortFor, r as listenWithFallback, t as LOOPBACK_HOST } from
5
5
  import { Hono } from "hono";
6
6
  import { createAdaptorServer } from "@hono/node-server";
7
7
  import { WebSocketServer } from "ws";
8
+ //#region src/consumer/providers.ts
9
+ /** fetchHttp head 等待期取消键序号(per 进程单调;abortKey 注册表关联)。 */
10
+ let fetchAbortKeySeq = 0;
8
11
  /**
9
12
  * full jitter:delay = random() * min(cap, base * 2^attempt)。
10
13
  * attempt 从 0 起(首次重连窗口 [0, base]);封顶后窗口恒为 [0, cap]。
@@ -175,6 +178,7 @@ var ProviderConnection = class {
175
178
  });
176
179
  let aborted = false;
177
180
  let tunnel = null;
181
+ const abortKey = ++fetchAbortKeySeq;
178
182
  (async () => {
179
183
  try {
180
184
  const resp = await session.fetchHttp({
@@ -182,7 +186,8 @@ var ProviderConnection = class {
182
186
  path: input.path,
183
187
  headers,
184
188
  ...input.body.length > 0 ? { body: [input.body] } : {},
185
- ...input.upgrade ? { keepOpen: true } : {}
189
+ ...input.upgrade ? { keepOpen: true } : {},
190
+ abortKey
186
191
  });
187
192
  if (aborted) {
188
193
  try {
@@ -259,6 +264,9 @@ var ProviderConnection = class {
259
264
  id,
260
265
  abort: () => {
261
266
  aborted = true;
267
+ try {
268
+ session.abortFetch?.(abortKey);
269
+ } catch {}
262
270
  try {
263
271
  tunnel?.abort?.();
264
272
  } catch {}
@@ -825,6 +825,7 @@ async function forwardHttp(ctx, plan, t) {
825
825
  /** js-backend-fetch 路径:连接期探测 + fetch(fetchImpl 测试注入缝保留于此)。 */
826
826
  const nativeResponse = async () => {
827
827
  const probe = ctx.probeConnect ?? defaultProbeConnect;
828
+ if (ctrl.signal.aborted || ctx.signal.aborted) throw new ProbeFailedError();
828
829
  try {
829
830
  await probe(plan.url, t.connectMs);
830
831
  } catch {
@@ -971,6 +972,8 @@ async function forwardHttp(ctx, plan, t) {
971
972
  }
972
973
  //#endregion
973
974
  //#region src/provider/engine.ts
975
+ /** per-peer 并发授权会话容量(LRU 逐出——内核暂无会话终结通知的防泄漏上限)。 */
976
+ const SESSION_AUTH_CAP = 32;
974
977
  /** 错误码 → 载体响应(shared 映射表;null status(本地中止族)→ 504 语义)。 */
975
978
  function errorCarrierResponse(code, message) {
976
979
  const m = ERROR_HTTP_MAPPING[code] ?? {
@@ -1091,23 +1094,34 @@ var ProviderEngine = class {
1091
1094
  async refreshSession(ps) {
1092
1095
  if (!ps.authed()) return;
1093
1096
  const dir = this.directory();
1094
- const { valid } = evaluateKeyring(ps.keyring, dir);
1095
- if (valid.length === 0) {
1096
- ps.keyring = [];
1097
- ps.grants = [];
1097
+ let anyAlive = false;
1098
+ for (const sessionId of [...ps.sessionAuthIds()]) {
1099
+ const sa = ps.sessionAuthOf(sessionId);
1100
+ if (sa === void 0) continue;
1101
+ const { valid } = evaluateKeyring(sa.keyring, dir);
1102
+ if (valid.length === 0) {
1103
+ ps.dropSessionAuth(sessionId);
1104
+ continue;
1105
+ }
1106
+ anyAlive = true;
1107
+ const header = buildAuthOk(valid, dir, { refresh: true });
1108
+ const json = JSON.stringify(header);
1109
+ if (json === sa.lastView) {
1110
+ sa.grants = valid;
1111
+ continue;
1112
+ }
1113
+ this.catalogSeq++;
1114
+ sa.grants = valid;
1115
+ sa.lastView = json;
1116
+ ps.notifyWatch(sessionId, header);
1117
+ }
1118
+ if (!anyAlive) {
1098
1119
  this.keyIndex.untrack(ps);
1099
1120
  ps.notifyWatchInvalidated();
1100
1121
  this.fabric.disconnect(ps.peerId).catch(() => void 0);
1101
1122
  return;
1102
1123
  }
1103
- const header = buildAuthOk(valid, dir, { refresh: true });
1104
- const json = JSON.stringify(header);
1105
- if (json === ps.lastView) return;
1106
- this.catalogSeq++;
1107
- ps.grants = valid;
1108
- ps.lastView = json;
1109
1124
  this.keyIndex.track(ps);
1110
- ps.notifyWatch(header);
1111
1125
  }
1112
1126
  async addPeer(peerId) {
1113
1127
  if (this.stopped) return;
@@ -1154,12 +1168,14 @@ var ProviderPeerServer = class {
1154
1168
  disposed = false;
1155
1169
  active = /* @__PURE__ */ new Map();
1156
1170
  acquired = /* @__PURE__ */ new Map();
1157
- /** 最近一次 AUTH 呈交的钥环原文(仅内存;撤钥后重算用;MUST NOT 进日志)。 */
1158
- keyring = [];
1159
- grants = [];
1160
- lastView = "";
1161
- /** watch 长轮询等待者(目录变更时唤醒;授权失效以 "invalid" 唤醒 → 401)。 */
1162
- watchWaiters = /* @__PURE__ */ new Set();
1171
+ /**
1172
+ * session_id → 授权态(LRU;上限防泄漏——内核暂无「会话终结」通知,旧
1173
+ * session 条目由容量逐出。恢复轮 sessionId 稳定,逐出只发生在远超活跃
1174
+ * 会话数的场景)。
1175
+ */
1176
+ sessionAuths = /* @__PURE__ */ new Map();
1177
+ /** watch 长轮询等待者(目录变更按各自 session 视图唤醒;失效 → 401)。 */
1178
+ watchWaiters = /* @__PURE__ */ new Map();
1163
1179
  constructor(engine, peerId, fabric) {
1164
1180
  this.engine = engine;
1165
1181
  this.peerId = peerId;
@@ -1168,31 +1184,85 @@ var ProviderPeerServer = class {
1168
1184
  async start(serveHttpImpl) {
1169
1185
  this.server = await serveHttpImpl(this.fabric, this.peerId, (req) => this.handle(req));
1170
1186
  }
1187
+ /** 任一会话持有有效授权(peer 级观测)。 */
1171
1188
  authed() {
1172
- return this.grants.length > 0;
1189
+ for (const sa of this.sessionAuths.values()) if (sa.grants.length > 0) return true;
1190
+ return false;
1191
+ }
1192
+ /** 该会话的授权态(无 → undefined:未 AUTH/已失效/被逐出)。访问即提升
1193
+ * LRU 位次(Map 重插——访问序逐出,非仅插入序)。 */
1194
+ sessionAuthOf(sessionId) {
1195
+ const sa = this.sessionAuths.get(sessionId);
1196
+ if (sa !== void 0) {
1197
+ this.sessionAuths.delete(sessionId);
1198
+ this.sessionAuths.set(sessionId, sa);
1199
+ }
1200
+ return sa;
1201
+ }
1202
+ /** 会话 id 快照(engine.refreshSession 迭代用)。 */
1203
+ sessionAuthIds() {
1204
+ return [...this.sessionAuths.keys()];
1205
+ }
1206
+ /** 摘除会话授权态(refresh 裁剪路径——全钥失效的会话;watch 随之唤醒 401)。 */
1207
+ dropSessionAuth(sessionId) {
1208
+ this.sessionAuths.delete(sessionId);
1209
+ this.invalidateWatch(sessionId);
1210
+ }
1211
+ /** 写入该会话授权态(LRU 容量逐出最旧)。 */
1212
+ putSessionAuth(sessionId, keyring, grants) {
1213
+ this.sessionAuths.delete(sessionId);
1214
+ this.sessionAuths.set(sessionId, {
1215
+ keyring,
1216
+ grants,
1217
+ lastView: ""
1218
+ });
1219
+ while (this.sessionAuths.size > SESSION_AUTH_CAP) {
1220
+ const oldest = this.sessionAuths.keys().next().value;
1221
+ if (oldest === void 0) break;
1222
+ this.sessionAuths.delete(oldest);
1223
+ this.invalidateWatch(oldest);
1224
+ }
1173
1225
  }
1174
1226
  get keys() {
1175
- return this.keyring;
1227
+ const out = /* @__PURE__ */ new Set();
1228
+ for (const sa of this.sessionAuths.values()) for (const k of sa.keyring) out.add(k);
1229
+ return [...out];
1176
1230
  }
1177
1231
  get keyIds() {
1178
- return new Set(this.grants.map((g) => g.keyId));
1232
+ const out = /* @__PURE__ */ new Set();
1233
+ for (const sa of this.sessionAuths.values()) for (const g of sa.grants) out.add(g.keyId);
1234
+ return out;
1179
1235
  }
1180
1236
  /** 撤键/目录变更后的刷新:唤醒 watch 长轮询(全量视图;refresh 语义不变)。 */
1181
1237
  async pushRefresh(header) {
1182
- this.lastView = JSON.stringify(header);
1183
- this.notifyWatch(header);
1238
+ this.notifyWatchAll(header);
1184
1239
  }
1185
1240
  disconnect(reason) {
1186
1241
  this.disposeLocal(reason);
1187
1242
  }
1188
- /** 唤醒全部 watch 等待者(视图变更)。 */
1189
- notifyWatch(view) {
1190
- for (const wake of [...this.watchWaiters]) wake(view);
1243
+ /** 会话授权失效(drop/无效 AUTH/逐出):唤醒该会话全部 watch 等待者以
1244
+ * 401 收敛(5.2-P2——此前删集合不唤醒,在途长轮询干等到 20s 超时)。 */
1245
+ invalidateWatch(sessionId) {
1246
+ const waiters = this.watchWaiters.get(sessionId);
1247
+ if (waiters === void 0) return;
1248
+ for (const wake of [...waiters]) wake("invalid");
1249
+ this.watchWaiters.delete(sessionId);
1250
+ }
1251
+ /** 唤醒指定会话的 watch 等待者(该会话自己的刷新视图)。 */
1252
+ notifyWatch(sessionId, view) {
1253
+ const waiters = this.watchWaiters.get(sessionId);
1254
+ if (waiters === void 0) return;
1255
+ for (const wake of [...waiters]) wake(view);
1256
+ this.watchWaiters.delete(sessionId);
1257
+ }
1258
+ /** 唤醒全部 watch 等待者(键重加等 peer 级推送:并集视图,各会话自行重同步)。 */
1259
+ notifyWatchAll(view) {
1260
+ for (const waiters of [...this.watchWaiters.values()]) for (const wake of [...waiters]) wake(view);
1191
1261
  this.watchWaiters.clear();
1192
1262
  }
1193
1263
  /** 授权失效:唤醒等待者以 401 收敛(watch 循环退出,由 active 转换重启)。 */
1194
1264
  notifyWatchInvalidated() {
1195
- for (const wake of [...this.watchWaiters]) wake("invalid");
1265
+ for (const waiters of [...this.watchWaiters.values()]) for (const wake of [...waiters]) wake("invalid");
1196
1266
  this.watchWaiters.clear();
1197
1267
  }
1198
1268
  /** 本地善后(撤钥/引擎关闭):中止全部在途、释放限额、停 HTTP 引擎、断 fabric 会话。 */
@@ -1213,6 +1283,8 @@ var ProviderPeerServer = class {
1213
1283
  let result;
1214
1284
  if (barePath === "/_aifly/auth" && req.method === "POST") result = await this.handleAuth(req);
1215
1285
  else if (barePath === "/_aifly/catalog-watch" && req.method === "GET") result = await this.handleWatch(req);
1286
+ else if (barePath === "/_aifly/auth" || barePath === "/_aifly/catalog-watch") result = errorCarrierResponse(ERROR_CODE.forbidden_method, `method not allowed on control endpoint: ${req.method} ${barePath}`);
1287
+ else if (barePath.startsWith("/_aifly/")) result = errorCarrierResponse(ERROR_CODE.unauthorized, "unauthorized");
1216
1288
  else result = await this.handleForward(req);
1217
1289
  return result;
1218
1290
  }
@@ -1227,7 +1299,7 @@ var ProviderPeerServer = class {
1227
1299
  });
1228
1300
  return out;
1229
1301
  }
1230
- /** AUTH(重复 AUTH 以最后一次为准:钥环变更 = 重授权)。 */
1302
+ /** AUTH(重复 AUTH 以最后一次为准:钥环变更 = 重授权;授权按 session_id 隔离)。 */
1231
1303
  async handleAuth(req) {
1232
1304
  let parsedBody;
1233
1305
  try {
@@ -1240,18 +1312,16 @@ var ProviderPeerServer = class {
1240
1312
  if (!parsed.success) return errorCarrierResponse(ERROR_CODE.protocol_error, "auth body schema rejected");
1241
1313
  const decision = handleAuthFrame(parsed.data, this.engine.directory());
1242
1314
  if (decision.kind === "err") {
1243
- this.keyring = [];
1244
- this.grants = [];
1245
- this.engine.keySessionIndex().untrack(this);
1315
+ this.sessionAuths.delete(req.sessionId);
1316
+ this.invalidateWatch(req.sessionId);
1317
+ if (!this.authed()) this.engine.keySessionIndex().untrack(this);
1246
1318
  return {
1247
1319
  status: 403,
1248
1320
  headers: this.jsonHeaders(),
1249
1321
  bodyChunks: [Buffer.from(JSON.stringify(decision.header))]
1250
1322
  };
1251
1323
  }
1252
- this.keyring = decision.keys;
1253
- this.grants = decision.valid;
1254
- this.lastView = JSON.stringify(decision.header);
1324
+ this.putSessionAuth(req.sessionId, decision.keys, decision.valid);
1255
1325
  this.engine.keySessionIndex().track(this);
1256
1326
  return {
1257
1327
  status: 200,
@@ -1261,17 +1331,18 @@ var ProviderPeerServer = class {
1261
1331
  }
1262
1332
  /** 目录刷新长轮询:since 落后即时回;未变更挂起至视图变更(200)或超时(204)。 */
1263
1333
  async handleWatch(req) {
1264
- if (!this.authed()) return errorCarrierResponse(ERROR_CODE.unauthorized, "session is not authenticated");
1334
+ const sa = this.sessionAuthOf(req.sessionId);
1335
+ if (sa === void 0 || sa.grants.length === 0) return errorCarrierResponse(ERROR_CODE.unauthorized, "session is not authenticated");
1265
1336
  const query = req.path.split("?", 2)[1] ?? "";
1266
1337
  const sinceRaw = Number(new URLSearchParams(query).get("since") ?? "0");
1267
1338
  const since = Number.isFinite(sinceRaw) && sinceRaw >= 0 ? Math.floor(sinceRaw) : 0;
1268
1339
  const current = this.engine.currentCatalogSeq();
1269
1340
  if (since < current) {
1270
1341
  const dir = this.engine.directory();
1271
- const { valid } = evaluateKeyring(this.keyring, dir);
1342
+ const { valid } = evaluateKeyring(sa.keyring, dir);
1272
1343
  if (valid.length === 0) return errorCarrierResponse(ERROR_CODE.unauthorized, "no valid key remains");
1273
1344
  const header = buildAuthOk(valid, dir, { refresh: true });
1274
- this.grants = valid;
1345
+ sa.grants = valid;
1275
1346
  return {
1276
1347
  status: 200,
1277
1348
  headers: this.jsonHeaders({ "x-aifly-catalog-seq": String(current) }),
@@ -1280,16 +1351,27 @@ var ProviderPeerServer = class {
1280
1351
  }
1281
1352
  const changed = await new Promise((resolve) => {
1282
1353
  const timer = setTimeout(() => {
1283
- this.watchWaiters.delete(wake);
1354
+ let waiters = this.watchWaiters.get(req.sessionId);
1355
+ waiters?.delete(wake);
1356
+ if (waiters !== void 0 && waiters.size === 0) this.watchWaiters.delete(req.sessionId);
1284
1357
  resolve(null);
1285
1358
  }, CATALOG_WATCH_TIMEOUT_MS);
1286
1359
  const wake = (view) => {
1287
1360
  clearTimeout(timer);
1288
1361
  resolve(view);
1289
1362
  };
1290
- this.watchWaiters.add(wake);
1363
+ let waiters = this.watchWaiters.get(req.sessionId);
1364
+ if (waiters === void 0) {
1365
+ waiters = /* @__PURE__ */ new Set();
1366
+ this.watchWaiters.set(req.sessionId, waiters);
1367
+ }
1368
+ waiters.add(wake);
1291
1369
  });
1292
1370
  if (changed === "invalid") return errorCarrierResponse(ERROR_CODE.unauthorized, "authorization invalidated");
1371
+ if (changed !== null) {
1372
+ const saAfter = this.sessionAuthOf(req.sessionId);
1373
+ if (saAfter === void 0 || saAfter.grants.length === 0) return errorCarrierResponse(ERROR_CODE.unauthorized, "session is not authenticated");
1374
+ }
1293
1375
  if (changed === null) return {
1294
1376
  status: 204,
1295
1377
  headers: [{
@@ -1304,13 +1386,15 @@ var ProviderPeerServer = class {
1304
1386
  };
1305
1387
  }
1306
1388
  async handleForward(req) {
1307
- if (!this.authed()) return errorCarrierResponse(ERROR_CODE.unauthorized, "session is not authenticated");
1389
+ const sa = this.sessionAuthOf(req.sessionId);
1390
+ if (sa === void 0 || sa.grants.length === 0) return errorCarrierResponse(ERROR_CODE.unauthorized, "session is not authenticated");
1391
+ if (req.signal.aborted) return errorCarrierResponse(ERROR_CODE.aborted, "request cancelled before dispatch");
1308
1392
  const serviceHeader = req.headers.find((h) => h.name === AIFLY_SERVICE_HEADER)?.value;
1309
1393
  if (serviceHeader === void 0) return errorCarrierResponse(ERROR_CODE.protocol_error, `missing ${AIFLY_SERVICE_HEADER} header`);
1310
1394
  const method = req.method.toUpperCase();
1311
1395
  if (!HTTP_METHODS.includes(method)) return errorCarrierResponse(ERROR_CODE.forbidden_method, `http method not allowed: ${method}`);
1312
1396
  const service = this.engine.store.getService(serviceHeader);
1313
- const grant = service === void 0 ? void 0 : this.grants.find((g) => this.engine.groupHasService(g.group, serviceHeader));
1397
+ const grant = service === void 0 ? void 0 : sa.grants.find((g) => this.engine.groupHasService(g.group, serviceHeader));
1314
1398
  if (service === void 0 || service.enabled === false || grant === void 0) return errorCarrierResponse(ERROR_CODE.unknown_service, "service not available");
1315
1399
  const acquired = this.engine.limits.acquire(grant.keyId, grant.group);
1316
1400
  if (!acquired.ok) return errorCarrierResponse(acquired.code, acquired.code === "rate_limited" ? "group concurrency limit reached" : "daily request quota reached");
@@ -1349,6 +1433,11 @@ var ProviderPeerServer = class {
1349
1433
  };
1350
1434
  const outcome = new CarrierOutcome((status, headers) => req.respondStreaming(status, headers));
1351
1435
  const ctrl = new AbortController();
1436
+ const abortUpstream = () => {
1437
+ ctrl.abort(new UpstreamAbortError(ERROR_CODE.aborted, true));
1438
+ };
1439
+ req.signal.addEventListener("abort", abortUpstream, { once: true });
1440
+ if (req.signal.aborted) abortUpstream();
1352
1441
  const act = {
1353
1442
  ctrl,
1354
1443
  keyId: grant.keyId,
@@ -2,7 +2,7 @@ import { n as UsageError, r as reportCliError } from "./errors-BGtxPkM7.mjs";
2
2
  import { n as parseArgv } from "./args-CSxXW9eD.mjs";
3
3
  import { t as resolveHttpProxy } from "./proxy-D7VMUVEg.mjs";
4
4
  import { d as resolvedRelayUrls, f as str, u as resolveDataDir } from "./common-DqSyhR6F.mjs";
5
- import { n as startProviderDaemon } from "./serve-BlWkrYrl.mjs";
5
+ import { n as startProviderDaemon } from "./serve-BB6-4Ixd.mjs";
6
6
  import { homedir } from "node:os";
7
7
  //#region src/cli/commands/provider/serve.ts
8
8
  const SPEC = {
@@ -4,7 +4,7 @@ import { m as SERVICE_ENTRY_SCHEMA } from "./rpc-contract-BAz-C8fx.mjs";
4
4
  import { t as resolveHttpProxy } from "./proxy-D7VMUVEg.mjs";
5
5
  import { n as StoreError } from "./store-CmHtxOCd.mjs";
6
6
  import { d as resolvedRelayUrls, f as str, i as openStore, l as requireString, u as resolveDataDir } from "./common-DqSyhR6F.mjs";
7
- import { i as buildServiceEntry, t as openExistingFabric } from "./serve-BlWkrYrl.mjs";
7
+ import { i as buildServiceEntry, t as openExistingFabric } from "./serve-BB6-4Ixd.mjs";
8
8
  import { homedir } from "node:os";
9
9
  import { z } from "zod";
10
10
  //#region src/provider/link.ts
@@ -1,7 +1,7 @@
1
1
  import { n as parseArgv } from "./args-CSxXW9eD.mjs";
2
2
  import { n as consumersRoot, s as listKeyrings } from "./store-Bu4I1rNj.mjs";
3
3
  import { a as ringsForRun, n as ctxHomedir, r as ctxOut, t as createSdkFabricFactory } from "./common-9KRvrs5f.mjs";
4
- import { n as createFabricSessionFactory, t as startEngine } from "./runtime-D9rSByOO.mjs";
4
+ import { n as createFabricSessionFactory, t as startEngine } from "./runtime-DKmrkfNT.mjs";
5
5
  import { homedir } from "node:os";
6
6
  //#region src/cli/commands/consumer/status.ts
7
7
  /** 状态显示名(spec 六态)。 */
@@ -2,7 +2,7 @@ import { r as reportCliError } from "./errors-BGtxPkM7.mjs";
2
2
  import { n as parseArgv } from "./args-CSxXW9eD.mjs";
3
3
  import { t as resolveHttpProxy } from "./proxy-D7VMUVEg.mjs";
4
4
  import { d as resolvedRelayUrls, f as str, i as openStore, u as resolveDataDir } from "./common-DqSyhR6F.mjs";
5
- import { a as detailDisplayLines, r as buildServiceDetail, t as openExistingFabric } from "./serve-BlWkrYrl.mjs";
5
+ import { a as detailDisplayLines, r as buildServiceDetail, t as openExistingFabric } from "./serve-BB6-4Ixd.mjs";
6
6
  import { homedir } from "node:os";
7
7
  //#region src/cli/commands/provider/status.ts
8
8
  const SPEC = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-fly",
3
- "version": "0.5.0-alpha.1",
3
+ "version": "0.6.0-alpha.1",
4
4
  "description": "ai-fly — peer-to-peer HTTP/WebSocket bridge with AI-ready presets, over OpenDWeb fabric",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "type": "module",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@hono/node-server": "^2.1.1",
35
- "@jixo/opendweb-client-sdk": "^0.5.0",
35
+ "@jixo/opendweb-client-sdk": "^0.6.0",
36
36
  "@opentray/ext-webview": "0.23.0",
37
37
  "@orpc/contract": "1.14.6",
38
38
  "@orpc/server": "1.14.6",