ai-fly 0.3.2 → 0.4.0-alpha.10

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.
Files changed (72) hide show
  1. package/dist/ai-fly.js +23 -6
  2. package/dist/app/main.js +9047 -0
  3. package/dist/{common-CqxqIg6D.mjs → common-C51SAE5f.mjs} +17 -6
  4. package/dist/{common-CgxCXeTt.mjs → common-CanLn0Qt.mjs} +1 -1
  5. package/dist/{daemon-ZWUSWAgM.mjs → daemon-BWgyJMyB.mjs} +3 -3
  6. package/dist/{forget-BXL2x4Wv.mjs → forget-B3KRkHho.mjs} +2 -2
  7. package/dist/{frames-BDqvhB2Y.mjs → frames-BDz8buix.mjs} +1 -0
  8. package/dist/{group-B96IKEDF.mjs → group-BdnvRD2t.mjs} +1 -1
  9. package/dist/hook-CvAMGts4.mjs +228 -0
  10. package/dist/hooks-DUrXA7PL.mjs +142 -0
  11. package/dist/{import-rpBFh_pa.mjs → import-CTkKGPsa.mjs} +4 -4
  12. package/dist/{join-u1DqTU3U.mjs → join-BRow9_3-.mjs} +3 -3
  13. package/dist/{join-CaFx5yoF.mjs → join-d-pqyf8e.mjs} +3 -3
  14. package/dist/{key-BiEp995L.mjs → key-CTL_AXOh.mjs} +24 -8
  15. package/dist/{key-KcUU3yhJ.mjs → key-D_66hrWW.mjs} +3 -3
  16. package/dist/{local-test-C3HGjGY3.mjs → local-test-BZHGo22F.mjs} +1 -1
  17. package/dist/{models-dev-2UfQoIpQ.mjs → models-dev-CDEyd2k3.mjs} +21 -1
  18. package/dist/{mux-CS1zhF4W.mjs → mux-BaIDugDq.mjs} +2 -2
  19. package/dist/{ports-BRXd5UXh.mjs → ports-TQ4tWmiJ.mjs} +2 -2
  20. package/dist/{presets-C73CAMZ6.mjs → presets-DleOUQiT.mjs} +2 -2
  21. package/dist/{revoke-CkpvK33Q.mjs → revoke-DTFW_EF1.mjs} +2 -2
  22. package/dist/{rewrite-xZHWnyJk.mjs → rewrite-CEzfYH9n.mjs} +45 -26
  23. package/dist/{route-test-Oew0CO1U.mjs → route-test-D2LQyX7c.mjs} +4 -4
  24. package/dist/{rpc-contract-5qyWzT5t.mjs → rpc-contract-cB5SuyQ_.mjs} +64 -9
  25. package/dist/{run-3pdPsD8e.mjs → run-D8kgXdId.mjs} +3 -3
  26. package/dist/{runtime-DNs9GtGp.mjs → runtime-C_pLA5F0.mjs} +3 -3
  27. package/dist/{secret-COdVHzjH.mjs → secret-P2RgHy2h.mjs} +2 -2
  28. package/dist/{secrets-BYI6ooTJ.mjs → secrets-1Hmddmwy.mjs} +2 -2
  29. package/dist/secrets-C9IYp93v.mjs +2 -0
  30. package/dist/{serve-DSBlodTF.mjs → serve-B51lmr9M.mjs} +2 -2
  31. package/dist/{serve-Be4zdKVj.mjs → serve-CY7ZFOFM.mjs} +6 -6
  32. package/dist/{service-B5uORhl3.mjs → service-D6TNolyh.mjs} +36 -9
  33. package/dist/{settings-DU0YqNDt.mjs → settings-Rq1zLoxY.mjs} +1 -1
  34. package/dist/{settings-C1Hb4zwd.mjs → settings-XCvAzDK8.mjs} +2 -2
  35. package/dist/{share-Cug0944N.mjs → share-DdtbAylA.mjs} +28 -13
  36. package/dist/{status-SkNsxGnk.mjs → status-DSVQ3YHm.mjs} +3 -3
  37. package/dist/{status-Bttb9aPj.mjs → status-uE2-kOyK.mjs} +3 -3
  38. package/dist/{store-CQShpYar.mjs → store-DOFDy1rY.mjs} +2 -2
  39. package/dist/{store-CrTUwskE.mjs → store-EGzVd-dn.mjs} +29 -4
  40. package/dist/{test-mlaZC1y5.mjs → test-DW4BF7xJ.mjs} +2 -2
  41. package/hooks/codex.cjs +12 -0
  42. package/hooks/env.cjs +10 -0
  43. package/hooks/file.cjs +27 -0
  44. package/hooks/secret.cjs +11 -0
  45. package/package.json +6 -2
  46. package/resources/app-icons/app-icon.icns +0 -0
  47. package/resources/app-icons/app-icon.ico +0 -0
  48. package/resources/app-icons/app-icon.json +84 -0
  49. package/resources/app-icons/app-icon.png +0 -0
  50. package/resources/app-icons/linux/128x128/app-icon.png +0 -0
  51. package/resources/app-icons/linux/16x16/app-icon.png +0 -0
  52. package/resources/app-icons/linux/256x256/app-icon.png +0 -0
  53. package/resources/app-icons/linux/32x32/app-icon.png +0 -0
  54. package/resources/app-icons/linux/48x48/app-icon.png +0 -0
  55. package/resources/app-icons/linux/512x512/app-icon.png +0 -0
  56. package/resources/app-icons/linux/64x64/app-icon.png +0 -0
  57. package/resources/app-icons/tray-icon.png +0 -0
  58. package/webui/dist/assets/index-8MLhHHM0.js +74 -0
  59. package/webui/dist/assets/index-ihWSPzNq.css +2 -0
  60. package/webui/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  61. package/webui/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  62. package/webui/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  63. package/webui/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  64. package/webui/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  65. package/webui/dist/assets/share-tech-mono-latin-400-normal-15MgdvEM.woff +0 -0
  66. package/webui/dist/assets/share-tech-mono-latin-400-normal-CCqdbj5z.woff2 +0 -0
  67. package/webui/dist/icons/presets/anthropic.svg +5 -0
  68. package/webui/dist/icons/presets/codex.svg +5 -0
  69. package/webui/dist/icons/presets/deepseek.svg +5 -0
  70. package/webui/dist/icons/presets/openai.svg +5 -0
  71. package/webui/dist/index.html +13 -0
  72. package/dist/secrets-u19-8EyW.mjs +0 -2
