@nextclaw/app-runtime 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +29 -4
  2. package/dist/bundle/app-bundle.service.js +14 -8
  3. package/dist/bundle/app-bundle.types.d.ts +2 -0
  4. package/dist/cli/app-runtime-cli.service.d.ts +3 -0
  5. package/dist/cli/app-runtime-cli.service.js +70 -2
  6. package/dist/cli/app-runtime-options.service.d.ts +10 -1
  7. package/dist/cli/app-runtime-options.service.js +39 -2
  8. package/dist/commands/create.controller.d.ts +2 -1
  9. package/dist/commands/create.controller.js +3 -2
  10. package/dist/commands/inspect.controller.js +2 -1
  11. package/dist/commands/run.controller.js +25 -7
  12. package/dist/commands/validate-publish.controller.d.ts +15 -0
  13. package/dist/commands/validate-publish.controller.js +31 -0
  14. package/dist/host/app-host.service.d.ts +3 -1
  15. package/dist/host/app-host.service.js +5 -1
  16. package/dist/host/app-instance.service.js +1 -0
  17. package/dist/index.d.ts +11 -3
  18. package/dist/index.js +9 -1
  19. package/dist/install/app-installation.service.js +1 -0
  20. package/dist/install/app-installation.types.d.ts +1 -0
  21. package/dist/manifest/app-manifest.service.js +9 -3
  22. package/dist/manifest/app-manifest.types.d.ts +9 -3
  23. package/dist/package.js +1 -1
  24. package/dist/publish/app-publish-validation.service.d.ts +37 -0
  25. package/dist/publish/app-publish-validation.service.js +76 -0
  26. package/dist/runtime/app-build.service.d.ts +24 -0
  27. package/dist/runtime/app-build.service.js +55 -0
  28. package/dist/runtime/app-runtime-toolchain.service.d.ts +30 -0
  29. package/dist/runtime/app-runtime-toolchain.service.js +96 -0
  30. package/dist/runtime/wasm-main-runner.service.js +1 -0
  31. package/dist/runtime/wasmtime-wasi-http-component.service.d.ts +24 -0
  32. package/dist/runtime/wasmtime-wasi-http-component.service.js +129 -0
  33. package/dist/scaffold/app-scaffold.service.d.ts +13 -2
  34. package/dist/scaffold/app-scaffold.service.js +39 -2
  35. package/dist/scaffold/app-ts-http-lite-scaffold-template.service.d.ts +18 -0
  36. package/dist/scaffold/app-ts-http-lite-scaffold-template.service.js +267 -0
  37. package/dist/scaffold/app-ts-http-scaffold-template.service.d.ts +25 -0
  38. package/dist/scaffold/app-ts-http-scaffold-template.service.js +496 -0
  39. package/package.json +1 -1
package/README.md CHANGED
@@ -6,9 +6,12 @@
6
6
 
7
7
  - `napp create <app-dir>`:生成一个最小可跑的微应用骨架
8
8
  - `napp inspect <app-dir>`:校验应用目录与 manifest
9
+ - `napp doctor`:检查本机 NApp/WASI HTTP 开发运行环境
10
+ - `napp build <app-dir> --install`:安装模板依赖并构建 TS/WASI HTTP 后端
9
11
  - `napp run <app-dir|app-id>`:启动本地宿主,支持目录运行和已安装应用运行
10
12
  - `napp dev <app-dir>`:当前等价于 `run`
11
13
  - `napp pack <app-dir>`:把应用目录打成 `.napp` bundle
14
+ - `napp validate-publish <app-dir>`:本地做发布前校验并输出体积/包内容 warning
12
15
  - `napp publish <app-dir>`:把应用目录发布到官方 apps registry
13
16
  - `napp install <app-dir|bundle.napp|app-id[@version]>`:从本地或 registry 安装应用
14
17
  - `napp update <app-id>`:更新已安装应用
@@ -33,7 +36,7 @@ napp --help
33
36
  napp --version
