@nextclaw/app-runtime 0.2.0 → 0.3.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 (58) hide show
  1. package/README.md +117 -4
  2. package/dist/bundle/app-bundle.service.d.ts +27 -0
  3. package/dist/bundle/app-bundle.service.js +133 -0
  4. package/dist/bundle/app-bundle.types.d.ts +24 -0
  5. package/dist/cli/app-runtime-cli.service.d.ts +27 -0
  6. package/dist/cli/app-runtime-cli.service.js +281 -0
  7. package/dist/cli/app-runtime-options.service.d.ts +60 -0
  8. package/dist/cli/app-runtime-options.service.js +215 -0
  9. package/dist/commands/create.controller.d.ts +14 -0
  10. package/dist/commands/grant.controller.d.ts +16 -0
  11. package/dist/commands/grant.controller.js +25 -0
  12. package/dist/commands/info.controller.d.ts +14 -0
  13. package/dist/commands/info.controller.js +27 -0
  14. package/dist/commands/install.controller.d.ts +15 -0
  15. package/dist/commands/install.controller.js +24 -0
  16. package/dist/commands/list.controller.d.ts +13 -0
  17. package/dist/commands/list.controller.js +25 -0
  18. package/dist/commands/pack.controller.d.ts +15 -0
  19. package/dist/commands/pack.controller.js +25 -0
  20. package/dist/commands/permissions.controller.d.ts +14 -0
  21. package/dist/commands/permissions.controller.js +26 -0
  22. package/dist/commands/registry.controller.d.ts +16 -0
  23. package/dist/commands/registry.controller.js +27 -0
  24. package/dist/commands/revoke.controller.d.ts +15 -0
  25. package/dist/commands/revoke.controller.js +24 -0
  26. package/dist/commands/run.controller.js +14 -6
  27. package/dist/commands/uninstall.controller.d.ts +15 -0
  28. package/dist/commands/uninstall.controller.js +23 -0
  29. package/dist/commands/update.controller.d.ts +16 -0
  30. package/dist/commands/update.controller.js +29 -0
  31. package/dist/host/app-instance.service.d.ts +3 -1
  32. package/dist/host/app-instance.service.js +2 -2
  33. package/dist/index.d.ts +26 -2
  34. package/dist/index.js +23 -2
  35. package/dist/install/app-installation.service.d.ts +37 -0
  36. package/dist/install/app-installation.service.js +255 -0
  37. package/dist/install/app-installation.types.d.ts +62 -0
  38. package/dist/main.js +5 -132
  39. package/dist/package.js +1 -1
  40. package/dist/paths/app-home.service.d.ts +16 -0
  41. package/dist/paths/app-home.service.js +42 -0
  42. package/dist/permissions/app-grant.service.d.ts +22 -0
  43. package/dist/permissions/app-grant.service.js +63 -0
  44. package/dist/permissions/app-permissions.service.d.ts +3 -1
  45. package/dist/permissions/app-permissions.service.js +12 -5
  46. package/dist/permissions/app-permissions.types.d.ts +28 -1
  47. package/dist/registry/app-registry-config.service.d.ts +16 -0
  48. package/dist/registry/app-registry-config.service.js +84 -0
  49. package/dist/registry/app-registry.service.d.ts +38 -0
  50. package/dist/registry/app-registry.service.js +115 -0
  51. package/dist/registry/app-registry.types.d.ts +33 -0
  52. package/dist/registry/app-remote-registry-client.service.d.ts +28 -0
  53. package/dist/registry/app-remote-registry-client.service.js +114 -0
  54. package/dist/registry/app-remote-registry.types.d.ts +52 -0
  55. package/dist/registry/app-remote-registry.types.js +4 -0
  56. package/dist/scaffold/app-scaffold.service.d.ts +19 -0
  57. package/dist/scaffold/app-scaffold.service.js +1 -1
  58. package/package.json +4 -2
package/README.md CHANGED
@@ -2,12 +2,22 @@
2
2
 
3
3
  `@nextclaw/app-runtime` 是一个独立的微应用 runtime/CLI 包。