@@ -1,4 +1,4 @@
1
- import { n as ROUTE_LOCAL_PREFIX, s as randomZ32 } from "./rpc-contract-5qyWzT5t.mjs";
1
+ import { n as ROUTE_LOCAL_PREFIX, s as randomZ32 } from "./rpc-contract-cB5SuyQ_.mjs";
2
2
  import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { z } from "zod";
@@ -189,7 +189,11 @@ const SERVICE_REWRITE_STORE_SCHEMA = z.strictObject({
189
189
  hostHeader: z.string().min(1).max(2048).optional(),
190
190
  pathPrefixStrip: z.string().min(1).max(2048).optional(),
191
191
  pathPrefixAppend: z.string().min(1).max(2048).optional(),
192
- headerSet: z.record(z.string().min(1).max(1024), z.string().max(8192)).optional(),
192
+ headerSet: z.record(z.string().min(1).max(1024), z.union([z.string().max(8192), z.strictObject({
193
+ hook: z.string().min(1).max(128),
194
+ args: z.record(z.string().min(1).max(128), z.string().max(2048)).optional(),
195
+ bearer: z.boolean().optional()
196
+ })])).optional(),
193
197
  headerRemove: z.array(z.string().min(1).max(1024)).max(32).optional()
194
198
  });