34
37
  ```
35
38
 
36
- 第一版先聚焦“独立可运行的微应用宿主 + 可分发、可安装、可更新、可授权的 CLI/runtime 闭环”,不接入现有 NextClaw 主产品路由、服务或 GUI app store。
39
+ 当前版本先聚焦“独立可运行的微应用宿主 + 可分发、可安装、可更新、可授权的 CLI/runtime 闭环”。普通用户入口推荐通过 NextClaw `nextclaw-app-runtime` skill 编排这些命令。
37
40
 
38
41
  ## 应用目录
39
42
 
@@ -41,6 +44,8 @@ napp --version
41
44
  manifest.json
42
45
  main/
43
46
  app.wasm
47
+ package.json # ts-http / ts-http-lite 模板存在
48
+ src/ # ts-http / ts-http-lite 模板存在
44
49
  ui/
45
50
  index.html
46
51
  assets/
@@ -48,11 +53,12 @@ assets/
48
53
 
49
54
  ## 当前 MVP 范围
50
55
 
51
- - `main` 执行形态:`wasm`
56
+ - `main` 执行形态:`wasm` 或 `wasi-http-component`
52
57
  - UI 装载:本地静态服务
53
58
  - 宿主桥接:`/__napp/*`
59
+ - WASI HTTP 业务 API:`/api/*`
54
60
  - 权限词汇:`documentAccess`、`allowedDomains`、`storage`、`capabilities`
55
- - 当前 Wasm 执行底座:Node 原生 `WebAssembly`
61
+ - 当前 Wasm 执行底座:Node 原生 `WebAssembly` 与 Wasmtime `serve`
56
62
  - 分发包形态:`.napp`(底层为 zip)
57
63
  - 安装目录:`~/.nextclaw/apps/packages/<app-id>/<version>/`
58
64
  - 用户数据目录:`~/.nextclaw/apps/data/<app-id>/`
@@ -65,12 +71,26 @@ assets/
65
71
  开发者工作流:
66
72
 
67
73
  ```bash
68
- napp create ./my-first-napp
74
+ napp doctor
75
+ napp create ./my-first-napp --template ts-http
76
+ napp build ./my-first-napp --install
69
77
  napp inspect ./my-first-napp
78
+ napp validate-publish ./my-first-napp
79
+ napp run ./my-first-napp --data ./my-first-napp/.napp/data
70
80
  napp pack ./my-first-napp
71
81
  napp publish ./my-first-napp
72
82
  ```
73
83
 
84
+ 体积优先工作流:
85
+
86
+ ```bash
87
+ napp doctor
88
+ napp create ./my-small-napp --template ts-http-lite
89
+ napp build ./my-small-napp --install
90
+ napp validate-publish ./my-small-napp
91
+ napp run ./my-small-napp --data ./my-small-napp/.napp/data
92
+ ```
93
+
74
94
  本地安装工作流:
75
95
 
76
96
  ```bash
@@ -112,6 +132,11 @@ napp permissions nextclaw.my-first-napp
112
132
  napp run nextclaw.my-first-napp
113
133
  ```
114
134
 
135
+ 模板选择建议:
136
+
137
+ - `ts-http`:默认推荐,开发体验优先,适合大多数普通前后端小应用
138
+ - `ts-http-lite`:体积优先,继续走官方 WASI HTTP 路线,但不使用默认 Hono 路由层
139
+
115
140
  已有示例应用:
116
141
 
117
142
  ```bash
@@ -10,7 +10,7 @@ var AppBundleService = class {
10
10
  }
11
11
  packAppDirectory = async (params) => {
12
12
  const bundle = await this.manifestService.load(params.appDirectory);
13
- const appFiles = await this.collectAppFiles(bundle.appDirectory);
13
+ const { appFiles, filePaths } = await this.collectAppFiles(bundle);
14
14
  const metadata = this.buildMetadata(bundle.manifest.id, bundle.manifest.name, bundle.manifest.version);
15
15
  const bundleJsonPath = ".napp/bundle.json";
16
16
  const checksumsJsonPath = ".napp/checksums.json";
@@ -30,7 +30,9 @@ var AppBundleService = class {
30
30
  await writeFile(outputPath, Buffer.from(archiveBytes));
31
31
  return {
32
32
  bundlePath: outputPath,
33
- metadata
33
+ metadata,
34
+ sizeBytes: archiveBytes.byteLength,
35
+ filePaths
34
36
  };
35
37
  };
36
38
  extractBundle = async (params) => {
@@ -59,15 +61,19 @@ var AppBundleService = class {
59
61
  checksums
60
62
  };
61
63
  };
62
- collectAppFiles = async (appDirectory) => {
63
- const filePaths = new Set(["manifest.json"]);
64
- await this.collectDirectoryPaths(path.join(appDirectory, "main"), appDirectory, filePaths);
65
- await this.collectDirectoryPaths(path.join(appDirectory, "ui"), appDirectory, filePaths);
66
- await this.collectDirectoryPaths(path.join(appDirectory, "assets"), appDirectory, filePaths);
64
+ collectAppFiles = async (bundle) => {
65
+ const appDirectory = bundle.appDirectory;
66
+ const filePaths = new Set([path.relative(appDirectory, bundle.manifestPath), path.relative(appDirectory, bundle.mainEntryPath)]);
67
+ await this.collectDirectoryPaths(bundle.uiDirectoryPath, appDirectory, filePaths);
68
+ await this.collectDirectoryPaths(bundle.assetsDirectoryPath, appDirectory, filePaths);
69
+ if (bundle.iconPath) filePaths.add(path.relative(appDirectory, bundle.iconPath));
67
70
  const sortedPaths = Array.from(filePaths).sort((left, right) => left.localeCompare(right));
68
71
  const appFiles = {};
69
72
  for (const relativePath of sortedPaths) appFiles[relativePath] = new Uint8Array(await readFile(path.join(appDirectory, relativePath)));
70
- return appFiles;
73
+ return {
74
+ appFiles,
75
+ filePaths: sortedPaths
76
+ };
71
77
  };
72
78
  collectDirectoryPaths = async (directoryPath, appDirectory, filePaths) => {
73
79
  try {
@@ -14,6 +14,8 @@ type AppBundleChecksums = {
14
14
  type AppBundlePackResult = {
15
15
  bundlePath: string;
16
16
  metadata: AppBundleMetadata;
17
+ sizeBytes: number;
18
+ filePaths: string[];
17
19
  };
18
20
  type AppBundleExtractResult = {
19
21
  appDirectory: string;
@@ -8,10 +8,13 @@ declare class AppRuntimeCliService {
8
8
  private dispatch;
9
9
  private handleCreate;
10
10
  private handleInspect;
11
+ private handleBuild;
12
+ private handleDoctor;
11
13
  private handleRun;
12
14
  private handleDev;
13
15
  private handlePack;
14
16
  private handlePublish;
17
+ private handleValidatePublish;
15
18
  private handleInstall;
16
19
  private handleUpdate;
17
20
  private handleUninstall;
@@ -14,6 +14,9 @@ import { RegistryCommand } from "../commands/registry.controller.js";
14
14
  import { RevokeCommand } from "../commands/revoke.controller.js";
15
15
  import { UninstallCommand } from "../commands/uninstall.controller.js";
16
16
  import { UpdateCommand } from "../commands/update.controller.js";
17
+ import { ValidatePublishCommand } from "../commands/validate-publish.controller.js";
18
+ import { AppRuntimeToolchainService } from "../runtime/app-runtime-toolchain.service.js";
19
+ import { AppBuildService } from "../runtime/app-build.service.js";
17
20
  import { AppRuntimeOptionsService } from "./app-runtime-options.service.js";
18
21
  //#region src/cli/app-runtime-cli.service.ts
19
22
  var AppRuntimeCliService = class {
@@ -44,6 +47,12 @@ var AppRuntimeCliService = class {
44
47
  case "inspect":
45
48
  await this.handleInspect(restArgs);
46
49
  return;
50
+ case "build":
51
+ await this.handleBuild(restArgs);
52
+ return;
53
+ case "doctor":
54
+ await this.handleDoctor(restArgs);
55
+ return;
47
56
  case "run":
48
57
  await this.handleRun(restArgs);
49
58
  return;
@@ -56,6 +65,9 @@ var AppRuntimeCliService = class {
56
65
  case "publish":
57
66
  await this.handlePublish(restArgs);
58
67
  return;
68
+ case "validate-publish":
69
+ await this.handleValidatePublish(restArgs);
70
+ return;
59
71
  case "install":
60
72
  await this.handleInstall(restArgs);
61
73
  return;
@@ -93,6 +105,7 @@ var AppRuntimeCliService = class {
93
105
  const options = this.optionsService.readCreateOptions(optionArgs);
94
106
  await new CreateCommand().run({
95
107
  appDirectory: target,
108
+ template: options.template,
96
109
  json: options.json,
97
110
  write: this.write
98
111
  });
@@ -106,6 +119,46 @@ var AppRuntimeCliService = class {
106
119
  write: this.write
107
120
  });
108
121
  };
122
+ handleBuild = async (restArgs) => {
123
+ const { target, optionArgs } = this.optionsService.readTarget("build", restArgs);
124
+ const options = this.optionsService.readBuildOptions(optionArgs);
125
+ const result = await new AppBuildService().build({
126
+ appDirectory: target,
127
+ install: options.install
128
+ });
129
+ if (options.json) {
130
+ this.write(`${JSON.stringify({
131
+ ok: true,
132
+ build: result
133
+ }, null, 2)}\n`);
134
+ return;
135
+ }
136
+ if (!result.built) {
137
+ this.write(`Build skipped: ${result.skippedReason ?? result.mainKind}\n`);
138
+ return;
139
+ }
140
+ this.write(`Built ${result.mainKind} app\n`);
141
+ this.write(`Main: ${result.mainEntryPath}\n`);
142
+ if (result.installedDependencies) this.write("Dependencies: installed\n");
143
+ };
144
+ handleDoctor = async (restArgs) => {
145
+ const options = this.optionsService.readJsonOnlyOptions(restArgs);
146
+ const result = await new AppRuntimeToolchainService().doctor();
147
+ if (options.json) {
148
+ this.write(`${JSON.stringify({
149
+ ok: result.ok,
150
+ doctor: result
151
+ }, null, 2)}\n`);
152
+ if (!result.ok) process.exitCode = 1;
153
+ return;
154
+ }
155
+ this.write(`NApp runtime doctor: ${result.ok ? "ok" : "not ready"}\n`);
156
+ for (const tool of result.tools) {
157
+ this.write(`${tool.ok ? "ok" : "missing"} ${tool.name}${tool.version ? ` ${tool.version}` : ""}\n`);
158
+ if (!tool.ok) this.write(` ${tool.installHint}\n`);
159
+ }
160
+ if (!result.ok) process.exitCode = 1;
161
+ };
109
162
  handleRun = async (restArgs) => {
110
163
  const { target, optionArgs } = this.optionsService.readTarget("run", restArgs);
111
164
  const options = this.optionsService.readRuntimeOptions(optionArgs);
@@ -113,6 +166,7 @@ var AppRuntimeCliService = class {
113
166
  appReference: target,
114
167
  host: options.host,
115
168
  port: options.port,
169
+ dataDirectory: options.dataDirectory,
116
170
  json: options.json,
117
171
  documentGrantMap: options.documentGrantMap,
118
172
  write: this.write
@@ -125,6 +179,7 @@ var AppRuntimeCliService = class {
125
179
  appReference: target,
126
180
  host: options.host,
127
181
  port: options.port,
182
+ dataDirectory: options.dataDirectory,
128
183
  json: options.json,
129
184
  documentGrantMap: options.documentGrantMap,
130
185
  write: this.write
@@ -152,6 +207,16 @@ var AppRuntimeCliService = class {
152
207
  write: this.write
153
208
  });
154
209
  };
210
+ handleValidatePublish = async (restArgs) => {
211
+ const { target, optionArgs } = this.optionsService.readTarget("validate-publish", restArgs);
212
+ const options = this.optionsService.readPublishOptions(optionArgs);
213
+ await new ValidatePublishCommand().run({
214
+ appDirectory: target,
215
+ metadataPath: options.metadataPath,
216
+ json: options.json,
217
+ write: this.write
218
+ });
219
+ };
155
220
  handleInstall = async (restArgs) => {
156
221
  const { target, optionArgs } = this.optionsService.readTarget("install", restArgs);
157
222
  const options = this.optionsService.readInstallOptions(optionArgs);
@@ -271,11 +336,14 @@ var AppRuntimeCliService = class {
271
336
  });
272
337
  };
273
338
  writeUsage = () => {
274
- this.write("Usage: napp create <app-dir> [--json]\n");
339
+ this.write("Usage: napp create <app-dir> [--template starter|ts-http|ts-http-lite] [--json]\n");
275
340
  this.write(" napp inspect <app-dir> [--json]\n");
276
- this.write(" napp <run|dev> <app-dir|app-id> [--host 127.0.0.1] [--port 3100] [--json] [--document scope=/path]\n");
341
+ this.write(" napp build <app-dir> [--install] [--json]\n");
342
+ this.write(" napp doctor [--json]\n");
343
+ this.write(" napp <run|dev> <app-dir|app-id> [--host 127.0.0.1] [--port 3100] [--data /path] [--json] [--document scope=/path]\n");
277
344
  this.write(" napp pack <app-dir> [--out bundle.napp] [--json]\n");
278
345
  this.write(" napp publish <app-dir> [--meta marketplace.json] [--api-base <url>] [--token <token>] [--json]\n");
346
+ this.write(" napp validate-publish <app-dir> [--meta marketplace.json] [--json]\n");
279
347
  this.write(" napp install <app-dir|bundle.napp|app-id[@version]> [--registry <url>] [--json]\n");
280
348
  this.write(" napp update <app-id> [--version <version>] [--registry <url>] [--json]\n");
281
349
  this.write(" napp uninstall <app-id> [--purge-data] [--json]\n");
@@ -1,19 +1,26 @@
1
1
  import { AppDocumentGrantMap } from "../permissions/app-permissions.types.js";
2
+ import { AppScaffoldTemplate } from "../scaffold/app-scaffold.service.js";
2
3
 
3
4
  //#region src/cli/app-runtime-options.service.d.ts
4
5
  type RuntimeCliOptions = {
5
6
  host: string;
6
7
  port: number;
8
+ dataDirectory?: string;
7
9
  json: boolean;
8
10
  documentGrantMap: AppDocumentGrantMap;
9
11
  };
10
12
  type CreateCliOptions = {
11
13
  json: boolean;
14
+ template: AppScaffoldTemplate;
12
15
  };
13
16
  type PackCliOptions = {
14
17
  json: boolean;
15
18
  outputPath?: string;
16
19
  };
20
+ type BuildCliOptions = {
21
+ json: boolean;
22
+ install: boolean;
23
+ };
17
24
  type JsonOnlyCliOptions = {
18
25
  json: boolean;
19
26
  };
@@ -50,7 +57,9 @@ declare class AppRuntimeOptionsService {
50
57
  optionArgs: string[];
51
58
  };
52
59
  readCreateOptions: (rawArgs: string[]) => CreateCliOptions;
60
+ private readCreateTemplate;
53
61
  readPackOptions: (rawArgs: string[]) => PackCliOptions;
62
+ readBuildOptions: (rawArgs: string[]) => BuildCliOptions;
54
63
  readJsonOnlyOptions: (rawArgs: string[]) => JsonOnlyCliOptions;
55
64
  readInstallOptions: (rawArgs: string[]) => InstallCliOptions;
56
65
  readUpdateOptions: (rawArgs: string[]) => UpdateCliOptions;
@@ -64,4 +73,4 @@ declare class AppRuntimeOptionsService {
64
73
  private requireOptionValue;
65
74
  }
66
75
  //#endregion
67
- export { AppRuntimeOptionsService, CreateCliOptions, GrantCliOptions, InstallCliOptions, JsonOnlyCliOptions, PackCliOptions, PublishCliOptions, RevokeCliOptions, RuntimeCliOptions, UninstallCliOptions, UpdateCliOptions };
76
+ export { AppRuntimeOptionsService, BuildCliOptions, CreateCliOptions, GrantCliOptions, InstallCliOptions, JsonOnlyCliOptions, PackCliOptions, PublishCliOptions, RevokeCliOptions, RuntimeCliOptions, UninstallCliOptions, UpdateCliOptions };
@@ -9,18 +9,31 @@ var AppRuntimeOptionsService = class {
9
9
  };
10
10
  };
11
11
  readCreateOptions = (rawArgs) => {
12
- const options = { json: false };
13
- for (const current of rawArgs) {
12
+ const options = {
13
+ json: false,
14
+ template: "starter"
15
+ };
16
+ for (let index = 0; index < rawArgs.length; index += 1) {
17
+ const current = rawArgs[index];
14
18
  if (!current?.startsWith("--")) throw new Error(`未知参数:${current}`);
19
+ const nextValue = rawArgs[index + 1];
15
20
  switch (current) {
16
21
  case "--json":
17
22
  options.json = true;
18
23
  break;
24
+ case "--template":
25
+ options.template = this.readCreateTemplate(this.requireOptionValue(current, nextValue));
26
+ index += 1;
27
+ break;
19
28
  default: throw new Error(`未知参数:${current}`);
20
29
  }
21
30
  }
22
31
  return options;
23
32
  };
33
+ readCreateTemplate = (rawTemplate) => {
34
+ if (rawTemplate === "starter" || rawTemplate === "ts-http" || rawTemplate === "ts-http-lite") return rawTemplate;
35
+ throw new Error("--template 只支持 starter、ts-http 或 ts-http-lite。");
36
+ };
24
37
  readPackOptions = (rawArgs) => {
25
38
  const options = { json: false };
26
39
  for (let index = 0; index < rawArgs.length; index += 1) {
@@ -40,6 +53,25 @@ var AppRuntimeOptionsService = class {
40
53
  }
41
54
  return options;
42
55
  };
56
+ readBuildOptions = (rawArgs) => {
57
+ const options = {
58
+ json: false,
59
+ install: false
60
+ };
61
+ for (const current of rawArgs) {
62
+ if (!current?.startsWith("--")) throw new Error(`未知参数:${current}`);
63
+ switch (current) {
64
+ case "--json":
65
+ options.json = true;
66
+ break;
67
+ case "--install":
68
+ options.install = true;
69
+ break;
70
+ default: throw new Error(`未知参数:${current}`);
71
+ }
72
+ }
73
+ return options;
74
+ };
43
75
  readJsonOnlyOptions = (rawArgs) => {
44
76
  const options = { json: false };
45
77
  for (const current of rawArgs) {
@@ -118,6 +150,7 @@ var AppRuntimeOptionsService = class {
118
150
  const options = {
119
151
  host: "127.0.0.1",
120
152
  port: 3100,
153
+ dataDirectory: void 0,
121
154
  json: false,
122
155
  documentGrantMap: {}
123
156
  };
@@ -138,6 +171,10 @@ var AppRuntimeOptionsService = class {
138
171
  case "--json":
139
172
  options.json = true;
140
173
  break;
174
+ case "--data":
175
+ options.dataDirectory = this.requireOptionValue(current, nextValue);
176
+ index += 1;
177
+ break;
141
178
  case "--document":
142
179
  this.assignDocumentGrant(options.documentGrantMap, this.requireOptionValue(current, nextValue));
143
180
  index += 1;
@@ -1,4 +1,4 @@
1
- import { AppScaffoldService } from "../scaffold/app-scaffold.service.js";
1
+ import { AppScaffoldService, AppScaffoldTemplate } from "../scaffold/app-scaffold.service.js";
2
2
 
3
3
  //#region src/commands/create.controller.d.ts
4
4
  declare class CreateCommand {
@@ -6,6 +6,7 @@ declare class CreateCommand {
6
6
  constructor(scaffoldService?: AppScaffoldService);
7
7
  run: (params: {
8
8
  appDirectory: string;
9
+ template: AppScaffoldTemplate;
9
10
  json: boolean;
10
11
  write: (text: string) => void;
11
12
  }) => Promise<void>;
@@ -5,8 +5,8 @@ var CreateCommand = class {
5
5
  this.scaffoldService = scaffoldService;
6
6
  }
7
7
  run = async (params) => {
8
- const { appDirectory, json, write } = params;
9
- const result = await this.scaffoldService.scaffold(appDirectory);
8
+ const { appDirectory, template, json, write } = params;
9
+ const result = await this.scaffoldService.scaffold(appDirectory, { template });
10
10
  if (json) {
11
11
  write(`${JSON.stringify({
12
12
  ok: true,
@@ -15,6 +15,7 @@ var CreateCommand = class {
15
15
  return;
16
16
  }
17
17
  write(`Created app scaffold at ${result.appDirectory}\n`);
18
+ write(`Template: ${result.template}\n`);
18
19
  write(`Manifest: ${result.manifestPath}\n`);
19
20
  write("Next: napp inspect <app-dir> && napp run <app-dir>\n");
20
21
  };
@@ -17,7 +17,8 @@ var InspectCommand = class {
17
17
  }
18
18
  write(`App: ${summary.name} (${summary.id})\n`);
19
19
  write(`Version: ${summary.version}\n`);
20
- write(`Action: ${summary.action}\n`);
20
+ write(`Main Kind: ${summary.mainKind}\n`);
21
+ if (summary.action) write(`Action: ${summary.action}\n`);
21
22
  write(`Main: ${summary.mainEntryPath}\n`);
22
23
  write(`UI: ${summary.uiEntryPath}\n`);
23
24
  };
@@ -2,6 +2,7 @@ import { AppManifestService } from "../manifest/app-manifest.service.js";
2
2
  import { AppHostService } from "../host/app-host.service.js";
3
3
  import { AppInstanceService } from "../host/app-instance.service.js";
4
4
  import { AppInstallationService } from "../install/app-installation.service.js";
5
+ import { WasmtimeWasiHttpComponentService } from "../runtime/wasmtime-wasi-http-component.service.js";
5
6
  //#region src/commands/run.controller.ts
6
7
  var RunCommand = class {
7
8
  constructor(manifestService = new AppManifestService(), installationService = new AppInstallationService()) {
@@ -9,19 +10,35 @@ var RunCommand = class {
9
10
  this.installationService = installationService;
10
11
  }
11
12
  run = async (params) => {
12
- const { appReference, host, port, json, documentGrantMap, write } = params;
13
+ const { appReference, host, port, dataDirectory, json, documentGrantMap, write } = params;
13
14
  const launch = await this.installationService.resolveLaunch(appReference, documentGrantMap);
14
15
  const bundle = await this.manifestService.load(launch.appDirectory);
15
16
  const appInstance = new AppInstanceService(bundle);
16
17
  await appInstance.initialize(launch.documentGrantMap, { appId: launch.appId });
17
18
  await this.installationService.persistGrants(launch.appId, launch.documentGrantMap);
18
- const appHost = new AppHostService(appInstance);
19
- const hostHandle = await appHost.start({
20
- host,
21
- port
22
- });
19
+ const wasiHttpComponentService = bundle.manifest.main.kind === "wasi-http-component" ? new WasmtimeWasiHttpComponentService() : void 0;
20
+ const effectiveDataDirectory = dataDirectory ?? launch.dataDirectory;
21
+ if (wasiHttpComponentService) {
22
+ if (!effectiveDataDirectory) throw new Error("wasi-http-component 应用需要通过 --data /path 指定后端数据目录。");
23
+ await wasiHttpComponentService.start({
24
+ wasmPath: bundle.mainEntryPath,
25
+ dataDirectory: effectiveDataDirectory
26
+ });
27
+ }
28
+ const appHost = new AppHostService(appInstance, wasiHttpComponentService);
29
+ let hostHandle;
30
+ try {
31
+ hostHandle = await appHost.start({
32
+ host,
33
+ port
34
+ });
35
+ } catch (error) {
36
+ await wasiHttpComponentService?.stop();
37
+ throw error;
38
+ }
23
39
  const shutdown = async () => {
24
40
  await appHost.stop();
41
+ await wasiHttpComponentService?.stop();
25
42
  process.exit(0);
26
43
  };
27
44
  process.once("SIGINT", () => {
@@ -36,7 +53,8 @@ var RunCommand = class {
36
53
  host: hostHandle,
37
54
  app: {
38
55
  appId: launch.appId ?? bundle.manifest.id,
39
- appDirectory: launch.appDirectory
56
+ appDirectory: launch.appDirectory,
57
+ dataDirectory: effectiveDataDirectory
40
58
  }
41
59
  }, null, 2)}\n`);
42
60
  return;
@@ -0,0 +1,15 @@
1
+ import { AppPublishValidationService } from "../publish/app-publish-validation.service.js";
2
+
3
+ //#region src/commands/validate-publish.controller.d.ts
4
+ declare class ValidatePublishCommand {
5
+ private readonly validationService;
6
+ constructor(validationService?: AppPublishValidationService);
7
+ run: (params: {
8
+ appDirectory: string;
9
+ metadataPath?: string;
10
+ json: boolean;
11
+ write: (text: string) => void;
12
+ }) => Promise<void>;
13
+ }
14
+ //#endregion
15
+ export { ValidatePublishCommand };
@@ -0,0 +1,31 @@
1
+ import { AppPublishValidationService } from "../publish/app-publish-validation.service.js";
2
+ //#region src/commands/validate-publish.controller.ts
3
+ var ValidatePublishCommand = class {
4
+ constructor(validationService = new AppPublishValidationService()) {
5
+ this.validationService = validationService;
6
+ }
7
+ run = async (params) => {
8
+ const { appDirectory, metadataPath, json, write } = params;
9
+ const result = await this.validationService.validate({
10
+ appDirectory,
11
+ metadataPath
12
+ });
13
+ if (json) {
14
+ write(`${JSON.stringify({
15
+ ok: true,
16
+ validation: result
17
+ }, null, 2)}\n`);
18
+ return;
19
+ }
20
+ write(`Publish validation ok for ${result.appId}@${result.version}\n`);
21
+ write(`Main kind: ${result.mainKind}\n`);
22
+ write(`Main: ${result.mainEntryPath}\n`);
23
+ write(`Metadata: ${result.metadataPath}\n`);
24
+ write(`Bundle size: ${result.bundleSizeBytes} bytes\n`);
25
+ write(`Main entry size: ${result.mainEntrySizeBytes} bytes\n`);
26
+ write(`Bundle files (${result.bundleFilePaths.length}): ${result.bundleFilePaths.join(", ")}\n`);
27
+ if (result.warnings.length > 0) for (const warning of result.warnings) write(`Warning [${warning.code}]: ${warning.message}\n`);
28
+ };
29
+ };
30
+ //#endregion
31
+ export { ValidatePublishCommand };
@@ -1,4 +1,5 @@
1
1
  import { AppInstanceService } from "./app-instance.service.js";
2
+ import { WasmtimeWasiHttpComponentService } from "../runtime/wasmtime-wasi-http-component.service.js";
2
3
 
3
4
  //#region src/host/app-host.service.d.ts
4
5
  type AppHostStartOptions = {
@@ -13,10 +14,11 @@ type AppHostHandle = {
13
14
  };
14
15
  declare class AppHostService {
15
16
  private readonly appInstance;
17
+ private readonly wasiHttpComponentService?;
16
18
  private server?;
17
19
  private readonly bridgeServer;
18
20
  private readonly uiServer;
19
- constructor(appInstance: AppInstanceService);
21
+ constructor(appInstance: AppInstanceService, wasiHttpComponentService?: WasmtimeWasiHttpComponentService | undefined);
20
22
  start: (options: AppHostStartOptions) => Promise<AppHostHandle>;
21
23
  stop: () => Promise<void>;
22
24
  private handleRequest;
@@ -6,8 +6,9 @@ var AppHostService = class {
6
6
  server;
7
7
  bridgeServer;
8
8
  uiServer;
9
- constructor(appInstance) {
9
+ constructor(appInstance, wasiHttpComponentService) {
10
10
  this.appInstance = appInstance;
11
+ this.wasiHttpComponentService = wasiHttpComponentService;
11
12
  this.bridgeServer = new HostBridgeServer(appInstance);
12
13
  this.uiServer = new UiServerService(appInstance.bundle);
13
14
  }
@@ -48,6 +49,9 @@ var AppHostService = class {
48
49
  };
49
50
  handleRequest = async (request, response) => {
50
51
  try {
52
+ if (this.wasiHttpComponentService) {
53
+ if (await this.wasiHttpComponentService.handleRequest(request, response)) return;
54
+ }
51
55
  if (await this.bridgeServer.handle(request, response)) return;
52
56
  await this.uiServer.handle(request, response);
53
57
  } catch (error) {
@@ -22,6 +22,7 @@ var AppInstanceService = class {
22
22
  return this.permissionsService.summarize(this.bundle, this.getPermissions());
23
23
  };
24
24
  runAction = async (action) => {
25
+ if (this.bundle.manifest.main.kind !== "wasm") throw new Error("当前应用不支持 __napp/run action,请通过 /api/* 调用 WASI HTTP 后端。");
25
26
  const expectedAction = this.bundle.manifest.main.action;
26
27
  if (action && action !== expectedAction) throw new Error(`当前应用只支持动作 ${expectedAction}。`);
27
28
  const input = await this.collectDocumentSummaryInput();
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AppDocumentAccessMode, AppDocumentAccessScope, AppMainManifest, AppManifest, AppManifestBundle, AppManifestSummary, AppPermissions, AppUiManifest } from "./manifest/app-manifest.types.js";
1
+ import { AppCoreWasmMainManifest, AppDocumentAccessMode, AppDocumentAccessScope, AppMainManifest, AppManifest, AppManifestBundle, AppManifestSummary, AppPermissions, AppUiManifest, AppWasiHttpComponentMainManifest } from "./manifest/app-manifest.types.js";
2
2
  import { AppManifestService } from "./manifest/app-manifest.service.js";
3
3
  import { AppBundleChecksums, AppBundleExtractResult, AppBundleMetadata, AppBundlePackResult } from "./bundle/app-bundle.types.js";
4
4
  import { AppBundleService } from "./bundle/app-bundle.service.js";
@@ -10,7 +10,10 @@ import { WasmSidecarClientService } from "./sidecar/wasm-sidecar-client.service.
10
10
  import { WasmMainRunnerService } from "./runtime/wasm-main-runner.service.js";
11
11
  import { AppInstanceService, AppRunResult } from "./host/app-instance.service.js";
12
12
  import { HostBridgeServer } from "./bridge/host-bridge.service.js";
13
- import { AppRuntimeOptionsService, CreateCliOptions, GrantCliOptions, InstallCliOptions, JsonOnlyCliOptions, PackCliOptions, PublishCliOptions, RevokeCliOptions, RuntimeCliOptions, UninstallCliOptions, UpdateCliOptions } from "./cli/app-runtime-options.service.js";
13
+ import { AppScaffoldFile, AppTsHttpScaffoldTemplateService } from "./scaffold/app-ts-http-scaffold-template.service.js";
14
+ import { AppTsHttpLiteScaffoldTemplateService } from "./scaffold/app-ts-http-lite-scaffold-template.service.js";
15
+ import { AppScaffoldResult, AppScaffoldService, AppScaffoldTemplate } from "./scaffold/app-scaffold.service.js";
16
+ import { AppRuntimeOptionsService, BuildCliOptions, CreateCliOptions, GrantCliOptions, InstallCliOptions, JsonOnlyCliOptions, PackCliOptions, PublishCliOptions, RevokeCliOptions, RuntimeCliOptions, UninstallCliOptions, UpdateCliOptions } from "./cli/app-runtime-options.service.js";
14
17
  import { AppRuntimeCliService } from "./cli/app-runtime-cli.service.js";
15
18
  import { CreateCommand } from "./commands/create.controller.js";
16
19
  import { AppHomeService } from "./paths/app-home.service.js";
@@ -38,6 +41,11 @@ import { RegistryCommand } from "./commands/registry.controller.js";
38
41
  import { RevokeCommand } from "./commands/revoke.controller.js";
39
42
  import { UpdateCommand } from "./commands/update.controller.js";
40
43
  import { UninstallCommand } from "./commands/uninstall.controller.js";
44
+ import { AppPublishValidationResult, AppPublishValidationService, AppPublishValidationWarning, AppPublishValidationWarningCode } from "./publish/app-publish-validation.service.js";
45
+ import { ValidatePublishCommand } from "./commands/validate-publish.controller.js";
46
+ import { WasmtimeWasiHttpComponentHandle, WasmtimeWasiHttpComponentService, WasmtimeWasiHttpComponentStartOptions } from "./runtime/wasmtime-wasi-http-component.service.js";
41
47
  import { AppHostHandle, AppHostService, AppHostStartOptions } from "./host/app-host.service.js";
48
+ import { AppRuntimeCommandResult, AppRuntimeDoctorResult, AppRuntimeToolStatus, AppRuntimeToolchainService } from "./runtime/app-runtime-toolchain.service.js";
49
+ import { AppBuildResult, AppBuildService } from "./runtime/app-build.service.js";
42
50
  import { UiServerService } from "./ui/ui-server.service.js";
43
- export { AppBundleChecksums, AppBundleExtractResult, AppBundleMetadata, AppBundlePackResult, AppBundleService, AppDocumentAccessMode, AppDocumentAccessScope, AppDocumentGrantMap, AppDocumentGrantMutationResult, AppDocumentGrantState, AppGrantService, AppHomeService, AppHostHandle, AppHostService, AppHostStartOptions, AppInfoResult, AppInstallResult, AppInstallSourceKind, AppInstallationService, AppInstalledPermissionState, AppInstanceService, AppLaunchResolution, AppMainManifest, AppManifest, AppManifestBundle, AppManifestService, AppManifestSummary, AppMarketplaceClientService, AppMarketplaceMetadata, AppMarketplaceMetadataService, AppPermissionSummary, AppPermissions, AppPermissionsService, AppPublishFile, AppPublishPayload, AppPublishResult, AppPublishService, AppPublisher, AppRegistry, AppRegistryAppRecord, AppRegistryConfig, AppRegistryConfigService, AppRegistryConfigSnapshot, AppRegistryInstalledVersion, AppRegistryService, AppRemoteRegistryClientService, AppRemoteRegistryDocument, AppRemoteRegistryResolution, AppRemoteRegistryVersion, AppRunResult, AppRuntimeCliService, AppRuntimeOptionsService, AppUiManifest, AppUninstallResult, AppUpdateResult, CreateCliOptions, CreateCommand, DEFAULT_APP_MARKETPLACE_API_BASE, DEFAULT_APP_REGISTRY_URL, GrantCliOptions, GrantCommand, HostBridgeServer, InfoCommand, InstallCliOptions, InstallCommand, InstalledAppListItem, JsonOnlyCliOptions, ListCommand, MainRunRequest, MainRunResult, MainRunnerService, PackCliOptions, PackCommand, PermissionsCommand, PlatformAuthStateService, PlatformPublishAuthState, PublishCliOptions, PublishCommand, RegistryCommand, ResolvedDocumentGrant, ResolvedPermissions, RevokeCliOptions, RevokeCommand, RuntimeCliOptions, UiServerService, UninstallCliOptions, UninstallCommand, UpdateCliOptions, UpdateCommand, WasmDocumentSummaryInput, WasmMainRunnerService, WasmSidecarClientService };
51
+ export { AppBuildResult, AppBuildService, AppBundleChecksums, AppBundleExtractResult, AppBundleMetadata, AppBundlePackResult, AppBundleService, AppCoreWasmMainManifest, AppDocumentAccessMode, AppDocumentAccessScope, AppDocumentGrantMap, AppDocumentGrantMutationResult, AppDocumentGrantState, AppGrantService, AppHomeService, AppHostHandle, AppHostService, AppHostStartOptions, AppInfoResult, AppInstallResult, AppInstallSourceKind, AppInstallationService, AppInstalledPermissionState, AppInstanceService, AppLaunchResolution, AppMainManifest, AppManifest, AppManifestBundle, AppManifestService, AppManifestSummary, AppMarketplaceClientService, AppMarketplaceMetadata, AppMarketplaceMetadataService, AppPermissionSummary, AppPermissions, AppPermissionsService, AppPublishFile, AppPublishPayload, AppPublishResult, AppPublishService, AppPublishValidationResult, AppPublishValidationService, AppPublishValidationWarning, AppPublishValidationWarningCode, AppPublisher, AppRegistry, AppRegistryAppRecord, AppRegistryConfig, AppRegistryConfigService, AppRegistryConfigSnapshot, AppRegistryInstalledVersion, AppRegistryService, AppRemoteRegistryClientService, AppRemoteRegistryDocument, AppRemoteRegistryResolution, AppRemoteRegistryVersion, AppRunResult, AppRuntimeCliService, AppRuntimeCommandResult, AppRuntimeDoctorResult, AppRuntimeOptionsService, AppRuntimeToolStatus, AppRuntimeToolchainService, AppScaffoldFile, AppScaffoldResult, AppScaffoldService, AppScaffoldTemplate, AppTsHttpLiteScaffoldTemplateService, AppTsHttpScaffoldTemplateService, AppUiManifest, AppUninstallResult, AppUpdateResult, AppWasiHttpComponentMainManifest, BuildCliOptions, CreateCliOptions, CreateCommand, DEFAULT_APP_MARKETPLACE_API_BASE, DEFAULT_APP_REGISTRY_URL, GrantCliOptions, GrantCommand, HostBridgeServer, InfoCommand, InstallCliOptions, InstallCommand, InstalledAppListItem, JsonOnlyCliOptions, ListCommand, MainRunRequest, MainRunResult, MainRunnerService, PackCliOptions, PackCommand, PermissionsCommand, PlatformAuthStateService, PlatformPublishAuthState, PublishCliOptions, PublishCommand, RegistryCommand, ResolvedDocumentGrant, ResolvedPermissions, RevokeCliOptions, RevokeCommand, RuntimeCliOptions, UiServerService, UninstallCliOptions, UninstallCommand, UpdateCliOptions, UpdateCommand, ValidatePublishCommand, WasmDocumentSummaryInput, WasmMainRunnerService, WasmSidecarClientService, WasmtimeWasiHttpComponentHandle, WasmtimeWasiHttpComponentService, WasmtimeWasiHttpComponentStartOptions };