@adep/cli 0.0.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/index.js ADDED
@@ -0,0 +1,4411 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // packages/cli/src/credentials.ts
13
+ import { mkdir, open, readFile, rm, stat } from "node:fs/promises";
14
+ import { dirname } from "node:path";
15
+ async function saveCredentials(paths, credentials) {
16
+ await mkdir(dirname(paths.credentialsFile), { recursive: true });
17
+ const handle = await open(paths.credentialsFile, "w", 384);
18
+ try {
19
+ await handle.writeFile(JSON.stringify(credentials, null, 2));
20
+ } finally {
21
+ await handle.close();
22
+ }
23
+ await chmodStrict(paths.credentialsFile);
24
+ }
25
+ async function chmodStrict(file) {
26
+ const info = await stat(file);
27
+ const mode = info.mode & 511;
28
+ if (mode !== 384) {
29
+ const { chmod } = await import("node:fs/promises");
30
+ await chmod(file, 384);
31
+ }
32
+ }
33
+ async function loadCredentials(paths) {
34
+ try {
35
+ const raw = await readFile(paths.credentialsFile, "utf8");
36
+ const parsed = JSON.parse(raw);
37
+ if (typeof parsed["server"] !== "string" || typeof parsed["email"] !== "string" || typeof parsed["encodedToken"] !== "string") {
38
+ return null;
39
+ }
40
+ return {
41
+ server: parsed["server"],
42
+ email: parsed["email"],
43
+ encodedToken: parsed["encodedToken"]
44
+ };
45
+ } catch {
46
+ return null;
47
+ }
48
+ }
49
+ async function clearCredentials(paths) {
50
+ await rm(paths.credentialsFile, { force: true });
51
+ }
52
+ function encodeToken(token) {
53
+ return Buffer.from(token, "utf8").toString("base64");
54
+ }
55
+ function decodeToken(encoded) {
56
+ return Buffer.from(encoded, "base64").toString("utf8");
57
+ }
58
+ var init_credentials = __esm({
59
+ "packages/cli/src/credentials.ts"() {
60
+ "use strict";
61
+ }
62
+ });
63
+
64
+ // packages/cli/src/auth.ts
65
+ function sessionCookieOf(setCookie) {
66
+ const line = setCookie.find(
67
+ (entry) => entry.startsWith("better-auth.session_token=") && !/max-age=0/i.test(entry)
68
+ );
69
+ if (line === void 0) {
70
+ throw new CliError("LOGIN_FAILED", "\u767B\u5F55\u6210\u529F\u4F46\u672A\u8FD4\u56DE\u4F1A\u8BDD token\uFF0C\u8BF7\u68C0\u67E5\u5E73\u53F0\u7248\u672C");
71
+ }
72
+ return line.split(";")[0];
73
+ }
74
+ async function login(paths, input) {
75
+ const server = input.server.replace(/\/+$/, "");
76
+ let response;
77
+ try {
78
+ response = await fetch(`${server}/api/auth/sign-in/email`, {
79
+ method: "POST",
80
+ headers: { "content-type": "application/json" },
81
+ body: JSON.stringify({ email: input.email, password: input.password })
82
+ });
83
+ } catch (error) {
84
+ throw new CliError(
85
+ "SERVER_UNREACHABLE",
86
+ `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
87
+ );
88
+ }
89
+ if (response.status !== 200) {
90
+ throw new CliError("LOGIN_FAILED", "\u767B\u5F55\u5931\u8D25\uFF1A\u90AE\u7BB1\u6216\u5BC6\u7801\u4E0D\u6B63\u786E\uFF08\u6216\u8BE5\u8D26\u53F7\u672A\u6CE8\u518C\uFF09");
91
+ }
92
+ const token = sessionCookieOf(response.headers.getSetCookie());
93
+ await saveCredentials(paths, {
94
+ server,
95
+ email: input.email,
96
+ encodedToken: encodeToken(token)
97
+ });
98
+ return { email: input.email };
99
+ }
100
+ async function whoami(paths) {
101
+ const credentials = await loadCredentials(paths);
102
+ if (credentials === null) {
103
+ throw new CliError("NOT_LOGGED_IN", "\u672A\u767B\u5F55\uFF1A\u8BF7\u5148\u6267\u884C adep login");
104
+ }
105
+ const response = await fetch(`${credentials.server}/api/auth/get-session`, {
106
+ headers: { cookie: `better-auth.session_token=${decodeToken(credentials.encodedToken)}` }
107
+ });
108
+ if (response.status !== 200) {
109
+ throw new CliError("SESSION_EXPIRED", "\u4F1A\u8BDD\u5DF2\u5931\u6548\uFF1A\u8BF7\u91CD\u65B0\u6267\u884C adep login");
110
+ }
111
+ const body = await response.json();
112
+ const email = body?.user?.email;
113
+ if (typeof email !== "string") {
114
+ throw new CliError("SESSION_EXPIRED", "\u4F1A\u8BDD\u5DF2\u5931\u6548\uFF1A\u8BF7\u91CD\u65B0\u6267\u884C adep login");
115
+ }
116
+ return { server: credentials.server, email };
117
+ }
118
+ async function logout(paths) {
119
+ const credentials = await loadCredentials(paths);
120
+ if (credentials !== null) {
121
+ try {
122
+ await fetch(`${credentials.server}/api/auth/sign-out`, {
123
+ method: "POST",
124
+ headers: { cookie: `better-auth.session_token=${decodeToken(credentials.encodedToken)}` }
125
+ });
126
+ } catch {
127
+ }
128
+ await clearCredentials(paths);
129
+ }
130
+ }
131
+ var CliError;
132
+ var init_auth = __esm({
133
+ "packages/cli/src/auth.ts"() {
134
+ "use strict";
135
+ init_credentials();
136
+ CliError = class extends Error {
137
+ constructor(code, message, exitCode = 1) {
138
+ super(message);
139
+ this.code = code;
140
+ this.exitCode = exitCode;
141
+ this.name = "CliError";
142
+ }
143
+ };
144
+ }
145
+ });
146
+
147
+ // packages/cli/src/widget/build.ts
148
+ import { createHash } from "node:crypto";
149
+ import { join as join2, resolve as resolve2 } from "node:path";
150
+ import { build as esbuildBuild } from "esbuild";
151
+ async function buildWidget(options) {
152
+ const root = resolve2(options.cwd);
153
+ const entry = join2(root, options.entry ?? "src/index.ts");
154
+ const result = await esbuildBuild({
155
+ entryPoints: [entry],
156
+ bundle: true,
157
+ write: false,
158
+ format: "esm",
159
+ target: ["es2020"],
160
+ logLevel: "error",
161
+ loader: { ".ts": "ts", ".tsx": "tsx", ".js": "js", ".jsx": "jsx" },
162
+ ...options.framework === "react" ? { jsx: "automatic", jsxImportSource: "react" } : {}
163
+ });
164
+ const text = result.outputFiles?.[0]?.text ?? "";
165
+ if (text.length === 0) {
166
+ throw new WidgetError("EMPTY_BUILD", "\u6784\u5EFA\u4EA7\u7269\u4E3A\u7A7A\uFF1A\u8BF7\u68C0\u67E5 widget \u5165\u53E3\u662F\u5426\u6B63\u786E");
167
+ }
168
+ const hash = createHash("sha256").update(text).digest("hex");
169
+ return { text, hash };
170
+ }
171
+ var WidgetError;
172
+ var init_build = __esm({
173
+ "packages/cli/src/widget/build.ts"() {
174
+ "use strict";
175
+ WidgetError = class extends Error {
176
+ constructor(code, message) {
177
+ super(message);
178
+ this.code = code;
179
+ this.name = "WidgetError";
180
+ }
181
+ };
182
+ }
183
+ });
184
+
185
+ // packages/cli/src/widget/templates.ts
186
+ function vue3Files(name) {
187
+ return {
188
+ ...TS_BASE(),
189
+ "manifest.json": MANIFEST(name, "vue3"),
190
+ "package.json": `{
191
+ "name": "${name}",
192
+ "version": "0.1.0",
193
+ "private": true,
194
+ "type": "module",
195
+ "scripts": {
196
+ "typecheck": "tsc --noEmit",
197
+ "dev": "adep widget dev",
198
+ "widget:publish": "adep widget publish -p"
199
+ },
200
+ "dependencies": {
201
+ "vue": "^3.5.0",
202
+ "@adep/types": "workspace:*"
203
+ },
204
+ "devDependencies": {
205
+ "typescript": "^5.5.0"
206
+ }
207
+ }
208
+ `,
209
+ "src/theme.css": THEME_CSS,
210
+ "src/App.ts": `import { defineComponent, h } from 'vue'
211
+
212
+ /** \u7EC4\u4EF6 props \u4E0E manifest.json \u7684 props schema \u5BF9\u9F50\uFF08contracts/ \u6821\u9A8C\u5B57\u6BB5\u5B50\u96C6\uFF09\u3002 */
213
+ export const App = defineComponent({
214
+ name: 'HelloVue',
215
+ props: {
216
+ title: { type: String, default: 'Hello' },
217
+ },
218
+ setup(props) {
219
+ return () =>
220
+ h('div', { style: { padding: 'var(--adep-space-4)' } }, [
221
+ h('h2', { style: { color: 'var(--adep-color-accent)' } }, props.title),
222
+ h(
223
+ 'p',
224
+ { style: { color: 'var(--adep-color-text-secondary)' } },
225
+ 'Vue 3 \u6E32\u67D3\u51FD\u6570\u7EC4\u4EF6\u3002\u4E3B\u9898\u53D8\u91CF\u4E0E\u9274\u6743 token \u7531\u5BBF\u4E3B\u6CE8\u5165\u3002'
226
+ ),
227
+ ])
228
+ },
229
+ })
230
+ `,
231
+ "src/index.ts": `// Widget \u8FD0\u884C\u65F6\u5165\u53E3\uFF08FE-002\uFF09\u3002\u5BFC\u51FA HarnessWidgetRuntime \u4E09\u4EF6\u5957\uFF1A
232
+ // __harness / mount(host, ctx) / unmount(host)\u3002
233
+ // \u7EC4\u4EF6\u4EE5\u6E32\u67D3\u51FD\u6570\u7F16\u5199\uFF08\u975E SFC\uFF09\uFF0Cesbuild \u514D\u63D2\u4EF6\u76F4\u7F16\uFF08M3 MVP\uFF1B.vue SFC \u8D70 Vite \u5C5E\u4E8C\u671F\uFF09\u3002
234
+ import { createApp, type App as VueApp } from 'vue'
235
+ import type { HarnessMountHost, HarnessWidgetContext } from '@adep/types'
236
+ import { App } from './App'
237
+
238
+ // \u5BBF\u4E3B \u2192 \u6302\u8F7D\u7684 app \u5F15\u7528\uFF0Cunmount \u65F6\u7528\u5B8C\u91CA\u653E\uFF08WeakMap \u4E0D\u963B\u6B62\u5BBF\u4E3B\u56DE\u6536\uFF09\u3002
239
+ const mounted = new WeakMap<object, { app: VueApp; root: HTMLElement }>()
240
+
241
+ export const __harness = true as const
242
+
243
+ export function mount(host: HarnessMountHost, ctx: HarnessWidgetContext): void {
244
+ const root = document.createElement('div')
245
+ host.appendChild(root)
246
+ const app = createApp(App, ctx.props as never)
247
+ app.mount(root)
248
+ mounted.set(host, { app, root })
249
+ }
250
+
251
+ export function unmount(host: HarnessMountHost): void {
252
+ const entry = mounted.get(host)
253
+ if (entry === undefined) return
254
+ entry.app.unmount()
255
+ host.removeChild(entry.root)
256
+ mounted.delete(host)
257
+ }
258
+ `,
259
+ "src/mock-props.json": MOCK_PROPS
260
+ };
261
+ }
262
+ function reactFiles(name) {
263
+ return {
264
+ ...TS_BASE(),
265
+ "manifest.json": MANIFEST(name, "react"),
266
+ "package.json": `{
267
+ "name": "${name}",
268
+ "version": "0.1.0",
269
+ "private": true,
270
+ "type": "module",
271
+ "scripts": {
272
+ "typecheck": "tsc --noEmit",
273
+ "dev": "adep widget dev",
274
+ "widget:publish": "adep widget publish -p"
275
+ },
276
+ "dependencies": {
277
+ "react": "^18.3.0",
278
+ "react-dom": "^18.3.0",
279
+ "@adep/types": "workspace:*"
280
+ },
281
+ "devDependencies": {
282
+ "@types/react": "^18.3.0",
283
+ "@types/react-dom": "^18.3.0",
284
+ "typescript": "^5.5.0"
285
+ }
286
+ }
287
+ `,
288
+ "src/theme.css": THEME_CSS,
289
+ "src/App.tsx": `import type { CSSProperties } from 'react'
290
+
291
+ /** \u7EC4\u4EF6 props \u4E0E manifest.json \u7684 props schema \u5BF9\u9F50\uFF08contracts/ \u6821\u9A8C\u5B57\u6BB5\u5B50\u96C6\uFF09\u3002 */
292
+ export interface WidgetProps {
293
+ title: string
294
+ }
295
+
296
+ const styleRoot: CSSProperties = { padding: 'var(--adep-space-4)' }
297
+ const styleTitle: CSSProperties = { color: 'var(--adep-color-accent)', margin: 0 }
298
+ const styleDesc: CSSProperties = { color: 'var(--adep-color-text-secondary)' }
299
+
300
+ export default function App(props: WidgetProps): React.JSX.Element {
301
+ return (
302
+ <div style={styleRoot}>
303
+ <h2 style={styleTitle}>{props.title}</h2>
304
+ <p style={styleDesc}>React 18 \u7EC4\u4EF6\u3002\u4E3B\u9898\u53D8\u91CF\u4E0E\u9274\u6743 token \u7531\u5BBF\u4E3B\u6CE8\u5165\u3002</p>
305
+ </div>
306
+ )
307
+ }
308
+ `,
309
+ "src/index.tsx": `// Widget \u8FD0\u884C\u65F6\u5165\u53E3\uFF08FE-002\uFF09\u3002\u5BFC\u51FA HarnessWidgetRuntime \u4E09\u4EF6\u5957\uFF1A
310
+ // __harness / mount(host, ctx) / unmount(host)\u3002
311
+ import { createRoot, type Root } from 'react-dom/client'
312
+ import type { HarnessMountHost, HarnessWidgetContext } from '@adep/types'
313
+ import App from './App'
314
+
315
+ const mounted = new WeakMap<object, { root: Root; host: HTMLElement }>()
316
+
317
+ export const __harness = true as const
318
+
319
+ export function mount(host: HarnessMountHost, ctx: HarnessWidgetContext): void {
320
+ const container = document.createElement('div')
321
+ host.appendChild(container)
322
+ const root = createRoot(container)
323
+ root.render(<App {...(ctx.props as never)} />)
324
+ mounted.set(host, { root, host: container })
325
+ }
326
+
327
+ export function unmount(host: HarnessMountHost): void {
328
+ const entry = mounted.get(host)
329
+ if (entry === undefined) return
330
+ entry.root.unmount()
331
+ host.removeChild(entry.host)
332
+ mounted.delete(host)
333
+ }
334
+ `,
335
+ "src/mock-props.json": MOCK_PROPS
336
+ };
337
+ }
338
+ function widgetTemplateFiles(name, template) {
339
+ return template === "react-ts" ? reactFiles(name) : vue3Files(name);
340
+ }
341
+ var WIDGET_TEMPLATES, TS_BASE, MANIFEST, THEME_CSS, MOCK_PROPS;
342
+ var init_templates = __esm({
343
+ "packages/cli/src/widget/templates.ts"() {
344
+ "use strict";
345
+ WIDGET_TEMPLATES = ["vue3-ts", "react-ts"];
346
+ TS_BASE = () => ({
347
+ "tsconfig.json": `{
348
+ "compilerOptions": {
349
+ "target": "ES2020",
350
+ "module": "ESNext",
351
+ "moduleResolution": "Bundler",
352
+ "strict": true,
353
+ "jsx": "react-jsx",
354
+ "skipLibCheck": true,
355
+ "noEmit": true
356
+ },
357
+ "include": ["src"]
358
+ }
359
+ `,
360
+ "README.md": `# <widget>
361
+
362
+ AgentDeploy \u5FAE\u524D\u7AEF\u7EC4\u4EF6\uFF08widget\uFF09\u3002
363
+
364
+ - \`adep widget dev\`\uFF1A\u672C\u5730\u5BBF\u4E3B\u6C99\u7BB1\uFF08\u4E3B\u9898\u53D8\u91CF + mock props + token \u6CE8\u5165 + \u70ED\u66F4\u65B0\uFF09
365
+ - \`adep widget publish -p <project-slug>\`\uFF1A\u6309\u6846\u67B6\u6784\u5EFA \u2192 \u4E0A\u4F20\u5E73\u53F0\u9759\u6001\u8D44\u6E90 \u2192 \u7248\u672C\u5316\u8F93\u51FA URL
366
+
367
+ > \u7EC4\u4EF6\u5165\u53E3\u5BFC\u51FA \`__harness\` / \`mount(host, ctx)\` / \`unmount(host)\`\uFF0C\u5951\u7EA6\u89C1
368
+ > \`@adep/types\` \u7684 HarnessWidgetRuntime\uFF1B\u5BBF\u4E3B\u7528 \`<RemoteWidget>\` \u6309\u9700\u62C9\u53D6\u3002
369
+ `,
370
+ ".gitignore": "node_modules/\n.adep/\ndist/\n"
371
+ });
372
+ MANIFEST = (name, framework) => `{
373
+ "name": "${name}",
374
+ "framework": "${framework}",
375
+ "props": {
376
+ "type": "object",
377
+ "properties": {
378
+ "title": { "type": "string" }
379
+ },
380
+ "required": ["title"]
381
+ },
382
+ "entry": "../dist/index.js"
383
+ }
384
+ `;
385
+ THEME_CSS = `/* \u8BBE\u8BA1\u7CFB\u7EDF\u4E3B\u9898\u53D8\u91CF\uFF1A\u5BBF\u4E3B\u7ECF CSS Variables \u6CE8\u5165\uFF08FE-002 widget dev\uFF09\u3002
386
+ \u672C\u5730\u6C99\u7BB1\u7F3A\u7701\u4EE5\u4E0B\u503C\uFF1B\u90E8\u7F72\u540E\u7531 Web IDE / \u5BBF\u4E3B\u4FA7\u6CE8\u5165\u540C\u540D\u5B57\u7684\u53D8\u91CF\u8986\u76D6\u3002 */
387
+ :root {
388
+ --adep-color-accent: #3370ff;
389
+ --adep-color-text: #1f2329;
390
+ --adep-color-text-secondary: #4c5561;
391
+ --adep-space-4: 16px;
392
+ }
393
+ `;
394
+ MOCK_PROPS = `{
395
+ "title": "Hello from mock props"
396
+ }
397
+ `;
398
+ }
399
+ });
400
+
401
+ // packages/cli/src/widget/init.ts
402
+ var init_exports = {};
403
+ __export(init_exports, {
404
+ WIDGET_TEMPLATES: () => WIDGET_TEMPLATES,
405
+ WidgetInitError: () => WidgetInitError,
406
+ initWidget: () => initWidget
407
+ });
408
+ import { mkdir as mkdir3, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
409
+ import { dirname as dirname3, join as join3, resolve as resolve3 } from "node:path";
410
+ async function initWidget(cwd, name, template) {
411
+ if (!WIDGET_NAME_RE.test(name)) {
412
+ throw new WidgetInitError(
413
+ "INVALID_NAME",
414
+ `widget \u540D "${name}" \u4E0D\u5408\u6CD5\uFF1A\u9700\u4EE5\u5C0F\u5199\u5B57\u6BCD\u5F00\u5934\uFF0C\u4EC5\u542B\u5C0F\u5199\u5B57\u6BCD / \u6570\u5B57 / \u8FDE\u5B57\u7B26`
415
+ );
416
+ }
417
+ if (!WIDGET_TEMPLATES.includes(template)) {
418
+ throw new WidgetInitError("INVALID_TEMPLATE", `\u672A\u77E5\u6A21\u677F "${template}"\uFF1A\u53EF\u9009 vue3-ts | react-ts`);
419
+ }
420
+ const projectPath = resolve3(cwd, name);
421
+ let existing;
422
+ try {
423
+ existing = await stat3(projectPath);
424
+ } catch {
425
+ existing = null;
426
+ }
427
+ if (existing !== null) {
428
+ throw new WidgetInitError("DIR_EXISTS", `\u76EE\u5F55 ${projectPath} \u5DF2\u5B58\u5728\uFF1A\u8BF7\u6362\u4E00\u4E2A\u540D\u5B57\u6216\u5148\u5220\u9664`);
429
+ }
430
+ const files = widgetTemplateFiles(name, template);
431
+ await mkdir3(projectPath, { recursive: true });
432
+ await Promise.all(
433
+ Object.entries(files).map(async ([rel, content]) => {
434
+ const target = join3(projectPath, rel);
435
+ await mkdir3(dirname3(target), { recursive: true });
436
+ await writeFile2(target, content);
437
+ })
438
+ );
439
+ return { projectPath, files: Object.keys(files).toSorted() };
440
+ }
441
+ var WidgetInitError, WIDGET_NAME_RE;
442
+ var init_init = __esm({
443
+ "packages/cli/src/widget/init.ts"() {
444
+ "use strict";
445
+ init_templates();
446
+ WidgetInitError = class extends Error {
447
+ constructor(code, message) {
448
+ super(message);
449
+ this.code = code;
450
+ this.name = "WidgetInitError";
451
+ }
452
+ };
453
+ WIDGET_NAME_RE = /^[a-z][a-z0-9-]{0,62}$/;
454
+ }
455
+ });
456
+
457
+ // packages/cli/src/prompt.ts
458
+ var prompt_exports = {};
459
+ __export(prompt_exports, {
460
+ createPrompt: () => createPrompt
461
+ });
462
+ import { createInterface } from "node:readline/promises";
463
+ import { Writable } from "node:stream";
464
+ function createPrompt(input = process.stdin) {
465
+ const rl = createInterface({ input, output: process.stdout, terminal: true });
466
+ let muted = null;
467
+ return {
468
+ async ask(question) {
469
+ const answer = await rl.question(question);
470
+ return answer.trim();
471
+ },
472
+ async askHidden(question) {
473
+ muted = createInterface({ input, output: new MutedStream(), terminal: true });
474
+ const answer = await muted.question(question);
475
+ muted.close();
476
+ muted = null;
477
+ process.stdout.write("\n");
478
+ return answer.trim();
479
+ },
480
+ close() {
481
+ muted?.close();
482
+ rl.close();
483
+ }
484
+ };
485
+ }
486
+ var MutedStream;
487
+ var init_prompt = __esm({
488
+ "packages/cli/src/prompt.ts"() {
489
+ "use strict";
490
+ MutedStream = class extends Writable {
491
+ write(_chunk, ...rest) {
492
+ void rest;
493
+ return true;
494
+ }
495
+ };
496
+ }
497
+ });
498
+
499
+ // packages/runtime/src/shared/capability-keys.ts
500
+ var RPC_CAPABILITY_KEY, CHAIN_CAPABILITY_KEY, DB_RPC;
501
+ var init_capability_keys = __esm({
502
+ "packages/runtime/src/shared/capability-keys.ts"() {
503
+ "use strict";
504
+ RPC_CAPABILITY_KEY = "__adepRpc";
505
+ CHAIN_CAPABILITY_KEY = "__adepChain";
506
+ DB_RPC = {
507
+ /** 直通方法(如 query):`(method=query, args=[sql, params])`。 */
508
+ query: "query",
509
+ /** 读取 owned 表变更流(DB-006):`(method=changes, args=[table, query])`。 */
510
+ changes: "changes",
511
+ /** 开启事务:`begin → txId`。 */
512
+ begin: "begin",
513
+ /** 提交事务:`commit, args=[txId]`。 */
514
+ commit: "commit",
515
+ /** 回滚事务:`rollback, args=[txId]`。 */
516
+ rollback: "rollback",
517
+ /** 执行一条链:`chain, args=[ChainRequest]`。 */
518
+ chain: "chain"
519
+ };
520
+ }
521
+ });
522
+
523
+ // packages/runtime/src/shared/executor-runtime.ts
524
+ function isHttpStatus(status) {
525
+ return typeof status === "number" && Number.isInteger(status) && status >= 400 && status <= 599;
526
+ }
527
+ function normalizeHttpStatus(status) {
528
+ return isHttpStatus(status) ? status : 500;
529
+ }
530
+ var ExecutorError, TIMEOUT_CODE, OOM_CODE, DEFAULT_TIMEOUT_MS, DEFAULT_MEMORY_LIMIT_MB;
531
+ var init_executor_runtime = __esm({
532
+ "packages/runtime/src/shared/executor-runtime.ts"() {
533
+ "use strict";
534
+ ExecutorError = class extends Error {
535
+ constructor(status, code, message) {
536
+ super(message);
537
+ this.status = status;
538
+ this.code = code;
539
+ this.name = "ExecutorError";
540
+ }
541
+ };
542
+ TIMEOUT_CODE = "FN_EXEC_TIMEOUT";
543
+ OOM_CODE = "FN_EXEC_OOM";
544
+ DEFAULT_TIMEOUT_MS = 1e4;
545
+ DEFAULT_MEMORY_LIMIT_MB = 128;
546
+ }
547
+ });
548
+
549
+ // packages/runtime/src/functions/runtime/executor.ts
550
+ var init_executor = __esm({
551
+ "packages/runtime/src/functions/runtime/executor.ts"() {
552
+ "use strict";
553
+ init_executor_runtime();
554
+ }
555
+ });
556
+
557
+ // packages/runtime/src/functions/domain.ts
558
+ var MAX_TOTAL_SOURCE_BYTES, FnError;
559
+ var init_domain = __esm({
560
+ "packages/runtime/src/functions/domain.ts"() {
561
+ "use strict";
562
+ MAX_TOTAL_SOURCE_BYTES = 256 * 1024;
563
+ FnError = class extends Error {
564
+ status;
565
+ code;
566
+ constructor(status, code, message) {
567
+ super(message);
568
+ this.status = status;
569
+ this.code = code;
570
+ this.name = "FnError";
571
+ }
572
+ };
573
+ }
574
+ });
575
+
576
+ // packages/runtime/src/functions/deps/manifest.ts
577
+ import { createHash as createHash2 } from "node:crypto";
578
+ function isVersionRangeSpec(spec) {
579
+ if (spec === "*" || spec === "latest") return true;
580
+ const unions = spec.split("||");
581
+ return unions.every((union) => {
582
+ const trimmed = union.trim();
583
+ if (trimmed.length === 0) return false;
584
+ const hyphen = trimmed.split(" - ");
585
+ if (hyphen.length === 2) {
586
+ return COMPARATOR_PATTERN.test(hyphen[0].trim()) && COMPARATOR_PATTERN.test(hyphen[1].trim());
587
+ }
588
+ return trimmed.split(/\s+/).every((part) => COMPARATOR_PATTERN.test(part));
589
+ });
590
+ }
591
+ function parseManifestDependencies(content) {
592
+ let parsed;
593
+ try {
594
+ parsed = JSON.parse(content);
595
+ } catch {
596
+ throw new FnError(400, "DEP_INVALID_MANIFEST", "package.json \u4E0D\u662F\u5408\u6CD5 JSON");
597
+ }
598
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
599
+ throw new FnError(400, "DEP_INVALID_MANIFEST", "package.json \u9876\u5C42\u5FC5\u987B\u662F\u5BF9\u8C61");
600
+ }
601
+ const raw = parsed["dependencies"];
602
+ if (raw === void 0) return {};
603
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
604
+ throw new FnError(400, "DEP_INVALID_MANIFEST", "dependencies \u5FC5\u987B\u662F { \u5305\u540D: \u7248\u672C\u8303\u56F4 } \u5BF9\u8C61");
605
+ }
606
+ const entries = Object.entries(raw);
607
+ if (entries.length > MANIFEST_MAX_DEPS) {
608
+ throw new FnError(
609
+ 400,
610
+ "DEP_INVALID_MANIFEST",
611
+ `\u4F9D\u8D56\u6761\u76EE\u8D85\u8FC7\u4E0A\u9650\uFF08${MANIFEST_MAX_DEPS} \u4E2A\uFF0C\u5F53\u524D ${entries.length} \u4E2A\uFF09`
612
+ );
613
+ }
614
+ const dependencies = {};
615
+ for (const [name, spec] of entries) {
616
+ if (!PACKAGE_NAME_PATTERN.test(name)) {
617
+ throw new FnError(
618
+ 400,
619
+ "DEP_INVALID_MANIFEST",
620
+ `\u975E\u6CD5\u4F9D\u8D56\u540D "${name}"\uFF1A\u987B\u4E3A npm \u5305\u540D\uFF08scoped \u5F62\u5982 @scope/name\uFF09`
621
+ );
622
+ }
623
+ if (typeof spec !== "string" || !isVersionRangeSpec(spec)) {
624
+ throw new FnError(
625
+ 400,
626
+ "DEP_SPEC_REJECTED",
627
+ `\u4F9D\u8D56 "${name}" \u7684\u7248\u672C\u58F0\u660E "${String(spec)}" \u4E0D\u88AB\u63A5\u53D7\uFF1A\u53EA\u652F\u6301\u8BED\u4E49\u5316\u7248\u672C\u8303\u56F4\uFF08^/~/>=/\u7CBE\u786E\uFF09\uFF0CURL\u3001git\u3001file\u3001workspace \u53D6\u5305\u88AB registry \u767D\u540D\u5355\u62D2\u7EDD`
628
+ );
629
+ }
630
+ dependencies[name] = spec;
631
+ }
632
+ return dependencies;
633
+ }
634
+ function tryParseManifestDependencies(content) {
635
+ if (content === void 0) return {};
636
+ try {
637
+ return parseManifestDependencies(content);
638
+ } catch {
639
+ return {};
640
+ }
641
+ }
642
+ function classifyDependencies(dependencies, builtin) {
643
+ const builtinDeps = {};
644
+ const customDeps = {};
645
+ for (const [name, spec] of Object.entries(dependencies)) {
646
+ if (builtin.includes(name)) builtinDeps[name] = spec;
647
+ else customDeps[name] = spec;
648
+ }
649
+ return { builtinDeps, customDeps };
650
+ }
651
+ function depsKeyOf(dependencies) {
652
+ const canonical = Object.entries(dependencies).map(([name, version]) => `${name}@${version}`).toSorted().join("\n");
653
+ return createHash2("sha256").update(canonical).digest("hex").slice(0, 16);
654
+ }
655
+ var PACKAGE_NAME_PATTERN, COMPARATOR_PATTERN, MANIFEST_MAX_DEPS;
656
+ var init_manifest = __esm({
657
+ "packages/runtime/src/functions/deps/manifest.ts"() {
658
+ "use strict";
659
+ init_domain();
660
+ PACKAGE_NAME_PATTERN = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-._~]+$/;
661
+ COMPARATOR_PATTERN = /^(?:\^|~|>=|<=|>|<|=)?\d+(?:\.(?:\d+|x|X|\*)){0,2}(?:-[\w.-]+)?(?:\+[\w.-]+)?$/;
662
+ MANIFEST_MAX_DEPS = 100;
663
+ }
664
+ });
665
+
666
+ // packages/runtime/src/functions/deps/resolve.ts
667
+ import { resolve as resolve4 } from "node:path";
668
+ function resolveExecutionDeps(config, projectId, manifestContent) {
669
+ const manifest = tryParseManifestDependencies(manifestContent);
670
+ const { customDeps } = classifyDependencies(manifest, config.builtin);
671
+ const custom = Object.keys(customDeps);
672
+ return {
673
+ // 绝对化(相对进程 cwd,与 installer 侧 resolve(rootDir) 同基准):worker 的 createRequire 需要确定路径
674
+ dir: custom.length === 0 ? null : resolve4(config.rootDir, projectId, depsKeyOf(customDeps)),
675
+ builtin: [...config.builtin],
676
+ custom
677
+ };
678
+ }
679
+ var init_resolve = __esm({
680
+ "packages/runtime/src/functions/deps/resolve.ts"() {
681
+ "use strict";
682
+ init_manifest();
683
+ }
684
+ });
685
+
686
+ // packages/runtime/src/functions/runtime/worker-executor.ts
687
+ import { readFileSync } from "node:fs";
688
+ import { fileURLToPath, pathToFileURL } from "node:url";
689
+ import { dirname as dirname4, join as join4 } from "node:path";
690
+ import { Worker } from "node:worker_threads";
691
+ function resolveWorkerEntry(baseDir = fileURLToPath(new URL(".", import.meta.url))) {
692
+ const candidates = [
693
+ join4(baseDir, "worker-entry.js"),
694
+ join4(baseDir, "worker-entry.ts"),
695
+ join4(baseDir, "domains/functions/runtime/worker-entry.js"),
696
+ join4(baseDir, "domains/functions/runtime/worker-entry.ts")
697
+ ];
698
+ let current = baseDir;
699
+ for (let depth = 0; depth < 8; depth += 1) {
700
+ candidates.push(
701
+ join4(current, "packages/runtime/src/functions/runtime/worker-entry.js"),
702
+ join4(current, "packages/runtime/src/functions/runtime/worker-entry.ts")
703
+ );
704
+ const parent = dirname4(current);
705
+ if (parent === current) break;
706
+ current = parent;
707
+ }
708
+ for (const candidate of candidates) {
709
+ try {
710
+ readFileSync(candidate);
711
+ return pathToFileURL(candidate);
712
+ } catch {
713
+ continue;
714
+ }
715
+ }
716
+ throw new Error("\u65E0\u6CD5\u5B9A\u4F4D worker \u5165\u53E3\uFF08worker-entry.ts / worker-entry.js\uFF09");
717
+ }
718
+ function rpcReply(worker, id, ok, payload) {
719
+ worker.postMessage({
720
+ type: "rpc-response",
721
+ id,
722
+ ok,
723
+ ...payload?.result === void 0 ? {} : { result: payload.result },
724
+ ...payload?.error === void 0 ? {} : { error: payload.error }
725
+ });
726
+ }
727
+ var WorkerFunctionExecutor;
728
+ var init_worker_executor = __esm({
729
+ "packages/runtime/src/functions/runtime/worker-executor.ts"() {
730
+ "use strict";
731
+ init_executor();
732
+ init_resolve();
733
+ WorkerFunctionExecutor = class {
734
+ depsConfig;
735
+ fetchConfig;
736
+ constructor(options = {}) {
737
+ this.depsConfig = options.deps;
738
+ this.fetchConfig = options.fetch;
739
+ }
740
+ async execute(input) {
741
+ const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS;
742
+ const memoryLimitMb = input.memoryLimitMb ?? DEFAULT_MEMORY_LIMIT_MB;
743
+ const entry = input.entry ?? "index.ts";
744
+ const deps = this.depsConfig === void 0 ? void 0 : resolveExecutionDeps(this.depsConfig, input.project.id, input.files["package.json"]);
745
+ const logs = [];
746
+ return new Promise((resolve12, reject) => {
747
+ let worker;
748
+ try {
749
+ worker = new Worker(resolveWorkerEntry(), {
750
+ workerData: {
751
+ files: input.files,
752
+ entry,
753
+ request: input.request,
754
+ capabilities: input.capabilities ?? [],
755
+ ...input.env === void 0 ? {} : { env: input.env },
756
+ ...deps === void 0 ? {} : { deps },
757
+ ...this.fetchConfig === void 0 ? {} : { fetch: this.fetchConfig }
758
+ },
759
+ resourceLimits: { maxOldGenerationSizeMb: memoryLimitMb }
760
+ });
761
+ } catch (error) {
762
+ reject(
763
+ new ExecutorError(
764
+ 500,
765
+ "FN_EXEC_ERROR",
766
+ error instanceof Error ? error.message : "worker \u6784\u9020\u5931\u8D25"
767
+ )
768
+ );
769
+ return;
770
+ }
771
+ const timer = setTimeout(() => {
772
+ void worker.terminate();
773
+ reject(
774
+ new ExecutorError(504, TIMEOUT_CODE, `\u51FD\u6570\u6267\u884C\u8D85\u8FC7 ${timeoutMs}ms \u9650\u5236\uFF0Cworker \u5DF2\u88AB\u56DE\u6536`)
775
+ );
776
+ }, timeoutMs);
777
+ worker.on(
778
+ "message",
779
+ (message) => {
780
+ if (message.type === "rpc") {
781
+ const handler = input.rpcHandlers?.[message.capability ?? ""];
782
+ if (handler === void 0) {
783
+ rpcReply(worker, message.id, false, {
784
+ error: `RPC \u80FD\u529B "${message.capability ?? ""}" \u672A\u6CE8\u518C`
785
+ });
786
+ return;
787
+ }
788
+ const rpcArgs = Array.isArray(message.args) ? message.args : [];
789
+ void (async () => {
790
+ try {
791
+ const result = await handler(message.method ?? "", rpcArgs);
792
+ rpcReply(worker, message.id, true, { result });
793
+ } catch (error) {
794
+ rpcReply(worker, message.id, false, {
795
+ error: error instanceof Error ? error.message : String(error)
796
+ });
797
+ }
798
+ })();
799
+ return;
800
+ }
801
+ if (message.type === "log") {
802
+ logs.push(`[${message.level ?? "log"}] ${message.message ?? ""}`);
803
+ return;
804
+ }
805
+ if (message.type === "result") {
806
+ clearTimeout(timer);
807
+ void worker.terminate();
808
+ resolve12({ body: message.body, logs });
809
+ return;
810
+ }
811
+ if (message.type === "error") {
812
+ clearTimeout(timer);
813
+ void worker.terminate();
814
+ const isOom = typeof message.message === "string" && /allocation\s+(failed|error)|out\s+of\s+memory|\bOOM\b/i.test(message.message);
815
+ reject(
816
+ isOom ? new ExecutorError(500, OOM_CODE, "\u51FD\u6570\u5185\u5B58\u8D85\u9650\uFF0C\u6267\u884C\u5DF2\u4E2D\u6B62") : (
817
+ // FN-011:函数抛错携带的 status 透传落 ExecutorError.status(非法/缺失 → 500 兼容旧形态)。
818
+ new ExecutorError(
819
+ normalizeHttpStatus(message.status),
820
+ message.code ?? "FN_EXEC_ERROR",
821
+ message.message ?? "\u51FD\u6570\u6267\u884C\u5931\u8D25"
822
+ )
823
+ )
824
+ );
825
+ }
826
+ }
827
+ );
828
+ worker.on("error", (error) => {
829
+ clearTimeout(timer);
830
+ const isOom = /allocation\s+(failed|error)|out\s+of\s+memory|\bOOM\b/i.test(error.message);
831
+ reject(
832
+ isOom ? new ExecutorError(500, OOM_CODE, "\u51FD\u6570\u5185\u5B58\u8D85\u9650\uFF0C\u6267\u884C\u5DF2\u4E2D\u6B62") : new ExecutorError(500, "FN_EXEC_ERROR", error.message)
833
+ );
834
+ });
835
+ });
836
+ }
837
+ async dispose() {
838
+ }
839
+ };
840
+ }
841
+ });
842
+
843
+ // packages/runtime/src/database/builder/dialect.ts
844
+ function dialectFor(driver) {
845
+ return driver.engine === "pg" ? postgresDialect : sqliteDialect;
846
+ }
847
+ var sqliteDialect, postgresDialect;
848
+ var init_dialect = __esm({
849
+ "packages/runtime/src/database/builder/dialect.ts"() {
850
+ "use strict";
851
+ sqliteDialect = {
852
+ name: "sqlite",
853
+ placeholder: () => "?",
854
+ quote: (identifier) => `"${identifier.replace(/"/g, '""')}"`,
855
+ lastInsertIdClause: () => "",
856
+ upsertConflictClause: (columns) => ` ON CONFLICT (${columns.map((column) => `"${column.replace(/"/g, '""')}"`).join(", ")}) DO NOTHING`
857
+ };
858
+ postgresDialect = {
859
+ name: "postgres",
860
+ placeholder: (index) => `$${index + 1}`,
861
+ quote: (identifier) => `"${identifier.replace(/"/g, '""')}"`,
862
+ lastInsertIdClause: () => " RETURNING id",
863
+ upsertConflictClause: (columns) => ` ON CONFLICT (${columns.map((column) => `"${column.replace(/"/g, '""')}"`).join(", ")}) DO NOTHING`
864
+ };
865
+ }
866
+ });
867
+
868
+ // packages/runtime/src/database/provision/identifier.ts
869
+ function assertIdentifier(name) {
870
+ if (!IDENTIFIER_PATTERN.test(name)) {
871
+ throw new DbError(
872
+ 400,
873
+ "DB_UNSAFE_OP",
874
+ `\u975E\u6CD5\u6807\u8BC6\u7B26 "${name.slice(0, 32)}"\uFF1A\u4EC5\u5141\u8BB8\u5B57\u6BCD / \u4E0B\u5212\u7EBF\u5F00\u5934\u7684\u5B57\u6BCD\u6570\u5B57\u4E0B\u5212\u7EBF\u7EC4\u5408`
875
+ );
876
+ }
877
+ }
878
+ function quoteIdentifier(name) {
879
+ assertIdentifier(name);
880
+ return `"${name.replace(/"/g, '""')}"`;
881
+ }
882
+ var DbError, IDENTIFIER_PATTERN;
883
+ var init_identifier = __esm({
884
+ "packages/runtime/src/database/provision/identifier.ts"() {
885
+ "use strict";
886
+ DbError = class extends Error {
887
+ constructor(status, code, message) {
888
+ super(message);
889
+ this.status = status;
890
+ this.code = code;
891
+ this.name = "DbError";
892
+ }
893
+ };
894
+ IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]{0,62}$/;
895
+ }
896
+ });
897
+
898
+ // packages/runtime/src/database/builder/guards.ts
899
+ function unsafeOperation(message) {
900
+ return new DbError(400, "DB_UNSAFE_OP", message);
901
+ }
902
+ function stripLiterals(sql) {
903
+ return sql.replace(/'[^']*(?:''[^']*)*'/g, "").replace(/"[^"]*(?:""[^"]*)*"/g, "").replace(/--[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
904
+ }
905
+ function assertReadOnlyQuery(sql) {
906
+ const stripped = stripLiterals(sql);
907
+ if (stripped.includes(";")) {
908
+ throw unsafeOperation("\u4EC5\u5141\u8BB8\u5355\u6761\u8BED\u53E5\uFF0C\u7981\u6B62\u591A\u8BED\u53E5\u5806\u53E0");
909
+ }
910
+ const head = stripped.trim().replace(/^\(+/, "").trim().toUpperCase();
911
+ if (!head.startsWith("SELECT") && !head.startsWith("WITH")) {
912
+ throw unsafeOperation("cloud.db.query \u4EC5\u5141\u8BB8\u53EA\u8BFB\u67E5\u8BE2\uFF08SELECT / WITH\uFF09");
913
+ }
914
+ if (/ATTACH|DETACH/.test(stripped.toUpperCase())) {
915
+ throw unsafeOperation("\u7981\u6B62\u8DE8\u5E93\u64CD\u4F5C\uFF08ATTACH / DETACH\uFF09");
916
+ }
917
+ if (/SQLITE_\w+/i.test(stripped)) {
918
+ throw unsafeOperation("\u7981\u6B62\u8BBF\u95EE\u7CFB\u7EDF\u8868\uFF08sqlite_*\uFF09");
919
+ }
920
+ }
921
+ var init_guards = __esm({
922
+ "packages/runtime/src/database/builder/guards.ts"() {
923
+ "use strict";
924
+ init_identifier();
925
+ }
926
+ });
927
+
928
+ // packages/runtime/src/database/builder/owned.ts
929
+ function changeLogTable(table) {
930
+ const name = `${CHANGE_LOG_PREFIX}${table}`;
931
+ assertIdentifier(name);
932
+ return name;
933
+ }
934
+ function assertUserColumn(name) {
935
+ assertIdentifier(name);
936
+ if (name.startsWith("__") && name !== OWNED_OWNER_KEY) {
937
+ throw new DbError(400, "DB_UNSAFE_OP", `\u4FDD\u7559\u524D\u7F00 "__" \u7684\u5217\u540D\u4E0D\u88AB\u5141\u8BB8\uFF1A${name.slice(0, 32)}`);
938
+ }
939
+ if (name.startsWith("_adep_")) {
940
+ throw new DbError(
941
+ 400,
942
+ "DB_UNSAFE_OP",
943
+ `\u5E73\u53F0\u4FDD\u7559\u6BB5 "_adep_" \u7684\u5217\u540D\u4E0D\u88AB\u5141\u8BB8\uFF1A${name.slice(0, 32)}`
944
+ );
945
+ }
946
+ }
947
+ async function hasChangeLog(driver, table) {
948
+ if (driver.engine === "pg") {
949
+ return await driver.get(
950
+ "SELECT 1 FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = $1",
951
+ [changeLogTable(table)]
952
+ ) !== null;
953
+ }
954
+ return await driver.get("SELECT 1 AS x FROM sqlite_master WHERE type = ? AND name = ?", [
955
+ "table",
956
+ changeLogTable(table)
957
+ ]) !== null;
958
+ }
959
+ async function assertOwned(driver, table) {
960
+ if (!await hasChangeLog(driver, table)) {
961
+ throw unsafeOperation(`\u8868 "${table}" \u4E0D\u662F owned \u8868\uFF08\u7F3A\u5C11\u53D8\u66F4\u6D41\u8868 ${changeLogTable(table)}\uFF09`);
962
+ }
963
+ }
964
+ async function appendChange(driver, table, op, id, ownerKey, before, after) {
965
+ const ph = dialectFor(driver).placeholder;
966
+ await driver.run(
967
+ `INSERT INTO ${quoteIdentifier(changeLogTable(table))} ("ts","op","id","__owner_key","before","after") VALUES (${ph(0)},${ph(1)},${ph(2)},${ph(3)},${ph(4)},${ph(5)})`,
968
+ [
969
+ (/* @__PURE__ */ new Date()).toISOString(),
970
+ op,
971
+ id,
972
+ ownerKey,
973
+ before === null ? null : JSON.stringify(before),
974
+ after === null ? null : JSON.stringify(after)
975
+ ]
976
+ );
977
+ }
978
+ async function runOwnedWrite(driver, fn) {
979
+ await driver.run("SAVEPOINT _adep_change");
980
+ try {
981
+ await fn(driver);
982
+ await driver.run("RELEASE SAVEPOINT _adep_change");
983
+ } catch (error) {
984
+ await driver.run("ROLLBACK TO SAVEPOINT _adep_change");
985
+ await driver.run("RELEASE SAVEPOINT _adep_change");
986
+ throw error;
987
+ }
988
+ }
989
+ function parseChange(row) {
990
+ const before = row["before"];
991
+ const after = row["after"];
992
+ return {
993
+ seq: Number(row["seq"]),
994
+ ts: String(row["ts"]),
995
+ op: row["op"],
996
+ id: String(row["id"]),
997
+ ownerKey: row["__owner_key"] === null || row["__owner_key"] === void 0 ? null : String(row["__owner_key"]),
998
+ before: before === null || before === void 0 ? null : JSON.parse(String(before)),
999
+ after: after === null || after === void 0 ? null : JSON.parse(String(after))
1000
+ };
1001
+ }
1002
+ async function readChanges(driver, table, query = {}) {
1003
+ await assertOwned(driver, table);
1004
+ const ph = dialectFor(driver).placeholder;
1005
+ const params = [];
1006
+ const conditions = [];
1007
+ if (query.afterSeq !== void 0) {
1008
+ if (!Number.isInteger(query.afterSeq) || query.afterSeq < 0) {
1009
+ throw unsafeOperation("afterSeq \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570");
1010
+ }
1011
+ conditions.push(`"seq" > ${ph(params.length)}`);
1012
+ params.push(query.afterSeq);
1013
+ }
1014
+ if (query.ownerKey !== void 0) {
1015
+ if (query.ownerKey === null) {
1016
+ conditions.push('"__owner_key" IS NULL');
1017
+ } else {
1018
+ conditions.push(`"__owner_key" = ${ph(params.length)}`);
1019
+ params.push(query.ownerKey);
1020
+ }
1021
+ }
1022
+ if (query.limit !== void 0) {
1023
+ if (!Number.isInteger(query.limit) || query.limit < 0) {
1024
+ throw unsafeOperation("limit \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570");
1025
+ }
1026
+ }
1027
+ let sql = `SELECT "seq","ts","op","id","__owner_key","before","after" FROM ` + quoteIdentifier(changeLogTable(table));
1028
+ if (conditions.length > 0) sql += ` WHERE ${conditions.join(" AND ")}`;
1029
+ sql += ' ORDER BY "seq" ASC';
1030
+ if (query.limit !== void 0) {
1031
+ sql += ` LIMIT ${ph(params.length)}`;
1032
+ params.push(query.limit);
1033
+ }
1034
+ const rows = await driver.all(sql, params);
1035
+ return rows.map(parseChange);
1036
+ }
1037
+ var OWNED_PK, OWNED_OWNER_KEY, CHANGE_LOG_PREFIX;
1038
+ var init_owned = __esm({
1039
+ "packages/runtime/src/database/builder/owned.ts"() {
1040
+ "use strict";
1041
+ init_identifier();
1042
+ init_dialect();
1043
+ init_guards();
1044
+ OWNED_PK = "id";
1045
+ OWNED_OWNER_KEY = "__owner_key";
1046
+ CHANGE_LOG_PREFIX = "_adep_changes_";
1047
+ }
1048
+ });
1049
+
1050
+ // packages/runtime/src/database/builder/ulid.ts
1051
+ import { randomFillSync } from "node:crypto";
1052
+ function encodeTime(now) {
1053
+ let ts = Math.trunc(now);
1054
+ let out = "";
1055
+ for (let i = 0; i < TIME_LEN; i++) {
1056
+ out = ENCODING[ts % 32] + out;
1057
+ ts = Math.floor(ts / 32);
1058
+ }
1059
+ return out;
1060
+ }
1061
+ function encodeRandom(bytes) {
1062
+ let out = "";
1063
+ let buffer = 0;
1064
+ let bits = 0;
1065
+ for (const byte of bytes) {
1066
+ buffer = buffer << 8 | byte;
1067
+ bits += 8;
1068
+ while (bits >= 5) {
1069
+ out += ENCODING[buffer >>> bits - 5 & 31];
1070
+ bits -= 5;
1071
+ }
1072
+ }
1073
+ return out.slice(0, RANDOM_LEN);
1074
+ }
1075
+ function incrBase32(prev) {
1076
+ const chars = prev.split("");
1077
+ for (let i = chars.length - 1; i >= 0; i--) {
1078
+ const idx = ENCODING.indexOf(chars[i]);
1079
+ if (idx < 31) {
1080
+ chars[i] = ENCODING[idx + 1];
1081
+ return chars.join("");
1082
+ }
1083
+ chars[i] = ENCODING[0];
1084
+ }
1085
+ return chars.join("");
1086
+ }
1087
+ function ulid(now = Date.now()) {
1088
+ const time = encodeTime(now);
1089
+ let random;
1090
+ if (now === lastTime) {
1091
+ random = incrBase32(lastRandom);
1092
+ } else {
1093
+ lastTime = now;
1094
+ const bytes = new Uint8Array(10);
1095
+ randomFillSync(bytes);
1096
+ random = encodeRandom(bytes);
1097
+ }
1098
+ lastRandom = random;
1099
+ return time + random;
1100
+ }
1101
+ var ENCODING, TIME_LEN, RANDOM_LEN, lastTime, lastRandom;
1102
+ var init_ulid = __esm({
1103
+ "packages/runtime/src/database/builder/ulid.ts"() {
1104
+ "use strict";
1105
+ ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
1106
+ TIME_LEN = 10;
1107
+ RANDOM_LEN = 16;
1108
+ lastTime = 0;
1109
+ lastRandom = "";
1110
+ }
1111
+ });
1112
+
1113
+ // packages/runtime/src/database/builder/table.ts
1114
+ function pushParam(params, dialect, value) {
1115
+ params.push(value);
1116
+ return dialect.placeholder(params.length - 1);
1117
+ }
1118
+ function assertHasWhere(state) {
1119
+ if (state.wheres.length === 0) {
1120
+ throw unsafeOperation("update / delete \u5FC5\u987B\u5148\u6307\u5B9A where\uFF08\u9632\u6B62\u5168\u8868\u8BEF\u6539 / \u8BEF\u5220\uFF09");
1121
+ }
1122
+ }
1123
+ async function resolveOwned(state, driver) {
1124
+ if (state.owned === true) {
1125
+ await assertOwned(driver, state.table);
1126
+ return true;
1127
+ }
1128
+ return state.owned ?? await hasChangeLog(driver, state.table);
1129
+ }
1130
+ function toOwnerKey(row) {
1131
+ const value = row[OWNED_OWNER_KEY];
1132
+ return value === null || value === void 0 ? null : String(value);
1133
+ }
1134
+ function ownedInsertRow(row) {
1135
+ const effective = { ...row };
1136
+ if (effective[OWNED_PK] === void 0) {
1137
+ effective[OWNED_PK] = ulid();
1138
+ }
1139
+ return effective;
1140
+ }
1141
+ async function captureBeforeRows(state, dialect, driver) {
1142
+ const select = compileSelect({ ...state, columns: [] }, dialect);
1143
+ return driver.all(select.sql, select.params);
1144
+ }
1145
+ function compileWhere(wheres, dialect, params) {
1146
+ return wheres.map((where) => {
1147
+ const quoted = dialect.quote(where.column);
1148
+ if (LIST_OPERATORS.has(where.operator)) {
1149
+ const values = where.value;
1150
+ if (values.length === 0) {
1151
+ throw unsafeOperation(`${where.operator.toUpperCase()} \u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u503C`);
1152
+ }
1153
+ const marks = values.map((value2) => pushParam(params, dialect, value2));
1154
+ return `${quoted} ${where.operator.toUpperCase()} (${marks.join(", ")})`;
1155
+ }
1156
+ const value = where.value;
1157
+ if (value === null) {
1158
+ if (where.operator === "=") return `${quoted} IS NULL`;
1159
+ if (where.operator === "!=") return `${quoted} IS NOT NULL`;
1160
+ }
1161
+ const mark = pushParam(params, dialect, value);
1162
+ return `${quoted} ${where.operator} ${mark}`;
1163
+ }).join(" AND ");
1164
+ }
1165
+ function compileSelect(state, dialect) {
1166
+ const params = [];
1167
+ const columns = state.columns.length > 0 ? state.columns.map((column) => dialect.quote(column)).join(", ") : "*";
1168
+ let sql = `SELECT ${columns} FROM ${dialect.quote(state.table)}`;
1169
+ if (state.wheres.length > 0) {
1170
+ sql += ` WHERE ${compileWhere(state.wheres, dialect, params)}`;
1171
+ }
1172
+ if (state.orderBys.length > 0) {
1173
+ sql += ` ORDER BY ${state.orderBys.map((order) => `${dialect.quote(order.column)} ${order.direction.toUpperCase()}`).join(", ")}`;
1174
+ }
1175
+ if (state.limit !== void 0) sql += ` LIMIT ${pushParam(params, dialect, state.limit)}`;
1176
+ if (state.offset !== void 0) sql += ` OFFSET ${pushParam(params, dialect, state.offset)}`;
1177
+ return { sql, params };
1178
+ }
1179
+ function compileCount(state, dialect) {
1180
+ const params = [];
1181
+ let sql = `SELECT count(*) AS n FROM ${dialect.quote(state.table)}`;
1182
+ if (state.wheres.length > 0) {
1183
+ sql += ` WHERE ${compileWhere(state.wheres, dialect, params)}`;
1184
+ }
1185
+ return { sql, params };
1186
+ }
1187
+ function compileInsert(table, row, dialect) {
1188
+ const entries = Object.entries(row);
1189
+ if (entries.length === 0) {
1190
+ throw unsafeOperation("insert \u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B57\u6BB5");
1191
+ }
1192
+ const params = [];
1193
+ const columns = entries.map(([name]) => {
1194
+ assertUserColumn(name);
1195
+ return dialect.quote(name);
1196
+ }).join(", ");
1197
+ const marks = entries.map(([, value]) => pushParam(params, dialect, value));
1198
+ return {
1199
+ sql: `INSERT INTO ${dialect.quote(table)} (${columns}) VALUES (${marks.join(", ")})`,
1200
+ params
1201
+ };
1202
+ }
1203
+ function compileInsertMany(table, rows, dialect) {
1204
+ if (rows.length === 0) {
1205
+ throw unsafeOperation("insertMany \u81F3\u5C11\u9700\u8981\u4E00\u884C");
1206
+ }
1207
+ const columns = [...new Set(rows.flatMap((row) => Object.keys(row)))];
1208
+ if (columns.length === 0) {
1209
+ throw unsafeOperation("insertMany \u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B57\u6BB5");
1210
+ }
1211
+ columns.forEach(assertUserColumn);
1212
+ const params = [];
1213
+ const quoted = columns.map((column) => dialect.quote(column)).join(", ");
1214
+ const valueGroups = rows.map((row) => {
1215
+ const marks = columns.map((column) => pushParam(params, dialect, row[column] ?? null));
1216
+ return `(${marks.join(", ")})`;
1217
+ });
1218
+ return {
1219
+ sql: `INSERT INTO ${dialect.quote(table)} (${quoted}) VALUES ${valueGroups.join(", ")}`,
1220
+ params
1221
+ };
1222
+ }
1223
+ function compileUpdate(table, wheres, values, dialect) {
1224
+ const entries = Object.entries(values);
1225
+ if (entries.length === 0) {
1226
+ throw unsafeOperation("update \u81F3\u5C11\u9700\u8981\u4E00\u4E2A\u5B57\u6BB5");
1227
+ }
1228
+ const params = [];
1229
+ const sets = entries.map(([name, value]) => {
1230
+ assertUserColumn(name);
1231
+ return `${dialect.quote(name)} = ${pushParam(params, dialect, value)}`;
1232
+ }).join(", ");
1233
+ const where = compileWhere(wheres, dialect, params);
1234
+ return { sql: `UPDATE ${dialect.quote(table)} SET ${sets} WHERE ${where}`, params };
1235
+ }
1236
+ function compileDelete(table, wheres, dialect) {
1237
+ const params = [];
1238
+ const where = compileWhere(wheres, dialect, params);
1239
+ return { sql: `DELETE FROM ${dialect.quote(table)} WHERE ${where}`, params };
1240
+ }
1241
+ function createTableBuilder(table, driver, dialect, options = {}) {
1242
+ assertIdentifier(table);
1243
+ const guardWrite = options.guardWrite ?? (() => void 0);
1244
+ const initialState = {
1245
+ table,
1246
+ columns: [],
1247
+ wheres: [],
1248
+ orderBys: [],
1249
+ limit: void 0,
1250
+ offset: void 0
1251
+ };
1252
+ const build = (state) => {
1253
+ const derived = (patch) => build({ ...state, ...patch });
1254
+ return {
1255
+ select(...columns) {
1256
+ columns.forEach(assertUserColumn);
1257
+ return derived({ columns });
1258
+ },
1259
+ owned() {
1260
+ return derived({ owned: true });
1261
+ },
1262
+ where(column, operatorOrValue, maybeValue) {
1263
+ assertUserColumn(column);
1264
+ let operator;
1265
+ let value;
1266
+ if (maybeValue !== void 0) {
1267
+ operator = operatorOrValue;
1268
+ if (!OPERATORS.has(operator)) {
1269
+ throw unsafeOperation(`\u4E0D\u652F\u6301\u7684\u64CD\u4F5C\u7B26 "${operator}"`);
1270
+ }
1271
+ if (LIST_OPERATORS.has(operator) && !Array.isArray(maybeValue)) {
1272
+ throw unsafeOperation(`${operator.toUpperCase()} \u9700\u8981\u6570\u7EC4\u503C`);
1273
+ }
1274
+ value = maybeValue;
1275
+ } else {
1276
+ operator = "=";
1277
+ value = operatorOrValue;
1278
+ }
1279
+ return derived({ wheres: [...state.wheres, { column, operator, value }] });
1280
+ },
1281
+ orderBy(column, direction = "asc") {
1282
+ assertUserColumn(column);
1283
+ if (direction !== "asc" && direction !== "desc") {
1284
+ throw unsafeOperation("orderBy \u65B9\u5411\u4EC5\u652F\u6301 asc / desc");
1285
+ }
1286
+ return derived({ orderBys: [...state.orderBys, { column, direction }] });
1287
+ },
1288
+ limit(n) {
1289
+ if (!Number.isInteger(n) || n < 0) {
1290
+ throw unsafeOperation("limit \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570");
1291
+ }
1292
+ return derived({ limit: n });
1293
+ },
1294
+ offset(n) {
1295
+ if (!Number.isInteger(n) || n < 0) {
1296
+ throw unsafeOperation("offset \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570");
1297
+ }
1298
+ return derived({ offset: n });
1299
+ },
1300
+ async get() {
1301
+ const compiled = compileSelect(state, dialect);
1302
+ return driver.all(compiled.sql, compiled.params);
1303
+ },
1304
+ async first() {
1305
+ const compiled = compileSelect({ ...state, limit: 1 }, dialect);
1306
+ return driver.get(compiled.sql, compiled.params);
1307
+ },
1308
+ async count() {
1309
+ const compiled = compileCount(state, dialect);
1310
+ const row = await driver.get(compiled.sql, compiled.params);
1311
+ return row === null ? 0 : Number(row["n"]);
1312
+ },
1313
+ async insert(row) {
1314
+ guardWrite();
1315
+ Object.keys(row).forEach(assertUserColumn);
1316
+ if (await resolveOwned(state, driver)) {
1317
+ const effective = ownedInsertRow(row);
1318
+ const ownerKey = toOwnerKey(effective);
1319
+ const compiled2 = compileInsert(state.table, effective, dialect);
1320
+ await runOwnedWrite(driver, async (d) => {
1321
+ await d.run(compiled2.sql, compiled2.params);
1322
+ await appendChange(
1323
+ d,
1324
+ state.table,
1325
+ "insert",
1326
+ String(effective[OWNED_PK]),
1327
+ ownerKey,
1328
+ null,
1329
+ effective
1330
+ );
1331
+ });
1332
+ return;
1333
+ }
1334
+ const compiled = compileInsert(state.table, row, dialect);
1335
+ await driver.run(compiled.sql, compiled.params);
1336
+ },
1337
+ async insertMany(rows) {
1338
+ guardWrite();
1339
+ const insertColumns = [...new Set(rows.flatMap((row) => Object.keys(row)))];
1340
+ insertColumns.forEach(assertUserColumn);
1341
+ if (await resolveOwned(state, driver)) {
1342
+ const effectiveRows = rows.map(ownedInsertRow);
1343
+ const compiled2 = compileInsertMany(state.table, effectiveRows, dialect);
1344
+ await runOwnedWrite(driver, async (d) => {
1345
+ await d.run(compiled2.sql, compiled2.params);
1346
+ for (const effective of effectiveRows) {
1347
+ await appendChange(
1348
+ d,
1349
+ state.table,
1350
+ "insert",
1351
+ String(effective[OWNED_PK]),
1352
+ toOwnerKey(effective),
1353
+ null,
1354
+ effective
1355
+ );
1356
+ }
1357
+ });
1358
+ return;
1359
+ }
1360
+ const compiled = compileInsertMany(state.table, rows, dialect);
1361
+ await driver.run(compiled.sql, compiled.params);
1362
+ },
1363
+ async update(values) {
1364
+ guardWrite();
1365
+ assertHasWhere(state);
1366
+ Object.keys(values).forEach(assertUserColumn);
1367
+ if (await resolveOwned(state, driver)) {
1368
+ const before = await captureBeforeRows(state, dialect, driver);
1369
+ const compiled2 = compileUpdate(state.table, state.wheres, values, dialect);
1370
+ await runOwnedWrite(driver, async (d) => {
1371
+ await d.run(compiled2.sql, compiled2.params);
1372
+ for (const row of before) {
1373
+ const after = { ...row, ...values };
1374
+ await appendChange(
1375
+ d,
1376
+ state.table,
1377
+ "update",
1378
+ String(row[OWNED_PK]),
1379
+ toOwnerKey(row),
1380
+ row,
1381
+ after
1382
+ );
1383
+ }
1384
+ });
1385
+ return before.length;
1386
+ }
1387
+ const compiled = compileUpdate(state.table, state.wheres, values, dialect);
1388
+ return (await driver.run(compiled.sql, compiled.params)).changes;
1389
+ },
1390
+ async delete() {
1391
+ guardWrite();
1392
+ assertHasWhere(state);
1393
+ if (await resolveOwned(state, driver)) {
1394
+ const before = await captureBeforeRows(state, dialect, driver);
1395
+ const compiled2 = compileDelete(state.table, state.wheres, dialect);
1396
+ await runOwnedWrite(driver, async (d) => {
1397
+ await d.run(compiled2.sql, compiled2.params);
1398
+ for (const row of before) {
1399
+ await appendChange(
1400
+ d,
1401
+ state.table,
1402
+ "delete",
1403
+ String(row[OWNED_PK]),
1404
+ toOwnerKey(row),
1405
+ row,
1406
+ null
1407
+ );
1408
+ }
1409
+ });
1410
+ return before.length;
1411
+ }
1412
+ const compiled = compileDelete(state.table, state.wheres, dialect);
1413
+ return (await driver.run(compiled.sql, compiled.params)).changes;
1414
+ }
1415
+ };
1416
+ };
1417
+ return build(initialState);
1418
+ }
1419
+ var OPERATORS, LIST_OPERATORS;
1420
+ var init_table = __esm({
1421
+ "packages/runtime/src/database/builder/table.ts"() {
1422
+ "use strict";
1423
+ init_identifier();
1424
+ init_guards();
1425
+ init_owned();
1426
+ init_ulid();
1427
+ OPERATORS = /* @__PURE__ */ new Set([
1428
+ "=",
1429
+ "!=",
1430
+ ">",
1431
+ ">=",
1432
+ "<",
1433
+ "<=",
1434
+ "like",
1435
+ "in",
1436
+ "not in"
1437
+ ]);
1438
+ LIST_OPERATORS = /* @__PURE__ */ new Set(["in", "not in"]);
1439
+ }
1440
+ });
1441
+
1442
+ // packages/runtime/src/database/builder/index.ts
1443
+ function createCloudDb(driver, options = {}) {
1444
+ const dialect = options.dialect ?? dialectFor(driver);
1445
+ let txState = TX_STATES.get(driver);
1446
+ if (txState === void 0) {
1447
+ txState = { inTransaction: false };
1448
+ TX_STATES.set(driver, txState);
1449
+ }
1450
+ const makeHandle = (handleOptions) => {
1451
+ const guardWrite = () => {
1452
+ if (txState !== void 0 && txState.inTransaction && !handleOptions.allowWriteDuringTx) {
1453
+ throw unsafeOperation("\u4E8B\u52A1\u8FDB\u884C\u4E2D\uFF1A\u7981\u6B62\u5728\u4E8B\u52A1\u5916\u5BF9\u540C\u4E00\u9879\u76EE\u5E93\u6267\u884C\u5199\u64CD\u4F5C");
1454
+ }
1455
+ };
1456
+ const handle = {
1457
+ table(name) {
1458
+ return createTableBuilder(name, driver, dialect, { guardWrite });
1459
+ },
1460
+ async transaction(fn) {
1461
+ if (txState !== void 0 && txState.inTransaction) {
1462
+ throw unsafeOperation("\u4E0D\u5141\u8BB8\u5D4C\u5957\u4E8B\u52A1\uFF1A\u4E8B\u52A1\u5185\u7981\u6B62\u518D\u6B21\u8C03\u7528 transaction()");
1463
+ }
1464
+ txState.inTransaction = true;
1465
+ await driver.run("BEGIN");
1466
+ const txHandle = makeHandle({ allowWriteDuringTx: true });
1467
+ try {
1468
+ const result = await fn(txHandle);
1469
+ await driver.run("COMMIT");
1470
+ return result;
1471
+ } catch (error) {
1472
+ await driver.run("ROLLBACK");
1473
+ throw error;
1474
+ } finally {
1475
+ txState.inTransaction = false;
1476
+ }
1477
+ },
1478
+ async query(sql, params) {
1479
+ if (!Array.isArray(params)) {
1480
+ throw unsafeOperation("query \u7684 params \u5FC5\u987B\u63D0\u4F9B\uFF08\u65E0\u53C2\u4F20 []\uFF09");
1481
+ }
1482
+ guardWrite();
1483
+ assertReadOnlyQuery(sql);
1484
+ return driver.all(sql, params);
1485
+ },
1486
+ async changes(table, query = {}) {
1487
+ return readChanges(driver, table, query);
1488
+ }
1489
+ };
1490
+ return handle;
1491
+ };
1492
+ return makeHandle({ allowWriteDuringTx: false });
1493
+ }
1494
+ var TX_STATES;
1495
+ var init_builder = __esm({
1496
+ "packages/runtime/src/database/builder/index.ts"() {
1497
+ "use strict";
1498
+ init_dialect();
1499
+ init_guards();
1500
+ init_owned();
1501
+ init_table();
1502
+ TX_STATES = /* @__PURE__ */ new WeakMap();
1503
+ }
1504
+ });
1505
+
1506
+ // packages/runtime/src/database/sdk/cloud.ts
1507
+ import { randomUUID } from "node:crypto";
1508
+ function errorWithCode(error) {
1509
+ const code = typeof error === "object" && error !== null && typeof error.code === "string" ? error.code : void 0;
1510
+ if (code !== void 0 && error instanceof Error) {
1511
+ return new Error(`[${code}] ${error.message}`);
1512
+ }
1513
+ return error;
1514
+ }
1515
+ function createDbCapability(driver, options = {}) {
1516
+ const db = createCloudDb(driver);
1517
+ const activeTxs = /* @__PURE__ */ new Map();
1518
+ const guardTxWrite = (txId, terminal) => {
1519
+ if (txId === void 0) {
1520
+ if (activeTxs.size > 0 && WRITE_TERMINALS.has(terminal)) {
1521
+ throw unsafeOperation("\u4E8B\u52A1\u8FDB\u884C\u4E2D\uFF1A\u7981\u6B62\u5728\u4E8B\u52A1\u5916\u5BF9\u540C\u4E00\u9879\u76EE\u5E93\u6267\u884C\u5199\u64CD\u4F5C");
1522
+ }
1523
+ return;
1524
+ }
1525
+ if (!activeTxs.has(txId)) {
1526
+ throw unsafeOperation("\u5F15\u7528\u7684\u4E8B\u52A1\u5DF2\u7ED3\u675F\u6216\u4E0D\u5B58\u5728");
1527
+ }
1528
+ };
1529
+ const runChain = async (request) => {
1530
+ const tableName = request.rootArgs[0];
1531
+ if (typeof tableName !== "string" && typeof tableName !== "number") {
1532
+ throw unsafeOperation("table \u9700\u8981\u8868\u540D\u5B57\u7B26\u4E32");
1533
+ }
1534
+ let builder = db.table(String(tableName));
1535
+ for (const step of request.steps) {
1536
+ const invoke = builder[step.method];
1537
+ if (typeof invoke !== "function") {
1538
+ throw unsafeOperation(`\u4E91\u6570\u636E\u5E93\u4E0D\u652F\u6301\u94FE\u5F0F\u65B9\u6CD5 "${String(step.method)}"`);
1539
+ }
1540
+ builder = invoke(...step.args);
1541
+ }
1542
+ guardTxWrite(request.txId, request.terminal);
1543
+ if (WRITE_TERMINALS.has(request.terminal) && options.beforeWrite !== void 0) {
1544
+ await options.beforeWrite(driver);
1545
+ }
1546
+ const terminal = builder[request.terminal];
1547
+ if (typeof terminal !== "function") {
1548
+ throw unsafeOperation(`\u4E91\u6570\u636E\u5E93\u4E0D\u652F\u6301\u7EC8\u503C\u65B9\u6CD5 "${request.terminal}"`);
1549
+ }
1550
+ return terminal(...request.terminalArgs);
1551
+ };
1552
+ const handler = async (method, args) => {
1553
+ try {
1554
+ switch (method) {
1555
+ case DB_RPC.query: {
1556
+ const [sql, params] = args;
1557
+ return await db.query(sql, params);
1558
+ }
1559
+ case DB_RPC.changes: {
1560
+ const [table, query] = args;
1561
+ return await db.changes(table, query);
1562
+ }
1563
+ case DB_RPC.begin: {
1564
+ if (activeTxs.size > 0) throw unsafeOperation("\u4E0D\u5141\u8BB8\u5D4C\u5957\u4E8B\u52A1");
1565
+ await driver.run("BEGIN");
1566
+ const txId = randomUUID();
1567
+ activeTxs.set(txId, true);
1568
+ return txId;
1569
+ }
1570
+ case DB_RPC.commit: {
1571
+ const [txId] = args;
1572
+ if (!activeTxs.has(txId)) throw unsafeOperation("\u5F15\u7528\u7684\u4E8B\u52A1\u5DF2\u7ED3\u675F\u6216\u4E0D\u5B58\u5728");
1573
+ activeTxs.delete(txId);
1574
+ await driver.run("COMMIT");
1575
+ return void 0;
1576
+ }
1577
+ case DB_RPC.rollback: {
1578
+ const [txId] = args;
1579
+ if (activeTxs.has(txId)) {
1580
+ activeTxs.delete(txId);
1581
+ await driver.run("ROLLBACK");
1582
+ }
1583
+ return void 0;
1584
+ }
1585
+ case DB_RPC.chain: {
1586
+ const request = args[0];
1587
+ return await runChain(request);
1588
+ }
1589
+ default:
1590
+ throw new Error(`\u672A\u77E5\u7684 cloud.db \u65B9\u6CD5 "${String(method)}"`);
1591
+ }
1592
+ } catch (error) {
1593
+ throw errorWithCode(error);
1594
+ }
1595
+ };
1596
+ return {
1597
+ capabilities: [{ name: "db", value: { [CHAIN_CAPABILITY_KEY]: CLOUD_DB_SPEC } }],
1598
+ rpcHandlers: { db: handler }
1599
+ };
1600
+ }
1601
+ var CLOUD_DB_SPEC, WRITE_TERMINALS;
1602
+ var init_cloud = __esm({
1603
+ "packages/runtime/src/database/sdk/cloud.ts"() {
1604
+ "use strict";
1605
+ init_capability_keys();
1606
+ init_builder();
1607
+ init_guards();
1608
+ CLOUD_DB_SPEC = {
1609
+ kind: "cloud-db",
1610
+ rootMethod: "table",
1611
+ stepMethods: ["select", "where", "orderBy", "limit", "offset"],
1612
+ terminalMethods: ["get", "first", "count", "insert", "insertMany", "update", "delete"],
1613
+ directMethods: ["query", "changes"],
1614
+ transactionMethod: "transaction"
1615
+ };
1616
+ WRITE_TERMINALS = /* @__PURE__ */ new Set(["insert", "insertMany", "update", "delete"]);
1617
+ }
1618
+ });
1619
+
1620
+ // packages/cli/src/sim/sql-engine.ts
1621
+ function ident(raw) {
1622
+ return raw.trim().replace(/^"|"$/g, "").trim();
1623
+ }
1624
+ function toNumber(raw) {
1625
+ const t = raw.trim();
1626
+ if (t === "?") return null;
1627
+ const n = Number(t);
1628
+ return Number.isNaN(n) ? null : n;
1629
+ }
1630
+ function stripQuotes(raw) {
1631
+ const t = raw.trim();
1632
+ if (/^'.*'$/.test(t)) return t.slice(1, -1);
1633
+ if (/^".*"$/.test(t)) return t.slice(1, -1);
1634
+ return t;
1635
+ }
1636
+ function parseCreateTable(ddl) {
1637
+ const m = /^CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s*\(([\s\S]*)\)$/i.exec(
1638
+ ddl.trim()
1639
+ );
1640
+ if (m === null) return null;
1641
+ const name = ident(m[1]);
1642
+ const body = m[2];
1643
+ const columns = [];
1644
+ for (const part of body.split(",")) {
1645
+ const tokens = part.trim().split(/\s+/);
1646
+ const colName = ident(tokens[0] ?? "");
1647
+ const type = (tokens[1] ?? "TEXT").toUpperCase();
1648
+ const primaryKey = tokens.includes("PRIMARY") && tokens.includes("KEY");
1649
+ const autoincrement = primaryKey && tokens.includes("AUTOINCREMENT");
1650
+ columns.push({ name: colName, type, primaryKey, autoincrement });
1651
+ }
1652
+ return { name, columns };
1653
+ }
1654
+ function parseWhereClauses(whereRaw, cursor) {
1655
+ const clauses = [];
1656
+ for (const part of whereRaw.split(/\s+AND\s+/i)) {
1657
+ const t = part.trim();
1658
+ if (t.length === 0) continue;
1659
+ if (/\bIS\s+NULL\b/i.test(t)) {
1660
+ const col2 = ident(t.split(/\s+IS\s+NULL\b/i)[0] ?? "");
1661
+ clauses.push({ column: col2, operator: "IS NULL", value: null, list: false });
1662
+ continue;
1663
+ }
1664
+ if (/\bIS\s+NOT\s+NULL\b/i.test(t)) {
1665
+ const col2 = ident(t.split(/\s+IS\s+NOT\s+NULL\b/i)[0] ?? "");
1666
+ clauses.push({ column: col2, operator: "IS NOT NULL", value: null, list: false });
1667
+ continue;
1668
+ }
1669
+ const opMatch = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s*(=|!=|>=|<=|>|<|like|in|not\s+in)\s*(.+)$/i.exec(
1670
+ t
1671
+ );
1672
+ if (opMatch === null) continue;
1673
+ const col = ident(opMatch[1] ?? "");
1674
+ const op = (opMatch[3] ?? opMatch[2] ?? "").toLowerCase();
1675
+ const rhs = (opMatch[4] ?? "").trim();
1676
+ if (op === "in" || op === "not in") {
1677
+ const inner = rhs.replace(/^\(|\)$/g, "");
1678
+ const items = splitListItems(inner);
1679
+ const list = items.map((item) => {
1680
+ if (item.trim() === "?") return cursor.take();
1681
+ return stripQuotes(item);
1682
+ });
1683
+ clauses.push({ column: col, operator: op, value: list, list: true });
1684
+ continue;
1685
+ }
1686
+ let value;
1687
+ if (rhs === "?") {
1688
+ value = cursor.take();
1689
+ } else {
1690
+ value = stripQuotes(rhs);
1691
+ }
1692
+ clauses.push({ column: col, operator: op, value, list: false });
1693
+ }
1694
+ return clauses;
1695
+ }
1696
+ function matchWhere(clauses, row) {
1697
+ return clauses.every((c) => matchValue(row[c.column], c));
1698
+ }
1699
+ function splitListItems(inner) {
1700
+ const items = [];
1701
+ let depth = 0;
1702
+ let buffer = "";
1703
+ for (let i = 0; i < inner.length; i += 1) {
1704
+ const ch = inner[i];
1705
+ if (ch === "(") depth += 1;
1706
+ else if (ch === ")") depth -= 1;
1707
+ if (ch === "," && depth === 0) {
1708
+ items.push(buffer);
1709
+ buffer = "";
1710
+ } else {
1711
+ buffer += ch;
1712
+ }
1713
+ }
1714
+ items.push(buffer);
1715
+ return items;
1716
+ }
1717
+ function matchValue(value, clause) {
1718
+ const op = clause.operator;
1719
+ if (op === "IS NULL") return value === null || value === void 0;
1720
+ if (op === "IS NOT NULL") return value !== null && value !== void 0;
1721
+ if (op === "in") return clause.value.some((item) => value === item);
1722
+ if (op === "not in") return !clause.value.some((item) => value === item);
1723
+ if (op === "like") {
1724
+ if (typeof value !== "string") return false;
1725
+ const pattern = String(clause.value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/%/g, ".*").replace(/_/g, ".");
1726
+ return new RegExp(`^${pattern}$`, "s").test(value);
1727
+ }
1728
+ const left = value;
1729
+ const right = clause.value;
1730
+ switch (op) {
1731
+ case "=":
1732
+ return left === right;
1733
+ case "!=":
1734
+ return left !== right;
1735
+ case ">":
1736
+ return left !== null && right !== null && left > right;
1737
+ case ">=":
1738
+ return left !== null && right !== null && left >= right;
1739
+ case "<":
1740
+ return left !== null && right !== null && left < right;
1741
+ case "<=":
1742
+ return left !== null && right !== null && left <= right;
1743
+ default:
1744
+ return false;
1745
+ }
1746
+ }
1747
+ function assertReadOnly(sql) {
1748
+ const stripped = sql.replace(/'[^']*(?:''[^']*)*'/g, "").replace(/"[^"]*(?:""[^"]*)*"/g, "").replace(/--[^\n]*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
1749
+ if (stripped.includes(";")) throw new SimDbError("DB_UNSAFE_OP", "\u4EC5\u5141\u8BB8\u5355\u6761\u8BED\u53E5\uFF0C\u7981\u6B62\u591A\u8BED\u53E5\u5806\u53E0");
1750
+ const head = stripped.trim().replace(/^\(+/, "").trim().toUpperCase();
1751
+ if (!head.startsWith("SELECT") && !head.startsWith("WITH")) {
1752
+ throw new SimDbError("DB_UNSAFE_OP", "cloud.db.query \u4EC5\u5141\u8BB8\u53EA\u8BFB\u67E5\u8BE2\uFF08SELECT / WITH\uFF09");
1753
+ }
1754
+ if (/ATTACH|DETACH/.test(stripped.toUpperCase())) {
1755
+ throw new SimDbError("DB_UNSAFE_OP", "\u7981\u6B62\u8DE8\u5E93\u64CD\u4F5C\uFF08ATTACH / DETACH\uFF09");
1756
+ }
1757
+ if (/SQLITE_\w+/i.test(stripped) && !/SQLITE_MASTER\b/i.test(stripped)) {
1758
+ throw new SimDbError("DB_UNSAFE_OP", "\u7981\u6B62\u8BBF\u95EE\u7CFB\u7EDF\u8868\uFF08sqlite_*\uFF09");
1759
+ }
1760
+ }
1761
+ function indexAfter(start, matches, tail) {
1762
+ const candidates = matches.filter((x) => x !== null && x.index > start).map((x) => x.index);
1763
+ const end = candidates.length === 0 ? -1 : Math.min(...candidates);
1764
+ return end === -1 ? tail.length : end;
1765
+ }
1766
+ function project(rows, selectRaw) {
1767
+ if (/^count\s*\(\s*\*/i.test(selectRaw) || /^count\s*\(\s*1\)/i.test(selectRaw)) {
1768
+ const alias = selectRaw.match(/\bAS\s+([A-Za-z_][A-Za-z0-9_]*)/i)?.[1] ?? "n";
1769
+ return [{ [alias]: rows.length }];
1770
+ }
1771
+ const constMatch = /^(\d+)\s+AS\s+([A-Za-z_][A-Za-z0-9_]*)/i.exec(selectRaw);
1772
+ if (constMatch !== null) {
1773
+ return [{ [constMatch[2]]: Number(constMatch[1]) }];
1774
+ }
1775
+ if (selectRaw.trim() === "*") return rows;
1776
+ const cols = selectRaw.split(",").map((s) => ident(s.trim()));
1777
+ return rows.map((row) => {
1778
+ const out = {};
1779
+ for (const col of cols) out[col] = row[col];
1780
+ return out;
1781
+ });
1782
+ }
1783
+ var SimDbError, ParamCursor, SimSqlEngine;
1784
+ var init_sql_engine = __esm({
1785
+ "packages/cli/src/sim/sql-engine.ts"() {
1786
+ "use strict";
1787
+ SimDbError = class extends Error {
1788
+ constructor(code, message) {
1789
+ super(message);
1790
+ this.code = code;
1791
+ this.name = "SimDbError";
1792
+ }
1793
+ };
1794
+ ParamCursor = class {
1795
+ constructor(params) {
1796
+ this.params = params;
1797
+ }
1798
+ index = 0;
1799
+ take() {
1800
+ const v = this.params[this.index];
1801
+ this.index += 1;
1802
+ return v ?? null;
1803
+ }
1804
+ };
1805
+ SimSqlEngine = class {
1806
+ tables = {};
1807
+ storage;
1808
+ memoryOnly;
1809
+ savepointDepth = 0;
1810
+ txSnapshot = null;
1811
+ constructor(options = {}) {
1812
+ this.storage = options.storage ?? { load: async () => null, save: async () => void 0 };
1813
+ this.memoryOnly = options.memoryOnly ?? false;
1814
+ }
1815
+ async load() {
1816
+ if (this.memoryOnly) return;
1817
+ const persisted = await this.storage.load();
1818
+ if (persisted !== null) this.tables = persisted;
1819
+ }
1820
+ async persist() {
1821
+ if (this.memoryOnly) return;
1822
+ await this.storage.save(this.tables);
1823
+ }
1824
+ ensureTable(name) {
1825
+ let table = this.tables[name];
1826
+ if (table === void 0) {
1827
+ table = { columns: [], rows: [], nextAutoincrement: 1 };
1828
+ this.tables[name] = table;
1829
+ }
1830
+ return table;
1831
+ }
1832
+ applyAutoincrement(table, row) {
1833
+ const pk = table.columns.find((c) => c.primaryKey && c.autoincrement);
1834
+ if (pk === void 0) return;
1835
+ const val = row[pk.name];
1836
+ if (val !== null && val !== void 0) {
1837
+ const n = Number(val);
1838
+ if (Number.isInteger(n) && n >= table.nextAutoincrement) table.nextAutoincrement = n + 1;
1839
+ return;
1840
+ }
1841
+ row[pk.name] = table.nextAutoincrement;
1842
+ table.nextAutoincrement += 1;
1843
+ }
1844
+ catalog() {
1845
+ const out = [];
1846
+ for (const [name] of Object.entries(this.tables)) {
1847
+ out.push({ type: "table", name, tbl_name: name });
1848
+ }
1849
+ return out;
1850
+ }
1851
+ async run(sql, params = []) {
1852
+ const stmt = sql.trim();
1853
+ if (/^BEGIN\s*$/i.test(stmt)) {
1854
+ this.txSnapshot = structuredClone(this.tables);
1855
+ return { changes: 0 };
1856
+ }
1857
+ if (/^COMMIT\s*$/i.test(stmt)) {
1858
+ this.txSnapshot = null;
1859
+ await this.persist();
1860
+ return { changes: 0 };
1861
+ }
1862
+ if (/^ROLLBACK\s*$/i.test(stmt)) {
1863
+ if (this.txSnapshot !== null) {
1864
+ this.tables = this.txSnapshot;
1865
+ this.txSnapshot = null;
1866
+ }
1867
+ await this.persist();
1868
+ return { changes: 0 };
1869
+ }
1870
+ if (/^SAVEPOINT\s+/i.test(stmt)) {
1871
+ this.savepointDepth += 1;
1872
+ return { changes: 0 };
1873
+ }
1874
+ if (/^RELEASE\s+SAVEPOINT\s+/i.test(stmt)) {
1875
+ this.savepointDepth = Math.max(0, this.savepointDepth - 1);
1876
+ return { changes: 0 };
1877
+ }
1878
+ if (/^ROLLBACK\s+TO\s+SAVEPOINT\s+/i.test(stmt)) return { changes: 0 };
1879
+ if (/^CREATE\s+TABLE/i.test(stmt)) {
1880
+ const parsed = parseCreateTable(stmt);
1881
+ if (parsed === null) throw new SimDbError("DB_UNSAFE_OP", `\u65E0\u6CD5\u89E3\u6790\u5EFA\u8868\u8BED\u53E5`);
1882
+ if (this.tables[parsed.name] === void 0) {
1883
+ this.tables[parsed.name] = { columns: parsed.columns, rows: [], nextAutoincrement: 1 };
1884
+ await this.persist();
1885
+ }
1886
+ return { changes: 0 };
1887
+ }
1888
+ if (/^INSERT\s+INTO/i.test(stmt)) return this.execInsert(stmt, params);
1889
+ if (/^UPDATE\s+/i.test(stmt)) return this.execUpdate(stmt, params);
1890
+ if (/^DELETE\s+FROM/i.test(stmt)) return this.execDelete(stmt, params);
1891
+ throw new SimDbError("DB_UNSAFE_OP", `sim SQL \u5F15\u64CE\u4E0D\u652F\u6301\u8BE5\u8BED\u53E5`);
1892
+ }
1893
+ execInsert(sql, params) {
1894
+ const match = /^INSERT\s+INTO\s+((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s*\(([^)]*)\)\s*VALUES\s*([\s\S]+)$/i.exec(
1895
+ sql
1896
+ );
1897
+ if (match === null) throw new SimDbError("DB_UNSAFE_OP", "\u65E0\u6CD5\u89E3\u6790 INSERT");
1898
+ const tableName = ident(match[1]);
1899
+ const cols = match[3].split(",").map(ident);
1900
+ const valueBody = match[4].trim();
1901
+ const cursor = new ParamCursor(params);
1902
+ const table = this.ensureTable(tableName);
1903
+ let inserted = 0;
1904
+ for (const group of splitListItems(valueBody)) {
1905
+ const inner = group.trim().replace(/^\(|\)$/g, "");
1906
+ const values = splitListItems(inner).map(
1907
+ (item) => item.trim() === "?" ? cursor.take() : stripQuotes(item)
1908
+ );
1909
+ const row = {};
1910
+ cols.forEach((col, i) => {
1911
+ row[col] = values[i] ?? null;
1912
+ });
1913
+ this.applyAutoincrement(table, row);
1914
+ table.rows.push(row);
1915
+ inserted += 1;
1916
+ }
1917
+ void this.persist();
1918
+ return { changes: inserted };
1919
+ }
1920
+ execUpdate(sql, params) {
1921
+ const match = /^UPDATE\s+((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+SET\s+([\s\S]+?)\s+WHERE\s+([\s\S]+)$/i.exec(
1922
+ sql
1923
+ );
1924
+ if (match === null) throw new SimDbError("DB_UNSAFE_OP", "UPDATE \u5FC5\u987B\u5E26 WHERE");
1925
+ const tableName = ident(match[1]);
1926
+ const setRaw = match[3];
1927
+ const whereRaw = match[4];
1928
+ const cursor = new ParamCursor(params);
1929
+ const sets = splitListItems(setRaw).map((part) => {
1930
+ const [col, , mark] = part.trim().split(/\s+/);
1931
+ return { col: ident(col ?? ""), mark: mark ?? "?" };
1932
+ });
1933
+ const table = this.ensureTable(tableName);
1934
+ const boundSets = sets.map((set) => ({
1935
+ col: set.col,
1936
+ value: set.mark === "?" ? cursor.take() : stripQuotes(set.mark)
1937
+ }));
1938
+ const whereClauses = parseWhereClauses(whereRaw, cursor);
1939
+ let changes = 0;
1940
+ for (const row of table.rows) {
1941
+ if (!matchWhere(whereClauses, row)) continue;
1942
+ for (const set of boundSets) {
1943
+ row[set.col] = set.value;
1944
+ }
1945
+ changes += 1;
1946
+ }
1947
+ void this.persist();
1948
+ return { changes };
1949
+ }
1950
+ execDelete(sql, params) {
1951
+ const match = /^DELETE\s+FROM\s+((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+WHERE\s+([\s\S]+)$/i.exec(sql);
1952
+ if (match === null) throw new SimDbError("DB_UNSAFE_OP", "DELETE \u5FC5\u987B\u5E26 WHERE");
1953
+ const tableName = ident(match[1]);
1954
+ const whereRaw = match[3];
1955
+ const cursor = new ParamCursor(params);
1956
+ const table = this.ensureTable(tableName);
1957
+ const whereClauses = parseWhereClauses(whereRaw, cursor);
1958
+ const keep = [];
1959
+ let changes = 0;
1960
+ for (const row of table.rows) {
1961
+ if (!matchWhere(whereClauses, row)) keep.push(row);
1962
+ else changes += 1;
1963
+ }
1964
+ table.rows = keep;
1965
+ void this.persist();
1966
+ return { changes };
1967
+ }
1968
+ select(sql, params) {
1969
+ const m = /^SELECT\s+([\s\S]+?)\s+FROM\s+((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))([\s\S]*)$/i.exec(
1970
+ sql.trim()
1971
+ );
1972
+ if (m === null) throw new SimDbError("DB_UNSAFE_OP", "\u65E0\u6CD5\u89E3\u6790 SELECT");
1973
+ const selectRaw = m[1].trim();
1974
+ const tableName = ident(m[2]);
1975
+ const tail = m[4] ?? "";
1976
+ const cursor = new ParamCursor(params);
1977
+ if (tableName.toLowerCase() === "sqlite_master") {
1978
+ return project(this.catalog(), selectRaw);
1979
+ }
1980
+ const table = this.ensureTable(tableName);
1981
+ const whereMatch = /\bWHERE\b/i.exec(tail);
1982
+ const orderMatch = /\bORDER\s+BY\b/i.exec(tail);
1983
+ const limitMatch = /\bLIMIT\b/i.exec(tail);
1984
+ const offsetMatch = /\bOFFSET\b/i.exec(tail);
1985
+ const whereRaw = whereMatch === null ? "" : tail.slice(
1986
+ whereMatch.index + whereMatch[0].length,
1987
+ indexAfter(whereMatch.index, [orderMatch, limitMatch, offsetMatch], tail)
1988
+ );
1989
+ let rows = table.rows;
1990
+ if (whereRaw.trim().length > 0) {
1991
+ const clauses = parseWhereClauses(whereRaw, cursor);
1992
+ rows = rows.filter((row) => matchWhere(clauses, row));
1993
+ }
1994
+ if (orderMatch !== null) {
1995
+ const orderRaw = tail.slice(
1996
+ orderMatch.index + orderMatch[0].length,
1997
+ indexAfter(orderMatch.index, [limitMatch, offsetMatch], tail)
1998
+ );
1999
+ const oc = /^\s*((?:"[^"]+")|([A-Za-z_][A-Za-z0-9_]*))\s+(asc|desc)/i.exec(orderRaw);
2000
+ if (oc !== null) {
2001
+ const col = ident(oc[1]);
2002
+ const dir = oc[3].toLowerCase();
2003
+ rows = [...rows].toSorted((a, b) => {
2004
+ const av = a[col];
2005
+ const bv = b[col];
2006
+ const cmp = av === bv ? 0 : av === null ? -1 : bv === null ? 1 : av > bv ? 1 : -1;
2007
+ return dir === "desc" ? -cmp : cmp;
2008
+ });
2009
+ }
2010
+ }
2011
+ if (limitMatch !== null) {
2012
+ const limRaw = tail.slice(
2013
+ limitMatch.index + limitMatch[0].length,
2014
+ indexAfter(limitMatch.index, [offsetMatch], tail)
2015
+ );
2016
+ const lim = limRaw.trim() === "?" ? cursor.take() : toNumber(limRaw);
2017
+ if (typeof lim === "number") rows = rows.slice(0, lim);
2018
+ }
2019
+ if (offsetMatch !== null) {
2020
+ const offRaw = tail.slice(
2021
+ offsetMatch.index + offsetMatch[0].length,
2022
+ indexAfter(offsetMatch.index, [limitMatch], tail)
2023
+ );
2024
+ const off = offRaw.trim() === "?" ? cursor.take() : toNumber(offRaw);
2025
+ if (typeof off === "number") rows = rows.slice(off);
2026
+ }
2027
+ return project(rows, selectRaw);
2028
+ }
2029
+ async all(sql, params = []) {
2030
+ assertReadOnly(sql);
2031
+ return this.select(sql, params);
2032
+ }
2033
+ async get(sql, params = []) {
2034
+ assertReadOnly(sql);
2035
+ return this.select(sql, params)[0] ?? null;
2036
+ }
2037
+ async close() {
2038
+ void this.savepointDepth;
2039
+ }
2040
+ };
2041
+ }
2042
+ });
2043
+
2044
+ // packages/cli/src/sim/db.ts
2045
+ function toProjectDriver(engine) {
2046
+ return {
2047
+ engine: "sqlite",
2048
+ run: (sql, params = []) => engine.run(sql, params),
2049
+ all: (sql, params = []) => engine.all(sql, params),
2050
+ get: (sql, params = []) => engine.get(sql, params),
2051
+ close: () => engine.close()
2052
+ };
2053
+ }
2054
+ function createSimDbCapability(options = {}) {
2055
+ const engine = new SimSqlEngine({
2056
+ storage: options.storage ?? { load: async () => null, save: async () => void 0 },
2057
+ memoryOnly: options.storage === void 0
2058
+ });
2059
+ const driver = toProjectDriver(engine);
2060
+ const bundle = createDbCapability(driver);
2061
+ return { bundle, engine, driver };
2062
+ }
2063
+ var init_db = __esm({
2064
+ "packages/cli/src/sim/db.ts"() {
2065
+ "use strict";
2066
+ init_cloud();
2067
+ init_sql_engine();
2068
+ }
2069
+ });
2070
+
2071
+ // packages/runtime/src/storage/driver.ts
2072
+ function assertSafeStoragePath(path) {
2073
+ if (typeof path !== "string" || path.length === 0) {
2074
+ throw new StorageError(400, STORAGE_CODES.invalidPath, "\u5B58\u50A8\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
2075
+ }
2076
+ if (path.length > 1024) {
2077
+ throw new StorageError(400, STORAGE_CODES.invalidPath, "\u5B58\u50A8\u8DEF\u5F84\u8FC7\u957F\uFF08\u4E0A\u9650 1024 \u5B57\u7B26\uFF09");
2078
+ }
2079
+ if (path.startsWith("/") || /^[A-Za-z]:[\\/]/.test(path) || /[\0\r\n]/.test(path)) {
2080
+ throw new StorageError(400, STORAGE_CODES.invalidPath, "\u5B58\u50A8\u8DEF\u5F84\u5FC5\u987B\u662F\u9879\u76EE\u6876\u5185\u7684\u76F8\u5BF9\u8DEF\u5F84");
2081
+ }
2082
+ const segments = path.split("/");
2083
+ for (const segment of segments) {
2084
+ if (segment === "" || segment === "." || segment === "..") {
2085
+ throw new StorageError(
2086
+ 400,
2087
+ STORAGE_CODES.invalidPath,
2088
+ `\u5B58\u50A8\u8DEF\u5F84\u542B\u975E\u6CD5\u6BB5 "${segment}"\uFF08\u7981\u6B62\u7A7A\u6BB5 / . / .. \u7A7F\u8D8A\uFF09`
2089
+ );
2090
+ }
2091
+ if (/[\\]/.test(segment)) {
2092
+ throw new StorageError(400, STORAGE_CODES.invalidPath, "\u5B58\u50A8\u8DEF\u5F84\u7981\u6B62\u53CD\u659C\u6760");
2093
+ }
2094
+ }
2095
+ return path;
2096
+ }
2097
+ var PROJECT_QUOTA_BYTES, StorageError, STORAGE_CODES;
2098
+ var init_driver = __esm({
2099
+ "packages/runtime/src/storage/driver.ts"() {
2100
+ "use strict";
2101
+ PROJECT_QUOTA_BYTES = 1024 * 1024 * 1024;
2102
+ StorageError = class extends Error {
2103
+ constructor(status, code, message) {
2104
+ super(message);
2105
+ this.status = status;
2106
+ this.code = code;
2107
+ this.name = "StorageError";
2108
+ }
2109
+ };
2110
+ STORAGE_CODES = {
2111
+ invalidPath: "STORAGE_INVALID_PATH",
2112
+ notFound: "STORAGE_NOT_FOUND",
2113
+ quotaExceeded: "STORAGE_QUOTA_EXCEEDED"
2114
+ };
2115
+ }
2116
+ });
2117
+
2118
+ // packages/runtime/src/storage/signature.ts
2119
+ import { createHmac, timingSafeEqual } from "node:crypto";
2120
+ function sign(secret, projectId, path, expires) {
2121
+ const payload = `${projectId}|${path}|${expires}`;
2122
+ return createHmac("sha256", secret).update(payload).digest("hex");
2123
+ }
2124
+ function signDownloadUrl(config, projectId, path, ttlSeconds = DEFAULT_SIGN_TTL_SECONDS) {
2125
+ const expires = Math.floor(Date.now() / 1e3) + ttlSeconds;
2126
+ const base = `${config.baseUrl}/api/v1/projects/${encodeURIComponent(projectId)}/files/${encodeURIComponent(path)}`;
2127
+ const signature = sign(config.secret, projectId, path, expires);
2128
+ return `${base}?${SIGN_EXPIRES_KEY}=${expires}&${SIGN_SIGNATURE_KEY}=${signature}`;
2129
+ }
2130
+ var DEFAULT_SIGN_TTL_SECONDS, SIGN_EXPIRES_KEY, SIGN_SIGNATURE_KEY;
2131
+ var init_signature = __esm({
2132
+ "packages/runtime/src/storage/signature.ts"() {
2133
+ "use strict";
2134
+ DEFAULT_SIGN_TTL_SECONDS = 15 * 60;
2135
+ SIGN_EXPIRES_KEY = "x-expires";
2136
+ SIGN_SIGNATURE_KEY = "x-signature";
2137
+ }
2138
+ });
2139
+
2140
+ // packages/runtime/src/storage/cloud.ts
2141
+ function asBytes(data) {
2142
+ if (typeof data === "string") return new TextEncoder().encode(data);
2143
+ if (data instanceof ArrayBuffer) return new Uint8Array(data);
2144
+ if (data instanceof Uint8Array) return data;
2145
+ const candidate = data;
2146
+ if (candidate.data instanceof Uint8Array) return candidate.data;
2147
+ throw new StorageError(400, STORAGE_CODES.invalidPath, "\u4E0D\u652F\u6301\u7684\u5B58\u50A8\u6570\u636E\u7C7B\u578B");
2148
+ }
2149
+ function toStoredFile(meta) {
2150
+ return {
2151
+ path: meta.path,
2152
+ size: meta.size,
2153
+ visibility: meta.visibility,
2154
+ ...meta.contentType === void 0 ? {} : { contentType: meta.contentType },
2155
+ ...meta.updatedAt === void 0 ? {} : { updatedAt: meta.updatedAt }
2156
+ };
2157
+ }
2158
+ function createStorageCapability(driver, signer, projectId) {
2159
+ const handler = async (method, args) => {
2160
+ switch (method) {
2161
+ case "upload": {
2162
+ const [path, data] = args;
2163
+ return toStoredFile(
2164
+ await driver.put(projectId, path, asBytes(data), { visibility: DEFAULT_VISIBILITY })
2165
+ );
2166
+ }
2167
+ case "get": {
2168
+ const [path] = args;
2169
+ return (await driver.get(projectId, path)).data;
2170
+ }
2171
+ case "remove": {
2172
+ const [path] = args;
2173
+ await driver.remove(projectId, path);
2174
+ return void 0;
2175
+ }
2176
+ case "list": {
2177
+ const [prefix] = args;
2178
+ return (await driver.list(projectId, prefix)).map(toStoredFile);
2179
+ }
2180
+ case "getSignedUrl": {
2181
+ const [path, ttlSeconds] = args;
2182
+ return signDownloadUrl(signer, projectId, path, ttlSeconds);
2183
+ }
2184
+ default:
2185
+ throw new StorageError(
2186
+ 400,
2187
+ "STORAGE_INVALID_METHOD",
2188
+ `\u672A\u77E5\u7684 cloud.storage \u65B9\u6CD5 "${method}"`
2189
+ );
2190
+ }
2191
+ };
2192
+ return {
2193
+ capabilities: [{ name: "storage", value: { [RPC_CAPABILITY_KEY]: true } }],
2194
+ rpcHandlers: { storage: handler }
2195
+ };
2196
+ }
2197
+ var DEFAULT_VISIBILITY;
2198
+ var init_cloud2 = __esm({
2199
+ "packages/runtime/src/storage/cloud.ts"() {
2200
+ "use strict";
2201
+ init_capability_keys();
2202
+ init_driver();
2203
+ init_signature();
2204
+ DEFAULT_VISIBILITY = "private";
2205
+ }
2206
+ });
2207
+
2208
+ // packages/runtime/src/storage/driver/local.ts
2209
+ import { mkdir as mkdir4, readFile as readFile2, readdir, rm as rm2, stat as stat4, unlink, writeFile as writeFile3 } from "node:fs/promises";
2210
+ import { dirname as dirname5, join as join5 } from "node:path";
2211
+ function createLocalStorageDriver(options) {
2212
+ const quotaBytes = options.quotaBytes ?? PROJECT_QUOTA_BYTES;
2213
+ const bucketDir = (projectId) => join5(options.dir, projectId);
2214
+ const objectPath = (projectId, path) => join5(bucketDir(projectId), path);
2215
+ const metaPath = (projectId, path) => join5(dirname5(objectPath(projectId, path)), `${path.split("/").pop() ?? ""}${META_SUFFIX}`);
2216
+ const readStoredMeta = async (projectId, path) => {
2217
+ const raw = await readFile2(metaPath(projectId, path), "utf8");
2218
+ return JSON.parse(raw);
2219
+ };
2220
+ const writeStoredMeta = async (projectId, path, meta) => {
2221
+ const payload = {
2222
+ visibility: meta.visibility,
2223
+ size: meta.size,
2224
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2225
+ ...meta.contentType === void 0 ? {} : { contentType: meta.contentType }
2226
+ };
2227
+ await writeFile3(metaPath(projectId, path), JSON.stringify(payload), "utf8");
2228
+ };
2229
+ const totalSize = async (projectId) => {
2230
+ const root = bucketDir(projectId);
2231
+ let total = 0;
2232
+ const walk = async (dir) => {
2233
+ let entries;
2234
+ try {
2235
+ entries = await readdir(dir, { withFileTypes: true });
2236
+ } catch {
2237
+ return;
2238
+ }
2239
+ const tasks = [];
2240
+ for (const entry of entries) {
2241
+ const full = join5(dir, entry.name);
2242
+ if (entry.isDirectory()) {
2243
+ tasks.push(walk(full));
2244
+ } else if (entry.isFile() && !entry.name.endsWith(META_SUFFIX)) {
2245
+ tasks.push(
2246
+ (async () => {
2247
+ try {
2248
+ const info = await stat4(full);
2249
+ total += info.size;
2250
+ } catch {
2251
+ }
2252
+ })()
2253
+ );
2254
+ }
2255
+ }
2256
+ await Promise.all(tasks);
2257
+ };
2258
+ await walk(root);
2259
+ return total;
2260
+ };
2261
+ return {
2262
+ async put(projectId, path, data, putOptions) {
2263
+ assertSafeStoragePath(path);
2264
+ if (!(data instanceof Uint8Array)) {
2265
+ throw new StorageError(400, "STORAGE_INVALID_PAYLOAD", "\u5199\u5165\u5185\u5BB9\u5FC5\u987B\u662F\u5B57\u8282\u6570\u7EC4");
2266
+ }
2267
+ const used = await totalSize(projectId);
2268
+ let existingSize = 0;
2269
+ try {
2270
+ existingSize = (await stat4(objectPath(projectId, path))).size;
2271
+ } catch {
2272
+ existingSize = 0;
2273
+ }
2274
+ const projected = used - existingSize + data.byteLength;
2275
+ if (options.quotaCheck !== void 0) {
2276
+ await options.quotaCheck(projectId, projected);
2277
+ } else if (projected > quotaBytes) {
2278
+ throw new StorageError(
2279
+ 413,
2280
+ STORAGE_CODES.quotaExceeded,
2281
+ `\u9879\u76EE\u5B58\u50A8\u7A7A\u95F4\u4E0D\u8DB3\uFF1A\u914D\u989D ${quotaBytes} \u5B57\u8282\u5DF2\u7528\u5C3D\uFF08STORAGE_QUOTA_EXCEEDED\uFF09`
2282
+ );
2283
+ }
2284
+ const dest = objectPath(projectId, path);
2285
+ await mkdir4(dirname5(dest), { recursive: true });
2286
+ await writeFile3(dest, data);
2287
+ await writeStoredMeta(projectId, path, {
2288
+ visibility: putOptions.visibility,
2289
+ size: data.byteLength,
2290
+ ...putOptions.contentType === void 0 ? {} : { contentType: putOptions.contentType }
2291
+ });
2292
+ const meta = await readStoredMeta(projectId, path);
2293
+ return {
2294
+ path,
2295
+ size: meta.size,
2296
+ visibility: meta.visibility,
2297
+ updatedAt: meta.updatedAt,
2298
+ ...meta.contentType === void 0 ? {} : { contentType: meta.contentType }
2299
+ };
2300
+ },
2301
+ async get(projectId, path) {
2302
+ assertSafeStoragePath(path);
2303
+ let meta;
2304
+ try {
2305
+ meta = await readStoredMeta(projectId, path);
2306
+ } catch {
2307
+ throw new StorageError(404, STORAGE_CODES.notFound, `\u6587\u4EF6 "${path}" \u4E0D\u5B58\u5728`);
2308
+ }
2309
+ const data = await readFile2(objectPath(projectId, path));
2310
+ const result = {
2311
+ path,
2312
+ size: meta.size,
2313
+ visibility: meta.visibility,
2314
+ updatedAt: meta.updatedAt,
2315
+ ...meta.contentType === void 0 ? {} : { contentType: meta.contentType }
2316
+ };
2317
+ return { data, meta: result };
2318
+ },
2319
+ async getMeta(projectId, path) {
2320
+ assertSafeStoragePath(path);
2321
+ let meta;
2322
+ try {
2323
+ meta = await readStoredMeta(projectId, path);
2324
+ } catch {
2325
+ throw new StorageError(404, STORAGE_CODES.notFound, `\u6587\u4EF6 "${path}" \u4E0D\u5B58\u5728`);
2326
+ }
2327
+ const result = {
2328
+ path,
2329
+ size: meta.size,
2330
+ visibility: meta.visibility,
2331
+ updatedAt: meta.updatedAt,
2332
+ ...meta.contentType === void 0 ? {} : { contentType: meta.contentType }
2333
+ };
2334
+ return result;
2335
+ },
2336
+ async remove(projectId, path) {
2337
+ assertSafeStoragePath(path);
2338
+ let exists = true;
2339
+ try {
2340
+ await stat4(objectPath(projectId, path));
2341
+ } catch {
2342
+ exists = false;
2343
+ }
2344
+ if (!exists) {
2345
+ throw new StorageError(404, STORAGE_CODES.notFound, `\u6587\u4EF6 "${path}" \u4E0D\u5B58\u5728`);
2346
+ }
2347
+ await rm2(objectPath(projectId, path), { force: true });
2348
+ await unlink(metaPath(projectId, path)).catch(() => void 0);
2349
+ },
2350
+ async list(projectId, prefix) {
2351
+ if (prefix !== void 0 && prefix !== "") {
2352
+ const segments = prefix.split("/");
2353
+ if (prefix.startsWith("/") || /[\\]/.test(prefix) || segments.some((segment) => segment === "..")) {
2354
+ throw new StorageError(
2355
+ 400,
2356
+ STORAGE_CODES.invalidPath,
2357
+ `\u975E\u6CD5\u524D\u7F00 "${prefix}"\uFF08\u7981\u6B62 / \u5F00\u5934\u3001\u53CD\u659C\u6760\u6216 .. \u7A7F\u8D8A\uFF09`
2358
+ );
2359
+ }
2360
+ }
2361
+ const root = bucketDir(projectId);
2362
+ const metas = [];
2363
+ const walk = async (dir, relative2) => {
2364
+ let entries;
2365
+ try {
2366
+ entries = await readdir(dir, { withFileTypes: true });
2367
+ } catch {
2368
+ return;
2369
+ }
2370
+ const tasks = [];
2371
+ for (const entry of entries) {
2372
+ if (entry.name.endsWith(META_SUFFIX)) continue;
2373
+ const full = join5(dir, entry.name);
2374
+ const rel = relative2 === "" ? entry.name : `${relative2}/${entry.name}`;
2375
+ if (entry.isFile()) {
2376
+ if (prefix !== void 0 && !rel.startsWith(prefix)) continue;
2377
+ tasks.push(
2378
+ (async () => {
2379
+ try {
2380
+ const payload = JSON.parse(
2381
+ await readFile2(full + META_SUFFIX, "utf8")
2382
+ );
2383
+ metas.push({
2384
+ path: rel,
2385
+ size: payload.size,
2386
+ visibility: payload.visibility,
2387
+ updatedAt: payload.updatedAt,
2388
+ ...payload.contentType === void 0 ? {} : { contentType: payload.contentType }
2389
+ });
2390
+ } catch {
2391
+ }
2392
+ })()
2393
+ );
2394
+ } else if (entry.isDirectory()) {
2395
+ if (prefix !== void 0 && !rel.startsWith(prefix)) {
2396
+ const subIncluded = prefix.startsWith(rel + "/") || rel.startsWith(prefix);
2397
+ if (!subIncluded) continue;
2398
+ }
2399
+ tasks.push(walk(full, rel));
2400
+ }
2401
+ }
2402
+ await Promise.all(tasks);
2403
+ };
2404
+ await walk(root, "");
2405
+ metas.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
2406
+ return metas;
2407
+ },
2408
+ async usage(projectId) {
2409
+ return totalSize(projectId);
2410
+ }
2411
+ };
2412
+ }
2413
+ var META_SUFFIX;
2414
+ var init_local = __esm({
2415
+ "packages/runtime/src/storage/driver/local.ts"() {
2416
+ "use strict";
2417
+ init_driver();
2418
+ META_SUFFIX = ".adep-meta.json";
2419
+ }
2420
+ });
2421
+
2422
+ // packages/cli/src/sim/storage.ts
2423
+ import { join as join6 } from "node:path";
2424
+ function createSimStorageCapability(options) {
2425
+ const dir = join6(options.cwd, ".adep", "sim", "storage");
2426
+ const driver = createLocalStorageDriver({ dir });
2427
+ const signer = {
2428
+ secret: options.secret ?? "adep-sim-secret",
2429
+ baseUrl: options.baseUrl ?? "http://127.0.0.1:8787"
2430
+ };
2431
+ const bundle = createStorageCapability(driver, signer, options.projectId ?? "sim-project");
2432
+ return { bundle, driver };
2433
+ }
2434
+ var init_storage = __esm({
2435
+ "packages/cli/src/sim/storage.ts"() {
2436
+ "use strict";
2437
+ init_cloud2();
2438
+ init_local();
2439
+ }
2440
+ });
2441
+
2442
+ // packages/cli/src/sim/realtime.ts
2443
+ var SimRealtime;
2444
+ var init_realtime = __esm({
2445
+ "packages/cli/src/sim/realtime.ts"() {
2446
+ "use strict";
2447
+ SimRealtime = class {
2448
+ seq = 0;
2449
+ subscribers = /* @__PURE__ */ new Map();
2450
+ /** 向某 channel 广播一条消息;返回被投递的连接数(单进程内)。 */
2451
+ publish(channel, data, publisher) {
2452
+ this.seq += 1;
2453
+ const message = {
2454
+ channel,
2455
+ seq: this.seq,
2456
+ data,
2457
+ publishedAt: (/* @__PURE__ */ new Date()).toISOString(),
2458
+ ...publisher === void 0 ? {} : { publisher }
2459
+ };
2460
+ const set = this.subscribers.get(channel);
2461
+ if (set === void 0) return { delivered: 0 };
2462
+ let delivered = 0;
2463
+ for (const listener of set) {
2464
+ listener(message);
2465
+ delivered += 1;
2466
+ }
2467
+ return { delivered };
2468
+ }
2469
+ /** 订阅某 channel;返回退订函数。 */
2470
+ subscribe(channel, listener) {
2471
+ let set = this.subscribers.get(channel);
2472
+ if (set === void 0) {
2473
+ set = /* @__PURE__ */ new Set();
2474
+ this.subscribers.set(channel, set);
2475
+ }
2476
+ set.add(listener);
2477
+ return () => {
2478
+ set?.delete(listener);
2479
+ };
2480
+ }
2481
+ /** 当前有订阅者的 channel 数(调试用)。 */
2482
+ channelCount() {
2483
+ return this.subscribers.size;
2484
+ }
2485
+ };
2486
+ }
2487
+ });
2488
+
2489
+ // packages/cli/src/sim/runtime.ts
2490
+ import { mkdir as mkdir5, readFile as readFile3, writeFile as writeFile4 } from "node:fs/promises";
2491
+ import { dirname as dirname6, join as join7 } from "node:path";
2492
+ function simDir(cwd) {
2493
+ return join7(cwd, ".adep", "sim");
2494
+ }
2495
+ function mergeBundles(bundles) {
2496
+ const capabilities = [];
2497
+ const byName = /* @__PURE__ */ new Map();
2498
+ for (const bundle of bundles) {
2499
+ for (const cap of bundle.capabilities) {
2500
+ const existing = byName.get(cap.name);
2501
+ if (existing !== void 0) capabilities.splice(capabilities.indexOf(existing), 1);
2502
+ byName.set(cap.name, cap);
2503
+ capabilities.push(cap);
2504
+ }
2505
+ }
2506
+ const rpcHandlers = {};
2507
+ for (const bundle of bundles) {
2508
+ for (const [name, handler] of Object.entries(bundle.rpcHandlers)) {
2509
+ rpcHandlers[name] = handler;
2510
+ }
2511
+ }
2512
+ return { capabilities, rpcHandlers };
2513
+ }
2514
+ function jsonStorage(cwd) {
2515
+ const file = join7(simDir(cwd), "db.json");
2516
+ return {
2517
+ async load() {
2518
+ try {
2519
+ const raw = await readFile3(file, "utf8");
2520
+ return JSON.parse(raw);
2521
+ } catch {
2522
+ return null;
2523
+ }
2524
+ },
2525
+ async save(tables) {
2526
+ await mkdir5(dirname6(file), { recursive: true });
2527
+ await writeFile4(file, JSON.stringify(tables), "utf8");
2528
+ }
2529
+ };
2530
+ }
2531
+ async function createSimRuntime(options) {
2532
+ const db = createSimDbCapability({
2533
+ storage: options.dbStorage ?? jsonStorage(options.cwd),
2534
+ ...options.log === void 0 ? {} : { log: options.log }
2535
+ });
2536
+ const storage = createSimStorageCapability({
2537
+ cwd: options.cwd,
2538
+ ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl },
2539
+ projectId: options.projectId ?? "local"
2540
+ });
2541
+ const realtime = new SimRealtime();
2542
+ const bundle = mergeBundles([db.bundle, storage.bundle]);
2543
+ await db.engine.load();
2544
+ return {
2545
+ bundle,
2546
+ realtime,
2547
+ db,
2548
+ dispose: async () => {
2549
+ await db.driver.close();
2550
+ }
2551
+ };
2552
+ }
2553
+ var init_runtime = __esm({
2554
+ "packages/cli/src/sim/runtime.ts"() {
2555
+ "use strict";
2556
+ init_db();
2557
+ init_storage();
2558
+ init_realtime();
2559
+ }
2560
+ });
2561
+
2562
+ // packages/cli/src/sim/env.ts
2563
+ import { readFile as readFile4 } from "node:fs/promises";
2564
+ import { join as join8 } from "node:path";
2565
+ function parseEnv(content) {
2566
+ const env = {};
2567
+ for (const raw of content.split(/\r?\n/)) {
2568
+ const line = raw.trim();
2569
+ if (line.length === 0 || line.startsWith("#")) continue;
2570
+ const eq = line.indexOf("=");
2571
+ if (eq === -1) continue;
2572
+ const key = line.slice(0, eq).trim();
2573
+ if (key.length === 0) continue;
2574
+ env[key] = line.slice(eq + 1).trim();
2575
+ }
2576
+ return env;
2577
+ }
2578
+ async function loadSimEnv(cwd, config = {}) {
2579
+ const envRoot = await readFile4(join8(cwd, ".env"), "utf8").catch(() => "");
2580
+ const envLocal = await readFile4(join8(cwd, ".env.local"), "utf8").catch(() => "");
2581
+ const merged = { ...parseEnv(envRoot), ...parseEnv(envLocal) };
2582
+ for (const secret of config.secrets ?? []) {
2583
+ if (merged[secret] !== void 0) continue;
2584
+ if (process.env[secret] !== void 0) {
2585
+ merged[secret] = process.env[secret];
2586
+ continue;
2587
+ }
2588
+ throw new Error(
2589
+ `secret "${secret}" \u672A\u914D\u7F6E\uFF1A\u8BF7\u5728 .env.local \u6DFB\u52A0 ${secret}=<value>\uFF0C\u6216\u7528\u73AF\u5883\u53D8\u91CF\u5BFC\u51FA\u540E\u91CD\u8BD5 adep dev\uFF08\u6A21\u62DF\u73AF\u5883\u6C38\u4E0D\u843D\u76D8\u8BE5\u503C\uFF09`
2590
+ );
2591
+ }
2592
+ return merged;
2593
+ }
2594
+ var init_env = __esm({
2595
+ "packages/cli/src/sim/env.ts"() {
2596
+ "use strict";
2597
+ }
2598
+ });
2599
+
2600
+ // packages/cli/src/sim/invoke.ts
2601
+ function createSimInvokeHandler(options) {
2602
+ return async (method, args) => {
2603
+ if (method !== "invoke") {
2604
+ throw new Error(`\u672A\u77E5\u7684 cloud.invoke \u65B9\u6CD5 "${method}"`);
2605
+ }
2606
+ const input = args[0];
2607
+ if (typeof input?.name !== "string" || input.name.length === 0) {
2608
+ throw new Error("cloud.invoke \u9700\u8981\u76EE\u6807\u51FD\u6570\u540D\uFF08InvokeInput.name\uFF09");
2609
+ }
2610
+ const targetEntry = `${input.name}.ts`;
2611
+ const executeInput = {
2612
+ project: { id: "local", slug: "local" },
2613
+ fn: { id: input.name, name: input.name },
2614
+ files: options.files,
2615
+ entry: targetEntry,
2616
+ request: {
2617
+ method: "POST",
2618
+ path: `/${input.name}`,
2619
+ query: input.query ?? {},
2620
+ headers: {},
2621
+ ...input.body === void 0 ? {} : { body: input.body }
2622
+ },
2623
+ timeoutMs: 1e4,
2624
+ ...options.env === void 0 ? {} : { env: options.env }
2625
+ };
2626
+ const result = await options.executor.execute(executeInput);
2627
+ return result.body;
2628
+ };
2629
+ }
2630
+ var init_invoke = __esm({
2631
+ "packages/cli/src/sim/invoke.ts"() {
2632
+ "use strict";
2633
+ }
2634
+ });
2635
+
2636
+ // packages/cli/src/sim/boundary.ts
2637
+ var SIM_BOUNDARIES;
2638
+ var init_boundary = __esm({
2639
+ "packages/cli/src/sim/boundary.ts"() {
2640
+ "use strict";
2641
+ SIM_BOUNDARIES = [
2642
+ {
2643
+ kind: "capability",
2644
+ title: "\u89E6\u53D1\u5668\u4E0D\u81EA\u52A8\u6267\u884C",
2645
+ detail: "\u5B9A\u65F6 / \u4E8B\u4EF6\u89E6\u53D1\u5668\u53EA\u767B\u8BB0\uFF0C\u4E0D\u7531\u6A21\u62DF\u5668\u81EA\u52A8\u89E6\u53D1\uFF08\u672C\u5730\u4EE5\u624B\u5DE5 HTTP \u8C03\u7528\u66FF\u4EE3\uFF09\u3002"
2646
+ },
2647
+ {
2648
+ kind: "diff",
2649
+ title: "\u65E0\u8DE8\u5B9E\u4F8B\u5E7F\u64AD",
2650
+ detail: "realtime \u4E3A\u5355\u8FDB\u7A0B\u5185\u5B58\u5E7F\u64AD\uFF1A\u4E0D\u652F\u6301\u8DE8\u8FDB\u7A0B / \u8DE8\u5B9E\u4F8B\uFF0C\u7EBF\u4E0A\u591A\u5B9E\u4F8B\u8BED\u4E49\u4E0D\u540C\u3002"
2651
+ },
2652
+ {
2653
+ kind: "capability",
2654
+ title: "\u65E0\u9650\u989D\u7B49\u4EF7",
2655
+ detail: "\u672C\u5730\u4E0D\u6267\u884C\u8BA1\u91CF / \u914D\u989D\u95E8\u7981\uFF08\u4E0D\u6309\u51FD\u6570\u8C03\u7528\u3001\u6D41\u91CF\u3001\u63A8\u9001\u8BA1\u6570\uFF09\uFF0C\u9650\u989D\u8BED\u4E49\u4EC5\u7EBF\u4E0A\u751F\u6548\u3002"
2656
+ },
2657
+ {
2658
+ kind: "diff",
2659
+ title: "\u4E0D\u8BA1\u91CF",
2660
+ detail: "\u672C\u6A21\u62DF\u8FD0\u884C\u65F6\u4E0D\u4EA7\u51FA\u8BA1\u91CF\u4E8B\u4EF6\uFF0C\u4E5F\u4E0D\u5199 billing\uFF1B\u79BB\u7EBF\u5F00\u53D1\u4E0D\u8BA1\u8D39\u3002"
2661
+ }
2662
+ ];
2663
+ }
2664
+ });
2665
+
2666
+ // packages/cli/src/dev.ts
2667
+ var dev_exports = {};
2668
+ __export(dev_exports, {
2669
+ loadConfig: () => loadConfig,
2670
+ parseEnvFile: () => parseEnvFile,
2671
+ startDevServer: () => startDevServer
2672
+ });
2673
+ import { createServer } from "node:http";
2674
+ import { watch } from "node:fs";
2675
+ import { mkdir as mkdir6, readdir as readdir2, readFile as readFile5, stat as stat5, writeFile as writeFile5 } from "node:fs/promises";
2676
+ import { basename, join as join9, resolve as resolve5 } from "node:path";
2677
+ async function loadConfig(cwd) {
2678
+ const name = basename(resolve5(cwd));
2679
+ const configPath = join9(cwd, "adep.config.ts");
2680
+ try {
2681
+ await stat5(configPath);
2682
+ } catch {
2683
+ return { name, functionsDir: "functions" };
2684
+ }
2685
+ const bun = globalThis.Bun;
2686
+ if (bun === void 0) return { name, functionsDir: "functions" };
2687
+ try {
2688
+ const mod = await import(configPath);
2689
+ return {
2690
+ name: mod.default?.name ?? name,
2691
+ functionsDir: mod.default?.functionsDir ?? "functions"
2692
+ };
2693
+ } catch {
2694
+ return { name, functionsDir: "functions" };
2695
+ }
2696
+ }
2697
+ function parseEnvFile(content) {
2698
+ const env = {};
2699
+ for (const raw of content.split(/\r?\n/)) {
2700
+ const line = raw.trim();
2701
+ if (line.length === 0 || line.startsWith("#")) continue;
2702
+ const eq = line.indexOf("=");
2703
+ if (eq === -1) continue;
2704
+ const key = line.slice(0, eq).trim();
2705
+ if (key.length === 0) continue;
2706
+ env[key] = line.slice(eq + 1).trim();
2707
+ }
2708
+ return env;
2709
+ }
2710
+ async function collectFunctions(dir) {
2711
+ const files = {};
2712
+ const walk = async (sub, prefix) => {
2713
+ let entries;
2714
+ try {
2715
+ entries = await readdir2(sub, { withFileTypes: true });
2716
+ } catch {
2717
+ return;
2718
+ }
2719
+ for (const entry of entries) {
2720
+ const rel = prefix.length === 0 ? entry.name : `${prefix}/${entry.name}`;
2721
+ const full = join9(sub, entry.name);
2722
+ if (entry.isDirectory()) {
2723
+ await walk(full, rel);
2724
+ } else if (entry.isFile() && entry.name.endsWith(".ts")) {
2725
+ files[rel] = await readFile5(full, "utf8");
2726
+ }
2727
+ }
2728
+ };
2729
+ await walk(dir, "");
2730
+ return files;
2731
+ }
2732
+ function bodyOf(req) {
2733
+ return new Promise((resolveBody, rejectBody) => {
2734
+ const chunks = [];
2735
+ req.on("data", (chunk) => chunks.push(chunk));
2736
+ req.on("end", () => {
2737
+ const raw = Buffer.concat(chunks).toString("utf8");
2738
+ if (raw.length === 0) {
2739
+ resolveBody(void 0);
2740
+ return;
2741
+ }
2742
+ try {
2743
+ resolveBody(JSON.parse(raw));
2744
+ } catch {
2745
+ resolveBody(raw);
2746
+ }
2747
+ });
2748
+ req.on("error", rejectBody);
2749
+ });
2750
+ }
2751
+ function writeJson(res, status, payload) {
2752
+ res.writeHead(status, { "content-type": "application/json" });
2753
+ res.end(JSON.stringify(payload));
2754
+ }
2755
+ function printBoundaries(log) {
2756
+ log("[adep] \u80FD\u529B\u8FB9\u754C\uFF08\u6A21\u62DF\u8FD0\u884C\u65F6\u53EA\u66FF\u6362\u4F20\u8F93/\u6301\u4E45\u5316\uFF0C\u4E0D\u6539\u5199\u8BED\u4E49\uFF09\uFF1A");
2757
+ for (const b of SIM_BOUNDARIES) {
2758
+ log(`[adep] - [${b.kind}] ${b.title}\uFF1A${b.detail}`);
2759
+ }
2760
+ }
2761
+ async function ensureGitignore(cwd) {
2762
+ const gitignorePath = join9(cwd, ".gitignore");
2763
+ const existing = await readFile5(gitignorePath, "utf8").catch(() => "");
2764
+ if (existing.split(/\r?\n/).includes(".adep/")) return;
2765
+ await writeFile5(gitignorePath, `${existing.replace(/\n+$/, "")}
2766
+ .adep/
2767
+ `, "utf8");
2768
+ }
2769
+ async function startDevServer(options) {
2770
+ const cwd = resolve5(options.cwd);
2771
+ const log = options.log ?? ((line) => process.stdout.write(`${line}
2772
+ `));
2773
+ const config = await loadConfig(cwd);
2774
+ const functionsDir = join9(cwd, config.functionsDir);
2775
+ const coldStartAt = Date.now();
2776
+ const executor = new WorkerFunctionExecutor();
2777
+ await mkdir6(functionsDir, { recursive: true });
2778
+ const runtime = await createSimRuntime({
2779
+ cwd,
2780
+ projectId: "local",
2781
+ baseUrl: `http://127.0.0.1:${options.port ?? 8787}`,
2782
+ log
2783
+ });
2784
+ await ensureGitignore(cwd);
2785
+ let files = await collectFunctions(functionsDir);
2786
+ let env = await loadSimEnv(cwd).catch(() => ({}));
2787
+ const dbBundle = runtime.bundle;
2788
+ const invokeHandler = createSimInvokeHandler({ executor, files });
2789
+ const reload = async () => {
2790
+ const [nextFiles, envText2] = await Promise.all([
2791
+ collectFunctions(functionsDir),
2792
+ readFile5(join9(cwd, ".env.local"), "utf8").catch(() => "")
2793
+ ]);
2794
+ files = nextFiles;
2795
+ env = parseEnvFile(envText2);
2796
+ };
2797
+ const envText = await readFile5(join9(cwd, ".env.local"), "utf8").catch(() => "");
2798
+ env = parseEnvFile(envText);
2799
+ let debounceTimer;
2800
+ let watcher;
2801
+ try {
2802
+ watcher = watch(cwd, { recursive: true }, () => {
2803
+ if (debounceTimer !== void 0) clearTimeout(debounceTimer);
2804
+ debounceTimer = setTimeout(() => {
2805
+ void reload();
2806
+ }, 120);
2807
+ });
2808
+ } catch {
2809
+ watcher = void 0;
2810
+ }
2811
+ const buildInput = async (fnName, url, req) => {
2812
+ const query = {};
2813
+ for (const key of new Set(url.searchParams.keys())) {
2814
+ const values = url.searchParams.getAll(key);
2815
+ query[key] = values.length > 1 ? values.join(",") : values[0] ?? "";
2816
+ }
2817
+ const headers = {};
2818
+ for (const [key, value] of Object.entries(req.headers)) {
2819
+ if (typeof value === "string") headers[key] = value;
2820
+ }
2821
+ const body = req.method === "GET" || req.method === "HEAD" ? void 0 : await bodyOf(req);
2822
+ const hasEnv = Object.keys(env).length > 0;
2823
+ return {
2824
+ project: { id: "local", slug: config.name },
2825
+ fn: { id: fnName, name: fnName },
2826
+ files,
2827
+ entry: `${fnName}.ts`,
2828
+ request: {
2829
+ method: req.method ?? "GET",
2830
+ path: url.pathname,
2831
+ query,
2832
+ headers,
2833
+ ...body === void 0 ? {} : { body }
2834
+ },
2835
+ // 模拟运行时能力:db / storage / realtime 各自只读复用线上装配,语义一致。
2836
+ capabilities: dbBundle.capabilities,
2837
+ rpcHandlers: {
2838
+ ...dbBundle.rpcHandlers,
2839
+ invoke: invokeHandler
2840
+ },
2841
+ timeoutMs: 1e4,
2842
+ ...hasEnv ? { env } : {}
2843
+ };
2844
+ };
2845
+ const handle = async (req, res) => {
2846
+ const url = new URL(req.url ?? "/", "http://127.0.0.1");
2847
+ const fnName = url.pathname.split("/").find((segment) => segment.length > 0);
2848
+ if (fnName === void 0) {
2849
+ writeJson(res, 400, {
2850
+ error: { code: "FN_NAME_REQUIRED", message: "\u4EE5 /{fnName} \u8C03\u7528\u672C\u5730\u51FD\u6570" }
2851
+ });
2852
+ return;
2853
+ }
2854
+ const entry = `${fnName}.ts`;
2855
+ const source = files[entry];
2856
+ if (source === void 0) {
2857
+ log(`[adep] ${req.method ?? "GET"} /${fnName} -> 404\uFF08\u51FD\u6570\u4E0D\u5B58\u5728\uFF09`);
2858
+ writeJson(res, 404, { error: { code: "FN_NOT_FOUND", message: `\u51FD\u6570 "${fnName}" \u4E0D\u5B58\u5728` } });
2859
+ return;
2860
+ }
2861
+ const input = await buildInput(fnName, url, req);
2862
+ const startedAt = performance.now();
2863
+ try {
2864
+ const result = await executor.execute(input);
2865
+ const durationMs = Math.round(performance.now() - startedAt);
2866
+ log(`[adep] ${req.method ?? "GET"} /${fnName} -> 200 ${durationMs}ms`);
2867
+ for (const line of result.logs) log(`[adep] ${line}`);
2868
+ writeJson(res, 200, result.body === void 0 ? null : result.body);
2869
+ } catch (error) {
2870
+ const durationMs = Math.round(performance.now() - startedAt);
2871
+ if (error instanceof ExecutorError) {
2872
+ log(
2873
+ `[adep] ${req.method ?? "GET"} /${fnName} -> ${error.status} ${durationMs}ms (${error.code})`
2874
+ );
2875
+ writeJson(res, error.status, { error: { code: error.code, message: error.message } });
2876
+ return;
2877
+ }
2878
+ log(`[adep] ${req.method ?? "GET"} /${fnName} -> 500 ${durationMs}ms`);
2879
+ writeJson(res, 500, {
2880
+ error: {
2881
+ code: "FN_EXEC_ERROR",
2882
+ message: error instanceof Error ? error.message : "\u51FD\u6570\u6267\u884C\u5931\u8D25"
2883
+ }
2884
+ });
2885
+ }
2886
+ };
2887
+ const server = createServer((req, res) => {
2888
+ void handle(req, res);
2889
+ });
2890
+ const port = options.port ?? 8787;
2891
+ await new Promise((resolveListen, rejectListen) => {
2892
+ server.once("error", rejectListen);
2893
+ server.listen(port, "127.0.0.1", () => {
2894
+ server.off("error", rejectListen);
2895
+ resolveListen();
2896
+ });
2897
+ });
2898
+ const address = server.address();
2899
+ const actualPort = typeof address === "object" && address !== null ? address.port : port;
2900
+ const baseUrl = `http://127.0.0.1:${actualPort}`;
2901
+ const coldStartMs = Date.now() - coldStartAt;
2902
+ log(`[adep] dev server listening on ${baseUrl}\uFF08\u6A21\u62DF\u8FD0\u884C\u65F6\uFF0C\u51B7\u542F\u52A8 ${coldStartMs}ms\uFF09`);
2903
+ log(`[adep] curl \u793A\u4F8B\uFF1Acurl ${baseUrl}/hello`);
2904
+ printBoundaries(log);
2905
+ log(`[adep] \u6A21\u62DF\u6570\u636E\u76EE\u5F55\uFF1A${simDir(cwd)}`);
2906
+ return {
2907
+ port: actualPort,
2908
+ baseUrl,
2909
+ close: async () => {
2910
+ if (debounceTimer !== void 0) clearTimeout(debounceTimer);
2911
+ watcher?.close();
2912
+ await new Promise((resolveClose) => server.close(() => resolveClose()));
2913
+ await executor.dispose();
2914
+ await runtime.dispose();
2915
+ }
2916
+ };
2917
+ }
2918
+ var init_dev = __esm({
2919
+ "packages/cli/src/dev.ts"() {
2920
+ "use strict";
2921
+ init_executor();
2922
+ init_worker_executor();
2923
+ init_runtime();
2924
+ init_env();
2925
+ init_invoke();
2926
+ init_boundary();
2927
+ }
2928
+ });
2929
+
2930
+ // packages/cli/src/client.ts
2931
+ async function envelopeError(response, fallbackCode, parsed) {
2932
+ const payload = parsed ?? null;
2933
+ return new CliError(
2934
+ payload?.error?.code ?? fallbackCode,
2935
+ payload?.error?.message ?? `\u5E73\u53F0\u8FD4\u56DE HTTP ${response.status}`
2936
+ );
2937
+ }
2938
+ async function parseBody(response) {
2939
+ const text = await response.text();
2940
+ if (text.length === 0) return null;
2941
+ try {
2942
+ return JSON.parse(text);
2943
+ } catch {
2944
+ return null;
2945
+ }
2946
+ }
2947
+ async function createClient(paths) {
2948
+ const credentials = await loadCredentials(paths);
2949
+ if (credentials === null) {
2950
+ throw new CliError("NOT_LOGGED_IN", "\u672A\u767B\u5F55\uFF1A\u8BF7\u5148\u6267\u884C adep login");
2951
+ }
2952
+ const server = credentials.server;
2953
+ const cookie = `better-auth.session_token=${decodeToken(credentials.encodedToken)}`;
2954
+ const request = async (path, init = {}, fallbackCode = "API_REQUEST_FAILED") => {
2955
+ const method = init.method ?? (init.body === void 0 ? "GET" : "POST");
2956
+ let response;
2957
+ try {
2958
+ response = await fetch(`${server}${path}`, {
2959
+ method,
2960
+ headers: { "content-type": "application/json", cookie },
2961
+ ...init.body === void 0 ? {} : { body: JSON.stringify(init.body) }
2962
+ });
2963
+ } catch (error) {
2964
+ throw new CliError(
2965
+ "SERVER_UNREACHABLE",
2966
+ `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
2967
+ );
2968
+ }
2969
+ const parsed = await parseBody(response);
2970
+ if (response.status < 200 || response.status >= 300) {
2971
+ throw await envelopeError(response, fallbackCode, parsed);
2972
+ }
2973
+ return parsed;
2974
+ };
2975
+ const upload = async (path, form, fallbackCode = "UPLOAD_FAILED") => {
2976
+ let response;
2977
+ try {
2978
+ response = await fetch(`${server}${path}`, {
2979
+ method: "POST",
2980
+ headers: { cookie },
2981
+ body: form
2982
+ });
2983
+ } catch (error) {
2984
+ throw new CliError(
2985
+ "SERVER_UNREACHABLE",
2986
+ `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
2987
+ );
2988
+ }
2989
+ if (response.status < 200 || response.status >= 300) {
2990
+ throw await envelopeError(response, fallbackCode, await parseBody(response));
2991
+ }
2992
+ return response;
2993
+ };
2994
+ const download = async (url, fallbackCode = "DOWNLOAD_FAILED") => {
2995
+ const target = url.startsWith("http") ? url : `${server}${url}`;
2996
+ let response;
2997
+ try {
2998
+ response = await fetch(target, { headers: { cookie } });
2999
+ } catch (error) {
3000
+ throw new CliError(
3001
+ "SERVER_UNREACHABLE",
3002
+ `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
3003
+ );
3004
+ }
3005
+ if (response.status < 200 || response.status >= 300) {
3006
+ throw await envelopeError(response, fallbackCode, await parseBody(response));
3007
+ }
3008
+ return response;
3009
+ };
3010
+ return { server, cookie, request, upload, download };
3011
+ }
3012
+ async function resolveSlug(cwd, slug) {
3013
+ if (slug !== void 0 && slug.length > 0) return slug;
3014
+ const config = await loadConfig(cwd);
3015
+ return config.name;
3016
+ }
3017
+ var init_client = __esm({
3018
+ "packages/cli/src/client.ts"() {
3019
+ "use strict";
3020
+ init_auth();
3021
+ init_credentials();
3022
+ init_dev();
3023
+ }
3024
+ });
3025
+
3026
+ // packages/cli/src/deploy.ts
3027
+ var deploy_exports = {};
3028
+ __export(deploy_exports, {
3029
+ collectEntries: () => collectEntries,
3030
+ deploy: () => deploy
3031
+ });
3032
+ import { createHash as createHash3 } from "node:crypto";
3033
+ import { readdir as readdir3, readFile as readFile6 } from "node:fs/promises";
3034
+ import { join as join10, resolve as resolve6, basename as basename2 } from "node:path";
3035
+ async function collectEntries(functionsDir) {
3036
+ const entries = {};
3037
+ let names;
3038
+ try {
3039
+ const dirents = await readdir3(functionsDir, { withFileTypes: true });
3040
+ names = dirents.filter((entry) => entry.isFile() && entry.name.endsWith(".ts")).map((entry) => basename2(entry.name, ".ts")).toSorted();
3041
+ } catch {
3042
+ return entries;
3043
+ }
3044
+ for (const name of names) {
3045
+ entries[name] = await readFile6(join10(functionsDir, `${name}.ts`), "utf8");
3046
+ }
3047
+ return entries;
3048
+ }
3049
+ function sha256Hex(content) {
3050
+ return createHash3("sha256").update(content).digest("hex");
3051
+ }
3052
+ async function deploy(paths, options) {
3053
+ const log = options.log ?? ((line) => process.stdout.write(`${line}
3054
+ `));
3055
+ const client = await createClient(paths);
3056
+ const cwd = resolve6(options.cwd);
3057
+ const config = await loadConfig(cwd);
3058
+ const slug = options.slug ?? config.name;
3059
+ const functionsDir = join10(cwd, config.functionsDir);
3060
+ const local = await collectEntries(functionsDir);
3061
+ if (Object.keys(local).length === 0) {
3062
+ throw new CliError("NO_FUNCTIONS", `${functionsDir} \u4E0B\u6CA1\u6709\u51FD\u6570\u6587\u4EF6`);
3063
+ }
3064
+ const remote = await client.request(
3065
+ "/api/v1/deploy/diff",
3066
+ {
3067
+ body: {
3068
+ slug,
3069
+ functions: Object.entries(local).map(([name, content]) => ({
3070
+ name,
3071
+ files: { "index.ts": sha256Hex(content) }
3072
+ }))
3073
+ }
3074
+ },
3075
+ "DEPLOY_FAILED"
3076
+ );
3077
+ const baseUrl = `${remote.scheme}://${remote.slug}.${remote.domain}`;
3078
+ const deployed = [];
3079
+ for (const item of remote.functions) {
3080
+ const content = local[item.name];
3081
+ if (item.action === "none") {
3082
+ deployed.push({
3083
+ name: item.name,
3084
+ action: "none",
3085
+ version: item.version ?? 0,
3086
+ url: `${baseUrl}/${item.name}`
3087
+ });
3088
+ continue;
3089
+ }
3090
+ log(`[adep] \u90E8\u7F72 ${item.name}\uFF08${item.action === "create" ? "\u65B0\u5EFA" : "\u53D8\u66F4"}\uFF09`);
3091
+ let functionId = item.id;
3092
+ if (functionId === null) {
3093
+ const created = await client.request(
3094
+ `/api/v1/projects/${remote.projectId}/functions`,
3095
+ {
3096
+ body: { name: item.name, files: { "index.ts": content } }
3097
+ }
3098
+ );
3099
+ functionId = created.id;
3100
+ } else {
3101
+ await client.request(`/api/v1/projects/${remote.projectId}/functions/${item.name}`, {
3102
+ method: "PATCH",
3103
+ body: { files: { "index.ts": content } }
3104
+ });
3105
+ }
3106
+ const published = await client.request(
3107
+ `/api/v1/functions/${functionId}/publish`,
3108
+ { method: "POST" }
3109
+ );
3110
+ deployed.push({
3111
+ name: item.name,
3112
+ action: item.action,
3113
+ version: published.version,
3114
+ url: `${baseUrl}/${item.name}`
3115
+ });
3116
+ }
3117
+ return {
3118
+ projectId: remote.projectId,
3119
+ slug: remote.slug,
3120
+ baseUrl,
3121
+ noChanges: deployed.every((function_) => function_.action === "none"),
3122
+ functions: deployed
3123
+ };
3124
+ }
3125
+ var init_deploy = __esm({
3126
+ "packages/cli/src/deploy.ts"() {
3127
+ "use strict";
3128
+ init_auth();
3129
+ init_client();
3130
+ init_dev();
3131
+ }
3132
+ });
3133
+
3134
+ // packages/cli/src/db.ts
3135
+ var db_exports = {};
3136
+ __export(db_exports, {
3137
+ dbExec: () => dbExec,
3138
+ dbRollback: () => dbRollback,
3139
+ dbSnapshotCreate: () => dbSnapshotCreate,
3140
+ dbSnapshotList: () => dbSnapshotList,
3141
+ dbSnapshotRestore: () => dbSnapshotRestore,
3142
+ dbStart: () => dbStart,
3143
+ dbStatus: () => dbStatus,
3144
+ dbStop: () => dbStop
3145
+ });
3146
+ import { resolve as resolve7 } from "node:path";
3147
+ async function open2(paths, options) {
3148
+ const client = await createClient(paths);
3149
+ const project2 = await resolveSlug(resolve7(options.cwd), options.slug);
3150
+ return { client, project: project2 };
3151
+ }
3152
+ async function dbStart(paths, options) {
3153
+ const { client, project: project2 } = await open2(paths, options);
3154
+ return client.request(`/api/v1/projects/${project2}/database`, { method: "POST" });
3155
+ }
3156
+ async function dbStatus(paths, options) {
3157
+ const { client, project: project2 } = await open2(paths, options);
3158
+ return client.request(`/api/v1/projects/${project2}/database`);
3159
+ }
3160
+ async function dbStop(paths, options) {
3161
+ const { client, project: project2 } = await open2(paths, options);
3162
+ return client.request(`/api/v1/projects/${project2}/database`, {
3163
+ method: "DELETE"
3164
+ });
3165
+ }
3166
+ async function dbExec(paths, options) {
3167
+ const { client, project: project2 } = await open2(paths, options);
3168
+ return client.request(
3169
+ `/api/v1/projects/${project2}/database/console/sql`,
3170
+ {
3171
+ method: "POST",
3172
+ body: {
3173
+ sql: options.sql,
3174
+ ...options.params === void 0 ? {} : { params: options.params },
3175
+ ...options.confirmTable === void 0 ? {} : { confirmTable: options.confirmTable }
3176
+ }
3177
+ },
3178
+ "SQL_EXEC_FAILED"
3179
+ );
3180
+ }
3181
+ async function dbSnapshotList(paths, options) {
3182
+ const { client, project: project2 } = await open2(paths, options);
3183
+ return client.request(
3184
+ `/api/v1/projects/${project2}/database/snapshots`
3185
+ );
3186
+ }
3187
+ async function dbSnapshotCreate(paths, options) {
3188
+ const { client, project: project2 } = await open2(paths, options);
3189
+ return client.request(`/api/v1/projects/${project2}/database/snapshots`, {
3190
+ method: "POST"
3191
+ });
3192
+ }
3193
+ async function dbSnapshotRestore(paths, options) {
3194
+ const { client, project: project2 } = await open2(paths, options);
3195
+ return client.request(
3196
+ `/api/v1/projects/${project2}/database/snapshots/${options.snapshotId}/restore`,
3197
+ { method: "POST" }
3198
+ );
3199
+ }
3200
+ async function dbRollback(paths, options) {
3201
+ const { client, project: project2 } = await open2(paths, options);
3202
+ return client.request(
3203
+ `/api/v1/projects/${project2}/database/rollback`,
3204
+ { method: "POST", body: { to: options.to } }
3205
+ );
3206
+ }
3207
+ var init_db2 = __esm({
3208
+ "packages/cli/src/db.ts"() {
3209
+ "use strict";
3210
+ init_client();
3211
+ }
3212
+ });
3213
+
3214
+ // packages/cli/src/storage.ts
3215
+ var storage_exports = {};
3216
+ __export(storage_exports, {
3217
+ contentTypeOf: () => contentTypeOf,
3218
+ storageDownload: () => storageDownload,
3219
+ storageList: () => storageList,
3220
+ storageRemove: () => storageRemove,
3221
+ storageUpload: () => storageUpload
3222
+ });
3223
+ import { mkdir as mkdir7, readFile as readFile7, stat as stat6, writeFile as writeFile6 } from "node:fs/promises";
3224
+ import { basename as basename3, dirname as dirname7, extname, join as join11, resolve as resolve8 } from "node:path";
3225
+ async function open3(paths, options) {
3226
+ const client = await createClient(paths);
3227
+ const project2 = await resolveSlug(resolve8(options.cwd), options.slug);
3228
+ return { client, project: project2 };
3229
+ }
3230
+ function contentTypeOf(path) {
3231
+ const map = {
3232
+ ".html": "text/html; charset=utf-8",
3233
+ ".htm": "text/html; charset=utf-8",
3234
+ ".css": "text/css; charset=utf-8",
3235
+ ".js": "text/javascript; charset=utf-8",
3236
+ ".mjs": "text/javascript; charset=utf-8",
3237
+ ".json": "application/json; charset=utf-8",
3238
+ ".png": "image/png",
3239
+ ".jpg": "image/jpeg",
3240
+ ".jpeg": "image/jpeg",
3241
+ ".gif": "image/gif",
3242
+ ".svg": "image/svg+xml",
3243
+ ".webp": "image/webp",
3244
+ ".ico": "image/x-icon",
3245
+ ".txt": "text/plain; charset=utf-8",
3246
+ ".md": "text/markdown; charset=utf-8",
3247
+ ".xml": "application/xml",
3248
+ ".wasm": "application/wasm",
3249
+ ".pdf": "application/pdf",
3250
+ ".zip": "application/zip",
3251
+ ".woff": "font/woff",
3252
+ ".woff2": "font/woff2",
3253
+ ".ttf": "font/ttf",
3254
+ ".otf": "font/otf"
3255
+ };
3256
+ return map[extname(path).toLowerCase()] ?? "application/octet-stream";
3257
+ }
3258
+ async function storageUpload(paths, options) {
3259
+ const { client, project: project2 } = await open3(paths, options);
3260
+ const local = resolve8(options.file);
3261
+ const info = await stat6(local).catch(() => null);
3262
+ if (info === null || !info.isFile()) {
3263
+ throw new CliError("FILE_NOT_FOUND", `\u672C\u5730\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${local}`);
3264
+ }
3265
+ const visibility = options.visibility ?? "private";
3266
+ const bytes = await readFile7(local);
3267
+ const form = new FormData();
3268
+ form.set("path", options.path);
3269
+ form.set("visibility", visibility);
3270
+ form.set(
3271
+ "file",
3272
+ new Blob([bytes], { type: contentTypeOf(options.path) }),
3273
+ basename3(local)
3274
+ );
3275
+ const response = await client.upload(
3276
+ `/api/v1/projects/${project2}/files`,
3277
+ form,
3278
+ "STORAGE_UPLOAD_FAILED"
3279
+ );
3280
+ const body = await response.json();
3281
+ return { ...body.file, ...body.signedUrl === void 0 ? {} : { signedUrl: body.signedUrl } };
3282
+ }
3283
+ async function storageList(paths, options) {
3284
+ const { client, project: project2 } = await open3(paths, options);
3285
+ const query = options.prefix === void 0 ? "" : `?prefix=${encodeURIComponent(options.prefix)}`;
3286
+ const body = await client.request(
3287
+ `/api/v1/projects/${project2}/files${query}`
3288
+ );
3289
+ return { project: project2, files: body.files };
3290
+ }
3291
+ async function resolveDownloadUrl(client, project2, path) {
3292
+ const body = await client.request(
3293
+ `/api/v1/projects/${project2}/files?prefix=${encodeURIComponent(path)}`
3294
+ );
3295
+ const entry = body.files.find((file) => file.path === path);
3296
+ const url = entry?.url ?? entry?.signedUrl;
3297
+ if (entry === void 0 || url === void 0 || url.length === 0) {
3298
+ throw new CliError("STORAGE_NOT_FOUND", `\u6587\u4EF6\u4E0D\u5B58\u5728\uFF1A${path}`);
3299
+ }
3300
+ return url;
3301
+ }
3302
+ async function storageDownload(paths, options) {
3303
+ const { client, project: project2 } = await open3(paths, options);
3304
+ const url = await resolveDownloadUrl(client, project2, options.path);
3305
+ const response = await client.download(url, "STORAGE_DOWNLOAD_FAILED");
3306
+ const bytes = Buffer.from(await response.arrayBuffer());
3307
+ const output = resolve8(options.output ?? join11(resolve8(options.cwd), basename3(options.path)));
3308
+ await mkdir7(dirname7(output), { recursive: true });
3309
+ await writeFile6(output, bytes);
3310
+ return { path: options.path, output, size: bytes.length };
3311
+ }
3312
+ async function storageRemove(paths, options) {
3313
+ const { client, project: project2 } = await open3(paths, options);
3314
+ return client.request(
3315
+ `/api/v1/projects/${project2}/files/${encodeURIComponent(options.path)}`,
3316
+ { method: "DELETE" }
3317
+ );
3318
+ }
3319
+ var init_storage2 = __esm({
3320
+ "packages/cli/src/storage.ts"() {
3321
+ "use strict";
3322
+ init_client();
3323
+ init_auth();
3324
+ }
3325
+ });
3326
+
3327
+ // packages/cli/src/hosting.ts
3328
+ var hosting_exports = {};
3329
+ __export(hosting_exports, {
3330
+ hostingConfig: () => hostingConfig,
3331
+ hostingDeploy: () => hostingDeploy,
3332
+ hostingInfo: () => hostingInfo,
3333
+ hostingPull: () => hostingPull
3334
+ });
3335
+ import { readdir as readdir4, readFile as readFile8, stat as stat7 } from "node:fs/promises";
3336
+ import { dirname as dirname8, join as join12, relative, resolve as resolve9, sep } from "node:path";
3337
+ async function open4(paths, options) {
3338
+ const client = await createClient(paths);
3339
+ const project2 = await resolveSlug(resolve9(options.cwd), options.slug);
3340
+ return { client, project: project2 };
3341
+ }
3342
+ async function hostingInfo(paths, options) {
3343
+ const { client, project: project2 } = await open4(paths, options);
3344
+ const body = await client.request(`/api/v1/projects/${project2}/hosting`);
3345
+ return {
3346
+ config: body.config,
3347
+ siteUrl: body.siteUrl,
3348
+ files: body.files ?? []
3349
+ };
3350
+ }
3351
+ async function collectSiteFiles(dir) {
3352
+ const root = resolve9(dir);
3353
+ const files = /* @__PURE__ */ new Map();
3354
+ const walk = async (sub) => {
3355
+ let entries;
3356
+ try {
3357
+ entries = await readdir4(sub, { withFileTypes: true });
3358
+ } catch {
3359
+ return;
3360
+ }
3361
+ for (const entry of entries) {
3362
+ const full = join12(sub, entry.name);
3363
+ if (entry.isDirectory()) {
3364
+ await walk(full);
3365
+ } else if (entry.isFile()) {
3366
+ const rel = relative(root, full).split(sep).join("/");
3367
+ files.set(rel, full);
3368
+ }
3369
+ }
3370
+ };
3371
+ await walk(root);
3372
+ return files;
3373
+ }
3374
+ async function hostingDeploy(paths, options) {
3375
+ const { client, project: project2 } = await open4(paths, options);
3376
+ const log = options.log ?? ((line) => process.stdout.write(`${line}
3377
+ `));
3378
+ const files = await collectSiteFiles(options.dir);
3379
+ if (files.size === 0) {
3380
+ throw new CliError("NO_SITE_FILES", `\u7AD9\u70B9\u76EE\u5F55\u4E3A\u7A7A\uFF1A${resolve9(options.dir)}`);
3381
+ }
3382
+ const uploaded = [];
3383
+ for (const [rel, full] of files) {
3384
+ log(`[adep] \u4E0A\u4F20 site/${rel}`);
3385
+ const info2 = await stat7(full);
3386
+ const bytes = await readFile8(full);
3387
+ const form = new FormData();
3388
+ form.set("path", `site/${rel}`);
3389
+ form.set("visibility", "public");
3390
+ form.set(
3391
+ "file",
3392
+ new Blob([bytes], { type: contentTypeOf(rel) }),
3393
+ rel.split("/").pop()
3394
+ );
3395
+ await client.upload(`/api/v1/projects/${project2}/files`, form, "HOSTING_UPLOAD_FAILED");
3396
+ uploaded.push({ path: `site/${rel}`, size: info2.size });
3397
+ }
3398
+ const config = await client.request(
3399
+ `/api/v1/projects/${project2}/hosting`,
3400
+ {
3401
+ method: "PUT",
3402
+ body: options.spa === void 0 ? { enabled: true } : { enabled: true, spaMode: options.spa }
3403
+ }
3404
+ );
3405
+ const info = await hostingInfo(paths, options);
3406
+ return { config: config.config, siteUrl: info.siteUrl, uploaded };
3407
+ }
3408
+ async function hostingPull(paths, options) {
3409
+ const { client } = await open4(paths, options);
3410
+ const log = options.log ?? ((line) => process.stdout.write(`${line}
3411
+ `));
3412
+ const info = await hostingInfo(paths, options);
3413
+ const outputDir = resolve9(options.output ?? resolve9(options.cwd));
3414
+ const { mkdir: mkdir8, writeFile: writeFile7 } = await import("node:fs/promises");
3415
+ const files = [];
3416
+ for (const entry of info.files) {
3417
+ if (entry.visibility !== "public" || entry.path === HOSTING_CONFIG_PATH) continue;
3418
+ const url = entry.url;
3419
+ if (url === void 0 || url.length === 0) continue;
3420
+ log(`[adep] \u4E0B\u8F7D ${entry.path}`);
3421
+ const response = await client.download(url, "HOSTING_DOWNLOAD_FAILED");
3422
+ const bytes = Buffer.from(await response.arrayBuffer());
3423
+ const rel = entry.path.replace(/^site\//, "");
3424
+ const target = join12(outputDir, ...rel.split("/"));
3425
+ await mkdir8(dirname8(target), { recursive: true });
3426
+ await writeFile7(target, bytes);
3427
+ files.push({ path: entry.path, size: bytes.length });
3428
+ }
3429
+ return { siteUrl: info.siteUrl, outputDir, files };
3430
+ }
3431
+ async function hostingConfig(paths, options) {
3432
+ const { client, project: project2 } = await open4(paths, options);
3433
+ const body = {};
3434
+ if (options.enabled !== void 0) body["enabled"] = options.enabled;
3435
+ if (options.spa !== void 0) body["spaMode"] = options.spa;
3436
+ const result = await client.request(
3437
+ `/api/v1/projects/${project2}/hosting`,
3438
+ { method: "PUT", body }
3439
+ );
3440
+ return result.config;
3441
+ }
3442
+ var HOSTING_CONFIG_PATH;
3443
+ var init_hosting = __esm({
3444
+ "packages/cli/src/hosting.ts"() {
3445
+ "use strict";
3446
+ init_client();
3447
+ init_auth();
3448
+ init_storage2();
3449
+ HOSTING_CONFIG_PATH = "site/.hosting.json";
3450
+ }
3451
+ });
3452
+
3453
+ // packages/cli/src/widget/dev.ts
3454
+ var dev_exports2 = {};
3455
+ __export(dev_exports2, {
3456
+ loadWidgetProject: () => loadWidgetProject,
3457
+ startWidgetDev: () => startWidgetDev
3458
+ });
3459
+ import { createServer as createServer2 } from "node:http";
3460
+ import { watch as watch2 } from "node:fs";
3461
+ import { readFile as readFile9, stat as stat8 } from "node:fs/promises";
3462
+ import { join as join13, resolve as resolve10 } from "node:path";
3463
+ async function loadWidgetProject(cwd) {
3464
+ const fallback = {
3465
+ name: "widget",
3466
+ framework: "vue3"
3467
+ };
3468
+ const manifestPath = join13(resolve10(cwd), "manifest.json");
3469
+ try {
3470
+ await stat8(manifestPath);
3471
+ } catch {
3472
+ return fallback;
3473
+ }
3474
+ try {
3475
+ const raw = await readFile9(manifestPath, "utf8");
3476
+ const parsed = JSON.parse(raw);
3477
+ return {
3478
+ name: typeof parsed["name"] === "string" ? parsed["name"] : fallback.name,
3479
+ framework: parsed["framework"] === "react" ? "react" : "vue3"
3480
+ };
3481
+ } catch {
3482
+ return fallback;
3483
+ }
3484
+ }
3485
+ function sandboxHtml(name, framework) {
3486
+ return `<!doctype html>
3487
+ <html>
3488
+ <head>
3489
+ <meta charset="utf-8" />
3490
+ <title>adep widget dev \u2014 ${name}</title>
3491
+ <link rel="stylesheet" href="/__widget/theme.css" />
3492
+ <style>
3493
+ body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #f5f6f7; margin: 0; padding: 24px; }
3494
+ #toolbar { display: flex; gap: 12px; align-items: center; font-size: 13px; color: #4c5561; margin-bottom: 16px; }
3495
+ #toolbar .dot { width: 8px; height: 8px; border-radius: 50%; background: #99a2ad; }
3496
+ #toolbar .dot.on { background: #16a34a; }
3497
+ #sandbox { background: #fff; border: 1px solid #e5e6eb; border-radius: 8px; min-height: 120px; }
3498
+ code { background: #eef0f3; padding: 2px 6px; border-radius: 4px; }
3499
+ </style>
3500
+ </head>
3501
+ <body>
3502
+ <div id="toolbar"><span id="status"><span class="dot" id="dot"></span> sandbox connecting\u2026</span></div>
3503
+ <div id="sandbox"></div>
3504
+ <script type="module">
3505
+ const q = new URLSearchParams(location.search)
3506
+ const token = q.get('token') ?? ''
3507
+ document.getElementById('status').textContent = 'token: ' + (token ? 'injected' : '(none)')
3508
+ const hostEl = document.getElementById('sandbox')
3509
+ const host = hostEl.attachShadow({ mode: 'open' })
3510
+ let version = 0
3511
+
3512
+ async function load(v) {
3513
+ host.textContent = ''
3514
+ let props = {}
3515
+ try { props = await (await fetch('/__widget/mock-props')).json() } catch { props = {} }
3516
+ const mod = await import('/__widget/index.js?v=' + v)
3517
+ mod.mount(host, {
3518
+ widgetName: '${name}',
3519
+ framework: '${framework}',
3520
+ props,
3521
+ host: {
3522
+ getProjectId: () => 'local-dev',
3523
+ invokeFunction: async () => ({})
3524
+ }
3525
+ })
3526
+ }
3527
+
3528
+ function markConnected() {
3529
+ const dot = document.getElementById('dot')
3530
+ dot.classList.add('on')
3531
+ document.getElementById('status').firstChild.textContent = 'sandbox live \u2014 watch src/\uFF0C\u4FDD\u5B58\u540E\u81EA\u52A8\u70ED\u66F4\u65B0 '
3532
+ }
3533
+
3534
+ const es = new EventSource('/__widget/events')
3535
+ es.addEventListener('rebuild', (e) => {
3536
+ version = Number(e.data) || 0
3537
+ load(version).catch((err) => { console.error(err); host.textContent = 'mount error: ' + err.message })
3538
+ })
3539
+ es.addEventListener('open', (e) => {
3540
+ e.preventDefault()
3541
+ markConnected()
3542
+ if (version === 0) load(0)
3543
+ })
3544
+ </script>
3545
+ </body>
3546
+ </html>
3547
+ `;
3548
+ }
3549
+ async function startWidgetDev(options) {
3550
+ const cwd = resolve10(options.cwd);
3551
+ const log = options.log ?? ((line) => process.stdout.write(`${line}
3552
+ `));
3553
+ const project2 = await loadWidgetProject(cwd);
3554
+ const framework = options.framework ?? project2.framework;
3555
+ let state = { text: "", version: 0 };
3556
+ const rebuild = async () => {
3557
+ const built = await buildWidget({ cwd, framework });
3558
+ const next = { text: built.text, version: state.version + 1 };
3559
+ state = next;
3560
+ return next;
3561
+ };
3562
+ try {
3563
+ await rebuild();
3564
+ } catch (error) {
3565
+ throw new WidgetError(
3566
+ "BUILD_FAILED",
3567
+ `widget \u6784\u5EFA\u5931\u8D25\uFF1A${error instanceof Error ? error.message : String(error)}`
3568
+ );
3569
+ }
3570
+ const clients = /* @__PURE__ */ new Set();
3571
+ const broadcast = (version) => {
3572
+ for (const res of clients) {
3573
+ res.write(`event: rebuild
3574
+ data: ${version}
3575
+
3576
+ `);
3577
+ }
3578
+ };
3579
+ let debounceTimer;
3580
+ let watcher;
3581
+ try {
3582
+ watcher = watch2(cwd, { recursive: true }, () => {
3583
+ if (debounceTimer !== void 0) clearTimeout(debounceTimer);
3584
+ debounceTimer = setTimeout(() => {
3585
+ void buildWidget({ cwd, framework }).then((built) => {
3586
+ const next = { text: built.text, version: state.version + 1 };
3587
+ state = next;
3588
+ broadcast(next.version);
3589
+ log(`[adep] widget rebuilt v${next.version}`);
3590
+ return void 0;
3591
+ }).catch((error) => {
3592
+ log(`[adep] rebuild failed: ${error instanceof Error ? error.message : String(error)}`);
3593
+ });
3594
+ }, 120);
3595
+ });
3596
+ } catch {
3597
+ watcher = void 0;
3598
+ }
3599
+ const readTheme = async () => {
3600
+ try {
3601
+ return await readFile9(join13(cwd, "src", "theme.css"), "utf8");
3602
+ } catch {
3603
+ return null;
3604
+ }
3605
+ };
3606
+ const readProps = async () => {
3607
+ try {
3608
+ return await readFile9(join13(cwd, "src", "mock-props.json"), "utf8");
3609
+ } catch {
3610
+ return null;
3611
+ }
3612
+ };
3613
+ const handle = async (req, res) => {
3614
+ const url = new URL(req.url ?? "/", "http://127.0.0.1");
3615
+ if (url.pathname === "/") {
3616
+ res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
3617
+ res.end(sandboxHtml(project2.name, framework));
3618
+ return;
3619
+ }
3620
+ if (url.pathname === "/__widget/index.js") {
3621
+ const version = url.searchParams.get("v");
3622
+ if (version !== null && Number(version) > state.version) {
3623
+ await rebuild().catch(() => void 0);
3624
+ }
3625
+ res.writeHead(200, { "content-type": "application/javascript; charset=utf-8" });
3626
+ res.end(state.text);
3627
+ return;
3628
+ }
3629
+ if (url.pathname === "/__widget/theme.css") {
3630
+ const css = await readTheme();
3631
+ if (css === null) {
3632
+ res.writeHead(404).end("not found");
3633
+ return;
3634
+ }
3635
+ res.writeHead(200, { "content-type": "text/css; charset=utf-8" });
3636
+ res.end(css);
3637
+ return;
3638
+ }
3639
+ if (url.pathname === "/__widget/mock-props") {
3640
+ const props = await readProps();
3641
+ res.writeHead(200, { "content-type": "application/json; charset=utf-8" });
3642
+ res.end(props ?? "{}");
3643
+ return;
3644
+ }
3645
+ if (url.pathname === "/__widget/events") {
3646
+ res.writeHead(200, {
3647
+ "content-type": "text/event-stream",
3648
+ "cache-control": "no-cache",
3649
+ connection: "keep-alive"
3650
+ });
3651
+ res.write(": connected\n\n");
3652
+ clients.add(res);
3653
+ req.on("close", () => {
3654
+ clients.delete(res);
3655
+ });
3656
+ return;
3657
+ }
3658
+ res.writeHead(404).end("not found");
3659
+ };
3660
+ const server = createServer2((req, res) => {
3661
+ void handle(req, res);
3662
+ });
3663
+ await new Promise((resolveListen, rejectListen) => {
3664
+ server.once("error", rejectListen);
3665
+ server.listen(options.port ?? 8788, "127.0.0.1", () => {
3666
+ server.off("error", rejectListen);
3667
+ resolveListen();
3668
+ });
3669
+ });
3670
+ const address = server.address();
3671
+ const port = typeof address === "object" && address !== null ? address.port : options.port ?? 8788;
3672
+ const baseUrl = `http://127.0.0.1:${port}`;
3673
+ return {
3674
+ port,
3675
+ baseUrl,
3676
+ close: async () => {
3677
+ if (debounceTimer !== void 0) clearTimeout(debounceTimer);
3678
+ watcher?.close();
3679
+ for (const res of clients) res.end();
3680
+ clients.clear();
3681
+ await new Promise((resolveClose) => server.close(() => resolveClose()));
3682
+ }
3683
+ };
3684
+ }
3685
+ var init_dev2 = __esm({
3686
+ "packages/cli/src/widget/dev.ts"() {
3687
+ "use strict";
3688
+ init_build();
3689
+ }
3690
+ });
3691
+
3692
+ // packages/cli/src/widget/publish.ts
3693
+ var publish_exports = {};
3694
+ __export(publish_exports, {
3695
+ publishWidget: () => publishWidget
3696
+ });
3697
+ import { readFile as readFile10 } from "node:fs/promises";
3698
+ import { basename as basename4, join as join14, resolve as resolve11 } from "node:path";
3699
+ async function publishWidget(paths, options) {
3700
+ const log = options.log ?? ((line) => process.stdout.write(`${line}
3701
+ `));
3702
+ const client = await createClient(paths);
3703
+ const root = resolve11(options.cwd);
3704
+ const project2 = await loadWidgetProject(root);
3705
+ const framework = options.framework ?? project2.framework;
3706
+ let version = "0.1.0";
3707
+ try {
3708
+ const pkg = JSON.parse(await readFile10(join14(root, "package.json"), "utf8"));
3709
+ if (typeof pkg["version"] === "string" && pkg["version"].length > 0) version = pkg["version"];
3710
+ } catch {
3711
+ version = "0.1.0";
3712
+ }
3713
+ const name = project2.name === "widget" ? basename4(root) : project2.name;
3714
+ log(`[adep] \u6784\u5EFA ${name}\uFF08${framework}\uFF09v${version} \u2026`);
3715
+ const built = await buildWidget({ cwd: root, framework });
3716
+ const path = `widgets/${name}/${version}/index.js`;
3717
+ const form = new FormData();
3718
+ form.set("path", path);
3719
+ form.set("visibility", "public");
3720
+ form.set("file", new Blob([built.text], { type: "text/javascript" }), "index.js");
3721
+ await client.upload(`/api/v1/projects/${options.project}/files`, form, "PUBLISH_UPLOAD_FAILED");
3722
+ const prefix = encodeURIComponent(`widgets/${name}/${version}/`);
3723
+ const listing = await client.request(
3724
+ `/api/v1/projects/${options.project}/files?prefix=${prefix}`
3725
+ );
3726
+ const entry = (listing.files ?? []).find((file) => file.path?.endsWith("index.js"));
3727
+ const url = entry?.url;
3728
+ if (typeof url !== "string" || url.length === 0) {
3729
+ throw new WidgetError("URL_MISSING", "\u4E0A\u4F20\u6210\u529F\u4F46\u65E0\u6CD5\u89E3\u6790\u4EA7\u7269 URL\uFF0C\u8BF7\u68C0\u67E5\u5E73\u53F0\u5B58\u50A8\u914D\u7F6E");
3730
+ }
3731
+ log(`[adep] \u5DF2\u53D1\u5E03 ${name} v${version}\uFF08hash ${built.hash.slice(0, 8)}\u2026\uFF09`);
3732
+ return { name, version, framework, url, hash: built.hash };
3733
+ }
3734
+ var init_publish = __esm({
3735
+ "packages/cli/src/widget/publish.ts"() {
3736
+ "use strict";
3737
+ init_client();
3738
+ init_build();
3739
+ init_dev2();
3740
+ }
3741
+ });
3742
+
3743
+ // packages/cli/src/cli.ts
3744
+ init_auth();
3745
+ import { Command } from "commander";
3746
+ import { createRequire } from "node:module";
3747
+
3748
+ // packages/cli/src/config.ts
3749
+ function resolvePaths(env = process.env) {
3750
+ const home = env["ADEP_HOME"] ?? `${env["HOME"] ?? ""}/.adep`;
3751
+ return { home, credentialsFile: `${home}/credentials` };
3752
+ }
3753
+ function resolveServer(env = process.env) {
3754
+ return (env["ADEP_SERVER"] ?? "https://adep.jajabjbj.top").replace(/\/+$/, "");
3755
+ }
3756
+
3757
+ // packages/cli/src/init.ts
3758
+ import { mkdir as mkdir2, stat as stat2, writeFile } from "node:fs/promises";
3759
+ import { dirname as dirname2, join, resolve } from "node:path";
3760
+ var InitError = class extends Error {
3761
+ constructor(code, message) {
3762
+ super(message);
3763
+ this.code = code;
3764
+ this.name = "InitError";
3765
+ }
3766
+ };
3767
+ var ADEP_CONFIG = (name, template) => `import { defineConfig } from 'adep/config'
3768
+
3769
+ // adep \u9879\u76EE\u914D\u7F6E\uFF1ACLI\uFF08dev / deploy\uFF09\u4E0E\u5E73\u53F0\u6309\u6B64\u8BC6\u522B\u9879\u76EE\u3002
3770
+ export default defineConfig({
3771
+ name: '${name}',
3772
+ template: '${template}',
3773
+ })
3774
+ `;
3775
+ var README = (name, template) => `# ${name}
3776
+
3777
+ AgentDeploy \u9879\u76EE\uFF08\u6A21\u677F\uFF1A${template}\uFF09\u3002
3778
+
3779
+ - \`adep dev\`\uFF1A\u672C\u5730\u8C03\u8BD5\uFF08CLI-002 \u4EA4\u4ED8\uFF09
3780
+ - \`adep deploy\`\uFF1A\u53D1\u5E03\uFF08CLI-003 \u4EA4\u4ED8\uFF09
3781
+ `;
3782
+ var HELLO_FUNCTION = `import { defineFunction } from 'adep/function'
3783
+
3784
+ // \u793A\u4F8B\u51FD\u6570\uFF1Aadep deploy \u540E\u7ECF https://<project-slug>.<platform-domain>/hello \u89E6\u53D1\u3002
3785
+ export default defineFunction(async (ctx) => {
3786
+ const name = (ctx.query['name'] as string | undefined) ?? 'world'
3787
+ return { message: \`hello \${name}\` }
3788
+ })
3789
+ `;
3790
+ var FUNCTION_INDEX = `// \u51FD\u6570\u6A21\u5757\u5165\u53E3\uFF1A\u9879\u76EE\u91CC\u7684\u6BCF\u4E2A\u51FD\u6570\u662F functions/ \u4E0B\u7684\u72EC\u7ACB\u6587\u4EF6\uFF0C
3791
+ // \u9ED8\u8BA4\u5BFC\u51FA (ctx) => Response \u5F62\u72B6\u7684\u5904\u7406\u5668\uFF08\u5951\u7EA6\u89C1 @adep/types \u7684 FunctionContext\uFF09\u3002
3792
+ `;
3793
+ var EMPTY_INDEX = `// AgentDeploy \u9879\u76EE\u5165\u53E3\u3002M1 \u4E2D\u6A21\u677F\u6682\u65E0\u66F4\u591A\u5185\u5BB9\u2014\u2014\u51FD\u6570\u653E functions/\uFF0C\u914D\u7F6E\u89C1 adep.config.ts\u3002
3794
+ `;
3795
+ async function initProject(cwd, name, template) {
3796
+ if (!/^[a-z][a-z0-9-]{0,62}$/.test(name)) {
3797
+ throw new InitError(
3798
+ "INVALID_NAME",
3799
+ `\u9879\u76EE\u540D "${name}" \u4E0D\u5408\u6CD5\uFF1A\u9700\u4EE5\u5C0F\u5199\u5B57\u6BCD\u5F00\u5934\uFF0C\u4EC5\u542B\u5C0F\u5199\u5B57\u6BCD / \u6570\u5B57 / \u8FDE\u5B57\u7B26`
3800
+ );
3801
+ }
3802
+ const projectPath = resolve(cwd, name);
3803
+ let existing;
3804
+ try {
3805
+ existing = await stat2(projectPath);
3806
+ } catch {
3807
+ existing = null;
3808
+ }
3809
+ if (existing !== null) {
3810
+ throw new InitError("DIR_EXISTS", `\u76EE\u5F55 ${projectPath} \u5DF2\u5B58\u5728\uFF1A\u8BF7\u6362\u4E00\u4E2A\u540D\u5B57\u6216\u5148\u5220\u9664`);
3811
+ }
3812
+ const files = [
3813
+ { path: "adep.config.ts", content: ADEP_CONFIG(name, template) },
3814
+ { path: "README.md", content: README(name, template) }
3815
+ ];
3816
+ if (template === "function") {
3817
+ files.push({ path: "functions/hello.ts", content: HELLO_FUNCTION });
3818
+ files.push({ path: "functions/README.md", content: FUNCTION_INDEX });
3819
+ files.push({ path: ".gitignore", content: "node_modules/\ndata/\n.adep/\n" });
3820
+ } else {
3821
+ files.push({ path: ".gitignore", content: "node_modules/\ndata/\n.adep/\n" });
3822
+ files.push({ path: "README-EMPTY.md", content: EMPTY_INDEX });
3823
+ }
3824
+ await mkdir2(projectPath, { recursive: true });
3825
+ await Promise.all(
3826
+ files.map(async (file) => {
3827
+ const target = join(projectPath, file.path);
3828
+ await mkdir2(dirname2(target), { recursive: true });
3829
+ await writeFile(target, file.content);
3830
+ })
3831
+ );
3832
+ return { projectPath, files: files.map((file) => file.path) };
3833
+ }
3834
+
3835
+ // packages/cli/src/templates.ts
3836
+ init_auth();
3837
+ async function fetchTemplates(server) {
3838
+ let response;
3839
+ try {
3840
+ response = await fetch(`${server}/api/v1/templates`);
3841
+ } catch (error) {
3842
+ throw new CliError(
3843
+ "SERVER_UNREACHABLE",
3844
+ `\u65E0\u6CD5\u8FDE\u63A5\u5E73\u53F0 ${server}\uFF1A${error instanceof Error ? error.message : String(error)}`
3845
+ );
3846
+ }
3847
+ const text = await response.text();
3848
+ let parsed = null;
3849
+ try {
3850
+ parsed = text.length === 0 ? null : JSON.parse(text);
3851
+ } catch {
3852
+ parsed = null;
3853
+ }
3854
+ if (response.status < 200 || response.status >= 300) {
3855
+ const msg = parsed?.error;
3856
+ throw new CliError("TEMPLATE_LIST_FAILED", msg ?? `\u5E73\u53F0\u8FD4\u56DE HTTP ${response.status}`);
3857
+ }
3858
+ const templates = parsed?.templates;
3859
+ return templates ?? [];
3860
+ }
3861
+
3862
+ // packages/cli/src/cli.ts
3863
+ init_build();
3864
+ init_init();
3865
+ var requireJson = createRequire(import.meta.url);
3866
+ var APP_VERSION = requireJson("../package.json").version;
3867
+ function emitError(output, command, json, error) {
3868
+ if (error instanceof CliError || error instanceof InitError || error instanceof WidgetError || error instanceof WidgetInitError) {
3869
+ if (json) {
3870
+ output(
3871
+ JSON.stringify({
3872
+ ok: false,
3873
+ command,
3874
+ error: { code: error.code, message: error.message }
3875
+ })
3876
+ );
3877
+ } else {
3878
+ output(`\u9519\u8BEF\uFF1A${error.message}`);
3879
+ if (error instanceof CliError && error.code === "NOT_LOGGED_IN") {
3880
+ output("\u63D0\u793A\uFF1A\u5148\u6267\u884C adep login");
3881
+ }
3882
+ }
3883
+ process.exitCode = 1;
3884
+ return;
3885
+ }
3886
+ throw error;
3887
+ }
3888
+ function formatBytes(bytes) {
3889
+ if (bytes < 1024) return `${bytes} B`;
3890
+ const units = ["KB", "MB", "GB", "TB"];
3891
+ let value = bytes;
3892
+ let unit = -1;
3893
+ while (value >= 1024 && unit < units.length - 1) {
3894
+ value /= 1024;
3895
+ unit++;
3896
+ }
3897
+ return `${value.toFixed(unit < 0 ? 0 : 1)} ${units[unit] ?? "B"}`;
3898
+ }
3899
+ function formatTable(columns, rows) {
3900
+ const widths = columns.map((column) => column.length);
3901
+ for (const row of rows) {
3902
+ columns.forEach((column, index) => {
3903
+ const cell = String(row[column] ?? "");
3904
+ widths[index] = Math.max(widths[index], cell.length);
3905
+ });
3906
+ }
3907
+ const line = (cells) => cells.map((cell, index) => cell.padEnd(widths[index] ?? 0)).join(" ").trimEnd();
3908
+ const parts = [
3909
+ line(columns),
3910
+ ...rows.map((row) => line(columns.map((c) => String(row[c] ?? ""))))
3911
+ ];
3912
+ return parts.join("\n");
3913
+ }
3914
+ function parseBool(raw) {
3915
+ if (raw === void 0) return void 0;
3916
+ if (raw === "true") return true;
3917
+ if (raw === "false") return false;
3918
+ throw new CliError("INVALID_BOOLEAN", `\u5E03\u5C14\u53C2\u6570\u987B\u4E3A true \u6216 false\uFF0C\u6536\u5230 "${raw}"`);
3919
+ }
3920
+ function buildProgram(options = {}) {
3921
+ const output = options.output ?? ((line) => process.stdout.write(`${line}
3922
+ `));
3923
+ const paths = options.paths ?? resolvePaths();
3924
+ const cwd = options.cwd ?? process.cwd();
3925
+ const program2 = new Command();
3926
+ program2.name("adep").description("AgentDeploy CLI").version(APP_VERSION);
3927
+ program2.option("--json", "\u4EE5\u673A\u5668\u53EF\u8BFB JSON \u8F93\u51FA\uFF08Agent / \u811A\u672C\u8C03\u7528\uFF09", false);
3928
+ const jsonMode = () => program2.opts()["json"] === true;
3929
+ program2.command("login").description("\u767B\u5F55\u5E73\u53F0\uFF08better-auth \u90AE\u7BB1\u5BC6\u7801\u767B\u5F55\uFF1B\u8BBE\u5907\u6388\u6743\u6D41\u5F52 CORE \u57DF\u540E\u7EED\u4EFB\u52A1\uFF09").option("-s, --server <url>", "\u5E73\u53F0\u5730\u5740\uFF08\u7F3A\u7701\u8BFB\u53D6 ADEP_SERVER \u6216 http://localhost:3000\uFF09").option("-e, --email <email>", "\u767B\u5F55\u90AE\u7BB1").option("-p, --password <password>", "\u767B\u5F55\u5BC6\u7801\uFF08\u6CE8\u610F shell \u5386\u53F2\uFF1B\u7F3A\u7701\u4EA4\u4E92\u8F93\u5165\uFF09").action(async (flags) => {
3930
+ try {
3931
+ const server = flags.server ?? resolveServer();
3932
+ let email = flags.email;
3933
+ let password = flags.password;
3934
+ if (email === void 0 || password === void 0) {
3935
+ const { createPrompt: createPrompt2 } = await Promise.resolve().then(() => (init_prompt(), prompt_exports));
3936
+ const prompt = createPrompt2();
3937
+ email = email ?? await prompt.ask("\u90AE\u7BB1\uFF1A");
3938
+ password = password ?? await prompt.askHidden("\u5BC6\u7801\uFF1A");
3939
+ prompt.close();
3940
+ }
3941
+ const result = await login(paths, {
3942
+ server,
3943
+ email,
3944
+ password
3945
+ });
3946
+ if (jsonMode()) {
3947
+ output(JSON.stringify({ ok: true, command: "login", data: result }));
3948
+ } else {
3949
+ output(`\u5DF2\u767B\u5F55\uFF1A${result.email}\uFF08\u51ED\u636E\u5DF2\u5199\u5165 ${paths.credentialsFile}\uFF0C\u6743\u9650 0600\uFF09`);
3950
+ }
3951
+ } catch (error) {
3952
+ emitError(output, "login", jsonMode(), error);
3953
+ }
3954
+ });
3955
+ program2.command("whoami").description("\u663E\u793A\u5F53\u524D\u767B\u5F55\u8EAB\u4EFD").action(async () => {
3956
+ try {
3957
+ const result = await whoami(paths);
3958
+ if (jsonMode()) {
3959
+ output(JSON.stringify({ ok: true, command: "whoami", data: result }));
3960
+ } else {
3961
+ output(`${result.email} @ ${result.server}`);
3962
+ }
3963
+ } catch (error) {
3964
+ emitError(output, "whoami", jsonMode(), error);
3965
+ }
3966
+ });
3967
+ program2.command("logout").description("\u767B\u51FA\u5E76\u6E05\u9664\u672C\u5730\u51ED\u636E").action(async () => {
3968
+ try {
3969
+ await logout(paths);
3970
+ if (jsonMode()) {
3971
+ output(JSON.stringify({ ok: true, command: "logout", data: { done: true } }));
3972
+ } else {
3973
+ output("\u5DF2\u767B\u51FA");
3974
+ }
3975
+ } catch (error) {
3976
+ emitError(output, "logout", jsonMode(), error);
3977
+ }
3978
+ });
3979
+ program2.command("init").description("\u521D\u59CB\u5316\u9879\u76EE\uFF08\u6A21\u677F\uFF1Aempty / function\uFF09\uFF0C\u6216 --list \u4ECE\u5E73\u53F0\u53D6\u6A21\u677F\u6E05\u5355").argument("[name]", "\u9879\u76EE\u76EE\u5F55\u540D\uFF08\u914D\u5408 --list \u65F6\u53EF\u7701\u7565\uFF09").option("-t, --template <template>", "\u6A21\u677F\uFF1Aempty | function", "function").option("-l, --list", "\u4ECE\u5E73\u53F0 /api/v1/templates \u5217\u51FA\u53EF\u7528\u6A21\u677F\uFF08\u4E0D\u811A\u624B\u67B6\uFF09", false).option(
3980
+ "-s, --server <url>",
3981
+ "\u5E73\u53F0\u5730\u5740\uFF08--list \u7528\uFF1B\u7F3A\u7701\u8BFB ADEP_SERVER \u6216 http://localhost:3000\uFF09"
3982
+ ).action(
3983
+ async (name, flags) => {
3984
+ try {
3985
+ if (flags.list === true) {
3986
+ const server = flags.server ?? resolveServer();
3987
+ const templates = await fetchTemplates(server);
3988
+ if (jsonMode()) {
3989
+ output(JSON.stringify({ ok: true, command: "init", data: { templates } }));
3990
+ } else {
3991
+ for (const tpl of templates) {
3992
+ output(`${tpl.code} ${tpl.name} ${tpl.description ?? ""}`);
3993
+ }
3994
+ }
3995
+ return;
3996
+ }
3997
+ if (name === void 0) {
3998
+ throw new InitError("MISSING_NAME", "\u9700\u7ED9\u51FA\u9879\u76EE\u540D\uFF0C\u6216\u4F7F\u7528 --list \u5217\u51FA\u5E73\u53F0\u53EF\u7528\u6A21\u677F");
3999
+ }
4000
+ const template = flags.template;
4001
+ if (!["empty", "function"].includes(template)) {
4002
+ throw new InitError("INVALID_TEMPLATE", `\u672A\u77E5\u6A21\u677F "${template}"\uFF1A\u53EF\u9009 empty | function`);
4003
+ }
4004
+ const result = await initProject(cwd, name, template);
4005
+ if (jsonMode()) {
4006
+ output(JSON.stringify({ ok: true, command: "init", data: result }));
4007
+ } else {
4008
+ output(`\u5DF2\u521B\u5EFA ${result.projectPath}`);
4009
+ }
4010
+ } catch (error) {
4011
+ emitError(output, "init", jsonMode(), error);
4012
+ }
4013
+ }
4014
+ );
4015
+ program2.command("dev").description("\u672C\u5730\u8C03\u8BD5\uFF1A\u76D1\u542C functions/ \u70ED\u91CD\u8F7D\uFF0Chttp://localhost:<port>/<fnName>").option("-p, --port <port>", "\u76D1\u542C\u7AEF\u53E3\uFF08\u7F3A\u7701 8787\uFF09", "8787").action(async (flags) => {
4016
+ try {
4017
+ const { startDevServer: startDevServer2 } = await Promise.resolve().then(() => (init_dev(), dev_exports));
4018
+ const started = await startDevServer2({ cwd, port: Number(flags.port ?? "8787") });
4019
+ output(`[adep] dev server listening on ${started.baseUrl}\uFF08Ctrl-C \u9000\u51FA\uFF09`);
4020
+ await new Promise(() => void 0);
4021
+ } catch (error) {
4022
+ emitError(output, "dev", jsonMode(), error);
4023
+ }
4024
+ });
4025
+ program2.command("deploy").description("\u589E\u91CF\u90E8\u7F72\uFF1A\u5BF9\u6BD4\u8FDC\u7AEF\u54C8\u5E0C \u2192 \u4EC5\u4E0A\u4F20\u53D8\u66F4 \u2192 \u53D1\u5E03 \u2192 \u8F93\u51FA\u8BBF\u95EE\u57DF\u540D").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
4026
+ try {
4027
+ const { deploy: deploy2 } = await Promise.resolve().then(() => (init_deploy(), deploy_exports));
4028
+ const result = await deploy2(paths, {
4029
+ cwd,
4030
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4031
+ });
4032
+ if (jsonMode()) {
4033
+ output(JSON.stringify({ ok: true, command: "deploy", data: result }));
4034
+ } else {
4035
+ if (result.noChanges) {
4036
+ output("no changes\uFF1A\u5168\u90E8\u51FD\u6570\u4E0E\u5DF2\u53D1\u5E03\u7248\u672C\u4E00\u81F4\uFF0C\u672A\u4EA7\u751F\u65B0\u7248\u672C");
4037
+ }
4038
+ for (const fn of result.functions) {
4039
+ output(`${fn.name} v${fn.version} ${fn.url}`);
4040
+ }
4041
+ }
4042
+ } catch (error) {
4043
+ emitError(output, "deploy", jsonMode(), error);
4044
+ }
4045
+ });
4046
+ const db = program2.command("db").description("\u9879\u76EE\u6570\u636E\u5E93\u7EF4\u62A4\uFF1A\u542F\u52A8 / \u72B6\u6001 / \u505C\u6B62 / SQL / \u5FEB\u7167 / \u56DE\u6EDA").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09");
4047
+ db.command("start").description("\u542F\u52A8\u9879\u76EE\u6570\u636E\u5E93\uFF08\u5DF2\u5B58\u5728\u5219\u91CD\u65B0\u6FC0\u6D3B\uFF0C\u4E0D\u91CD\u5EFA\u6570\u636E\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
4048
+ try {
4049
+ const { dbStart: dbStart2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
4050
+ const result = await dbStart2(paths, {
4051
+ cwd,
4052
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4053
+ });
4054
+ if (jsonMode()) {
4055
+ output(JSON.stringify({ ok: true, command: "db start", data: result }));
4056
+ } else {
4057
+ output(
4058
+ `\u6570\u636E\u5E93\u5DF2\u5C31\u7EEA\uFF1A${result.projectId}\uFF08${result.journalMode}\uFF0C${result.usage.tableCount} \u8868 / ${result.usage.rowCount} \u884C / ${formatBytes(result.usage.sizeBytes)}\uFF09`
4059
+ );
4060
+ }
4061
+ } catch (error) {
4062
+ emitError(output, "db start", jsonMode(), error);
4063
+ }
4064
+ });
4065
+ db.command("status").description("\u67E5\u8BE2\u9879\u76EE\u6570\u636E\u5E93\u72B6\u6001\u4E0E\u7528\u91CF\uFF08\u4F53\u79EF / \u8868\u6570 / \u884C\u6570\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
4066
+ try {
4067
+ const { dbStatus: dbStatus2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
4068
+ const result = await dbStatus2(paths, {
4069
+ cwd,
4070
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4071
+ });
4072
+ if (jsonMode()) {
4073
+ output(JSON.stringify({ ok: true, command: "db status", data: result }));
4074
+ } else {
4075
+ output(
4076
+ `\u72B6\u6001\uFF1A${result.status}\uFF08${result.projectId}\uFF0C${result.usage.tableCount} \u8868 / ${result.usage.rowCount} \u884C / ${formatBytes(result.usage.sizeBytes)}\uFF09`
4077
+ );
4078
+ }
4079
+ } catch (error) {
4080
+ emitError(output, "db status", jsonMode(), error);
4081
+ }
4082
+ });
4083
+ db.command("stop").description("\u505C\u6B62\u9879\u76EE\u6570\u636E\u5E93\uFF08\u8FDE\u63A5\u5173\u95ED\u5E76\u6807\u8BB0\uFF1B\u6587\u4EF6\u4FDD\u7559\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
4084
+ try {
4085
+ const { dbStop: dbStop2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
4086
+ const result = await dbStop2(paths, {
4087
+ cwd,
4088
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4089
+ });
4090
+ if (jsonMode()) {
4091
+ output(JSON.stringify({ ok: true, command: "db stop", data: result }));
4092
+ } else {
4093
+ output(`\u6570\u636E\u5E93\u5DF2\u505C\u6B62\uFF1A${result.status}`);
4094
+ }
4095
+ } catch (error) {
4096
+ emitError(output, "db stop", jsonMode(), error);
4097
+ }
4098
+ });
4099
+ db.command("exec").description("\u6267\u884C\u5355\u6761 SQL\uFF08\u5199 / \u7834\u574F\u6027\u8BED\u53E5\u9700 --confirm-table \u4E8C\u6B21\u786E\u8BA4\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").requiredOption("--sql <sql>", "\u5F85\u6267\u884C SQL").option("--confirm-table <table>", "\u7834\u574F\u6027\u64CD\u4F5C\u7684\u76EE\u6807\u8868\u540D\uFF08\u4E8C\u6B21\u786E\u8BA4\uFF09").action(async (flags) => {
4100
+ try {
4101
+ const { dbExec: dbExec2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
4102
+ const result = await dbExec2(paths, {
4103
+ cwd,
4104
+ sql: flags.sql,
4105
+ ...flags.project === void 0 ? {} : { slug: flags.project },
4106
+ ...flags.confirmTable === void 0 ? {} : { confirmTable: flags.confirmTable }
4107
+ });
4108
+ if (jsonMode()) {
4109
+ output(JSON.stringify({ ok: true, command: "db exec", data: result }));
4110
+ } else {
4111
+ if (result.columns.length > 0) {
4112
+ output(formatTable(result.columns, result.rows));
4113
+ if (result.truncated) output(`\uFF08\u7ED3\u679C\u5DF2\u622A\u65AD\u5230 ${result.rows.length} \u884C\uFF09`);
4114
+ } else if (result.changes > 0) {
4115
+ output(`${result.changes} \u884C\u53D7\u5F71\u54CD`);
4116
+ } else {
4117
+ output("\u8BED\u53E5\u6267\u884C\u6210\u529F\uFF08\u65E0\u8FD4\u56DE\u884C\uFF09");
4118
+ }
4119
+ output(`\u8017\u65F6 ${result.elapsedMs}ms`);
4120
+ }
4121
+ } catch (error) {
4122
+ emitError(output, "db exec", jsonMode(), error);
4123
+ }
4124
+ });
4125
+ const snapshot = db.command("snapshot").description("\u6570\u636E\u5E93\u5FEB\u7167\uFF08\u4ED8\u8D39\u6863\u4F4D\uFF09\uFF1A\u5217\u51FA\uFF08\u7F3A\u7701\uFF09/ \u521B\u5EFA / \u8FD8\u539F");
4126
+ snapshot.command("list").description("\u5217\u51FA\u9879\u76EE\u6570\u636E\u5E93\u5FEB\u7167\uFF08\u6309\u521B\u5EFA\u65F6\u95F4\u5012\u5E8F\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
4127
+ try {
4128
+ const { dbSnapshotList: dbSnapshotList2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
4129
+ const result = await dbSnapshotList2(paths, {
4130
+ cwd,
4131
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4132
+ });
4133
+ if (jsonMode()) {
4134
+ output(JSON.stringify({ ok: true, command: "db snapshot list", data: result }));
4135
+ } else {
4136
+ if (result.snapshots.length === 0) {
4137
+ output("\u6682\u65E0\u5FEB\u7167");
4138
+ }
4139
+ for (const snap of result.snapshots) {
4140
+ output(
4141
+ `${snap.id} ${snap.type} ${snap.plan} ${formatBytes(snap.sizeBytes)} ${snap.createdAt}`
4142
+ );
4143
+ }
4144
+ }
4145
+ } catch (error) {
4146
+ emitError(output, "db snapshot list", jsonMode(), error);
4147
+ }
4148
+ });
4149
+ snapshot.command("create").description("\u521B\u5EFA\u624B\u52A8\u6570\u636E\u5E93\u5FEB\u7167\uFF08\u514D\u8D39\u7248\u5E73\u53F0\u8FD4\u56DE 403 \u6743\u76CA\u672A\u5F00\u653E\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
4150
+ try {
4151
+ const { dbSnapshotCreate: dbSnapshotCreate2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
4152
+ const result = await dbSnapshotCreate2(paths, {
4153
+ cwd,
4154
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4155
+ });
4156
+ if (jsonMode()) {
4157
+ output(JSON.stringify({ ok: true, command: "db snapshot create", data: result }));
4158
+ } else {
4159
+ output(`\u5FEB\u7167\u5DF2\u521B\u5EFA\uFF1A${result.id}\uFF08${result.plan}\uFF0C${formatBytes(result.sizeBytes)}\uFF09`);
4160
+ }
4161
+ } catch (error) {
4162
+ emitError(output, "db snapshot create", jsonMode(), error);
4163
+ }
4164
+ });
4165
+ snapshot.command("restore").description("\u6574\u4F53\u8FD8\u539F\u6570\u636E\u5E93\u5230\u5FEB\u7167\u65F6\u523B\uFF08\u4ED8\u8D39\u6863\u4F4D\uFF09").argument("<snapshotId>", "\u5FEB\u7167 id").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (snapshotId, flags) => {
4166
+ try {
4167
+ const { dbSnapshotRestore: dbSnapshotRestore2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
4168
+ const result = await dbSnapshotRestore2(paths, {
4169
+ cwd,
4170
+ snapshotId,
4171
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4172
+ });
4173
+ if (jsonMode()) {
4174
+ output(JSON.stringify({ ok: true, command: "db snapshot restore", data: result }));
4175
+ } else {
4176
+ output(`\u5DF2\u8FD8\u539F\u5230\u5FEB\u7167 ${result.snapshotId}`);
4177
+ }
4178
+ } catch (error) {
4179
+ emitError(output, "db snapshot restore", jsonMode(), error);
4180
+ }
4181
+ });
4182
+ db.command("rollback").description("\u65F6\u95F4\u70B9\u56DE\u6EDA\u5230\u6307\u5B9A\u65F6\u523B\uFF08\u56E2\u961F\u7248\uFF1B\u57FA\u4E8E\u53D8\u66F4\u6D41\u91CD\u653E\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").requiredOption("--to <iso-time>", "\u56DE\u6EDA\u76EE\u6807\u65F6\u523B\uFF08ISO 8601\uFF09").action(async (flags) => {
4183
+ try {
4184
+ const { dbRollback: dbRollback2 } = await Promise.resolve().then(() => (init_db2(), db_exports));
4185
+ const result = await dbRollback2(paths, {
4186
+ cwd,
4187
+ to: flags.to,
4188
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4189
+ });
4190
+ if (jsonMode()) {
4191
+ output(JSON.stringify({ ok: true, command: "db rollback", data: result }));
4192
+ } else {
4193
+ output(`\u5DF2\u56DE\u6EDA\u5230 ${result.to}\uFF08\u91CD\u653E ${result.reverted} \u6761\u53D8\u66F4\uFF09`);
4194
+ }
4195
+ } catch (error) {
4196
+ emitError(output, "db rollback", jsonMode(), error);
4197
+ }
4198
+ });
4199
+ const storage = program2.command("storage").description("\u4E91\u5B58\u50A8 / \u6587\u4EF6\u5B58\u50A8\uFF1A\u4E0A\u4F20 / \u4E0B\u8F7D / \u5217\u8868 / \u5220\u9664").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09");
4200
+ storage.command("upload").description("\u4E0A\u4F20\u5355\u4E2A\u6587\u4EF6\uFF08multipart\uFF1B\u5355\u6587\u4EF6 \u2264 50MB\uFF09").argument("<file>", "\u672C\u5730\u6587\u4EF6\u8DEF\u5F84").requiredOption("--path <remote-path>", "\u6876\u5185\u76EE\u6807\u8DEF\u5F84\uFF08\u5982 avatars/a.png\uFF09").option(
4201
+ "--visibility <public|private>",
4202
+ "public \u76F4\u8FDE / private \u7B7E\u540D\uFF08\u7F3A\u7701 private\uFF09",
4203
+ "private"
4204
+ ).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (file, flags) => {
4205
+ try {
4206
+ const { storageUpload: storageUpload2 } = await Promise.resolve().then(() => (init_storage2(), storage_exports));
4207
+ const result = await storageUpload2(paths, {
4208
+ cwd,
4209
+ file,
4210
+ path: flags.path,
4211
+ visibility: flags.visibility === "public" ? "public" : "private",
4212
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4213
+ });
4214
+ if (jsonMode()) {
4215
+ output(JSON.stringify({ ok: true, command: "storage upload", data: result }));
4216
+ } else {
4217
+ output(`\u5DF2\u4E0A\u4F20 ${result.path}\uFF08${result.visibility}\uFF0C${formatBytes(result.size)}\uFF09`);
4218
+ if (result.signedUrl !== void 0) output(`\u7B7E\u540D URL\uFF1A${result.signedUrl}`);
4219
+ }
4220
+ } catch (error) {
4221
+ emitError(output, "storage upload", jsonMode(), error);
4222
+ }
4223
+ });
4224
+ storage.command("download").description("\u4E0B\u8F7D\u6587\u4EF6\u5230\u672C\u5730\uFF08public \u76F4\u8FDE / private \u7B7E\u540D URL\uFF09").argument("<remote-path>", "\u6876\u5185\u6587\u4EF6\u8DEF\u5F84").option("-o, --output <file>", "\u672C\u5730\u8F93\u51FA\u8DEF\u5F84\uFF08\u7F3A\u7701\u5199\u5230 cwd\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (remotePath, flags) => {
4225
+ try {
4226
+ const { storageDownload: storageDownload2 } = await Promise.resolve().then(() => (init_storage2(), storage_exports));
4227
+ const result = await storageDownload2(paths, {
4228
+ cwd,
4229
+ path: remotePath,
4230
+ ...flags.output === void 0 ? {} : { output: flags.output },
4231
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4232
+ });
4233
+ if (jsonMode()) {
4234
+ output(JSON.stringify({ ok: true, command: "storage download", data: result }));
4235
+ } else {
4236
+ output(`\u5DF2\u4E0B\u8F7D ${result.path} \u2192 ${result.output}\uFF08${formatBytes(result.size)}\uFF09`);
4237
+ }
4238
+ } catch (error) {
4239
+ emitError(output, "storage download", jsonMode(), error);
4240
+ }
4241
+ });
4242
+ storage.command("ls").description("\u5217\u51FA\u9879\u76EE\u6587\u4EF6\uFF08\u6309\u524D\u7F00\u8FC7\u6EE4\uFF1Bpublic \u9644\u76F4\u8FDE url\u3001private \u9644\u7B7E\u540D url\uFF09").option("--prefix <prefix>", "\u6309\u524D\u7F00\u8FC7\u6EE4").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
4243
+ try {
4244
+ const { storageList: storageList2 } = await Promise.resolve().then(() => (init_storage2(), storage_exports));
4245
+ const result = await storageList2(paths, {
4246
+ cwd,
4247
+ ...flags.prefix === void 0 ? {} : { prefix: flags.prefix },
4248
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4249
+ });
4250
+ if (jsonMode()) {
4251
+ output(JSON.stringify({ ok: true, command: "storage ls", data: result }));
4252
+ } else {
4253
+ if (result.files.length === 0) {
4254
+ output("\uFF08\u65E0\u6587\u4EF6\uFF09");
4255
+ }
4256
+ for (const file of result.files) {
4257
+ output(
4258
+ `${file.path} ${file.visibility} ${formatBytes(file.size)} ${file.url ?? file.signedUrl ?? ""}`
4259
+ );
4260
+ }
4261
+ }
4262
+ } catch (error) {
4263
+ emitError(output, "storage ls", jsonMode(), error);
4264
+ }
4265
+ });
4266
+ storage.command("rm").description("\u5220\u9664\u6587\u4EF6\uFF08\u4EC5\u9879\u76EE\u6240\u6709\u8005\uFF09").argument("<remote-path>", "\u6876\u5185\u6587\u4EF6\u8DEF\u5F84").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (remotePath, flags) => {
4267
+ try {
4268
+ const { storageRemove: storageRemove2 } = await Promise.resolve().then(() => (init_storage2(), storage_exports));
4269
+ const result = await storageRemove2(paths, {
4270
+ cwd,
4271
+ path: remotePath,
4272
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4273
+ });
4274
+ if (jsonMode()) {
4275
+ output(JSON.stringify({ ok: true, command: "storage rm", data: result }));
4276
+ } else {
4277
+ output(`\u5DF2\u5220\u9664 ${remotePath}`);
4278
+ }
4279
+ } catch (error) {
4280
+ emitError(output, "storage rm", jsonMode(), error);
4281
+ }
4282
+ });
4283
+ const hosting = program2.command("hosting").description("\u9759\u6001\u6258\u7BA1\uFF1A\u67E5\u770B / \u90E8\u7F72 / \u62C9\u53D6 / \u914D\u7F6E").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09");
4284
+ hosting.command("info").description("\u67E5\u770B\u9759\u6001\u6258\u7BA1\u914D\u7F6E\u3001\u7AD9\u70B9\u5730\u5740\u4E0E\u6587\u4EF6\u6811").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
4285
+ try {
4286
+ const { hostingInfo: hostingInfo2 } = await Promise.resolve().then(() => (init_hosting(), hosting_exports));
4287
+ const result = await hostingInfo2(paths, {
4288
+ cwd,
4289
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4290
+ });
4291
+ if (jsonMode()) {
4292
+ output(JSON.stringify({ ok: true, command: "hosting info", data: result }));
4293
+ } else {
4294
+ output(
4295
+ `\u7AD9\u70B9\uFF1A${result.siteUrl}\uFF08\u6258\u7BA1 ${result.config.enabled ? "\u5F00" : "\u5173"}\uFF0CSPA \u56DE\u9000 ${result.config.spaMode ? "\u5F00" : "\u5173"}\uFF09`
4296
+ );
4297
+ for (const file of result.files) {
4298
+ output(`${file.path} ${formatBytes(file.size)}`);
4299
+ }
4300
+ }
4301
+ } catch (error) {
4302
+ emitError(output, "hosting info", jsonMode(), error);
4303
+ }
4304
+ });
4305
+ hosting.command("deploy").description("\u90E8\u7F72\u672C\u5730\u76EE\u5F55\u4E3A\u9759\u6001\u7AD9\u70B9\uFF1A\u9012\u5F52\u4E0A\u4F20\u5230 site/ \u5E76\u6253\u5F00\u6258\u7BA1").argument("<dir>", "\u672C\u5730\u7AD9\u70B9\u76EE\u5F55").option("--spa", "\u6253\u5F00\u6258\u7BA1\u5E76\u542F\u7528 SPA \u56DE\u9000\uFF08\u7F3A\u7701\u4EC5\u6253\u5F00\u6258\u7BA1\uFF09", false).option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (dir, flags) => {
4306
+ try {
4307
+ const { hostingDeploy: hostingDeploy2 } = await Promise.resolve().then(() => (init_hosting(), hosting_exports));
4308
+ const result = await hostingDeploy2(paths, {
4309
+ cwd,
4310
+ dir,
4311
+ ...flags.spa === true ? { spa: true } : {},
4312
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4313
+ });
4314
+ if (jsonMode()) {
4315
+ output(JSON.stringify({ ok: true, command: "hosting deploy", data: result }));
4316
+ } else {
4317
+ output(
4318
+ `\u7AD9\u70B9\u5DF2\u4E0A\u7EBF\uFF1A${result.siteUrl}\uFF08${result.uploaded.length} \u4E2A\u6587\u4EF6\uFF0CSPA \u56DE\u9000 ${result.config.spaMode ? "\u5F00" : "\u5173"}\uFF09`
4319
+ );
4320
+ }
4321
+ } catch (error) {
4322
+ emitError(output, "hosting deploy", jsonMode(), error);
4323
+ }
4324
+ });
4325
+ hosting.command("pull").description("\u62C9\u53D6\u7AD9\u70B9\u516C\u5F00\u6587\u4EF6\u5230\u672C\u5730\u76EE\u5F55\uFF08\u8DF3\u8FC7\u6258\u7BA1\u914D\u7F6E\uFF09").option("-o, --output <dir>", "\u672C\u5730\u8F93\u51FA\u76EE\u5F55\uFF08\u7F3A\u7701\u5199\u5230 cwd\uFF09").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
4326
+ try {
4327
+ const { hostingPull: hostingPull2 } = await Promise.resolve().then(() => (init_hosting(), hosting_exports));
4328
+ const result = await hostingPull2(paths, {
4329
+ cwd,
4330
+ ...flags.output === void 0 ? {} : { output: flags.output },
4331
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4332
+ });
4333
+ if (jsonMode()) {
4334
+ output(JSON.stringify({ ok: true, command: "hosting pull", data: result }));
4335
+ } else {
4336
+ output(
4337
+ `\u5DF2\u62C9\u53D6 ${result.files.length} \u4E2A\u6587\u4EF6 \u2192 ${result.outputDir}\uFF08\u7AD9\u70B9\uFF1A${result.siteUrl}\uFF09`
4338
+ );
4339
+ }
4340
+ } catch (error) {
4341
+ emitError(output, "hosting pull", jsonMode(), error);
4342
+ }
4343
+ });
4344
+ hosting.command("config").description("\u66F4\u65B0\u9759\u6001\u6258\u7BA1\u914D\u7F6E\uFF08\u6258\u7BA1\u5F00\u5173 / SPA \u56DE\u9000\u6A21\u5F0F\uFF0C\u5E42\u7B49\uFF09").option("--enabled <true|false>", "\u6258\u7BA1\u5F00\u5173").option("--spa <true|false>", "SPA \u56DE\u9000\u6A21\u5F0F").option("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug\uFF08\u7F3A\u7701\u53D6 adep.config.ts \u7684 name\uFF09").action(async (flags) => {
4345
+ try {
4346
+ const { hostingConfig: hostingConfig2 } = await Promise.resolve().then(() => (init_hosting(), hosting_exports));
4347
+ const enabled = parseBool(flags.enabled);
4348
+ const spa = parseBool(flags.spa);
4349
+ const config = await hostingConfig2(paths, {
4350
+ cwd,
4351
+ ...enabled === void 0 ? {} : { enabled },
4352
+ ...spa === void 0 ? {} : { spa },
4353
+ ...flags.project === void 0 ? {} : { slug: flags.project }
4354
+ });
4355
+ if (jsonMode()) {
4356
+ output(JSON.stringify({ ok: true, command: "hosting config", data: { config } }));
4357
+ } else {
4358
+ output(`\u6258\u7BA1 ${config.enabled ? "\u5F00" : "\u5173"}\uFF0CSPA \u56DE\u9000 ${config.spaMode ? "\u5F00" : "\u5173"}`);
4359
+ }
4360
+ } catch (error) {
4361
+ emitError(output, "hosting config", jsonMode(), error);
4362
+ }
4363
+ });
4364
+ const widget = program2.command("widget").description("\u5FAE\u524D\u7AEF\u7EC4\u4EF6\uFF08widget\uFF09\uFF1A\u811A\u624B\u67B6 / \u672C\u5730\u6C99\u7BB1 / \u53D1\u5E03");
4365
+ widget.command("init").description("\u521D\u59CB\u5316 widget \u5DE5\u7A0B\uFF08\u6A21\u677F\uFF1Avue3-ts / react-ts\uFF09").argument("<name>", "widget \u540D\u79F0\uFF08\u5C0F\u5199\u5B57\u6BCD\u5F00\u5934\uFF0C\u4EC5\u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u8FDE\u5B57\u7B26\uFF09").option("-t, --template <template>", "\u6A21\u677F\uFF1Avue3-ts | react-ts", "vue3-ts").action(async (name, flags) => {
4366
+ try {
4367
+ const { initWidget: initWidget2 } = await Promise.resolve().then(() => (init_init(), init_exports));
4368
+ const result = await initWidget2(cwd, name, flags.template);
4369
+ if (jsonMode()) {
4370
+ output(JSON.stringify({ ok: true, command: "widget init", data: result }));
4371
+ } else {
4372
+ output(`\u5DF2\u521B\u5EFA widget ${result.projectPath}`);
4373
+ }
4374
+ } catch (error) {
4375
+ emitError(output, "widget init", jsonMode(), error);
4376
+ }
4377
+ });
4378
+ widget.command("dev").description("\u672C\u5730\u5BBF\u4E3B\u6C99\u7BB1\uFF1A\u4E3B\u9898\u53D8\u91CF + mock props + token \u6CE8\u5165 + \u70ED\u66F4\u65B0").option("-p, --port <port>", "\u76D1\u542C\u7AEF\u53E3\uFF08\u7F3A\u7701 8788\uFF09", "8788").action(async (flags) => {
4379
+ try {
4380
+ const { startWidgetDev: startWidgetDev2 } = await Promise.resolve().then(() => (init_dev2(), dev_exports2));
4381
+ const started = await startWidgetDev2({ cwd, port: Number(flags.port ?? "8788") });
4382
+ output(
4383
+ `[adep] widget dev sandbox on ${started.baseUrl}\uFF08?token=<...> \u6CE8\u5165\u9274\u6743 token\uFF1BCtrl-C \u9000\u51FA\uFF09`
4384
+ );
4385
+ await new Promise(() => void 0);
4386
+ } catch (error) {
4387
+ emitError(output, "widget dev", jsonMode(), error);
4388
+ }
4389
+ });
4390
+ widget.command("publish").description("\u6309\u6846\u67B6\u6784\u5EFA \u2192 \u4E0A\u4F20\u5E73\u53F0\u9759\u6001\u8D44\u6E90 \u2192 \u7248\u672C\u5316\u8F93\u51FA URL").requiredOption("-p, --project <slug>", "\u76EE\u6807\u5E73\u53F0\u9879\u76EE slug").action(async (flags) => {
4391
+ try {
4392
+ const { publishWidget: publishWidget2 } = await Promise.resolve().then(() => (init_publish(), publish_exports));
4393
+ const result = await publishWidget2(paths, {
4394
+ cwd,
4395
+ project: flags.project
4396
+ });
4397
+ if (jsonMode()) {
4398
+ output(JSON.stringify({ ok: true, command: "widget publish", data: result }));
4399
+ } else {
4400
+ output(`${result.name} v${result.version} ${result.url}`);
4401
+ }
4402
+ } catch (error) {
4403
+ emitError(output, "widget publish", jsonMode(), error);
4404
+ }
4405
+ });
4406
+ return program2;
4407
+ }
4408
+
4409
+ // packages/cli/src/index.ts
4410
+ var program = buildProgram();
4411
+ await program.parseAsync(process.argv);