ai-fly 0.4.0-alpha.2 → 0.4.0-alpha.3

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
@@ -62,7 +62,7 @@ async function dispatch(command, rest) {
62
62
  const lazy = (load) => {
63
63
  return (argv, ctx) => load().then((m) => m.run([...argv], ctx));
64
64
  };
65
- return match(command).with("serve", () => lazy(() => import("./serve-FjBsmK5n.mjs"))(rest)).with("app", async () => {
65
+ return match(command).with("serve", () => lazy(() => import("./serve-CRcqQR0j.mjs"))(rest)).with("app", async () => {
66
66
  const { join, dirname } = await import("node:path");
67
67
  const { fileURLToPath } = await import("node:url");
68
68
  const { spawn } = await import("node:child_process");
@@ -77,7 +77,7 @@ async function dispatch(command, rest) {
77
77
  return await new Promise((resolve) => {
78
78
  child.once("exit", (c) => resolve(c ?? 0));
79
79
  });
80
- }).with("daemon", () => lazy(() => import("./daemon-C4kj0IwL.mjs"))(rest)).with("presets", () => lazy(() => import("./presets-DRO5N4Vm.mjs"))(rest)).with("secret", () => lazy(() => import("./secret-DKN75Vry.mjs"))(rest)).with("settings", async () => (await import("./settings-Dho5hk5Z.mjs")).runAsSettings(rest, {})).with("relay", async () => (await import("./settings-Dho5hk5Z.mjs")).runAsRelay(rest, {})).with("test", () => lazy(() => import("./test-Dxkkc-KN.mjs"))(rest)).with("service", () => lazy(() => import("./service-DnQhGK4m.mjs"))(rest)).with("group", () => lazy(() => import("./group-CjwGDch3.mjs"))(rest)).with("share", () => lazy(() => import("./share-DpQPO1eC.mjs"))(rest)).with("revoke", () => lazy(() => import("./revoke-CXTcFgoT.mjs"))(rest)).with("join", () => lazy(() => import("./join-BJMcNGV-.mjs"))(rest)).with("import", () => lazy(() => import("./import-Zy3LL_PR.mjs"))(rest)).with("run", () => lazy(() => import("./run-W7DBz_bR.mjs"))(rest)).with("ports", () => lazy(() => import("./ports-Csv91JOD.mjs"))(rest)).with("forget", () => lazy(() => import("./forget-oMwM-SsU.mjs"))(rest)).with("key", () => {
80
+ }).with("daemon", () => lazy(() => import("./daemon-CuxLimRD.mjs"))(rest)).with("presets", () => lazy(() => import("./presets-DRO5N4Vm.mjs"))(rest)).with("secret", () => lazy(() => import("./secret-DKN75Vry.mjs"))(rest)).with("settings", async () => (await import("./settings-Dho5hk5Z.mjs")).runAsSettings(rest, {})).with("relay", async () => (await import("./settings-Dho5hk5Z.mjs")).runAsRelay(rest, {})).with("test", () => lazy(() => import("./test-Dxkkc-KN.mjs"))(rest)).with("service", () => lazy(() => import("./service-CJq7aSR0.mjs"))(rest)).with("group", () => lazy(() => import("./group-CjwGDch3.mjs"))(rest)).with("share", () => lazy(() => import("./share-D7ChVNte.mjs"))(rest)).with("revoke", () => lazy(() => import("./revoke-h1X8Xr_T.mjs"))(rest)).with("join", () => lazy(() => import("./join-BJMcNGV-.mjs"))(rest)).with("import", () => lazy(() => import("./import-Zy3LL_PR.mjs"))(rest)).with("run", () => lazy(() => import("./run-W7DBz_bR.mjs"))(rest)).with("ports", () => lazy(() => import("./ports-Csv91JOD.mjs"))(rest)).with("forget", () => lazy(() => import("./forget-oMwM-SsU.mjs"))(rest)).with("key", () => {
81
81
  if (rest[0] === "add") return lazy(() => import("./key-BcNxtRJx.mjs"))(rest);
82
82
  return lazy(() => import("./key-TP7lZeqW.mjs"))(rest);
83
83
  }).with("status", async () => {
@@ -86,7 +86,7 @@ async function dispatch(command, rest) {
86
86
  const wantConsumer = scope === "consumer" || scope !== "provider" && consumersRootExists();
87
87
  const argv = scope === "provider" || scope === "consumer" ? tail : rest;
88
88
  let code = 0;
89
- if (wantProvider) code = Math.max(code, await lazy(() => import("./status-Ce-lxy52.mjs"))(argv));
89
+ if (wantProvider) code = Math.max(code, await lazy(() => import("./status-0NYOen8x.mjs"))(argv));
90
90
  if (wantConsumer) code = Math.max(code, await lazy(() => import("./status-BaRyycxh.mjs"))(argv));
91
91
  if (!wantProvider && !wantConsumer) process.stdout.write("nothing to report: no provider storage and no imported consumers\n");
92
92
  return code;
package/dist/app/main.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { createRequire } from "node:module";
1
2
  import { appendFileSync, chmodSync, existsSync, mkdirSync, promises, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, watch, writeFileSync } from "node:fs";
2
3
  import { homedir, platform } from "node:os";
3
4
  import path, { dirname, isAbsolute, join, resolve } from "node:path";
@@ -2624,6 +2625,41 @@ function evalJsonPath(root, jsonPath) {
2624
2625
  }
2625
2626
  return cur;
2626
2627
  }
2628
+ function parseScriptRef(value) {
2629
+ let body = value.slice(8);
2630
+ let bearer = false;
2631
+ if (body.endsWith("?bearer")) {
2632
+ bearer = true;
2633
+ body = body.slice(0, -7);
2634
+ }
2635
+ if (body === "") return null;
2636
+ return {
2637
+ path: body,
2638
+ bearer
2639
+ };
2640
+ }
2641
+ /**
2642
+ * 默认脚本凭据源:createRequire 同步加载 CJS 模块并返回其导出——
2643
+ * 函数导出由 resolveHeaderValue 每请求调用(值按调用计算,token 刷新即刻生效);
2644
+ * 脚本文件本身的修改需重启 daemon(require 缓存,跨 Node/Bun/Deno 一致)。
2645
+ * 信任模型与 $cmd 等价:脚本以 ai-fly 同权限执行宿主 IO(无 VM 隔离——
2646
+ * node:vm 非安全边界且 Bun/Deno 支持残缺,Owner 裁决 2026-09-12 取简方案)。
2647
+ */
2648
+ const defaultScriptCredentialSource = (modulePath) => {
2649
+ try {
2650
+ return createRequire(import.meta.url)(modulePath);
2651
+ } catch {
2652
+ return;
2653
+ }
2654
+ };
2655
+ /** 脚本导出归一:函数 / {default: fn} 取函数;其余视为无效(undefined)。 */
2656
+ function scriptExportFn(mod) {
2657
+ if (typeof mod === "function") return mod;
2658
+ if (mod !== null && typeof mod === "object" && "default" in mod) {
2659
+ const d = mod.default;
2660
+ if (typeof d === "function") return d;
2661
+ }
2662
+ }
2627
2663
  /** 默认文件凭据源:读文件 + JSON 解析 + 点径求值(仅字符串值;`~` 已在上层展开)。 */
2628
2664
  const defaultFileCredentialSource = (path, jsonPath) => {
2629
2665
  let raw;
@@ -2649,7 +2685,7 @@ const defaultFileCredentialSource = (path, jsonPath) => {
2649
2685
  * `$env:<VAR>` 语义保持——空串/未设置返回 undefined(= 省略该头)。
2650
2686
  * 各源可并存于不同头(逐头独立解析)。
2651
2687
  */
2652
- function resolveHeaderValue(value, env, secrets, files = defaultFileCredentialSource) {
2688
+ function resolveHeaderValue(value, env, secrets, files = defaultFileCredentialSource, scripts = defaultScriptCredentialSource) {
2653
2689
  if (value.startsWith("$secret:")) {
2654
2690
  const name = value.slice(8);
2655
2691
  const resolved = secrets?.(name);
@@ -2663,6 +2699,20 @@ function resolveHeaderValue(value, env, secrets, files = defaultFileCredentialSo
2663
2699
  if (resolved === void 0 || resolved === "") throw new SecretMissingError();
2664
2700
  return ref.bearer ? `Bearer ${resolved}` : resolved;
2665
2701
  }
2702
+ if (value.startsWith("$script:")) {
2703
+ const ref = parseScriptRef(value);
2704
+ if (ref === null) throw new SecretMissingError();
2705
+ const fn = scriptExportFn(scripts(ref.path.startsWith("~/") ? join(homedir(), ref.path.slice(1)) : ref.path));
2706
+ if (fn === void 0) throw new SecretMissingError();
2707
+ let resolved;
2708
+ try {
2709
+ resolved = fn({ homedir: homedir() });
2710
+ } catch {
2711
+ throw new SecretMissingError();
2712
+ }
2713
+ if (typeof resolved !== "string" || resolved === "") throw new SecretMissingError();
2714
+ return ref.bearer ? `Bearer ${resolved}` : resolved;
2715
+ }
2666
2716
  if (!value.startsWith("$env:")) return value;
2667
2717
  const name = value.slice(5);
2668
2718
  if (name === "") return void 0;
@@ -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-FjBsmK5n.mjs");
102
+ const { run: serveRun } = await import("./serve-CRcqQR0j.mjs");
103
103
  return serveRun([...startArgv], { homedir: home });
104
104
  }
105
105
  /** 后台 pid(活性核验;陈旧 pidfile 就地清理返回 null)。 */
@@ -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 str, l as resolveDataDir, u as resolvedRelayUrls } from "./common-BwKEJKOZ.mjs";
5
- import { t as openExistingFabric } from "./serve-GRJthOwO.mjs";
5
+ import { t as openExistingFabric } from "./serve-B61VHcLi.mjs";
6
6
  import { homedir } from "node:os";
7
7
  //#region src/cli/commands/provider/revoke.ts
8
8
  const SPEC = {
@@ -1,6 +1,7 @@
1
1
  import { a as routeLocalPrefix } from "./rpc-contract-CdiRZhUn.mjs";
2
2
  import { n as FORBIDDEN_REQ_HEADER_NAMES } from "./frames-BDqvhB2Y.mjs";
3
3
  import { a as parseUpstreamUrl, c as matchRequestPath, o as expandUriTemplate, s as compileMatchPattern } from "./store-YUMvMCBg.mjs";
4
+ import { createRequire } from "node:module";
4
5
  import { readFileSync } from "node:fs";
5
6
  import { homedir } from "node:os";
6
7
  import { join } from "node:path";
@@ -164,6 +165,41 @@ function evalJsonPath(root, jsonPath) {
164
165
  }
165
166
  return cur;
166
167
  }
168
+ function parseScriptRef(value) {
169
+ let body = value.slice(8);
170
+ let bearer = false;
171
+ if (body.endsWith("?bearer")) {
172
+ bearer = true;
173
+ body = body.slice(0, -7);
174
+ }
175
+ if (body === "") return null;
176
+ return {
177
+ path: body,
178
+ bearer
179
+ };
180
+ }
181
+ /**
182
+ * 默认脚本凭据源:createRequire 同步加载 CJS 模块并返回其导出——
183
+ * 函数导出由 resolveHeaderValue 每请求调用(值按调用计算,token 刷新即刻生效);
184
+ * 脚本文件本身的修改需重启 daemon(require 缓存,跨 Node/Bun/Deno 一致)。
185
+ * 信任模型与 $cmd 等价:脚本以 ai-fly 同权限执行宿主 IO(无 VM 隔离——
186
+ * node:vm 非安全边界且 Bun/Deno 支持残缺,Owner 裁决 2026-09-12 取简方案)。
187
+ */
188
+ const defaultScriptCredentialSource = (modulePath) => {
189
+ try {
190
+ return createRequire(import.meta.url)(modulePath);
191
+ } catch {
192
+ return;
193
+ }
194
+ };
195
+ /** 脚本导出归一:函数 / {default: fn} 取函数;其余视为无效(undefined)。 */
196
+ function scriptExportFn(mod) {
197
+ if (typeof mod === "function") return mod;
198
+ if (mod !== null && typeof mod === "object" && "default" in mod) {
199
+ const d = mod.default;
200
+ if (typeof d === "function") return d;
201
+ }
202
+ }
167
203
  /** 默认文件凭据源:读文件 + JSON 解析 + 点径求值(仅字符串值;`~` 已在上层展开)。 */
168
204
  const defaultFileCredentialSource = (path, jsonPath) => {
169
205
  let raw;
@@ -189,7 +225,7 @@ const defaultFileCredentialSource = (path, jsonPath) => {
189
225
  * `$env:<VAR>` 语义保持——空串/未设置返回 undefined(= 省略该头)。
190
226
  * 各源可并存于不同头(逐头独立解析)。
191
227
  */
192
- function resolveHeaderValue(value, env, secrets, files = defaultFileCredentialSource) {
228
+ function resolveHeaderValue(value, env, secrets, files = defaultFileCredentialSource, scripts = defaultScriptCredentialSource) {
193
229
  if (value.startsWith("$secret:")) {
194
230
  const name = value.slice(8);
195
231
  const resolved = secrets?.(name);
@@ -203,6 +239,20 @@ function resolveHeaderValue(value, env, secrets, files = defaultFileCredentialSo
203
239
  if (resolved === void 0 || resolved === "") throw new SecretMissingError();
204
240
  return ref.bearer ? `Bearer ${resolved}` : resolved;
205
241
  }
242
+ if (value.startsWith("$script:")) {
243
+ const ref = parseScriptRef(value);
244
+ if (ref === null) throw new SecretMissingError();
245
+ const fn = scriptExportFn(scripts(ref.path.startsWith("~/") ? join(homedir(), ref.path.slice(1)) : ref.path));
246
+ if (fn === void 0) throw new SecretMissingError();
247
+ let resolved;
248
+ try {
249
+ resolved = fn({ homedir: homedir() });
250
+ } catch {
251
+ throw new SecretMissingError();
252
+ }
253
+ if (typeof resolved !== "string" || resolved === "") throw new SecretMissingError();
254
+ return ref.bearer ? `Bearer ${resolved}` : resolved;
255
+ }
206
256
  if (!value.startsWith("$env:")) return value;
207
257
  const name = value.slice(5);
208
258
  if (name === "") return void 0;
@@ -1,6 +1,6 @@
1
1
  import { n as ROUTE_LOCAL_PREFIX } from "./rpc-contract-CdiRZhUn.mjs";
2
2
  import { t as formProbe } from "./local-test-DbpiPEsD.mjs";
3
- import { i as buildUpstreamRequest, t as PathNotOfferedError } from "./rewrite-BL3jNnFZ.mjs";
3
+ import { i as buildUpstreamRequest, t as PathNotOfferedError } from "./rewrite-WI8Ly8RX.mjs";
4
4
  //#region src/provider/route-test.ts
5
5
  const DEFAULT_TIMEOUT_MS = 2e4;
6
6
  const BODY_EXCERPT_MAX = 2e3;
@@ -2,7 +2,7 @@ import { c as RESP_META_HEADER_WHITELIST, i as FRAME_TYPE, s as REJECTED_CODE, t
2
2
  import { n as loadSdk } from "./proxy-D7VMUVEg.mjs";
3
3
  import { i as ensurePrivateDir, r as atomicWriteFileSync, t as ProviderStore } from "./store-YUMvMCBg.mjs";
4
4
  import { n as FabricWireAdapter, r as DEFAULT_BODY_CHUNK_BYTES, t as WireSession } from "./mux-BEXBL7rE.mjs";
5
- import { a as collectEnvVarNames, i as buildUpstreamRequest, n as RewriteError, r as SecretMissingError, s as buildServiceEntry, t as PathNotOfferedError } from "./rewrite-BL3jNnFZ.mjs";
5
+ import { a as collectEnvVarNames, i as buildUpstreamRequest, n as RewriteError, r as SecretMissingError, s as buildServiceEntry, t as PathNotOfferedError } from "./rewrite-WI8Ly8RX.mjs";
6
6
  import { t as SecretsStore } from "./secrets-DFdwYE_V.mjs";
7
7
  import { appendFileSync, existsSync, readFileSync, readdirSync, watch } from "node:fs";
8
8
  import "node:os";
@@ -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 str, l as resolveDataDir, u as resolvedRelayUrls } from "./common-BwKEJKOZ.mjs";
5
- import { n as startProviderDaemon } from "./serve-GRJthOwO.mjs";
5
+ import { n as startProviderDaemon } from "./serve-B61VHcLi.mjs";
6
6
  import { homedir } from "node:os";
7
7
  //#region src/cli/commands/provider/serve.ts
8
8
  const SPEC = {
@@ -218,7 +218,7 @@ async function test(options, positionals, home) {
218
218
  formRaw = (localPrefix !== void 0 ? routes.find((r) => r.localPrefix === localPrefix) : routes.length === 1 ? routes[0] : void 0)?.forms[0] ?? "openai-chat";
219
219
  }
220
220
  if (!ROUTE_FORMS.includes(formRaw)) throw new UsageError(`error: --form must be one of ${ROUTE_FORMS.join(", ")}`);
221
- const { testServiceRoute } = await import("./route-test-DqKRThLp.mjs");
221
+ const { testServiceRoute } = await import("./route-test-D9Y4QmJn.mjs");
222
222
  const { SecretsStore } = await import("./secrets-BKKxR3iB.mjs");
223
223
  const secretsStore = SecretsStore.open(dataDir);
224
224
  const hitLocalPrefix = options["local-prefix"] !== void 0 ? str(options["local-prefix"]) : (() => {
@@ -4,8 +4,8 @@ import { l as SERVICE_ENTRY_SCHEMA } from "./frames-BDqvhB2Y.mjs";
4
4
  import { t as resolveHttpProxy } from "./proxy-D7VMUVEg.mjs";
5
5
  import { n as StoreError } from "./store-YUMvMCBg.mjs";
6
6
  import { c as requireString, d as str, l as resolveDataDir, r as openStore, u as resolvedRelayUrls } from "./common-BwKEJKOZ.mjs";
7
- import { t as openExistingFabric } from "./serve-GRJthOwO.mjs";
8
- import { s as buildServiceEntry } from "./rewrite-BL3jNnFZ.mjs";
7
+ import { t as openExistingFabric } from "./serve-B61VHcLi.mjs";
8
+ import { s as buildServiceEntry } from "./rewrite-WI8Ly8RX.mjs";
9
9
  import { homedir } from "node:os";
10
10
  import { z } from "zod";
11
11
  //#region src/provider/link.ts
@@ -2,8 +2,8 @@ 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 str, l as resolveDataDir, r as openStore, u as resolvedRelayUrls } from "./common-BwKEJKOZ.mjs";
5
- import { t as openExistingFabric } from "./serve-GRJthOwO.mjs";
6
- import { c as detailDisplayLines, o as buildServiceDetail } from "./rewrite-BL3jNnFZ.mjs";
5
+ import { t as openExistingFabric } from "./serve-B61VHcLi.mjs";
6
+ import { c as detailDisplayLines, o as buildServiceDetail } from "./rewrite-WI8Ly8RX.mjs";
7
7
  import { homedir } from "node:os";
8
8
  //#region src/cli/commands/provider/status.ts
9
9
  const SPEC = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-fly",
3
- "version": "0.4.0-alpha.2",
3
+ "version": "0.4.0-alpha.3",
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",