4
4
 
5
- 当前 MVP 提供三件事:
5
+ 当前相对完善 MVP 提供下面这些能力:
6
6
 
7
7
  - `napp create <app-dir>`:生成一个最小可跑的微应用骨架
8
8
  - `napp inspect <app-dir>`:校验应用目录与 manifest
9
- - `napp run <app-dir>`:启动本地宿主,提供 UI 静态服务和桥接 API
9
+ - `napp run <app-dir|app-id>`:启动本地宿主,支持目录运行和已安装应用运行
10
10
  - `napp dev <app-dir>`:当前等价于 `run`
11
+ - `napp pack <app-dir>`:把应用目录打成 `.napp` bundle
12
+ - `napp install <app-dir|bundle.napp|app-id[@version]>`:从本地或 registry 安装应用
13
+ - `napp update <app-id>`:更新已安装应用
14
+ - `napp uninstall <app-id>`:卸载已安装应用
15
+ - `napp list`:列出已安装应用
16
+ - `napp info <app-id>`:查看已安装应用详情
17
+ - `napp registry [get|set|reset]`:查看或切换 registry
18
+ - `napp permissions <app-id>`:查看应用权限状态
19
+ - `napp grant <app-id> --document scope=/path`:写入目录授权
20
+ - `napp revoke <app-id> --document scope`:撤销目录授权
11
21
 
12
22
  ## 安装
13
23
 
@@ -22,7 +32,7 @@ napp --help
22
32
  napp --version