195
199
  /** 路径路由(M3-r7):按声明顺序命中的转发规则——prefix 模式(默认,
@@ -213,6 +217,8 @@ const SERVICE_STORE_SCHEMA = z.strictObject({
213
217
  match: z.array(SERVICE_MATCH_STORE_SCHEMA).max(64),
214
218
  upstream: z.string().min(1).max(2048),
215
219
  rewrite: SERVICE_REWRITE_STORE_SCHEMA.optional(),
220
+ /** 选中的 hooks 脚本名(内建库或 ~/.aifly/hooks/<name>.cjs)。 */
221
+ hooks: z.string().regex(/^[a-z][a-z0-9_-]{0,63}$/).optional(),
216
222
  routes: z.array(SERVICE_ROUTE_STORE_SCHEMA).max(3).optional(),
217
223
  defaultPort: z.number().int().min(1).max(65535)
218
224
  });
@@ -229,9 +235,17 @@ const KEY_STORE_SCHEMA = z.strictObject({
229
235
  keyId: z.string().min(1).max(128),
230
236
  group: z.string().min(1).max(256),
231
237
  hash: z.string().regex(/^[0-9a-f]{64}$/, "key hash must be 64 hex chars"),
238
+ /** key 名(Owner 裁决 2026-09-13:签发时必填,GUI 分组视图按名展示;
239
+ * 旧记录无此字段——迁移容忍,GUI 显示为未命名)。 */
240
+ name: z.string().min(1).max(128).optional(),
241
+ /** key 原文(Owner 裁决 2026-09-13:可随时复制取代仅签发时可见——本机
242
+ * 个人工具与密钥库明文同一威胁模型;旧记录只存哈希,无法补录)。 */
243
+ key: z.string().min(8).max(256).optional(),
232
244
  createdAt: z.number().int().min(0),
233
245
  revokedAt: z.number().int().min(0).optional()
234
246
  });
