ai-fly 0.1.1 → 0.3.0-alpha.2
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 +48 -22
- package/dist/args-CSxXW9eD.mjs +69 -0
- package/dist/common-CgxCXeTt.mjs +83 -0
- package/dist/common-CqxqIg6D.mjs +86 -0
- package/dist/config-BlZnFqx7.mjs +59 -0
- package/dist/daemon-DklsEniO.mjs +291 -0
- package/dist/{forget-BEbNwPip.mjs → forget-B17zGwj4.mjs} +3 -2
- package/dist/{sdk-C6xDRbzg.mjs → frames-BDqvhB2Y.mjs} +1 -10
- package/dist/{group-Csy9VmFb.mjs → group-B96IKEDF.mjs} +24 -4
- package/dist/{import-BVAFw5Tx.mjs → import-tilxdbTH.mjs} +8 -6
- package/dist/{join-E1_-Rt-7.mjs → join-DsKUAibH.mjs} +7 -5
- package/dist/{join-B9op0juF.mjs → join-hyqiwEek.mjs} +3 -3
- package/dist/{key-CK77IYXp.mjs → key-BiEp995L.mjs} +2 -2
- package/dist/{key-Bt4EWiuO.mjs → key-CNufbB__.mjs} +4 -3
- package/dist/local-test-C3HGjGY3.mjs +101 -0
- package/dist/models-dev-2UfQoIpQ.mjs +244 -0
- package/dist/{mux-xHl9Jrbi.mjs → mux-CS1zhF4W.mjs} +2 -2
- package/dist/{ports-BQukx7wS.mjs → ports-rRppuBgo.mjs} +3 -2
- package/dist/presets-C73CAMZ6.mjs +55 -0
- package/dist/proxy-D7VMUVEg.mjs +21 -0
- package/dist/{revoke-CyrOzc8t.mjs → revoke-CkpvK33Q.mjs} +5 -4
- package/dist/rewrite-xZHWnyJk.mjs +313 -0
- package/dist/route-test-Oew0CO1U.mjs +60 -0
- package/dist/rpc-contract-5qyWzT5t.mjs +638 -0
- package/dist/{run-Be8H-IRf.mjs → run-DbPXAm6h.mjs} +8 -5
- package/dist/{runtime-Dg4en1D8.mjs → runtime-D_nxUEjd.mjs} +3 -3
- package/dist/secret-SA37VND5.mjs +95 -0
- package/dist/secrets-BYI6ooTJ.mjs +113 -0
- package/dist/secrets-u19-8EyW.mjs +2 -0
- package/dist/{serve-DuyQMeJh.mjs → serve-Be4zdKVj.mjs} +14 -425
- package/dist/{serve-R03mDBwd.mjs → serve-DSBlodTF.mjs} +18 -6
- package/dist/service-B5uORhl3.mjs +232 -0
- package/dist/settings-C1Hb4zwd.mjs +34 -0
- package/dist/settings-DU0YqNDt.mjs +95 -0
- package/dist/{share-DGM2TOft.mjs → share-Cug0944N.mjs} +8 -5
- package/dist/{status-DRaKNvqz.mjs → status-B-j454u2.mjs} +7 -5
- package/dist/{status-W2OS7WB6.mjs → status-SkNsxGnk.mjs} +6 -4
- package/dist/{common-4VeA_3wo.mjs → store-BiTS2FTl.mjs} +3 -73
- package/dist/store-CrTUwskE.mjs +629 -0
- package/dist/test-Bc0OKBAi.mjs +64 -0
- package/package.json +1 -1
- package/dist/common-BULbPtYn.mjs +0 -1295
- package/dist/config-CO3WyW2H.mjs +0 -173
- package/dist/service-Cd4R47n4.mjs +0 -94
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { t as CliError } from "./errors-BGtxPkM7.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as
|
|
2
|
+
import { n as parseArgv } from "./args-CSxXW9eD.mjs";
|
|
3
|
+
import { n as consumersRoot, s as listKeyrings } from "./store-BiTS2FTl.mjs";
|
|
4
|
+
import { a as ringsForRun, i as printListeners, n as ctxHomedir, o as waitForSignals, r as ctxOut, t as createSdkFabricFactory } from "./common-CgxCXeTt.mjs";
|
|
5
|
+
import { n as createFabricProviderTransport, t as startEngine } from "./runtime-D_nxUEjd.mjs";
|
|
5
6
|
import { homedir } from "node:os";
|
|
6
7
|
//#region src/cli/commands/consumer/run.ts
|
|
7
8
|
async function run(argv, ctx = {}) {
|
|
@@ -11,7 +12,8 @@ async function run(argv, ctx = {}) {
|
|
|
11
12
|
tilde: true
|
|
12
13
|
},
|
|
13
14
|
"strict-ports": { type: "boolean" },
|
|
14
|
-
relay: { type: "multi" }
|
|
15
|
+
relay: { type: "multi" },
|
|
16
|
+
proxy: { type: "string" }
|
|
15
17
|
}, { homedir: ctx.homedir ?? homedir() });
|
|
16
18
|
const out = ctxOut(ctx);
|
|
17
19
|
const root = consumersRoot(options.data, ctxHomedir(ctx));
|
|
@@ -19,7 +21,8 @@ async function run(argv, ctx = {}) {
|
|
|
19
21
|
for (const w of warnings) out(`warning: ${w}`);
|
|
20
22
|
const engineRings = ringsForRun(rings);
|
|
21
23
|
if (engineRings.length === 0) throw new CliError("error: no imported providers - run 'ai-fly import <aifly1-link>' or 'ai-fly join <token>' first");
|
|
22
|
-
const factory = await createSdkFabricFactory(options.relay, ctx);
|
|
24
|
+
const factory = await createSdkFabricFactory(options.relay, ctx, void 0, options.proxy);
|
|
25
|
+
out(`gateway starting - booting fabric for ${engineRings.length} provider ring(s) (unreachable relays can stall this ~30s; Ctrl+C to abort)...`);
|
|
23
26
|
const engine = await startEngine({
|
|
24
27
|
rings: engineRings,
|
|
25
28
|
consumersRoot: root,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { i as splitBody, n as FabricWireAdapter, t as WireSession } from "./mux-
|
|
1
|
+
import { i as FRAME_TYPE, o as HTTP_METHODS } from "./frames-BDqvhB2Y.mjs";
|
|
2
|
+
import { c as loadKeyring, f as saveKeyring, t as applyCatalog, u as reconcileKeyMetadata } from "./store-BiTS2FTl.mjs";
|
|
3
|
+
import { i as splitBody, n as FabricWireAdapter, t as WireSession } from "./mux-CS1zhF4W.mjs";
|
|
4
4
|
import { n as desiredPortFor, r as listenWithFallback, t as LOOPBACK_HOST } from "./ports-pI59MtmI.mjs";
|
|
5
5
|
import { Hono } from "hono";
|
|
6
6
|
import { createAdaptorServer } from "@hono/node-server";
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { n as UsageError, r as reportCliError } from "./errors-BGtxPkM7.mjs";
|
|
2
|
+
import { n as parseArgv } from "./args-CSxXW9eD.mjs";
|
|
3
|
+
import { d as str, l as resolveDataDir } from "./common-CqxqIg6D.mjs";
|
|
4
|
+
import { t as SecretsStore } from "./secrets-BYI6ooTJ.mjs";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import process from "node:process";
|
|
7
|
+
import { createInterface } from "node:readline";
|
|
8
|
+
import { Writable } from "node:stream";
|
|
9
|
+
//#region src/cli/commands/provider/secret.ts
|
|
10
|
+
const SPEC = {
|
|
11
|
+
data: {
|
|
12
|
+
type: "string",
|
|
13
|
+
tilde: true
|
|
14
|
+
},
|
|
15
|
+
value: { type: "string" },
|
|
16
|
+
stdin: { type: "boolean" },
|
|
17
|
+
"no-bearer": { type: "boolean" }
|
|
18
|
+
};
|
|
19
|
+
const USAGE = `usage:
|
|
20
|
+
ai-fly secret set <name> [--value <v> | --stdin] [--no-bearer] [--data <dir>]
|
|
21
|
+
ai-fly secret list [--data <dir>]
|
|
22
|
+
ai-fly secret remove <name> [--data <dir>]
|
|
23
|
+
(the raw value is never displayed or returned - there is no 'secret get')`;
|
|
24
|
+
async function run(argv, ctx = {}) {
|
|
25
|
+
try {
|
|
26
|
+
const home = ctx.homedir ?? homedir();
|
|
27
|
+
const { options, positionals } = parseArgv(argv, SPEC, { homedir: home });
|
|
28
|
+
const sub = positionals[0];
|
|
29
|
+
if (sub === "set") return await set(options, positionals, home);
|
|
30
|
+
if (sub === "list") return list(options, home);
|
|
31
|
+
if (sub === "remove") return remove(options, positionals, home);
|
|
32
|
+
if (sub === void 0) throw new UsageError(USAGE);
|
|
33
|
+
throw new UsageError(`error: unknown secret subcommand '${sub}' (known: set, list, remove)`);
|
|
34
|
+
} catch (err) {
|
|
35
|
+
return reportCliError(err);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** 隐藏输入(TTY):回显屏蔽为 *;非 TTY 无 --value/--stdin 即报错。 */
|
|
39
|
+
async function readHidden(prompt) {
|
|
40
|
+
const muted = new Writable({ write(chunk, _enc, callback) {
|
|
41
|
+
process.stdout.write(/\r|\n/.test(String(chunk)) ? "\n" : "*");
|
|
42
|
+
callback();
|
|
43
|
+
} });
|
|
44
|
+
const rl = createInterface({
|
|
45
|
+
input: process.stdin,
|
|
46
|
+
output: muted,
|
|
47
|
+
terminal: true
|
|
48
|
+
});
|
|
49
|
+
const answer = await new Promise((resolve) => {
|
|
50
|
+
rl.question(prompt, (value) => resolve(value));
|
|
51
|
+
});
|
|
52
|
+
rl.close();
|
|
53
|
+
return answer;
|
|
54
|
+
}
|
|
55
|
+
async function set(options, positionals, home) {
|
|
56
|
+
const name = positionals[1];
|
|
57
|
+
if (name === void 0) throw new UsageError("error: secret set requires a <name> argument");
|
|
58
|
+
let value = options.value === void 0 ? void 0 : String(options.value);
|
|
59
|
+
if (options.stdin === true) value = await readFileSyncStdin();
|
|
60
|
+
else if (value === void 0) {
|
|
61
|
+
if (!process.stdin.isTTY) throw new UsageError("error: no TTY - pass --value <v> or --stdin for the secret value");
|
|
62
|
+
value = (await readHidden(`value for '${name}': `)).trim();
|
|
63
|
+
}
|
|
64
|
+
if (value === "") throw new UsageError("error: secret value must not be empty");
|
|
65
|
+
const entry = SecretsStore.open(resolveDataDir(void 0, home)).set(name, value, { bearerPrefix: options["no-bearer"] !== true });
|
|
66
|
+
process.stdout.write(`secret set: ${entry.name} (bearer prefix ${entry.bearerPrefix ? "on" : "off"}) - inject with service add --secret ${entry.name}\n`);
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
async function readFileSyncStdin() {
|
|
70
|
+
const chunks = [];
|
|
71
|
+
for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
|
|
72
|
+
return Buffer.concat(chunks).toString("utf8").trim();
|
|
73
|
+
}
|
|
74
|
+
function list(options, home) {
|
|
75
|
+
const secrets = SecretsStore.open(resolveDataDir(str(options.data), home)).list();
|
|
76
|
+
const out = (line) => {
|
|
77
|
+
process.stdout.write(`${line}\n`);
|
|
78
|
+
};
|
|
79
|
+
out(`secrets (${secrets.length})`);
|
|
80
|
+
for (const entry of secrets) {
|
|
81
|
+
const created = new Date(entry.createdAt).toISOString().slice(0, 16).replace("T", " ");
|
|
82
|
+
const updated = entry.updatedAt === entry.createdAt ? "" : ` updated ${new Date(entry.updatedAt).toISOString().slice(0, 16).replace("T", " ")}`;
|
|
83
|
+
out(` ${entry.name.padEnd(24)} ${created}${updated} bearer:${entry.bearerPrefix ? "on" : "off"}`);
|
|
84
|
+
}
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
function remove(options, positionals, home) {
|
|
88
|
+
const name = positionals[1];
|
|
89
|
+
if (name === void 0) throw new UsageError("error: secret remove requires a <name> argument");
|
|
90
|
+
SecretsStore.open(resolveDataDir(str(options.data), home)).remove(name);
|
|
91
|
+
process.stdout.write(`secret removed: ${name}\n`);
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { run };
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { r as SECRET_NAME_SCHEMA } from "./rpc-contract-5qyWzT5t.mjs";
|
|
2
|
+
import { i as ensurePrivateDir, n as StoreError, r as atomicWriteFileSync } from "./store-CrTUwskE.mjs";
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
//#region src/provider/secrets.ts
|
|
7
|
+
/** 文件形状:{ version: 1, secrets: { [name]: { value, createdAt, updatedAt, bearerPrefix } } }。
|
|
8
|
+
* 旧文件无 bearerPrefix 字段按 true 读入(zod default,写入时补齐)。 */
|
|
9
|
+
const SECRETS_FILE_SCHEMA = z.strictObject({
|
|
10
|
+
version: z.literal(1),
|
|
11
|
+
secrets: z.record(SECRET_NAME_SCHEMA, z.strictObject({
|
|
12
|
+
value: z.string().min(1).max(8192),
|
|
13
|
+
createdAt: z.number().int().min(0),
|
|
14
|
+
updatedAt: z.number().int().min(0),
|
|
15
|
+
bearerPrefix: z.boolean().default(true)
|
|
16
|
+
}))
|
|
17
|
+
});
|
|
18
|
+
const SECRETS_VALUE_MAX = 8192;
|
|
19
|
+
var SecretsStore = class SecretsStore {
|
|
20
|
+
dataDir;
|
|
21
|
+
constructor(dataDir) {
|
|
22
|
+
this.dataDir = dataDir;
|
|
23
|
+
}
|
|
24
|
+
static filePath(dataDir) {
|
|
25
|
+
return join(dataDir, "secrets.json");
|
|
26
|
+
}
|
|
27
|
+
/** 打开(确保目录存在;文件不存在视为空库——首次 set 时落盘)。 */
|
|
28
|
+
static open(dataDir) {
|
|
29
|
+
ensurePrivateDir(dataDir);
|
|
30
|
+
return new SecretsStore(dataDir);
|
|
31
|
+
}
|
|
32
|
+
/** 读盘 + 校验(不存在 → 空库;损坏/非法抛 StoreError(corrupt))。 */
|
|
33
|
+
read() {
|
|
34
|
+
const path = SecretsStore.filePath(this.dataDir);
|
|
35
|
+
if (!existsSync(path)) return {
|
|
36
|
+
version: 1,
|
|
37
|
+
secrets: {}
|
|
38
|
+
};
|
|
39
|
+
let raw;
|
|
40
|
+
try {
|
|
41
|
+
raw = readFileSync(path, "utf8");
|
|
42
|
+
} catch (err) {
|
|
43
|
+
throw new StoreError("corrupt", `error: cannot read ${path}: ${err.message}`);
|
|
44
|
+
}
|
|
45
|
+
let parsed;
|
|
46
|
+
try {
|
|
47
|
+
parsed = JSON.parse(raw);
|
|
48
|
+
} catch {
|
|
49
|
+
throw new StoreError("corrupt", `error: ${path} is not valid JSON (fix or remove it manually)`);
|
|
50
|
+
}
|
|
51
|
+
const result = SECRETS_FILE_SCHEMA.safeParse(parsed);
|
|
52
|
+
if (!result.success) throw new StoreError("corrupt", `error: ${path} failed validation: ${result.error.message}`);
|
|
53
|
+
return result.data;
|
|
54
|
+
}
|
|
55
|
+
write(data) {
|
|
56
|
+
atomicWriteFileSync(SecretsStore.filePath(this.dataDir), `${JSON.stringify(data, null, 2)}\n`);
|
|
57
|
+
}
|
|
58
|
+
/** 清单(名称/时间戳/bearer 开关;按名称排序稳定输出)。 */
|
|
59
|
+
list() {
|
|
60
|
+
const { secrets } = this.read();
|
|
61
|
+
return Object.entries(secrets).map(([name, entry]) => ({
|
|
62
|
+
name,
|
|
63
|
+
createdAt: entry.createdAt,
|
|
64
|
+
updatedAt: entry.updatedAt,
|
|
65
|
+
bearerPrefix: entry.bearerPrefix
|
|
66
|
+
})).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
67
|
+
}
|
|
68
|
+
/** 取值(未知名返回 undefined——由调用方决定失败语义,如 secret_missing)。 */
|
|
69
|
+
get(name) {
|
|
70
|
+
const entry = this.read().secrets[name];
|
|
71
|
+
return entry === void 0 ? void 0 : entry.value;
|
|
72
|
+
}
|
|
73
|
+
/** 解析为最终注入头值:bearerPrefix 开启时前拼 "Bearer "(幂等:值已以
|
|
74
|
+
* Bearer 开头则不再重复拼)。$secret:/test 一律走这里,不直接用 get()。 */
|
|
75
|
+
resolve(name) {
|
|
76
|
+
const entry = this.read().secrets[name];
|
|
77
|
+
if (entry === void 0) return void 0;
|
|
78
|
+
const bare = entry.value;
|
|
79
|
+
return { headerValue: entry.bearerPrefix && !/^Bearer\s/i.test(bare) ? `Bearer ${bare}` : bare };
|
|
80
|
+
}
|
|
81
|
+
/** 新增/覆写(返回清单投影;createdAt 首次落定时固定,覆写只动 updatedAt)。 */
|
|
82
|
+
set(name, value, opts) {
|
|
83
|
+
if (!SECRET_NAME_SCHEMA.safeParse(name).success) throw new StoreError("invalid", "error: secret name must be 1..128 chars of lowercase letters, digits, dot, dash, underscore");
|
|
84
|
+
if (value === "" || value.length > SECRETS_VALUE_MAX) throw new StoreError("invalid", `error: secret value must be 1..${SECRETS_VALUE_MAX} chars`);
|
|
85
|
+
const data = this.read();
|
|
86
|
+
const now = Date.now();
|
|
87
|
+
const previous = data.secrets[name];
|
|
88
|
+
const bearerPrefix = opts?.bearerPrefix ?? previous?.bearerPrefix ?? true;
|
|
89
|
+
const entry = {
|
|
90
|
+
value,
|
|
91
|
+
createdAt: previous === void 0 ? now : previous.createdAt,
|
|
92
|
+
updatedAt: now,
|
|
93
|
+
bearerPrefix
|
|
94
|
+
};
|
|
95
|
+
data.secrets[name] = entry;
|
|
96
|
+
this.write(data);
|
|
97
|
+
return {
|
|
98
|
+
name,
|
|
99
|
+
createdAt: entry.createdAt,
|
|
100
|
+
updatedAt: entry.updatedAt,
|
|
101
|
+
bearerPrefix
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** 删除(不存在抛 StoreError(not-found)——RPC 边界映射 NOT_FOUND)。 */
|
|
105
|
+
remove(name) {
|
|
106
|
+
const data = this.read();
|
|
107
|
+
if (data.secrets[name] === void 0) throw new StoreError("not-found", `error: secret '${name}' not found`);
|
|
108
|
+
delete data.secrets[name];
|
|
109
|
+
this.write(data);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
//#endregion
|
|
113
|
+
export { SecretsStore as t };
|