23
33
  ```
24
34
 
25
- 第一版先聚焦“独立可运行的微应用宿主”,不接入现有 NextClaw 主产品路由、服务或传播层。
35
+ 第一版先聚焦“独立可运行的微应用宿主 + 可分发、可安装、可更新、可授权的 CLI/runtime 闭环”,不接入现有 NextClaw 主产品路由、服务或 GUI app store。
26
36
 
27
37
  ## 应用目录
28
38
 
@@ -42,18 +52,121 @@ assets/
42
52
  - 宿主桥接:`/__napp/*`
43
53
  - 权限词汇:`documentAccess`、`allowedDomains`、`storage`、`capabilities`
44
54
  - 当前 Wasm 执行底座:Node 原生 `WebAssembly`
55
+ - 分发包形态:`.napp`(底层为 zip)
56
+ - 安装目录:`~/.nextclaw/apps/packages/<app-id>/<version>/`
57
+ - 用户数据目录:`~/.nextclaw/apps/data/<app-id>/`
58
+ - 本地 registry:`~/.nextclaw/apps/registry.json`
59
+ - 本地 config:`~/.nextclaw/apps/config.json`
60
+ - 默认 registry:`https://registry.nextclaw.com/`
61
+
62
+ ## 当前 MVP 工作流
63
+
64
+ 开发者工作流:
65
+
66
+ ```bash
67
+ napp create ./my-first-napp
68
+ napp inspect ./my-first-napp
69
+ napp pack ./my-first-napp
70
+ ```
71
+
72
+ 本地安装工作流:
73
+
74
+ ```bash
75
+ napp install ./my-first-napp
76
+ napp list
77
+ napp info nextclaw.my-first-napp
78
+ napp run nextclaw.my-first-napp
79
+ ```
80
+
81
+ registry 安装与更新工作流:
82
+
83
+ ```bash
84
+ napp registry set https://registry.example.com/
85
+ napp install nextclaw.hello-notes
86
+ napp permissions nextclaw.hello-notes
87
+ napp grant nextclaw.hello-notes --document notes=/absolute/path/to/notes
88
+ napp run nextclaw.hello-notes
89
+ napp update nextclaw.hello-notes
90
+ ```
91
+
92
+ 卸载与权限回收:
93
+
94
+ ```bash
95
+ napp revoke nextclaw.my-first-napp --document notes
96
+ napp uninstall nextclaw.my-first-napp
97
+ napp uninstall nextclaw.my-first-napp --purge-data
98
+ ```
45
99
 
46
100
  ## 示例
47
101
 
48
102
  ```bash
49
103
  napp create ./my-first-napp
50
104
  napp inspect ./my-first-napp
51
- napp run ./my-first-napp
105
+ napp pack ./my-first-napp
106
+ napp install ./my-first-napp
107
+ napp list
108
+ napp info nextclaw.my-first-napp
109
+ napp permissions nextclaw.my-first-napp
110
+ napp run nextclaw.my-first-napp
52
111
  ```
53
112
 
54
113
  已有示例应用:
55
114
 
56
115
  ```bash
57
116
  napp inspect ./apps/examples/hello-notes
117
+ napp pack ./apps/examples/hello-notes
118
+ napp install ./apps/examples/hello-notes
119
+ napp grant nextclaw.hello-notes --document notes=/absolute/path/to/notes
58
120
  napp run ./apps/examples/hello-notes --document notes=/absolute/path/to/notes
59
121
  ```
122
+
123
+ registry 示例:
124
+
125
+ ```bash
126
+ napp registry get
127
+ napp registry set https://registry.example.com/
128
+ napp install nextclaw.hello-notes
129
+ napp update nextclaw.hello-notes
130
+ ```
131
+
132
+ ## Bundle 结构
133
+
134
+ `.napp` bundle 的最小结构如下:
135
+
136
+ ```text
137
+ manifest.json
138
+ main/
139
+ ui/
140
+ assets/
141
+ .napp/
142
+ bundle.json
143
+ checksums.json
144
+ ```
145
+
146
+ ## Registry Metadata 结构
147
+
148
+ registry 按 npm 风格使用一个 base URL,再按 app id 拉取 metadata 文档。metadata 的最小结构如下:
149
+
150
+ ```json
151
+ {
152
+ "name": "nextclaw.hello-notes",
153
+ "description": "Registry-hosted Hello Notes",
154
+ "dist-tags": {
155
+ "latest": "0.2.0"
156
+ },
157
+ "versions": {
158
+ "0.2.0": {
159
+ "name": "nextclaw.hello-notes",
160
+ "version": "0.2.0",
161
+ "publisher": {
162
+ "id": "nextclaw",
163
+ "name": "NextClaw Official"
164
+ },
165
+ "dist": {
166
+ "bundle": "./-/hello-notes-0.2.0.napp",
167
+ "sha256": "<sha256>"
168
+ }
169
+ }
170
+ }
171
+ }
172
+ ```
@@ -0,0 +1,27 @@
1
+ import { AppManifestService } from "../manifest/app-manifest.service.js";
2
+ import { AppBundleExtractResult, AppBundlePackResult } from "./app-bundle.types.js";
3
+
4
+ //#region src/bundle/app-bundle.service.d.ts
5
+ declare class AppBundleService {
6
+ private readonly manifestService;
7
+ constructor(manifestService?: AppManifestService);
8
+ packAppDirectory: (params: {
9
+ appDirectory: string;
10
+ outputPath?: string;
11
+ }) => Promise<AppBundlePackResult>;
12
+ extractBundle: (params: {
13
+ bundlePath: string;
14
+ targetDirectory: string;
15
+ }) => Promise<AppBundleExtractResult>;
16
+ private collectAppFiles;
17
+ private collectDirectoryPaths;
18
+ private buildMetadata;
19
+ private buildChecksums;
20
+ private computeSha256;
21
+ private normalizeBundleFileName;
22
+ private normalizeArchiveEntry;
23
+ private readJsonFile;
24
+ private verifyChecksums;
25
+ }
26
+ //#endregion
27
+ export { AppBundleService };
@@ -0,0 +1,133 @@
1
+ import { AppManifestService } from "../manifest/app-manifest.service.js";
2
+ import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
3
+ import { createHash } from "node:crypto";
4
+ import path from "node:path";
5
+ import { strToU8, unzipSync, zipSync } from "fflate";
6
+ //#region src/bundle/app-bundle.service.ts
7
+ var AppBundleService = class {
8
+ constructor(manifestService = new AppManifestService()) {
9
+ this.manifestService = manifestService;
10
+ }
11
+ packAppDirectory = async (params) => {
12
+ const bundle = await this.manifestService.load(params.appDirectory);
13
+ const appFiles = await this.collectAppFiles(bundle.appDirectory);
14
+ const metadata = this.buildMetadata(bundle.manifest.id, bundle.manifest.name, bundle.manifest.version);
15
+ const bundleJsonPath = ".napp/bundle.json";
16
+ const checksumsJsonPath = ".napp/checksums.json";
17
+ const bundleJsonBytes = strToU8(`${JSON.stringify(metadata, null, 2)}\n`);
18
+ const checksums = this.buildChecksums({
19
+ ...appFiles,
20
+ [bundleJsonPath]: bundleJsonBytes
21
+ });
22
+ const checksumsJsonBytes = strToU8(`${JSON.stringify(checksums, null, 2)}\n`);
23
+ const archiveBytes = zipSync({
24
+ ...appFiles,
25
+ [bundleJsonPath]: bundleJsonBytes,
26
+ [checksumsJsonPath]: checksumsJsonBytes
27
+ }, { level: 9 });
28
+ const outputPath = params.outputPath ? path.resolve(params.outputPath) : path.join(path.dirname(bundle.appDirectory), `${this.normalizeBundleFileName(bundle.manifest.id)}-${bundle.manifest.version}.napp`);
29
+ await mkdir(path.dirname(outputPath), { recursive: true });
30
+ await writeFile(outputPath, Buffer.from(archiveBytes));
31
+ return {
32
+ bundlePath: outputPath,
33
+ metadata
34
+ };
35
+ };
36
+ extractBundle = async (params) => {
37
+ const bundlePath = path.resolve(params.bundlePath);
38
+ const targetDirectory = path.resolve(params.targetDirectory);
39
+ await rm(targetDirectory, {
40
+ recursive: true,
41
+ force: true
42
+ });
43
+ await mkdir(targetDirectory, { recursive: true });
44
+ const archive = unzipSync(new Uint8Array(await readFile(bundlePath)));
45
+ const entryNames = Object.keys(archive).sort((left, right) => left.localeCompare(right));
46
+ for (const entryName of entryNames) {
47
+ const normalizedEntry = this.normalizeArchiveEntry(entryName);
48
+ const targetPath = path.join(targetDirectory, normalizedEntry);
49
+ await mkdir(path.dirname(targetPath), { recursive: true });
50
+ await writeFile(targetPath, Buffer.from(archive[entryName]));
51
+ }
52
+ const metadata = await this.readJsonFile(path.join(targetDirectory, ".napp", "bundle.json"), "bundle metadata");
53
+ const checksums = await this.readJsonFile(path.join(targetDirectory, ".napp", "checksums.json"), "bundle checksums");
54
+ await this.verifyChecksums(targetDirectory, checksums);
55
+ await this.manifestService.load(targetDirectory);
56
+ return {
57
+ appDirectory: targetDirectory,
58
+ metadata,
59
+ checksums
60
+ };
61
+ };
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);
67
+ const sortedPaths = Array.from(filePaths).sort((left, right) => left.localeCompare(right));
68
+ const appFiles = {};
69
+ for (const relativePath of sortedPaths) appFiles[relativePath] = new Uint8Array(await readFile(path.join(appDirectory, relativePath)));
70
+ return appFiles;
71
+ };
72
+ collectDirectoryPaths = async (directoryPath, appDirectory, filePaths) => {
73
+ try {
74
+ const entries = await readdir(directoryPath, { withFileTypes: true });
75
+ for (const entry of entries) {
76
+ const entryPath = path.join(directoryPath, entry.name);
77
+ if (entry.isDirectory()) {
78
+ await this.collectDirectoryPaths(entryPath, appDirectory, filePaths);
79
+ continue;
80
+ }
81
+ if (!entry.isFile()) continue;
82
+ filePaths.add(path.relative(appDirectory, entryPath));
83
+ }
84
+ } catch {
85
+ return;
86
+ }
87
+ };
88
+ buildMetadata = (appId, name, version) => {
89
+ return {
90
+ bundleFormatVersion: 1,
91
+ appId,
92
+ name,
93
+ version,
94
+ entryManifest: "manifest.json",
95
+ checksumsFile: ".napp/checksums.json"
96
+ };
97
+ };
98
+ buildChecksums = (files) => {
99
+ const entries = Object.entries(files).sort(([left], [right]) => left.localeCompare(right));
100
+ return {
101
+ algorithm: "sha256",
102
+ files: Object.fromEntries(entries.map(([relativePath, fileBytes]) => [relativePath, this.computeSha256(fileBytes)]))
103
+ };
104
+ };
105
+ computeSha256 = (fileBytes) => {
106
+ return createHash("sha256").update(Buffer.from(fileBytes)).digest("hex");
107
+ };
108
+ normalizeBundleFileName = (appId) => {
109
+ return appId.replace(/[^a-zA-Z0-9._-]+/g, "-");
110
+ };
111
+ normalizeArchiveEntry = (entryName) => {
112
+ const normalized = entryName.replace(/\\/g, "/");
113
+ if (!normalized || normalized.startsWith("/") || normalized.includes("../")) throw new Error(`bundle 内包含非法路径:${entryName}`);
114
+ return normalized;
115
+ };
116
+ readJsonFile = async (filePath, label) => {
117
+ try {
118
+ return JSON.parse(await readFile(filePath, "utf-8"));
119
+ } catch (error) {
120
+ throw new Error(`无法读取 ${label}:${error instanceof Error ? error.message : String(error)}`);
121
+ }
122
+ };
123
+ verifyChecksums = async (appDirectory, checksums) => {
124
+ if (checksums.algorithm !== "sha256") throw new Error("当前只支持 sha256 checksums。");
125
+ const entries = Object.entries(checksums.files).sort(([left], [right]) => left.localeCompare(right));
126
+ for (const [relativePath, expectedHash] of entries) {
127
+ const fileBytes = new Uint8Array(await readFile(path.join(appDirectory, relativePath)));
128
+ if (this.computeSha256(fileBytes) !== expectedHash) throw new Error(`bundle checksum 校验失败:${relativePath}`);
129
+ }
130
+ };
131
+ };
132
+ //#endregion
133
+ export { AppBundleService };
@@ -0,0 +1,24 @@
1
+ //#region src/bundle/app-bundle.types.d.ts
2
+ type AppBundleMetadata = {
3
+ bundleFormatVersion: 1;
4
+ appId: string;
5
+ name: string;
6
+ version: string;
7
+ entryManifest: "manifest.json";
8
+ checksumsFile: ".napp/checksums.json";
9
+ };
10
+ type AppBundleChecksums = {
11
+ algorithm: "sha256";
12
+ files: Record<string, string>;
13
+ };
14
+ type AppBundlePackResult = {
15
+ bundlePath: string;
16
+ metadata: AppBundleMetadata;
17
+ };
18
+ type AppBundleExtractResult = {
19
+ appDirectory: string;
20
+ metadata: AppBundleMetadata;
21
+ checksums: AppBundleChecksums;
22
+ };
23
+ //#endregion
24
+ export { AppBundleChecksums, AppBundleExtractResult, AppBundleMetadata, AppBundlePackResult };
@@ -0,0 +1,27 @@
1
+ import { AppRuntimeOptionsService } from "./app-runtime-options.service.js";
2
+
3
+ //#region src/cli/app-runtime-cli.service.d.ts
4
+ declare class AppRuntimeCliService {
5
+ private readonly optionsService;
6
+ constructor(optionsService?: AppRuntimeOptionsService);
7
+ run: () => Promise<void>;
8
+ private dispatch;
9
+ private handleCreate;
10
+ private handleInspect;
11
+ private handleRun;
12
+ private handleDev;
13
+ private handlePack;
14
+ private handleInstall;
15
+ private handleUpdate;
16
+ private handleUninstall;
17
+ private handleList;
18
+ private handleInfo;
19
+ private handleRegistry;
20
+ private handlePermissions;
21
+ private handleGrant;
22
+ private handleRevoke;
23
+ private writeUsage;
24
+ private write;
25
+ }
26
+ //#endregion
27
+ export { AppRuntimeCliService };
@@ -0,0 +1,281 @@
1
+ import { version } from "../package.js";
2
+ import { CreateCommand } from "../commands/create.controller.js";
3
+ import { RunCommand } from "../commands/run.controller.js";
4
+ import { DevCommand } from "../commands/dev.controller.js";
5
+ import { GrantCommand } from "../commands/grant.controller.js";
6
+ import { InfoCommand } from "../commands/info.controller.js";
7
+ import { InspectCommand } from "../commands/inspect.controller.js";
8
+ import { InstallCommand } from "../commands/install.controller.js";
9
+ import { ListCommand } from "../commands/list.controller.js";
10
+ import { PackCommand } from "../commands/pack.controller.js";
11
+ import { PermissionsCommand } from "../commands/permissions.controller.js";
12
+ import { RegistryCommand } from "../commands/registry.controller.js";
13
+ import { RevokeCommand } from "../commands/revoke.controller.js";
14
+ import { UninstallCommand } from "../commands/uninstall.controller.js";
15
+ import { UpdateCommand } from "../commands/update.controller.js";
16
+ import { AppRuntimeOptionsService } from "./app-runtime-options.service.js";
17
+ //#region src/cli/app-runtime-cli.service.ts
18
+ var AppRuntimeCliService = class {
19
+ constructor(optionsService = new AppRuntimeOptionsService()) {
20
+ this.optionsService = optionsService;
21
+ }
22
+ run = async () => {
23
+ const [command, ...restArgs] = process.argv.slice(2);
24
+ if (command === "--help" || command === "help") {
25
+ this.writeUsage();
26
+ return;
27
+ }
28
+ if (command === "--version" || command === "version") {
29
+ this.write(`${version}\n`);
30
+ return;
31
+ }
32
+ if (!command) {
33
+ this.writeUsage();
34
+ process.exit(1);
35
+ }
36
+ await this.dispatch(command, restArgs);
37
+ };
38
+ dispatch = async (command, restArgs) => {
39
+ switch (command) {
40
+ case "create":
41
+ await this.handleCreate(restArgs);
42
+ return;
43
+ case "inspect":
44
+ await this.handleInspect(restArgs);
45
+ return;
46
+ case "run":
47
+ await this.handleRun(restArgs);
48
+ return;
49
+ case "dev":
50
+ await this.handleDev(restArgs);
51
+ return;
52
+ case "pack":
53
+ await this.handlePack(restArgs);
54
+ return;
55
+ case "install":
56
+ await this.handleInstall(restArgs);
57
+ return;
58
+ case "update":
59
+ await this.handleUpdate(restArgs);
60
+ return;
61
+ case "uninstall":
62
+ await this.handleUninstall(restArgs);
63
+ return;
64
+ case "list":
65
+ await this.handleList(restArgs);
66
+ return;
67
+ case "info":
68
+ await this.handleInfo(restArgs);
69
+ return;
70
+ case "registry":
71
+ await this.handleRegistry(restArgs);
72
+ return;
73
+ case "permissions":
74
+ await this.handlePermissions(restArgs);
75
+ return;
76
+ case "grant":
77
+ await this.handleGrant(restArgs);
78
+ return;
79
+ case "revoke":
80
+ await this.handleRevoke(restArgs);
81
+ return;
82
+ default:
83
+ this.writeUsage();
84
+ process.exit(1);
85
+ }
86
+ };
87
+ handleCreate = async (restArgs) => {
88
+ const { target, optionArgs } = this.optionsService.readTarget("create", restArgs);
89
+ const options = this.optionsService.readCreateOptions(optionArgs);
90
+ await new CreateCommand().run({
91
+ appDirectory: target,
92
+ json: options.json,
93
+ write: this.write
94
+ });
95
+ };
96
+ handleInspect = async (restArgs) => {
97
+ const { target, optionArgs } = this.optionsService.readTarget("inspect", restArgs);
98
+ const options = this.optionsService.readJsonOnlyOptions(optionArgs);
99
+ await new InspectCommand().run({
100
+ appDirectory: target,
101
+ json: options.json,
102
+ write: this.write
103
+ });
104
+ };
105
+ handleRun = async (restArgs) => {
106
+ const { target, optionArgs } = this.optionsService.readTarget("run", restArgs);
107
+ const options = this.optionsService.readRuntimeOptions(optionArgs);
108
+ await new RunCommand().run({
109
+ appReference: target,
110
+ host: options.host,
111
+ port: options.port,
112
+ json: options.json,
113
+ documentGrantMap: options.documentGrantMap,
114
+ write: this.write
115
+ });
116
+ };
117
+ handleDev = async (restArgs) => {
118
+ const { target, optionArgs } = this.optionsService.readTarget("dev", restArgs);
119
+ const options = this.optionsService.readRuntimeOptions(optionArgs);
120
+ await new DevCommand().run({
121
+ appReference: target,
122
+ host: options.host,
123
+ port: options.port,
124
+ json: options.json,
125
+ documentGrantMap: options.documentGrantMap,
126
+ write: this.write
127
+ });
128
+ };
129
+ handlePack = async (restArgs) => {
130
+ const { target, optionArgs } = this.optionsService.readTarget("pack", restArgs);
131
+ const options = this.optionsService.readPackOptions(optionArgs);
132
+ await new PackCommand().run({
133
+ appDirectory: target,
134
+ outputPath: options.outputPath,
135
+ json: options.json,
136
+ write: this.write
137
+ });
138
+ };
139
+ handleInstall = async (restArgs) => {
140
+ const { target, optionArgs } = this.optionsService.readTarget("install", restArgs);
141
+ const options = this.optionsService.readInstallOptions(optionArgs);
142
+ await new InstallCommand().run({
143
+ appSource: target,
144
+ registryUrl: options.registryUrl,
145
+ json: options.json,
146
+ write: this.write
147
+ });
148
+ };
149
+ handleUpdate = async (restArgs) => {
150
+ const { target, optionArgs } = this.optionsService.readTarget("update", restArgs);
151
+ const options = this.optionsService.readUpdateOptions(optionArgs);
152
+ await new UpdateCommand().run({
153
+ appId: target,
154
+ version: options.version,
155
+ registryUrl: options.registryUrl,
156
+ json: options.json,
157
+ write: this.write
158
+ });
159
+ };
160
+ handleUninstall = async (restArgs) => {
161
+ const { target, optionArgs } = this.optionsService.readTarget("uninstall", restArgs);
162
+ const options = this.optionsService.readUninstallOptions(optionArgs);
163
+ await new UninstallCommand().run({
164
+ appId: target,
165
+ purgeData: options.purgeData,
166
+ json: options.json,
167
+ write: this.write
168
+ });
169
+ };
170
+ handleList = async (restArgs) => {
171
+ const options = this.optionsService.readJsonOnlyOptions(restArgs);
172
+ await new ListCommand().run({
173
+ json: options.json,
174
+ write: this.write
175
+ });
176
+ };
177
+ handleInfo = async (restArgs) => {
178
+ const { target, optionArgs } = this.optionsService.readTarget("info", restArgs);
179
+ const options = this.optionsService.readJsonOnlyOptions(optionArgs);
180
+ await new InfoCommand().run({
181
+ appId: target,
182
+ json: options.json,
183
+ write: this.write
184
+ });
185
+ };
186
+ handleRegistry = async (restArgs) => {
187
+ const [actionOrUrl, ...optionArgs] = restArgs;
188
+ if (!actionOrUrl || actionOrUrl === "get") {
189
+ const options = this.optionsService.readJsonOnlyOptions(optionArgs);
190
+ await new RegistryCommand().run({
191
+ action: "get",
192
+ json: options.json,
193
+ write: this.write
194
+ });
195
+ return;
196
+ }
197
+ if (actionOrUrl === "--json") {
198
+ const options = this.optionsService.readJsonOnlyOptions([actionOrUrl, ...optionArgs]);
199
+ await new RegistryCommand().run({
200
+ action: "get",
201
+ json: options.json,
202
+ write: this.write
203
+ });
204
+ return;
205
+ }
206
+ if (actionOrUrl === "set") {
207
+ const { target, optionArgs: actionOptionArgs } = this.optionsService.readTarget("registry set", optionArgs);
208
+ const options = this.optionsService.readJsonOnlyOptions(actionOptionArgs);
209
+ await new RegistryCommand().run({
210
+ action: "set",
211
+ registryUrl: target,
212
+ json: options.json,
213
+ write: this.write
214
+ });
215
+ return;
216
+ }
217
+ if (actionOrUrl === "reset") {
218
+ const options = this.optionsService.readJsonOnlyOptions(optionArgs);
219
+ await new RegistryCommand().run({
220
+ action: "reset",
221
+ json: options.json,
222
+ write: this.write
223
+ });
224
+ return;
225
+ }
226
+ throw new Error(`未知 registry 子命令:${actionOrUrl}`);
227
+ };
228
+ handlePermissions = async (restArgs) => {
229
+ const { target, optionArgs } = this.optionsService.readTarget("permissions", restArgs);
230
+ const options = this.optionsService.readJsonOnlyOptions(optionArgs);
231
+ await new PermissionsCommand().run({
232
+ appId: target,
233
+ json: options.json,
234
+ write: this.write
235
+ });
236
+ };
237
+ handleGrant = async (restArgs) => {
238
+ const { target, optionArgs } = this.optionsService.readTarget("grant", restArgs);
239
+ const options = this.optionsService.readGrantOptions(optionArgs);
240
+ await new GrantCommand().run({
241
+ appId: target,
242
+ documentGrantMap: options.documentGrantMap,
243
+ json: options.json,
244
+ write: this.write
245
+ });
246
+ };
247
+ handleRevoke = async (restArgs) => {
248
+ const { target, optionArgs } = this.optionsService.readTarget("revoke", restArgs);
249
+ const options = this.optionsService.readRevokeOptions(optionArgs);
250
+ await new RevokeCommand().run({
251
+ appId: target,
252
+ documentScopeIds: options.documentScopeIds,
253
+ json: options.json,
254
+ write: this.write
255
+ });
256
+ };
257
+ writeUsage = () => {
258
+ this.write("Usage: napp create <app-dir> [--json]\n");
259
+ this.write(" napp inspect <app-dir> [--json]\n");
260
+ this.write(" napp <run|dev> <app-dir|app-id> [--host 127.0.0.1] [--port 3100] [--json] [--document scope=/path]\n");
261
+ this.write(" napp pack <app-dir> [--out bundle.napp] [--json]\n");
262
+ this.write(" napp install <app-dir|bundle.napp|app-id[@version]> [--registry <url>] [--json]\n");
263
+ this.write(" napp update <app-id> [--version <version>] [--registry <url>] [--json]\n");
264
+ this.write(" napp uninstall <app-id> [--purge-data] [--json]\n");
265
+ this.write(" napp list [--json]\n");
266
+ this.write(" napp info <app-id> [--json]\n");
267
+ this.write(" napp registry [get] [--json]\n");
268
+ this.write(" napp registry set <url> [--json]\n");
269
+ this.write(" napp registry reset [--json]\n");
270
+ this.write(" napp permissions <app-id> [--json]\n");
271
+ this.write(" napp grant <app-id> --document scope=/path [--json]\n");
272
+ this.write(" napp revoke <app-id> --document scope [--json]\n");
273
+ this.write(" napp --help\n");
274
+ this.write(" napp --version\n");
275
+ };
276
+ write = (text) => {
277
+ process.stdout.write(text);
278
+ };
279
+ };
280
+ //#endregion
281
+ export { AppRuntimeCliService };