247
+ /** key 名规则(同 SECRET_NAME_SCHEMA 词汇:小写开头,点横杠下划线)。 */
248
+ const KEY_NAME_SCHEMA = /^[a-z0-9][a-z0-9._-]*$/;
235
249
  const STORE_FILE_SCHEMA = z.strictObject({
236
250
  revision: z.number().int().min(0),
237
251
  meta: z.strictObject({ alias: z.string().min(1).max(256).optional() }).optional(),
@@ -364,6 +378,7 @@ var ProviderStore = class ProviderStore {
364
378
  match: input.match.map((m) => ({ ...m })),
365
379
  upstream: upstreamUrl.href,
366
380
  rewrite,
381
+ ...input.hooks !== void 0 ? { hooks: input.hooks } : {},
367
382
  ...routes !== void 0 ? { routes } : {},
368
383
  defaultPort
369
384
  };
@@ -466,9 +481,11 @@ var ProviderStore = class ProviderStore {
466
481
  listKeys() {
467
482
  return this.data.keys.map((k) => ({ ...k }));
468
483
  }
469
- /** 签发:原文仅本次返回,存储只落哈希。 */
470
- issueKey(groupName) {
484
+ /** 签发:name 缺省 "default";原文随记录落库(Owner 2026-09-13:随时
485
+ * 可复制)。name 是展示标签非身份(keyId 唯一),同组可重名。 */
486
+ issueKey(groupName, name = "default") {
471
487
  if (this.getGroup(groupName) === void 0) throw new StoreError("not-found", `error: group '${groupName}' not found`);
488
+ if (!KEY_NAME_SCHEMA.test(name)) throw new StoreError("invalid", "error: key name must match /^[a-z0-9][a-z0-9._-]*$/");
472
489
  let keyId;
473
490
  do
474
491
  keyId = randomZ32(8);
@@ -479,6 +496,8 @@ var ProviderStore = class ProviderStore {
479
496
  keyId,
480
497
  group: groupName,
481
498
  hash: hashKeyMaterial(key),
499
+ name,
500
+ key,
482
501
  createdAt
483
502
  });
484
503
  this.save();
@@ -488,6 +507,12 @@ var ProviderStore = class ProviderStore {
488
507
  createdAt
489
508
  };
490
509
  }
510
+ /** key 原文取回(旧记录只存哈希 → undefined;撤销/不存在 → undefined)。 */
511
+ getKeyMaterial(keyId) {
512
+ const found = this.data.keys.find((k) => k.keyId === keyId);
513
+ if (found === void 0 || found.revokedAt !== void 0) return void 0;
514
+ return found.key;
515
+ }
491
516
  /** 撤销(幂等:已撤销为 no-op)。 */
492
517
  revokeKey(keyId) {
493
518
  const found = this.data.keys.find((k) => k.keyId === keyId);
@@ -1,8 +1,8 @@
1
1
  import { n as UsageError, r as reportCliError } from "./errors-BGtxPkM7.mjs";
2
2
  import { n as parseArgv } from "./args-CSxXW9eD.mjs";
3
- import { n as consumersRoot, s as listKeyrings } from "./store-CQShpYar.mjs";
3
+ import { n as consumersRoot, s as listKeyrings } from "./store-DOFDy1rY.mjs";
4
4
  import { n as desiredPortFor } from "./ports-pI59MtmI.mjs";
5
- import { n as testLocalService } from "./local-test-C3HGjGY3.mjs";
5
+ import { n as testLocalService } from "./local-test-BZHGo22F.mjs";
6
6
  import { homedir } from "node:os";
7
7
  //#region src/cli/commands/consumer/test.ts
8
8
  const SPEC = {
@@ -0,0 +1,12 @@
1
+ // 内建 hooks 脚本:codex —— 读 codex CLI 登录态(~/.codex/auth.json)。
2
+ // 钩子清单(按函数名命名规范被发现):
3
+ // - authHeader(ctx) -> string:ChatGPT Codex backend 的 Bearer 认证头(去前缀裸值,
4
+ // 框架按需拼 "Bearer " 由 headerSet 配置的 bearer 决定——本脚本返回裸 token)。
5
+ module.exports.authHeader = function authHeader({ homedir }) {
6
+ const { readFileSync } = require("node:fs");
7
+ const { join } = require("node:path");
8
+ const auth = JSON.parse(readFileSync(join(homedir, ".codex", "auth.json"), "utf8"));
9
+ const token = auth && auth.tokens && auth.tokens.access_token;
10
+ if (typeof token !== "string" || token === "") throw new Error("codex auth.json missing access_token");
11
+ return token;
12
+ };
package/hooks/env.cjs ADDED
@@ -0,0 +1,10 @@
1
+ // 内建 hooks 脚本:env —— 环境变量桥。
2
+ // 钩子清单:
3
+ // - authHeader(ctx) -> string:读 args.var 指定的环境变量(OPENAI_API_KEY 等)。
4
+ module.exports.authHeader = function authHeader({ args, env: ctxEnv }) {
5
+ const name = args && args.var;
6
+ if (typeof name !== "string" || name === "") throw new Error("env hook requires args.var");
7
+ const value = (ctxEnv && ctxEnv(name)) || process.env[name];
8
+ if (value === undefined || value === "") throw new Error(`env '${name}' unset`);
9
+ return value;
10
+ };
package/hooks/file.cjs ADDED
@@ -0,0 +1,27 @@
1
+ // 内建 hooks 脚本:file —— JSON 文件取值(点径)。
2
+ // 钩子清单:
3
+ // - authHeader(ctx) -> string:读 args.path(支持 ~)+ args.jsonPath(.a.b 风格);
4
+ // args.bearer 为 "true"/"1" 时返回值拼 "Bearer " 前缀。
5
+ // watch 模式示例(返回 AsyncIterable):unwatchOnClose 实现见文档。
6
+ module.exports.authHeader = function authHeader({ homedir, args }) {
7
+ const { readFileSync } = require("node:fs");
8
+ const { join } = require("node:path");
9
+ const path = args && args.path;
10
+ const jsonPath = (args && args.jsonPath) || ".";
11
+ if (typeof path !== "string" || path === "") throw new Error("file hook requires args.path");
12
+ const abs = path.startsWith("~/") ? join(homedir, path.slice(1)) : path;
13
+ let doc;
14
+ try {
15
+ doc = JSON.parse(readFileSync(abs, "utf8"));
16
+ } catch {
17
+ throw new Error("file unreadable or invalid JSON");
18
+ }
19
+ let cur = doc;
20
+ for (const seg of jsonPath.split(".").filter(Boolean)) {
21
+ if (cur === null || cur === undefined) throw new Error("json path miss");
22
+ cur = cur[seg];
23
+ }
24
+ if (typeof cur !== "string" || cur === "") throw new Error("json path value missing");
25
+ const bearer = args && (args.bearer === "true" || args.bearer === "1");
26
+ return bearer ? `Bearer ${cur}` : cur;
27
+ };
@@ -0,0 +1,11 @@
1
+ // 内建 hooks 脚本:secret —— 密钥库(SecretsStore)桥。
2
+ // 钩子清单:
3
+ // - authHeader(ctx) -> string:读 args.name 指定的密钥(ctx.secrets 访问器;
4
+ // 值只进头不回显——$secret 法则不变)。
5
+ module.exports.authHeader = function authHeader({ args, secrets }) {
6
+ const name = args && args.name;
7
+ if (typeof name !== "string" || name === "") throw new Error("secret hook requires args.name");
8
+ const value = secrets && secrets(name);
9
+ if (value === undefined || value === "") throw new Error(`secret '${name}' not found`);
10
+ return value;
11
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-fly",
3
- "version": "0.3.2",
3
+ "version": "0.4.0-alpha.10",
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",
@@ -58,7 +58,11 @@
58
58
  "files": [
59
59
  "dist/*.js",
60
60
  "dist/*.mjs",
61
- "dist/*.d.ts"
61
+ "dist/*.d.ts",
62
+ "dist/app/**",
63
+ "hooks",
64
+ "webui/dist",
65
+ "resources/app-icons"
62
66
  ],
63
67
  "repository": {
64
68
  "type": "git",
Binary file
@@ -0,0 +1,84 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "appIcon": [
4
+ {
5
+ "platform": "darwin",
6
+ "format": "icns",
7
+ "source": {
8
+ "type": "file",
9
+ "path": "app-icon.icns"
10
+ }
11
+ },
12
+ {
13
+ "platform": "windows",
14
+ "format": "ico",
15
+ "source": {
16
+ "type": "file",
17
+ "path": "app-icon.ico"
18
+ }
19
+ },
20
+ {
21
+ "platform": "linux",
22
+ "format": "png",
23
+ "size": 16,
24
+ "source": {
25
+ "type": "file",
26
+ "path": "linux/16x16/app-icon.png"
27
+ }
28
+ },
29
+ {
30
+ "platform": "linux",
31
+ "format": "png",
32
+ "size": 32,
33
+ "source": {
34
+ "type": "file",
35
+ "path": "linux/32x32/app-icon.png"
36
+ }
37
+ },
38
+ {
39
+ "platform": "linux",
40
+ "format": "png",
41
+ "size": 48,
42
+ "source": {
43
+ "type": "file",
44
+ "path": "linux/48x48/app-icon.png"
45
+ }
46
+ },
47
+ {
48
+ "platform": "linux",
49
+ "format": "png",
50
+ "size": 64,
51
+ "source": {
52
+ "type": "file",
53
+ "path": "linux/64x64/app-icon.png"
54
+ }
55
+ },
56
+ {
57
+ "platform": "linux",
58
+ "format": "png",
59
+ "size": 128,
60
+ "source": {
61
+ "type": "file",
62
+ "path": "linux/128x128/app-icon.png"
63
+ }
64
+ },
65
+ {
66
+ "platform": "linux",
67
+ "format": "png",
68
+ "size": 256,
69
+ "source": {
70
+ "type": "file",
71
+ "path": "linux/256x256/app-icon.png"
72
+ }
73
+ },
74
+ {
75
+ "platform": "linux",
76
+ "format": "png",
77
+ "size": 512,
78
+ "source": {
79
+ "type": "file",
80
+ "path": "linux/512x512/app-icon.png"
81
+ }
82
+ }
83
+ ]
84
+ }
Binary file