@nextclaw/app-runtime 0.9.13 → 0.9.14

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 (306) hide show
  1. package/README.md +2 -2
  2. package/dist/{main.js → app/main.js} +2 -2
  3. package/dist/app/main.js.map +1 -0
  4. package/dist/{commands → controllers}/create.controller.d.ts +2 -2
  5. package/dist/controllers/create.controller.d.ts.map +1 -0
  6. package/dist/{commands → controllers}/create.controller.js +2 -2
  7. package/dist/controllers/create.controller.js.map +1 -0
  8. package/dist/{commands → controllers}/dev.controller.js +1 -1
  9. package/dist/controllers/dev.controller.js.map +1 -0
  10. package/dist/{commands → controllers}/grant.controller.d.ts +3 -3
  11. package/dist/controllers/grant.controller.d.ts.map +1 -0
  12. package/dist/{commands → controllers}/grant.controller.js +2 -2
  13. package/dist/controllers/grant.controller.js.map +1 -0
  14. package/dist/{commands → controllers}/info.controller.d.ts +2 -2
  15. package/dist/controllers/info.controller.d.ts.map +1 -0
  16. package/dist/{commands → controllers}/info.controller.js +2 -2
  17. package/dist/controllers/info.controller.js.map +1 -0
  18. package/dist/{commands → controllers}/inspect.controller.js +8 -2
  19. package/dist/controllers/inspect.controller.js.map +1 -0
  20. package/dist/{commands → controllers}/install.controller.d.ts +2 -2
  21. package/dist/controllers/install.controller.d.ts.map +1 -0
  22. package/dist/{commands → controllers}/install.controller.js +2 -2
  23. package/dist/controllers/install.controller.js.map +1 -0
  24. package/dist/{commands → controllers}/list.controller.d.ts +2 -2
  25. package/dist/controllers/list.controller.d.ts.map +1 -0
  26. package/dist/{commands → controllers}/list.controller.js +2 -2
  27. package/dist/controllers/list.controller.js.map +1 -0
  28. package/dist/controllers/pack.controller.d.ts +19 -0
  29. package/dist/controllers/pack.controller.d.ts.map +1 -0
  30. package/dist/{commands → controllers}/pack.controller.js +8 -4
  31. package/dist/controllers/pack.controller.js.map +1 -0
  32. package/dist/{commands → controllers}/permissions.controller.d.ts +2 -2
  33. package/dist/controllers/permissions.controller.d.ts.map +1 -0
  34. package/dist/{commands → controllers}/permissions.controller.js +2 -2
  35. package/dist/controllers/permissions.controller.js.map +1 -0
  36. package/dist/{commands → controllers}/publish.controller.d.ts +3 -3
  37. package/dist/controllers/publish.controller.d.ts.map +1 -0
  38. package/dist/{commands → controllers}/publish.controller.js +2 -2
  39. package/dist/controllers/publish.controller.js.map +1 -0
  40. package/dist/{commands → controllers}/registry.controller.d.ts +2 -2
  41. package/dist/controllers/registry.controller.d.ts.map +1 -0
  42. package/dist/{commands → controllers}/registry.controller.js +2 -2
  43. package/dist/controllers/registry.controller.js.map +1 -0
  44. package/dist/{commands → controllers}/revoke.controller.d.ts +2 -2
  45. package/dist/controllers/revoke.controller.d.ts.map +1 -0
  46. package/dist/{commands → controllers}/revoke.controller.js +2 -2
  47. package/dist/controllers/revoke.controller.js.map +1 -0
  48. package/dist/{commands → controllers}/run.controller.js +8 -6
  49. package/dist/controllers/run.controller.js.map +1 -0
  50. package/dist/{commands → controllers}/uninstall.controller.d.ts +2 -2
  51. package/dist/controllers/uninstall.controller.d.ts.map +1 -0
  52. package/dist/{commands → controllers}/uninstall.controller.js +2 -2
  53. package/dist/controllers/uninstall.controller.js.map +1 -0
  54. package/dist/{commands → controllers}/update.controller.d.ts +2 -2
  55. package/dist/controllers/update.controller.d.ts.map +1 -0
  56. package/dist/{commands → controllers}/update.controller.js +2 -2
  57. package/dist/controllers/update.controller.js.map +1 -0
  58. package/dist/{commands → controllers}/validate-publish.controller.d.ts +3 -3
  59. package/dist/controllers/validate-publish.controller.d.ts.map +1 -0
  60. package/dist/{commands → controllers}/validate-publish.controller.js +9 -5
  61. package/dist/controllers/validate-publish.controller.js.map +1 -0
  62. package/dist/index.d.ts +51 -51
  63. package/dist/index.js +46 -45
  64. package/dist/package.js +1 -1
  65. package/dist/{runtime → services}/app-build.service.d.ts +2 -2
  66. package/dist/services/app-build.service.d.ts.map +1 -0
  67. package/dist/{runtime → services}/app-build.service.js +4 -2
  68. package/dist/services/app-build.service.js.map +1 -0
  69. package/dist/{bundle → services}/app-bundle.service.d.ts +18 -6
  70. package/dist/services/app-bundle.service.d.ts.map +1 -0
  71. package/dist/services/app-bundle.service.js +305 -0
  72. package/dist/services/app-bundle.service.js.map +1 -0
  73. package/dist/{permissions → services}/app-grant.service.d.ts +4 -4
  74. package/dist/services/app-grant.service.d.ts.map +1 -0
  75. package/dist/{permissions → services}/app-grant.service.js +7 -4
  76. package/dist/services/app-grant.service.js.map +1 -0
  77. package/dist/{paths → services}/app-home.service.d.ts +1 -1
  78. package/dist/services/app-home.service.d.ts.map +1 -0
  79. package/dist/{paths → services}/app-home.service.js +1 -1
  80. package/dist/services/app-home.service.js.map +1 -0
  81. package/dist/{host → services}/app-host.service.d.ts +2 -2
  82. package/dist/services/app-host.service.d.ts.map +1 -0
  83. package/dist/{host → services}/app-host.service.js +3 -3
  84. package/dist/services/app-host.service.js.map +1 -0
  85. package/dist/services/app-install-source.service.js +72 -0
  86. package/dist/services/app-install-source.service.js.map +1 -0
  87. package/dist/{install → services}/app-installation.service.d.ts +15 -14
  88. package/dist/services/app-installation.service.d.ts.map +1 -0
  89. package/dist/services/app-installation.service.js +332 -0
  90. package/dist/services/app-installation.service.js.map +1 -0
  91. package/dist/services/app-instance.service.d.ts +34 -0
  92. package/dist/services/app-instance.service.d.ts.map +1 -0
  93. package/dist/{host → services}/app-instance.service.js +4 -4
  94. package/dist/services/app-instance.service.js.map +1 -0
  95. package/dist/{manifest → services}/app-manifest.service.d.ts +12 -2
  96. package/dist/services/app-manifest.service.d.ts.map +1 -0
  97. package/dist/services/app-manifest.service.js +271 -0
  98. package/dist/services/app-manifest.service.js.map +1 -0
  99. package/dist/{publish → services}/app-marketplace-client.service.d.ts +2 -2
  100. package/dist/services/app-marketplace-client.service.d.ts.map +1 -0
  101. package/dist/{publish → services}/app-marketplace-client.service.js +2 -2
  102. package/dist/services/app-marketplace-client.service.js.map +1 -0
  103. package/dist/{publish → services}/app-marketplace-metadata.service.d.ts +3 -3
  104. package/dist/services/app-marketplace-metadata.service.d.ts.map +1 -0
  105. package/dist/{publish → services}/app-marketplace-metadata.service.js +1 -1
  106. package/dist/services/app-marketplace-metadata.service.js.map +1 -0
  107. package/dist/{permissions → services}/app-permissions.service.d.ts +3 -3
  108. package/dist/services/app-permissions.service.d.ts.map +1 -0
  109. package/dist/{permissions → services}/app-permissions.service.js +4 -1
  110. package/dist/services/app-permissions.service.js.map +1 -0
  111. package/dist/{publish → services}/app-publish-validation.service.d.ts +9 -7
  112. package/dist/services/app-publish-validation.service.d.ts.map +1 -0
  113. package/dist/{publish → services}/app-publish-validation.service.js +14 -10
  114. package/dist/services/app-publish-validation.service.js.map +1 -0
  115. package/dist/{publish → services}/app-publish.service.d.ts +5 -5
  116. package/dist/services/app-publish.service.d.ts.map +1 -0
  117. package/dist/{publish → services}/app-publish.service.js +6 -6
  118. package/dist/services/app-publish.service.js.map +1 -0
  119. package/dist/{registry → services}/app-registry-config.service.d.ts +3 -3
  120. package/dist/{registry → services}/app-registry-config.service.d.ts.map +1 -1
  121. package/dist/{registry → services}/app-registry-config.service.js +3 -3
  122. package/dist/services/app-registry-config.service.js.map +1 -0
  123. package/dist/{registry → services}/app-registry.service.d.ts +18 -5
  124. package/dist/services/app-registry.service.d.ts.map +1 -0
  125. package/dist/services/app-registry.service.js +210 -0
  126. package/dist/services/app-registry.service.js.map +1 -0
  127. package/dist/{registry → services}/app-remote-registry-client.service.d.ts +6 -2
  128. package/dist/services/app-remote-registry-client.service.d.ts.map +1 -0
  129. package/dist/{registry → services}/app-remote-registry-client.service.js +54 -8
  130. package/dist/services/app-remote-registry-client.service.js.map +1 -0
  131. package/dist/{cli → services}/app-runtime-cli.service.d.ts +1 -1
  132. package/dist/services/app-runtime-cli.service.d.ts.map +1 -0
  133. package/dist/{cli → services}/app-runtime-cli.service.js +19 -19
  134. package/dist/services/app-runtime-cli.service.js.map +1 -0
  135. package/dist/{cli → services}/app-runtime-options.service.d.ts +6 -6
  136. package/dist/services/app-runtime-options.service.d.ts.map +1 -0
  137. package/dist/{cli → services}/app-runtime-options.service.js +3 -9
  138. package/dist/services/app-runtime-options.service.js.map +1 -0
  139. package/dist/{runtime → services}/app-runtime-toolchain.service.d.ts +1 -1
  140. package/dist/services/app-runtime-toolchain.service.d.ts.map +1 -0
  141. package/dist/{runtime → services}/app-runtime-toolchain.service.js +1 -1
  142. package/dist/services/app-runtime-toolchain.service.js.map +1 -0
  143. package/dist/{scaffold → services}/app-scaffold.service.d.ts +1 -1
  144. package/dist/{scaffold → services}/app-scaffold.service.d.ts.map +1 -1
  145. package/dist/{scaffold → services}/app-scaffold.service.js +1 -1
  146. package/dist/{scaffold → services}/app-scaffold.service.js.map +1 -1
  147. package/dist/{scaffold → services}/app-ts-http-lite-scaffold-template.service.d.ts +1 -1
  148. package/dist/{scaffold → services}/app-ts-http-lite-scaffold-template.service.d.ts.map +1 -1
  149. package/dist/{scaffold → services}/app-ts-http-lite-scaffold-template.service.js +1 -1
  150. package/dist/{scaffold → services}/app-ts-http-lite-scaffold-template.service.js.map +1 -1
  151. package/dist/{scaffold → services}/app-ts-http-scaffold-template.service.d.ts +1 -1
  152. package/dist/{scaffold → services}/app-ts-http-scaffold-template.service.d.ts.map +1 -1
  153. package/dist/{scaffold → services}/app-ts-http-scaffold-template.service.js +1 -1
  154. package/dist/{scaffold → services}/app-ts-http-scaffold-template.service.js.map +1 -1
  155. package/dist/{bridge → services}/host-bridge.service.d.ts +2 -2
  156. package/dist/services/host-bridge.service.d.ts.map +1 -0
  157. package/dist/{bridge → services}/host-bridge.service.js +1 -1
  158. package/dist/services/host-bridge.service.js.map +1 -0
  159. package/dist/services/main-runner.service.d.ts +9 -0
  160. package/dist/services/main-runner.service.d.ts.map +1 -0
  161. package/dist/services/main-runner.service.js +6 -0
  162. package/dist/services/main-runner.service.js.map +1 -0
  163. package/dist/{publish → services}/platform-auth-state.service.d.ts +1 -1
  164. package/dist/services/platform-auth-state.service.d.ts.map +1 -0
  165. package/dist/{publish → services}/platform-auth-state.service.js +1 -1
  166. package/dist/services/platform-auth-state.service.js.map +1 -0
  167. package/dist/{ui → services}/ui-server.service.d.ts +3 -3
  168. package/dist/services/ui-server.service.d.ts.map +1 -0
  169. package/dist/{ui → services}/ui-server.service.js +1 -1
  170. package/dist/services/ui-server.service.js.map +1 -0
  171. package/dist/{runtime → services}/wasm-main-runner.service.d.ts +3 -3
  172. package/dist/services/wasm-main-runner.service.d.ts.map +1 -0
  173. package/dist/{runtime → services}/wasm-main-runner.service.js +2 -2
  174. package/dist/services/wasm-main-runner.service.js.map +1 -0
  175. package/dist/{sidecar → services}/wasm-sidecar-client.service.d.ts +1 -1
  176. package/dist/services/wasm-sidecar-client.service.d.ts.map +1 -0
  177. package/dist/{sidecar → services}/wasm-sidecar-client.service.js +1 -1
  178. package/dist/services/wasm-sidecar-client.service.js.map +1 -0
  179. package/dist/{runtime → services}/wasmtime-wasi-http-component.service.d.ts +1 -1
  180. package/dist/services/wasmtime-wasi-http-component.service.d.ts.map +1 -0
  181. package/dist/{runtime → services}/wasmtime-wasi-http-component.service.js +1 -1
  182. package/dist/services/wasmtime-wasi-http-component.service.js.map +1 -0
  183. package/dist/{bundle → types}/app-bundle.types.d.ts +1 -1
  184. package/dist/types/app-bundle.types.d.ts.map +1 -0
  185. package/dist/{install → types}/app-installation.types.d.ts +27 -7
  186. package/dist/types/app-installation.types.d.ts.map +1 -0
  187. package/dist/types/app-manifest.types.d.ts +119 -0
  188. package/dist/types/app-manifest.types.d.ts.map +1 -0
  189. package/dist/types/app-manifest.types.js +11 -0
  190. package/dist/types/app-manifest.types.js.map +1 -0
  191. package/dist/{permissions → types}/app-permissions.types.d.ts +2 -2
  192. package/dist/types/app-permissions.types.d.ts.map +1 -0
  193. package/dist/{publish → types}/app-publish.types.d.ts +4 -4
  194. package/dist/types/app-publish.types.d.ts.map +1 -0
  195. package/dist/{publish → types}/app-publish.types.js +1 -1
  196. package/dist/types/app-publish.types.js.map +1 -0
  197. package/dist/{registry → types}/app-registry.types.d.ts +8 -4
  198. package/dist/types/app-registry.types.d.ts.map +1 -0
  199. package/dist/{registry → types}/app-remote-registry.types.d.ts +3 -3
  200. package/dist/types/app-remote-registry.types.d.ts.map +1 -0
  201. package/dist/{registry → types}/app-remote-registry.types.js +1 -1
  202. package/dist/types/app-remote-registry.types.js.map +1 -0
  203. package/dist/{runtime → types}/main-runner.types.d.ts +3 -3
  204. package/dist/types/main-runner.types.d.ts.map +1 -0
  205. package/package.json +10 -3
  206. package/dist/bridge/host-bridge.service.d.ts.map +0 -1
  207. package/dist/bridge/host-bridge.service.js.map +0 -1
  208. package/dist/bundle/app-bundle.service.d.ts.map +0 -1
  209. package/dist/bundle/app-bundle.service.js +0 -196
  210. package/dist/bundle/app-bundle.service.js.map +0 -1
  211. package/dist/bundle/app-bundle.types.d.ts.map +0 -1
  212. package/dist/cli/app-runtime-cli.service.d.ts.map +0 -1
  213. package/dist/cli/app-runtime-cli.service.js.map +0 -1
  214. package/dist/cli/app-runtime-options.service.d.ts.map +0 -1
  215. package/dist/cli/app-runtime-options.service.js.map +0 -1
  216. package/dist/commands/create.controller.d.ts.map +0 -1
  217. package/dist/commands/create.controller.js.map +0 -1
  218. package/dist/commands/dev.controller.js.map +0 -1
  219. package/dist/commands/grant.controller.d.ts.map +0 -1
  220. package/dist/commands/grant.controller.js.map +0 -1
  221. package/dist/commands/info.controller.d.ts.map +0 -1
  222. package/dist/commands/info.controller.js.map +0 -1
  223. package/dist/commands/inspect.controller.js.map +0 -1
  224. package/dist/commands/install.controller.d.ts.map +0 -1
  225. package/dist/commands/install.controller.js.map +0 -1
  226. package/dist/commands/list.controller.d.ts.map +0 -1
  227. package/dist/commands/list.controller.js.map +0 -1
  228. package/dist/commands/pack.controller.d.ts +0 -17
  229. package/dist/commands/pack.controller.d.ts.map +0 -1
  230. package/dist/commands/pack.controller.js.map +0 -1
  231. package/dist/commands/permissions.controller.d.ts.map +0 -1
  232. package/dist/commands/permissions.controller.js.map +0 -1
  233. package/dist/commands/publish.controller.d.ts.map +0 -1
  234. package/dist/commands/publish.controller.js.map +0 -1
  235. package/dist/commands/registry.controller.d.ts.map +0 -1
  236. package/dist/commands/registry.controller.js.map +0 -1
  237. package/dist/commands/revoke.controller.d.ts.map +0 -1
  238. package/dist/commands/revoke.controller.js.map +0 -1
  239. package/dist/commands/run.controller.js.map +0 -1
  240. package/dist/commands/uninstall.controller.d.ts.map +0 -1
  241. package/dist/commands/uninstall.controller.js.map +0 -1
  242. package/dist/commands/update.controller.d.ts.map +0 -1
  243. package/dist/commands/update.controller.js.map +0 -1
  244. package/dist/commands/validate-publish.controller.d.ts.map +0 -1
  245. package/dist/commands/validate-publish.controller.js.map +0 -1
  246. package/dist/host/app-host.service.d.ts.map +0 -1
  247. package/dist/host/app-host.service.js.map +0 -1
  248. package/dist/host/app-instance.service.d.ts +0 -34
  249. package/dist/host/app-instance.service.d.ts.map +0 -1
  250. package/dist/host/app-instance.service.js.map +0 -1
  251. package/dist/install/app-installation.service.d.ts.map +0 -1
  252. package/dist/install/app-installation.service.js +0 -276
  253. package/dist/install/app-installation.service.js.map +0 -1
  254. package/dist/install/app-installation.types.d.ts.map +0 -1
  255. package/dist/main.js.map +0 -1
  256. package/dist/manifest/app-manifest.service.d.ts.map +0 -1
  257. package/dist/manifest/app-manifest.service.js +0 -147
  258. package/dist/manifest/app-manifest.service.js.map +0 -1
  259. package/dist/manifest/app-manifest.types.d.ts +0 -68
  260. package/dist/manifest/app-manifest.types.d.ts.map +0 -1
  261. package/dist/paths/app-home.service.d.ts.map +0 -1
  262. package/dist/paths/app-home.service.js.map +0 -1
  263. package/dist/permissions/app-grant.service.d.ts.map +0 -1
  264. package/dist/permissions/app-grant.service.js.map +0 -1
  265. package/dist/permissions/app-permissions.service.d.ts.map +0 -1
  266. package/dist/permissions/app-permissions.service.js.map +0 -1
  267. package/dist/permissions/app-permissions.types.d.ts.map +0 -1
  268. package/dist/publish/app-marketplace-client.service.d.ts.map +0 -1
  269. package/dist/publish/app-marketplace-client.service.js.map +0 -1
  270. package/dist/publish/app-marketplace-metadata.service.d.ts.map +0 -1
  271. package/dist/publish/app-marketplace-metadata.service.js.map +0 -1
  272. package/dist/publish/app-publish-validation.service.d.ts.map +0 -1
  273. package/dist/publish/app-publish-validation.service.js.map +0 -1
  274. package/dist/publish/app-publish.service.d.ts.map +0 -1
  275. package/dist/publish/app-publish.service.js.map +0 -1
  276. package/dist/publish/app-publish.types.d.ts.map +0 -1
  277. package/dist/publish/app-publish.types.js.map +0 -1
  278. package/dist/publish/platform-auth-state.service.d.ts.map +0 -1
  279. package/dist/publish/platform-auth-state.service.js.map +0 -1
  280. package/dist/registry/app-registry-config.service.js.map +0 -1
  281. package/dist/registry/app-registry.service.d.ts.map +0 -1
  282. package/dist/registry/app-registry.service.js +0 -118
  283. package/dist/registry/app-registry.service.js.map +0 -1
  284. package/dist/registry/app-registry.types.d.ts.map +0 -1
  285. package/dist/registry/app-remote-registry-client.service.d.ts.map +0 -1
  286. package/dist/registry/app-remote-registry-client.service.js.map +0 -1
  287. package/dist/registry/app-remote-registry.types.d.ts.map +0 -1
  288. package/dist/registry/app-remote-registry.types.js.map +0 -1
  289. package/dist/runtime/app-build.service.d.ts.map +0 -1
  290. package/dist/runtime/app-build.service.js.map +0 -1
  291. package/dist/runtime/app-runtime-toolchain.service.d.ts.map +0 -1
  292. package/dist/runtime/app-runtime-toolchain.service.js.map +0 -1
  293. package/dist/runtime/main-runner.service.d.ts +0 -9
  294. package/dist/runtime/main-runner.service.d.ts.map +0 -1
  295. package/dist/runtime/main-runner.service.js +0 -6
  296. package/dist/runtime/main-runner.service.js.map +0 -1
  297. package/dist/runtime/main-runner.types.d.ts.map +0 -1
  298. package/dist/runtime/wasm-main-runner.service.d.ts.map +0 -1
  299. package/dist/runtime/wasm-main-runner.service.js.map +0 -1
  300. package/dist/runtime/wasmtime-wasi-http-component.service.d.ts.map +0 -1
  301. package/dist/runtime/wasmtime-wasi-http-component.service.js.map +0 -1
  302. package/dist/sidecar/wasm-sidecar-client.service.d.ts.map +0 -1
  303. package/dist/sidecar/wasm-sidecar-client.service.js.map +0 -1
  304. package/dist/ui/ui-server.service.d.ts.map +0 -1
  305. package/dist/ui/ui-server.service.js.map +0 -1
  306. /package/dist/{main.d.ts → app/main.d.ts} +0 -0
@@ -0,0 +1,271 @@
1
+ import { access, lstat, readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ //#region src/services/app-manifest.service.ts
4
+ const PACKAGE_ID_PATTERN = /^[a-z0-9]+(?:[.-][a-z0-9]+)*$/;
5
+ const COMPONENT_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
6
+ var AppManifestService = class {
7
+ load = async (appDirectory) => {
8
+ const normalizedDirectory = path.resolve(appDirectory);
9
+ const manifestPath = path.join(normalizedDirectory, "manifest.json");
10
+ const rawManifest = JSON.parse(await readFile(manifestPath, "utf-8"));
11
+ const manifest = this.parseManifest(rawManifest);
12
+ return manifest.schemaVersion === 1 ? await this.loadStandaloneBundle(normalizedDirectory, manifestPath, manifest) : await this.loadComponentBundle(normalizedDirectory, manifestPath, manifest);
13
+ };
14
+ summarize = (bundle) => {
15
+ if (bundle.manifest.schemaVersion === 2) {
16
+ const componentBundle = bundle;
17
+ return {
18
+ schemaVersion: 2,
19
+ id: componentBundle.manifest.id,
20
+ name: componentBundle.manifest.name,
21
+ version: componentBundle.manifest.version,
22
+ description: componentBundle.manifest.description,
23
+ manifestPath: componentBundle.manifestPath,
24
+ iconPath: componentBundle.iconPath,
25
+ primaryPanelId: componentBundle.primaryPanelId,
26
+ components: componentBundle.components
27
+ };
28
+ }
29
+ const standaloneBundle = bundle;
30
+ const permissions = standaloneBundle.manifest.permissions ?? {};
31
+ return {
32
+ schemaVersion: 1,
33
+ id: standaloneBundle.manifest.id,
34
+ name: standaloneBundle.manifest.name,
35
+ version: standaloneBundle.manifest.version,
36
+ description: standaloneBundle.manifest.description,
37
+ mainKind: standaloneBundle.manifest.main.kind,
38
+ action: standaloneBundle.manifest.main.kind === "wasm" ? standaloneBundle.manifest.main.action : void 0,
39
+ manifestPath: standaloneBundle.manifestPath,
40
+ mainEntryPath: standaloneBundle.mainEntryPath,
41
+ uiEntryPath: standaloneBundle.uiEntryPath,
42
+ iconPath: standaloneBundle.iconPath,
43
+ permissions
44
+ };
45
+ };
46
+ loadStandaloneBundle = async (appDirectory, manifestPath, manifest) => {
47
+ const mainEntryPath = await this.assertResolvedFile(appDirectory, manifest.main.entry, "main.entry");
48
+ const uiEntryPath = await this.assertResolvedFile(appDirectory, manifest.ui.entry, "ui.entry");
49
+ const iconPath = manifest.icon ? await this.assertResolvedFile(appDirectory, manifest.icon, "icon") : void 0;
50
+ return {
51
+ appDirectory,
52
+ manifestPath,
53
+ manifest,
54
+ mainEntryPath,
55
+ uiEntryPath,
56
+ uiDirectoryPath: path.dirname(uiEntryPath),
57
+ assetsDirectoryPath: path.join(appDirectory, "assets"),
58
+ iconPath
59
+ };
60
+ };
61
+ loadComponentBundle = async (appDirectory, manifestPath, manifest) => {
62
+ const components = [];
63
+ for (const [index, component] of manifest.components.entries()) {
64
+ const componentDirectory = await this.assertResolvedDirectory(appDirectory, component.path, `components[${index}].path`);
65
+ const componentId = await this.readComponentId(component, componentDirectory);
66
+ const expectedPrefix = `${manifest.id.replace(/[^a-z0-9]+/g, "-")}-`;
67
+ if (!componentId.startsWith(expectedPrefix)) throw new Error(`组件 ${componentId} 必须使用包前缀 ${expectedPrefix}。`);
68
+ components.push({
69
+ ...component,
70
+ id: componentId,
71
+ componentDirectory,
72
+ manifestPath: path.join(componentDirectory, component.kind === "panel" ? "panel-app.json" : "service-app.json")
73
+ });
74
+ }
75
+ const duplicateId = components.find((component, index) => components.findIndex((entry) => entry.id === component.id) !== index);
76
+ if (duplicateId) throw new Error(`components 包含重复组件 id:${duplicateId.id}`);
77
+ const panelIds = components.filter((component) => component.kind === "panel").map((component) => component.id);
78
+ const declaredPrimaryPanel = manifest.presentation?.primaryPanel;
79
+ if (declaredPrimaryPanel && !panelIds.includes(declaredPrimaryPanel)) throw new Error("presentation.primaryPanel 必须引用真实 Panel component id。");
80
+ if (panelIds.length > 1 && !declaredPrimaryPanel) throw new Error("包含多个 Panel 时必须声明 presentation.primaryPanel。");
81
+ if (panelIds.length === 0 && declaredPrimaryPanel) throw new Error("不含 Panel 的包不能声明 presentation.primaryPanel。");
82
+ const iconPath = manifest.icon ? await this.assertResolvedFile(appDirectory, manifest.icon, "icon") : void 0;
83
+ return {
84
+ appDirectory,
85
+ manifestPath,
86
+ manifest,
87
+ components,
88
+ assetsDirectoryPath: path.join(appDirectory, "assets"),
89
+ iconPath,
90
+ primaryPanelId: declaredPrimaryPanel ?? panelIds[0]
91
+ };
92
+ };
93
+ parseManifest = (rawManifest) => {
94
+ const candidate = this.assertObject(rawManifest, "manifest.json");
95
+ const schemaVersion = this.readNumber(candidate.schemaVersion, "schemaVersion");
96
+ if (schemaVersion !== 1 && schemaVersion !== 2) throw new Error("当前只支持 schemaVersion = 1 或 2。");
97
+ const common = this.parseCommonManifest(candidate);
98
+ if (schemaVersion === 1) return {
99
+ schemaVersion: 1,
100
+ ...common,
101
+ main: this.parseMain(candidate.main),
102
+ ui: this.parseUi(candidate.ui),
103
+ permissions: this.parsePermissions(candidate.permissions)
104
+ };
105
+ return {
106
+ schemaVersion: 2,
107
+ ...common,
108
+ engines: this.parseEngines(candidate.engines),
109
+ presentation: this.parsePresentation(candidate.presentation),
110
+ components: this.parseComponents(candidate.components)
111
+ };
112
+ };
113
+ parseCommonManifest = (candidate) => {
114
+ const id = this.readRequiredString(candidate.id, "id");
115
+ if (!PACKAGE_ID_PATTERN.test(id)) throw new Error("id 必须由小写字母、数字、点或连字符组成。");
116
+ return {
117
+ id,
118
+ name: this.readRequiredString(candidate.name, "name"),
119
+ version: this.readRequiredString(candidate.version, "version"),
120
+ description: this.readOptionalString(candidate.description, "description"),
121
+ icon: this.readOptionalString(candidate.icon, "icon")
122
+ };
123
+ };
124
+ parseMain = (rawMain) => {
125
+ const candidate = this.assertObject(rawMain, "main");
126
+ const kind = this.readRequiredString(candidate.kind, "main.kind");
127
+ if (kind === "wasm") return {
128
+ kind,
129
+ entry: this.readRequiredString(candidate.entry, "main.entry"),
130
+ export: this.readRequiredString(candidate.export, "main.export"),
131
+ action: this.readRequiredString(candidate.action, "main.action")
132
+ };
133
+ if (kind === "wasi-http-component") return {
134
+ kind,
135
+ entry: this.readRequiredString(candidate.entry, "main.entry")
136
+ };
137
+ throw new Error("当前 main.kind 只支持 wasm 或 wasi-http-component。");
138
+ };
139
+ parseUi = (rawUi) => {
140
+ const candidate = this.assertObject(rawUi, "ui");
141
+ return { entry: this.readRequiredString(candidate.entry, "ui.entry") };
142
+ };
143
+ parseComponents = (rawComponents) => {
144
+ if (!Array.isArray(rawComponents) || rawComponents.length === 0) throw new Error("components 必须是非空数组。");
145
+ const components = rawComponents.map((rawComponent, index) => {
146
+ const candidate = this.assertObject(rawComponent, `components[${index}]`);
147
+ const kind = this.readRequiredString(candidate.kind, `components[${index}].kind`);
148
+ if (kind !== "panel" && kind !== "service") throw new Error(`components[${index}].kind 只支持 panel 或 service。`);
149
+ return {
150
+ kind,
151
+ path: this.normalizeRelativePath(this.readRequiredString(candidate.path, `components[${index}].path`), `components[${index}].path`)
152
+ };
153
+ });
154
+ for (let leftIndex = 0; leftIndex < components.length; leftIndex += 1) for (let rightIndex = leftIndex + 1; rightIndex < components.length; rightIndex += 1) {
155
+ const left = components[leftIndex]?.path;
156
+ const right = components[rightIndex]?.path;
157
+ if (left && right && (left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`))) throw new Error(`components path 不能重复或重叠:${left} / ${right}`);
158
+ }
159
+ return components;
160
+ };
161
+ parseEngines = (rawEngines) => {
162
+ if (rawEngines === void 0) return;
163
+ const candidate = this.assertObject(rawEngines, "engines");
164
+ return { nextclaw: this.readOptionalString(candidate.nextclaw, "engines.nextclaw") };
165
+ };
166
+ parsePresentation = (rawPresentation) => {
167
+ if (rawPresentation === void 0) return;
168
+ const candidate = this.assertObject(rawPresentation, "presentation");
169
+ return { primaryPanel: this.readOptionalString(candidate.primaryPanel, "presentation.primaryPanel") };
170
+ };
171
+ readComponentId = async (component, componentDirectory) => {
172
+ const manifestFile = component.kind === "panel" ? "panel-app.json" : "service-app.json";
173
+ const raw = JSON.parse(await readFile(path.join(componentDirectory, manifestFile), "utf-8"));
174
+ const manifest = this.assertObject(raw, `${component.path}/${manifestFile}`);
175
+ const id = this.readRequiredString(manifest.id, `${component.path}/${manifestFile}.id`);
176
+ if (!COMPONENT_ID_PATTERN.test(id)) throw new Error(`组件 id 必须是 kebab-case:${id}`);
177
+ const directoryName = path.basename(componentDirectory);
178
+ const expectedId = component.kind === "panel" ? directoryName.replace(/\.panel$/, "") : directoryName;
179
+ if (component.kind === "panel" && !directoryName.endsWith(".panel")) throw new Error(`Panel component 目录必须以 .panel 结尾:${component.path}`);
180
+ if (id !== expectedId) throw new Error(`组件 id 必须与目录名一致:期望 ${expectedId},实际 ${id}`);
181
+ return id;
182
+ };
183
+ parsePermissions = (rawPermissions) => {
184
+ if (rawPermissions === void 0) return;
185
+ const candidate = this.assertObject(rawPermissions, "permissions");
186
+ return {
187
+ documentAccess: this.parseDocumentAccess(candidate.documentAccess),
188
+ allowedDomains: this.parseStringArray(candidate.allowedDomains, "permissions.allowedDomains"),
189
+ storage: this.parseStorage(candidate.storage),
190
+ capabilities: this.parseCapabilities(candidate.capabilities)
191
+ };
192
+ };
193
+ parseDocumentAccess = (rawDocumentAccess) => {
194
+ if (rawDocumentAccess === void 0) return;
195
+ if (!Array.isArray(rawDocumentAccess)) throw new Error("permissions.documentAccess 必须是数组。");
196
+ return rawDocumentAccess.map((scope, index) => {
197
+ const candidate = this.assertObject(scope, `permissions.documentAccess[${index}]`);
198
+ const mode = this.readRequiredString(candidate.mode, `permissions.documentAccess[${index}].mode`);
199
+ if (mode !== "read" && mode !== "read-write") throw new Error(`permissions.documentAccess[${index}].mode 只支持 read 或 read-write。`);
200
+ return {
201
+ id: this.readRequiredString(candidate.id, `permissions.documentAccess[${index}].id`),
202
+ mode,
203
+ description: this.readOptionalString(candidate.description, `permissions.documentAccess[${index}].description`)
204
+ };
205
+ });
206
+ };
207
+ parseStringArray = (rawValue, fieldName) => {
208
+ if (rawValue === void 0) return;
209
+ if (!Array.isArray(rawValue)) throw new Error(`${fieldName} 必须是字符串数组。`);
210
+ return rawValue.map((item, index) => this.readRequiredString(item, `${fieldName}[${index}]`));
211
+ };
212
+ parseStorage = (rawStorage) => {
213
+ if (rawStorage === void 0 || typeof rawStorage === "boolean") return rawStorage;
214
+ const candidate = this.assertObject(rawStorage, "permissions.storage");
215
+ return { namespace: this.readOptionalString(candidate.namespace, "permissions.storage.namespace") };
216
+ };
217
+ parseCapabilities = (rawCapabilities) => {
218
+ if (rawCapabilities === void 0) return;
219
+ const candidate = this.assertObject(rawCapabilities, "permissions.capabilities");
220
+ return { hostBridge: candidate.hostBridge === void 0 ? void 0 : this.readBoolean(candidate.hostBridge, "permissions.capabilities.hostBridge") };
221
+ };
222
+ assertResolvedFile = async (appDirectory, relativePath, fieldName) => {
223
+ const resolvedPath = this.resolveInside(appDirectory, relativePath, fieldName);
224
+ const stats = await lstat(resolvedPath);
225
+ if (!stats.isFile() || stats.isSymbolicLink()) throw new Error(`${fieldName} 必须指向包内普通文件。`);
226
+ return resolvedPath;
227
+ };
228
+ assertResolvedDirectory = async (appDirectory, relativePath, fieldName) => {
229
+ const resolvedPath = this.resolveInside(appDirectory, relativePath, fieldName);
230
+ const stats = await lstat(resolvedPath);
231
+ if (!stats.isDirectory() || stats.isSymbolicLink()) throw new Error(`${fieldName} 必须指向包内普通目录。`);
232
+ await access(resolvedPath);
233
+ return resolvedPath;
234
+ };
235
+ resolveInside = (appDirectory, relativePath, fieldName) => {
236
+ const normalizedPath = this.normalizeRelativePath(relativePath, fieldName);
237
+ const resolvedPath = path.resolve(appDirectory, normalizedPath);
238
+ const relative = path.relative(appDirectory, resolvedPath);
239
+ if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`${fieldName} 不能指向应用目录之外。`);
240
+ return resolvedPath;
241
+ };
242
+ normalizeRelativePath = (relativePath, fieldName) => {
243
+ if (path.isAbsolute(relativePath) || relativePath.includes("\0")) throw new Error(`${fieldName} 必须使用包内相对路径。`);
244
+ const segments = relativePath.replace(/\\/g, "/").split("/");
245
+ if (segments.some((segment) => !segment || segment === "." || segment === "..")) throw new Error(`${fieldName} 包含非法路径片段。`);
246
+ return segments.join("/");
247
+ };
248
+ assertObject = (value, fieldName) => {
249
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${fieldName} 必须是对象。`);
250
+ return value;
251
+ };
252
+ readRequiredString = (value, fieldName) => {
253
+ if (typeof value !== "string" || !value.trim()) throw new Error(`${fieldName} 必须是非空字符串。`);
254
+ return value.trim();
255
+ };
256
+ readOptionalString = (value, fieldName) => {
257
+ return value === void 0 ? void 0 : this.readRequiredString(value, fieldName);
258
+ };
259
+ readNumber = (value, fieldName) => {
260
+ if (typeof value !== "number" || Number.isNaN(value)) throw new Error(`${fieldName} 必须是数字。`);
261
+ return value;
262
+ };
263
+ readBoolean = (value, fieldName) => {
264
+ if (typeof value !== "boolean") throw new Error(`${fieldName} 必须是布尔值。`);
265
+ return value;
266
+ };
267
+ };
268
+ //#endregion
269
+ export { AppManifestService };
270
+
271
+ //# sourceMappingURL=app-manifest.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-manifest.service.js","names":[],"sources":["../../src/services/app-manifest.service.ts"],"sourcesContent":["import { access, lstat, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type {\n AppComponentManifest,\n AppComponentManifestBundle,\n AppComponentReference,\n AppDocumentAccessScope,\n AppManifest,\n AppManifestBundle,\n AppManifestSummary,\n AppPermissions,\n AppResolvedComponent,\n AppStandaloneManifest,\n AppStandaloneManifestBundle,\n} from \"#app-runtime/types/app-manifest.types.js\";\n\nconst PACKAGE_ID_PATTERN = /^[a-z0-9]+(?:[.-][a-z0-9]+)*$/;\nconst COMPONENT_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\nexport class AppManifestService {\n load = async (appDirectory: string): Promise<AppManifestBundle> => {\n const normalizedDirectory = path.resolve(appDirectory);\n const manifestPath = path.join(normalizedDirectory, \"manifest.json\");\n const rawManifest = JSON.parse(await readFile(manifestPath, \"utf-8\")) as unknown;\n const manifest = this.parseManifest(rawManifest);\n return manifest.schemaVersion === 1\n ? await this.loadStandaloneBundle(normalizedDirectory, manifestPath, manifest)\n : await this.loadComponentBundle(normalizedDirectory, manifestPath, manifest);\n };\n\n summarize = (bundle: AppManifestBundle): AppManifestSummary => {\n if (bundle.manifest.schemaVersion === 2) {\n const componentBundle = bundle as AppComponentManifestBundle;\n return {\n schemaVersion: 2,\n id: componentBundle.manifest.id,\n name: componentBundle.manifest.name,\n version: componentBundle.manifest.version,\n description: componentBundle.manifest.description,\n manifestPath: componentBundle.manifestPath,\n iconPath: componentBundle.iconPath,\n primaryPanelId: componentBundle.primaryPanelId,\n components: componentBundle.components,\n };\n }\n const standaloneBundle = bundle as AppStandaloneManifestBundle;\n const permissions = standaloneBundle.manifest.permissions ?? {};\n return {\n schemaVersion: 1,\n id: standaloneBundle.manifest.id,\n name: standaloneBundle.manifest.name,\n version: standaloneBundle.manifest.version,\n description: standaloneBundle.manifest.description,\n mainKind: standaloneBundle.manifest.main.kind,\n action:\n standaloneBundle.manifest.main.kind === \"wasm\"\n ? standaloneBundle.manifest.main.action\n : undefined,\n manifestPath: standaloneBundle.manifestPath,\n mainEntryPath: standaloneBundle.mainEntryPath,\n uiEntryPath: standaloneBundle.uiEntryPath,\n iconPath: standaloneBundle.iconPath,\n permissions,\n };\n };\n\n private loadStandaloneBundle = async (\n appDirectory: string,\n manifestPath: string,\n manifest: AppStandaloneManifest,\n ): Promise<AppStandaloneManifestBundle> => {\n const mainEntryPath = await this.assertResolvedFile(\n appDirectory,\n manifest.main.entry,\n \"main.entry\",\n );\n const uiEntryPath = await this.assertResolvedFile(\n appDirectory,\n manifest.ui.entry,\n \"ui.entry\",\n );\n const iconPath = manifest.icon\n ? await this.assertResolvedFile(appDirectory, manifest.icon, \"icon\")\n : undefined;\n return {\n appDirectory,\n manifestPath,\n manifest,\n mainEntryPath,\n uiEntryPath,\n uiDirectoryPath: path.dirname(uiEntryPath),\n assetsDirectoryPath: path.join(appDirectory, \"assets\"),\n iconPath,\n };\n };\n\n private loadComponentBundle = async (\n appDirectory: string,\n manifestPath: string,\n manifest: AppComponentManifest,\n ): Promise<AppComponentManifestBundle> => {\n const components: AppResolvedComponent[] = [];\n for (const [index, component] of manifest.components.entries()) {\n const componentDirectory = await this.assertResolvedDirectory(\n appDirectory,\n component.path,\n `components[${index}].path`,\n );\n const componentId = await this.readComponentId(component, componentDirectory);\n const expectedPrefix = `${manifest.id.replace(/[^a-z0-9]+/g, \"-\")}-`;\n if (!componentId.startsWith(expectedPrefix)) {\n throw new Error(\n `组件 ${componentId} 必须使用包前缀 ${expectedPrefix}。`,\n );\n }\n components.push({\n ...component,\n id: componentId,\n componentDirectory,\n manifestPath: path.join(\n componentDirectory,\n component.kind === \"panel\" ? \"panel-app.json\" : \"service-app.json\",\n ),\n });\n }\n const duplicateId = components.find(\n (component, index) => components.findIndex((entry) => entry.id === component.id) !== index,\n );\n if (duplicateId) {\n throw new Error(`components 包含重复组件 id:${duplicateId.id}`);\n }\n const panelIds = components\n .filter((component) => component.kind === \"panel\")\n .map((component) => component.id);\n const declaredPrimaryPanel = manifest.presentation?.primaryPanel;\n if (declaredPrimaryPanel && !panelIds.includes(declaredPrimaryPanel)) {\n throw new Error(\"presentation.primaryPanel 必须引用真实 Panel component id。\");\n }\n if (panelIds.length > 1 && !declaredPrimaryPanel) {\n throw new Error(\"包含多个 Panel 时必须声明 presentation.primaryPanel。\");\n }\n if (panelIds.length === 0 && declaredPrimaryPanel) {\n throw new Error(\"不含 Panel 的包不能声明 presentation.primaryPanel。\");\n }\n const iconPath = manifest.icon\n ? await this.assertResolvedFile(appDirectory, manifest.icon, \"icon\")\n : undefined;\n return {\n appDirectory,\n manifestPath,\n manifest,\n components,\n assetsDirectoryPath: path.join(appDirectory, \"assets\"),\n iconPath,\n primaryPanelId: declaredPrimaryPanel ?? panelIds[0],\n };\n };\n\n private parseManifest = (rawManifest: unknown): AppManifest => {\n const candidate = this.assertObject(rawManifest, \"manifest.json\");\n const schemaVersion = this.readNumber(candidate.schemaVersion, \"schemaVersion\");\n if (schemaVersion !== 1 && schemaVersion !== 2) {\n throw new Error(\"当前只支持 schemaVersion = 1 或 2。\");\n }\n const common = this.parseCommonManifest(candidate);\n if (schemaVersion === 1) {\n return {\n schemaVersion: 1,\n ...common,\n main: this.parseMain(candidate.main),\n ui: this.parseUi(candidate.ui),\n permissions: this.parsePermissions(candidate.permissions),\n };\n }\n return {\n schemaVersion: 2,\n ...common,\n engines: this.parseEngines(candidate.engines),\n presentation: this.parsePresentation(candidate.presentation),\n components: this.parseComponents(candidate.components),\n };\n };\n\n private parseCommonManifest = (candidate: Record<string, unknown>) => {\n const id = this.readRequiredString(candidate.id, \"id\");\n if (!PACKAGE_ID_PATTERN.test(id)) {\n throw new Error(\"id 必须由小写字母、数字、点或连字符组成。\");\n }\n return {\n id,\n name: this.readRequiredString(candidate.name, \"name\"),\n version: this.readRequiredString(candidate.version, \"version\"),\n description: this.readOptionalString(candidate.description, \"description\"),\n icon: this.readOptionalString(candidate.icon, \"icon\"),\n };\n };\n\n private parseMain = (rawMain: unknown): AppStandaloneManifest[\"main\"] => {\n const candidate = this.assertObject(rawMain, \"main\");\n const kind = this.readRequiredString(candidate.kind, \"main.kind\");\n if (kind === \"wasm\") {\n return {\n kind,\n entry: this.readRequiredString(candidate.entry, \"main.entry\"),\n export: this.readRequiredString(candidate.export, \"main.export\"),\n action: this.readRequiredString(candidate.action, \"main.action\"),\n };\n }\n if (kind === \"wasi-http-component\") {\n return {\n kind,\n entry: this.readRequiredString(candidate.entry, \"main.entry\"),\n };\n }\n throw new Error(\"当前 main.kind 只支持 wasm 或 wasi-http-component。\");\n };\n\n private parseUi = (rawUi: unknown): AppStandaloneManifest[\"ui\"] => {\n const candidate = this.assertObject(rawUi, \"ui\");\n return { entry: this.readRequiredString(candidate.entry, \"ui.entry\") };\n };\n\n private parseComponents = (rawComponents: unknown): AppComponentReference[] => {\n if (!Array.isArray(rawComponents) || rawComponents.length === 0) {\n throw new Error(\"components 必须是非空数组。\");\n }\n const components = rawComponents.map((rawComponent, index) => {\n const candidate = this.assertObject(rawComponent, `components[${index}]`);\n const kind = this.readRequiredString(candidate.kind, `components[${index}].kind`);\n if (kind !== \"panel\" && kind !== \"service\") {\n throw new Error(`components[${index}].kind 只支持 panel 或 service。`);\n }\n const normalizedKind: AppComponentReference[\"kind\"] = kind;\n return {\n kind: normalizedKind,\n path: this.normalizeRelativePath(\n this.readRequiredString(candidate.path, `components[${index}].path`),\n `components[${index}].path`,\n ),\n };\n });\n for (let leftIndex = 0; leftIndex < components.length; leftIndex += 1) {\n for (let rightIndex = leftIndex + 1; rightIndex < components.length; rightIndex += 1) {\n const left = components[leftIndex]?.path;\n const right = components[rightIndex]?.path;\n if (left && right && (left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`))) {\n throw new Error(`components path 不能重复或重叠:${left} / ${right}`);\n }\n }\n }\n return components;\n };\n\n private parseEngines = (\n rawEngines: unknown,\n ): AppComponentManifest[\"engines\"] => {\n if (rawEngines === undefined) {\n return undefined;\n }\n const candidate = this.assertObject(rawEngines, \"engines\");\n return { nextclaw: this.readOptionalString(candidate.nextclaw, \"engines.nextclaw\") };\n };\n\n private parsePresentation = (\n rawPresentation: unknown,\n ): AppComponentManifest[\"presentation\"] => {\n if (rawPresentation === undefined) {\n return undefined;\n }\n const candidate = this.assertObject(rawPresentation, \"presentation\");\n return {\n primaryPanel: this.readOptionalString(\n candidate.primaryPanel,\n \"presentation.primaryPanel\",\n ),\n };\n };\n\n private readComponentId = async (\n component: AppComponentReference,\n componentDirectory: string,\n ): Promise<string> => {\n const manifestFile = component.kind === \"panel\" ? \"panel-app.json\" : \"service-app.json\";\n const raw = JSON.parse(\n await readFile(path.join(componentDirectory, manifestFile), \"utf-8\"),\n ) as unknown;\n const manifest = this.assertObject(raw, `${component.path}/${manifestFile}`);\n const id = this.readRequiredString(manifest.id, `${component.path}/${manifestFile}.id`);\n if (!COMPONENT_ID_PATTERN.test(id)) {\n throw new Error(`组件 id 必须是 kebab-case:${id}`);\n }\n const directoryName = path.basename(componentDirectory);\n const expectedId = component.kind === \"panel\"\n ? directoryName.replace(/\\.panel$/, \"\")\n : directoryName;\n if (component.kind === \"panel\" && !directoryName.endsWith(\".panel\")) {\n throw new Error(`Panel component 目录必须以 .panel 结尾:${component.path}`);\n }\n if (id !== expectedId) {\n throw new Error(`组件 id 必须与目录名一致:期望 ${expectedId},实际 ${id}`);\n }\n return id;\n };\n\n private parsePermissions = (rawPermissions: unknown): AppPermissions | undefined => {\n if (rawPermissions === undefined) {\n return undefined;\n }\n const candidate = this.assertObject(rawPermissions, \"permissions\");\n return {\n documentAccess: this.parseDocumentAccess(candidate.documentAccess),\n allowedDomains: this.parseStringArray(candidate.allowedDomains, \"permissions.allowedDomains\"),\n storage: this.parseStorage(candidate.storage),\n capabilities: this.parseCapabilities(candidate.capabilities),\n };\n };\n\n private parseDocumentAccess = (rawDocumentAccess: unknown): AppDocumentAccessScope[] | undefined => {\n if (rawDocumentAccess === undefined) {\n return undefined;\n }\n if (!Array.isArray(rawDocumentAccess)) {\n throw new Error(\"permissions.documentAccess 必须是数组。\");\n }\n return rawDocumentAccess.map((scope, index) => {\n const candidate = this.assertObject(scope, `permissions.documentAccess[${index}]`);\n const mode = this.readRequiredString(candidate.mode, `permissions.documentAccess[${index}].mode`);\n if (mode !== \"read\" && mode !== \"read-write\") {\n throw new Error(`permissions.documentAccess[${index}].mode 只支持 read 或 read-write。`);\n }\n return {\n id: this.readRequiredString(candidate.id, `permissions.documentAccess[${index}].id`),\n mode,\n description: this.readOptionalString(\n candidate.description,\n `permissions.documentAccess[${index}].description`,\n ),\n };\n });\n };\n\n private parseStringArray = (rawValue: unknown, fieldName: string): string[] | undefined => {\n if (rawValue === undefined) {\n return undefined;\n }\n if (!Array.isArray(rawValue)) {\n throw new Error(`${fieldName} 必须是字符串数组。`);\n }\n return rawValue.map((item, index) => this.readRequiredString(item, `${fieldName}[${index}]`));\n };\n\n private parseStorage = (rawStorage: unknown): AppPermissions[\"storage\"] | undefined => {\n if (rawStorage === undefined || typeof rawStorage === \"boolean\") {\n return rawStorage;\n }\n const candidate = this.assertObject(rawStorage, \"permissions.storage\");\n return { namespace: this.readOptionalString(candidate.namespace, \"permissions.storage.namespace\") };\n };\n\n private parseCapabilities = (rawCapabilities: unknown): AppPermissions[\"capabilities\"] | undefined => {\n if (rawCapabilities === undefined) {\n return undefined;\n }\n const candidate = this.assertObject(rawCapabilities, \"permissions.capabilities\");\n return {\n hostBridge: candidate.hostBridge === undefined\n ? undefined\n : this.readBoolean(candidate.hostBridge, \"permissions.capabilities.hostBridge\"),\n };\n };\n\n private assertResolvedFile = async (\n appDirectory: string,\n relativePath: string,\n fieldName: string,\n ): Promise<string> => {\n const resolvedPath = this.resolveInside(appDirectory, relativePath, fieldName);\n const stats = await lstat(resolvedPath);\n if (!stats.isFile() || stats.isSymbolicLink()) {\n throw new Error(`${fieldName} 必须指向包内普通文件。`);\n }\n return resolvedPath;\n };\n\n private assertResolvedDirectory = async (\n appDirectory: string,\n relativePath: string,\n fieldName: string,\n ): Promise<string> => {\n const resolvedPath = this.resolveInside(appDirectory, relativePath, fieldName);\n const stats = await lstat(resolvedPath);\n if (!stats.isDirectory() || stats.isSymbolicLink()) {\n throw new Error(`${fieldName} 必须指向包内普通目录。`);\n }\n await access(resolvedPath);\n return resolvedPath;\n };\n\n private resolveInside = (appDirectory: string, relativePath: string, fieldName: string): string => {\n const normalizedPath = this.normalizeRelativePath(relativePath, fieldName);\n const resolvedPath = path.resolve(appDirectory, normalizedPath);\n const relative = path.relative(appDirectory, resolvedPath);\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new Error(`${fieldName} 不能指向应用目录之外。`);\n }\n return resolvedPath;\n };\n\n private normalizeRelativePath = (relativePath: string, fieldName: string): string => {\n if (path.isAbsolute(relativePath) || relativePath.includes(\"\\0\")) {\n throw new Error(`${fieldName} 必须使用包内相对路径。`);\n }\n const segments = relativePath.replace(/\\\\/g, \"/\").split(\"/\");\n if (segments.some((segment) => !segment || segment === \".\" || segment === \"..\")) {\n throw new Error(`${fieldName} 包含非法路径片段。`);\n }\n return segments.join(\"/\");\n };\n\n private assertObject = (value: unknown, fieldName: string): Record<string, unknown> => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`${fieldName} 必须是对象。`);\n }\n return value as Record<string, unknown>;\n };\n\n private readRequiredString = (value: unknown, fieldName: string): string => {\n if (typeof value !== \"string\" || !value.trim()) {\n throw new Error(`${fieldName} 必须是非空字符串。`);\n }\n return value.trim();\n };\n\n private readOptionalString = (value: unknown, fieldName: string): string | undefined => {\n return value === undefined ? undefined : this.readRequiredString(value, fieldName);\n };\n\n private readNumber = (value: unknown, fieldName: string): number => {\n if (typeof value !== \"number\" || Number.isNaN(value)) {\n throw new Error(`${fieldName} 必须是数字。`);\n }\n return value;\n };\n\n private readBoolean = (value: unknown, fieldName: string): boolean => {\n if (typeof value !== \"boolean\") {\n throw new Error(`${fieldName} 必须是布尔值。`);\n }\n return value;\n };\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { AppPublishPayload, AppPublishResult } from "./app-publish.types.js";
1
+ import { AppPublishPayload, AppPublishResult } from "../types/app-publish.types.js";
2
2
 
3
- //#region src/publish/app-marketplace-client.service.d.ts
3
+ //#region src/services/app-marketplace-client.service.d.ts
4
4
  declare class AppMarketplaceClientService {
5
5
  publish: (params: {
6
6
  payload: AppPublishPayload;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-marketplace-client.service.d.ts","names":[],"sources":["../../src/services/app-marketplace-client.service.ts"],"mappings":";;;cAGa,2BAAA;EACX,OAAA,GAAiB,MAAA;IACf,OAAA,EAAS,iBAAA;IACT,UAAA;IACA,KAAA;EAAA,MACE,OAAA,CAAQ,gBAAA;EAAA,QAyCJ,gBAAA;AAAA"}
@@ -1,5 +1,5 @@
1
- import "./app-publish.types.js";
2
- //#region src/publish/app-marketplace-client.service.ts
1
+ import "../types/app-publish.types.js";
2
+ //#region src/services/app-marketplace-client.service.ts
3
3
  var AppMarketplaceClientService = class {
4
4
  publish = async (params) => {
5
5
  const apiBaseUrl = this.normalizeApiBase(params.apiBaseUrl ?? "https://apps-registry.nextclaw.io");
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-marketplace-client.service.js","names":[],"sources":["../../src/services/app-marketplace-client.service.ts"],"sourcesContent":["import type { AppPublishPayload, AppPublishResult } from \"#app-runtime/types/app-publish.types.js\";\nimport { DEFAULT_APP_MARKETPLACE_API_BASE } from \"#app-runtime/types/app-publish.types.js\";\n\nexport class AppMarketplaceClientService {\n publish = async (params: {\n payload: AppPublishPayload;\n apiBaseUrl?: string;\n token?: string;\n }): Promise<AppPublishResult> => {\n const apiBaseUrl = this.normalizeApiBase(\n params.apiBaseUrl ?? DEFAULT_APP_MARKETPLACE_API_BASE,\n );\n const token = params.token?.trim();\n if (!token) {\n throw new Error(\"缺少 marketplace publish token。请先登录 NextClaw,或传入 --token。\");\n }\n const response = await fetch(`${apiBaseUrl}/api/v1/apps/publish`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n authorization: `Bearer ${token}`,\n accept: \"application/json\",\n },\n body: JSON.stringify(params.payload),\n });\n const payload = await response.json().catch(() => null);\n if (!response.ok) {\n const message =\n typeof payload === \"object\" &&\n payload &&\n \"error\" in payload &&\n typeof (payload as { error?: { message?: unknown } }).error?.message === \"string\"\n ? (payload as { error: { message: string } }).error.message\n : `${response.status} ${response.statusText}`;\n throw new Error(`发布 app 失败:${message}`);\n }\n const data =\n typeof payload === \"object\" &&\n payload &&\n \"data\" in payload &&\n typeof (payload as { data?: unknown }).data === \"object\"\n ? (payload as { data: AppPublishResult }).data\n : null;\n if (!data) {\n throw new Error(\"marketplace publish 返回格式无效。\");\n }\n return data;\n };\n\n private normalizeApiBase = (apiBaseUrl: string): string => {\n const normalized = new URL(apiBaseUrl);\n return normalized.toString().replace(/\\/+$/, \"\");\n };\n}\n"],"mappings":";;AAGA,IAAa,8BAAb,MAAyC;CACvC,UAAU,OAAO,WAIgB;EAC/B,MAAM,aAAa,KAAK,iBACtB,OAAO,cAAA,oCACR;EACD,MAAM,QAAQ,OAAO,OAAO,MAAM;AAClC,MAAI,CAAC,MACH,OAAM,IAAI,MAAM,0DAA0D;EAE5E,MAAM,WAAW,MAAM,MAAM,GAAG,WAAW,uBAAuB;GAChE,QAAQ;GACR,SAAS;IACP,gBAAgB;IAChB,eAAe,UAAU;IACzB,QAAQ;IACT;GACD,MAAM,KAAK,UAAU,OAAO,QAAQ;GACrC,CAAC;EACF,MAAM,UAAU,MAAM,SAAS,MAAM,CAAC,YAAY,KAAK;AACvD,MAAI,CAAC,SAAS,IAAI;GAChB,MAAM,UACJ,OAAO,YAAY,YACnB,WACA,WAAW,WACX,OAAQ,QAA8C,OAAO,YAAY,WACpE,QAA2C,MAAM,UAClD,GAAG,SAAS,OAAO,GAAG,SAAS;AACrC,SAAM,IAAI,MAAM,aAAa,UAAU;;EAEzC,MAAM,OACJ,OAAO,YAAY,YACnB,WACA,UAAU,WACV,OAAQ,QAA+B,SAAS,WAC3C,QAAuC,OACxC;AACN,MAAI,CAAC,KACH,OAAM,IAAI,MAAM,8BAA8B;AAEhD,SAAO;;CAGT,oBAA4B,eAA+B;AAEzD,SADmB,IAAI,IAAI,WAAW,CACpB,UAAU,CAAC,QAAQ,QAAQ,GAAG"}
@@ -1,7 +1,7 @@
1
- import { AppManifest } from "../manifest/app-manifest.types.js";
2
- import { AppMarketplaceMetadata } from "./app-publish.types.js";
1
+ import { AppManifest } from "../types/app-manifest.types.js";
2
+ import { AppMarketplaceMetadata } from "../types/app-publish.types.js";
3
3
 
4
- //#region src/publish/app-marketplace-metadata.service.d.ts
4
+ //#region src/services/app-marketplace-metadata.service.d.ts
5
5
  declare class AppMarketplaceMetadataService {
6
6
  load: (params: {
7
7
  appDirectory: string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-marketplace-metadata.service.d.ts","names":[],"sources":["../../src/services/app-marketplace-metadata.service.ts"],"mappings":";;;;cAMa,6BAAA;EACX,IAAA,GAAc,MAAA;IACZ,YAAA;IACA,QAAA,EAAU,WAAA;IACV,YAAA;EAAA,MACE,OAAA,CAAQ,sBAAA;EASZ,mBAAA,GAA6B,MAAA;IAC3B,YAAA;IACA,YAAA;EAAA,MACE,OAAA,CAAQ,KAAA;IAAQ,IAAA;IAAc,KAAA,EAAO,MAAA;EAAA;EAAA,QAoBjC,aAAA;EAAA,QA+BA,cAAA;EAAA,QAiBA,kBAAA;EAAA,QAOA,kBAAA;EAAA,QAUA,eAAA;EAAA,QASA,mBAAA;EAAA,QAaA,oBAAA;AAAA"}
@@ -1,7 +1,7 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { existsSync } from "node:fs";
4
- //#region src/publish/app-marketplace-metadata.service.ts
4
+ //#region src/services/app-marketplace-metadata.service.ts
5
5
  var AppMarketplaceMetadataService = class {
6
6
  load = async (params) => {
7
7
  const { appDirectory, manifest, metadataPath: customMetadataPath } = params;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-marketplace-metadata.service.js","names":[],"sources":["../../src/services/app-marketplace-metadata.service.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { AppManifest } from \"#app-runtime/types/app-manifest.types.js\";\nimport type { AppMarketplaceMetadata } from \"#app-runtime/types/app-publish.types.js\";\n\nexport class AppMarketplaceMetadataService {\n load = async (params: {\n appDirectory: string;\n manifest: AppManifest;\n metadataPath?: string;\n }): Promise<AppMarketplaceMetadata> => {\n const { appDirectory, manifest, metadataPath: customMetadataPath } = params;\n const metadataPath = customMetadataPath\n ? path.resolve(customMetadataPath)\n : path.join(path.resolve(appDirectory), \"marketplace.json\");\n const raw = JSON.parse(await readFile(metadataPath, \"utf-8\")) as unknown;\n return this.parseMetadata(raw, manifest);\n };\n\n collectPublishFiles = async (params: {\n appDirectory: string;\n metadataPath?: string;\n }): Promise<Array<{ path: string; bytes: Buffer }>> => {\n const appDirectory = path.resolve(params.appDirectory);\n const publishFiles: Array<{ path: string; bytes: Buffer }> = [];\n const metadataPath = params.metadataPath\n ? path.resolve(params.metadataPath)\n : path.join(appDirectory, \"marketplace.json\");\n publishFiles.push({\n path: \"marketplace.json\",\n bytes: Buffer.from(await readFile(metadataPath)),\n });\n const readmePath = path.join(appDirectory, \"README.md\");\n if (existsSync(readmePath)) {\n publishFiles.push({\n path: \"README.md\",\n bytes: Buffer.from(await readFile(readmePath)),\n });\n }\n return publishFiles;\n };\n\n private parseMetadata = (\n rawMetadata: unknown,\n manifest: AppManifest,\n ): AppMarketplaceMetadata => {\n if (!rawMetadata || typeof rawMetadata !== \"object\" || Array.isArray(rawMetadata)) {\n throw new Error(\"marketplace.json 必须是对象。\");\n }\n const candidate = rawMetadata as Record<string, unknown>;\n const slug = this.readRequiredString(candidate.slug, \"slug\");\n const summary = this.readRequiredString(candidate.summary, \"summary\");\n const description = this.readOptionalString(candidate.description, \"description\");\n const author =\n this.readOptionalString(candidate.author, \"author\") ?? manifest.name;\n const publisher = this.parsePublisher(candidate.publisher);\n return {\n slug,\n summary,\n summaryI18n: this.readLocalizedTextMap(candidate.summaryI18n, \"summaryI18n\", summary),\n description,\n descriptionI18n: description\n ? this.readLocalizedTextMap(candidate.descriptionI18n, \"descriptionI18n\", description)\n : undefined,\n author,\n tags: this.readStringArray(candidate.tags, \"tags\"),\n sourceRepo: this.readOptionalString(candidate.sourceRepo, \"sourceRepo\"),\n homepage: this.readOptionalString(candidate.homepage, \"homepage\"),\n featured: this.readOptionalBoolean(candidate.featured, \"featured\") ?? false,\n publisher,\n };\n };\n\n private parsePublisher = (\n rawPublisher: unknown,\n ): AppMarketplaceMetadata[\"publisher\"] => {\n if (rawPublisher === undefined) {\n return undefined;\n }\n if (!rawPublisher || typeof rawPublisher !== \"object\" || Array.isArray(rawPublisher)) {\n throw new Error(\"publisher 必须是对象。\");\n }\n const candidate = rawPublisher as Record<string, unknown>;\n return {\n id: this.readRequiredString(candidate.id, \"publisher.id\"),\n name: this.readRequiredString(candidate.name, \"publisher.name\"),\n url: this.readOptionalString(candidate.url, \"publisher.url\"),\n };\n };\n\n private readRequiredString = (value: unknown, fieldName: string): string => {\n if (typeof value !== \"string\" || !value.trim()) {\n throw new Error(`${fieldName} 必须是非空字符串。`);\n }\n return value.trim();\n };\n\n private readOptionalString = (\n value: unknown,\n fieldName: string,\n ): string | undefined => {\n if (value === undefined) {\n return undefined;\n }\n return this.readRequiredString(value, fieldName);\n };\n\n private readStringArray = (value: unknown, fieldName: string): string[] => {\n if (!Array.isArray(value) || value.length === 0) {\n throw new Error(`${fieldName} 必须是非空字符串数组。`);\n }\n return value.map((item, index) =>\n this.readRequiredString(item, `${fieldName}[${index}]`),\n );\n };\n\n private readOptionalBoolean = (\n value: unknown,\n fieldName: string,\n ): boolean | undefined => {\n if (value === undefined) {\n return undefined;\n }\n if (typeof value !== \"boolean\") {\n throw new Error(`${fieldName} 必须是布尔值。`);\n }\n return value;\n };\n\n private readLocalizedTextMap = (\n value: unknown,\n fieldName: string,\n fallbackEn: string,\n ): Record<string, string> => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`${fieldName} 必须是对象。`);\n }\n const candidate = value as Record<string, unknown>;\n const normalized = Object.fromEntries(\n Object.entries(candidate).map(([locale, localeValue]) => [\n locale,\n this.readRequiredString(localeValue, `${fieldName}.${locale}`),\n ]),\n );\n if (!normalized.en) {\n normalized.en = fallbackEn;\n }\n return normalized;\n };\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import { AppManifestBundle } from "../manifest/app-manifest.types.js";
2
- import { AppDocumentGrantMap, AppPermissionSummary, ResolvedPermissions } from "./app-permissions.types.js";
1
+ import { AppManifestBundle } from "../types/app-manifest.types.js";
2
+ import { AppDocumentGrantMap, AppPermissionSummary, ResolvedPermissions } from "../types/app-permissions.types.js";
3
3
 
4
- //#region src/permissions/app-permissions.service.d.ts
4
+ //#region src/services/app-permissions.service.d.ts
5
5
  declare class AppPermissionsService {
6
6
  resolve: (bundle: AppManifestBundle, documentGrantMap: AppDocumentGrantMap, context?: {
7
7
  appId?: string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-permissions.service.d.ts","names":[],"sources":["../../src/services/app-permissions.service.ts"],"mappings":";;;;cAca,qBAAA;EACX,OAAA,GACE,MAAA,EAAQ,iBAAA,EACR,gBAAA,EAAkB,mBAAA,EAClB,OAAA;IACE,KAAA;EAAA,MAED,OAAA,CAAQ,mBAAA;EA8BX,SAAA,GACE,MAAA,EAAQ,iBAAA,EACR,WAAA,EAAa,mBAAA,KACZ,oBAAA;EAAA,QAaK,oBAAA;AAAA"}
@@ -1,8 +1,10 @@
1
+ import { isAppStandaloneManifestBundle } from "../types/app-manifest.types.js";
1
2
  import { access } from "node:fs/promises";
2
3
  import path from "node:path";
3
- //#region src/permissions/app-permissions.service.ts
4
+ //#region src/services/app-permissions.service.ts
4
5
  var AppPermissionsService = class {
5
6
  resolve = async (bundle, documentGrantMap, context) => {
7
+ if (!isAppStandaloneManifestBundle(bundle)) throw new Error("schema v2 组合包权限由 Panel/Service runtime grant 管理。");
6
8
  const requestedPermissions = bundle.manifest.permissions ?? {};
7
9
  return {
8
10
  documentAccess: requestedPermissions.documentAccess === void 0 ? [] : await Promise.all(requestedPermissions.documentAccess.map((scope) => this.resolveDocumentGrant(scope, documentGrantMap, context?.appId))),
@@ -15,6 +17,7 @@ var AppPermissionsService = class {
15
17
  };
16
18
  };
17
19
  summarize = (bundle, permissions) => {
20
+ if (!isAppStandaloneManifestBundle(bundle)) throw new Error("schema v2 组合包权限由 Panel/Service runtime grant 管理。");
18
21
  return {
19
22
  requested: bundle.manifest.permissions ?? {},
20
23
  documentAccess: permissions.documentAccess,
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-permissions.service.js","names":[],"sources":["../../src/services/app-permissions.service.ts"],"sourcesContent":["import { access } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type {\n AppDocumentAccessScope,\n AppManifestBundle,\n} from \"#app-runtime/types/app-manifest.types.js\";\nimport { isAppStandaloneManifestBundle } from \"#app-runtime/types/app-manifest.types.js\";\nimport type {\n AppDocumentGrantMap,\n AppPermissionSummary,\n ResolvedDocumentGrant,\n ResolvedPermissions,\n} from \"#app-runtime/types/app-permissions.types.js\";\n\nexport class AppPermissionsService {\n resolve = async (\n bundle: AppManifestBundle,\n documentGrantMap: AppDocumentGrantMap,\n context?: {\n appId?: string;\n },\n ): Promise<ResolvedPermissions> => {\n if (!isAppStandaloneManifestBundle(bundle)) {\n throw new Error(\"schema v2 组合包权限由 Panel/Service runtime grant 管理。\");\n }\n const requestedPermissions = bundle.manifest.permissions ?? {};\n const documentAccess =\n requestedPermissions.documentAccess === undefined\n ? []\n : await Promise.all(\n requestedPermissions.documentAccess.map((scope) =>\n this.resolveDocumentGrant(scope, documentGrantMap, context?.appId),\n ),\n );\n\n return {\n documentAccess,\n allowedDomains: requestedPermissions.allowedDomains ?? [],\n storage: {\n enabled: requestedPermissions.storage !== undefined && requestedPermissions.storage !== false,\n namespace:\n typeof requestedPermissions.storage === \"object\"\n ? requestedPermissions.storage.namespace\n : undefined,\n },\n capabilities: {\n hostBridge: requestedPermissions.capabilities?.hostBridge !== false,\n },\n };\n };\n\n summarize = (\n bundle: AppManifestBundle,\n permissions: ResolvedPermissions,\n ): AppPermissionSummary => {\n if (!isAppStandaloneManifestBundle(bundle)) {\n throw new Error(\"schema v2 组合包权限由 Panel/Service runtime grant 管理。\");\n }\n return {\n requested: bundle.manifest.permissions ?? {},\n documentAccess: permissions.documentAccess,\n allowedDomains: permissions.allowedDomains,\n storage: permissions.storage,\n capabilities: permissions.capabilities,\n };\n };\n\n private resolveDocumentGrant = async (\n scope: AppDocumentAccessScope,\n documentGrantMap: AppDocumentGrantMap,\n appId?: string,\n ): Promise<ResolvedDocumentGrant> => {\n const grantedPath = documentGrantMap[scope.id];\n if (!grantedPath) {\n if (appId) {\n throw new Error(\n `缺少 documentAccess 授权:${scope.id}。请先执行 napp grant ${appId} --document ${scope.id}=/absolute/path`,\n );\n }\n throw new Error(\n `缺少 documentAccess 授权:${scope.id}。请通过 --document ${scope.id}=/absolute/path 提供授权。`,\n );\n }\n const normalizedPath = path.resolve(grantedPath);\n try {\n await access(normalizedPath);\n } catch {\n throw new Error(`documentAccess 授权路径不存在:${scope.id} -> ${normalizedPath}`);\n }\n return {\n id: scope.id,\n mode: scope.mode,\n description: scope.description,\n path: normalizedPath,\n };\n };\n}\n"],"mappings":";;;;AAcA,IAAa,wBAAb,MAAmC;CACjC,UAAU,OACR,QACA,kBACA,YAGiC;AACjC,MAAI,CAAC,8BAA8B,OAAO,CACxC,OAAM,IAAI,MAAM,mDAAmD;EAErE,MAAM,uBAAuB,OAAO,SAAS,eAAe,EAAE;AAU9D,SAAO;GACL,gBATA,qBAAqB,mBAAmB,KAAA,IACpC,EAAE,GACF,MAAM,QAAQ,IACZ,qBAAqB,eAAe,KAAK,UACvC,KAAK,qBAAqB,OAAO,kBAAkB,SAAS,MAAM,CACnE,CACF;GAIL,gBAAgB,qBAAqB,kBAAkB,EAAE;GACzD,SAAS;IACP,SAAS,qBAAqB,YAAY,KAAA,KAAa,qBAAqB,YAAY;IACxF,WACE,OAAO,qBAAqB,YAAY,WACpC,qBAAqB,QAAQ,YAC7B,KAAA;IACP;GACD,cAAc,EACZ,YAAY,qBAAqB,cAAc,eAAe,OAC/D;GACF;;CAGH,aACE,QACA,gBACyB;AACzB,MAAI,CAAC,8BAA8B,OAAO,CACxC,OAAM,IAAI,MAAM,mDAAmD;AAErE,SAAO;GACL,WAAW,OAAO,SAAS,eAAe,EAAE;GAC5C,gBAAgB,YAAY;GAC5B,gBAAgB,YAAY;GAC5B,SAAS,YAAY;GACrB,cAAc,YAAY;GAC3B;;CAGH,uBAA+B,OAC7B,OACA,kBACA,UACmC;EACnC,MAAM,cAAc,iBAAiB,MAAM;AAC3C,MAAI,CAAC,aAAa;AAChB,OAAI,MACF,OAAM,IAAI,MACR,wBAAwB,MAAM,GAAG,mBAAmB,MAAM,cAAc,MAAM,GAAG,iBAClF;AAEH,SAAM,IAAI,MACR,wBAAwB,MAAM,GAAG,kBAAkB,MAAM,GAAG,uBAC7D;;EAEH,MAAM,iBAAiB,KAAK,QAAQ,YAAY;AAChD,MAAI;AACF,SAAM,OAAO,eAAe;UACtB;AACN,SAAM,IAAI,MAAM,0BAA0B,MAAM,GAAG,MAAM,iBAAiB;;AAE5E,SAAO;GACL,IAAI,MAAM;GACV,MAAM,MAAM;GACZ,aAAa,MAAM;GACnB,MAAM;GACP"}
@@ -1,9 +1,9 @@
1
- import { AppManifestService } from "../manifest/app-manifest.service.js";
2
- import { AppDistributionMode } from "../bundle/app-bundle.types.js";
3
- import { AppBundleService } from "../bundle/app-bundle.service.js";
1
+ import { AppManifestService } from "./app-manifest.service.js";
2
+ import { AppDistributionMode } from "../types/app-bundle.types.js";
3
+ import { AppBundleService } from "./app-bundle.service.js";
4
4
  import { AppMarketplaceMetadataService } from "./app-marketplace-metadata.service.js";
5
5
 
6
- //#region src/publish/app-publish-validation.service.d.ts
6
+ //#region src/services/app-publish-validation.service.d.ts
7
7
  type AppPublishValidationWarningCode = "main-entry-large" | "bundle-large";
8
8
  type AppPublishValidationWarning = {
9
9
  code: AppPublishValidationWarningCode;
@@ -16,9 +16,11 @@ type AppPublishValidationResult = {
16
16
  appId: string;
17
17
  version: string;
18
18
  distributionMode: AppDistributionMode;
19
- mainKind: string;
20
- mainEntryPath: string;
21
- mainEntrySizeBytes: number;
19
+ profile: "standalone" | "components";
20
+ mainKind?: string;
21
+ mainEntryPath?: string;
22
+ mainEntrySizeBytes?: number;
23
+ componentCount?: number;
22
24
  bundleSizeBytes: number;
23
25
  bundleFilePaths: string[];
24
26
  warnings: AppPublishValidationWarning[];
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-publish-validation.service.d.ts","names":[],"sources":["../../src/services/app-publish-validation.service.ts"],"mappings":";;;;;;KAgBY,+BAAA;AAAA,KAIA,2BAAA;EACV,IAAA,EAAM,+BAAA;EACN,OAAA;AAAA;AAAA,KAGU,0BAAA;EACV,EAAA;EACA,YAAA;EACA,YAAA;EACA,KAAA;EACA,OAAA;EACA,gBAAA,EAAkB,mBAAA;EAClB,OAAA;EACA,QAAA;EACA,aAAA;EACA,kBAAA;EACA,cAAA;EACA,eAAA;EACA,eAAA;EACA,QAAA,EAAU,2BAAA;AAAA;AAAA,cAGC,2BAAA;EAAA,iBAEQ,eAAA;EAAA,iBACA,eAAA;EAAA,iBACA,aAAA;cAFA,eAAA,GAAiB,kBAAA,EACjB,eAAA,GAAiB,6BAAA,EACjB,aAAA,GAAe,gBAAA;EAGlC,QAAA,GAAkB,MAAA;IAChB,YAAA;IACA,YAAA;IACA,IAAA,GAAO,mBAAA;EAAA,MACL,OAAA,CAAQ,0BAAA;EAAA,QAyDJ,aAAA;EAAA,QAqBA,WAAA;AAAA"}
@@ -1,10 +1,11 @@
1
- import { AppManifestService } from "../manifest/app-manifest.service.js";
2
- import { AppBundleService } from "../bundle/app-bundle.service.js";
1
+ import { AppManifestService } from "./app-manifest.service.js";
2
+ import { isAppComponentManifestBundle, isAppStandaloneManifestBundle } from "../types/app-manifest.types.js";
3
+ import { AppBundleService } from "./app-bundle.service.js";
3
4
  import { AppMarketplaceMetadataService } from "./app-marketplace-metadata.service.js";
4
5
  import { mkdtemp, rm, stat } from "node:fs/promises";
5
6
  import path from "node:path";
6
7
  import { tmpdir } from "node:os";
7
- //#region src/publish/app-publish-validation.service.ts
8
+ //#region src/services/app-publish-validation.service.ts
8
9
  const MAIN_ENTRY_WARN_BYTES = 10 * 1024 * 1024;
9
10
  const BUNDLE_WARN_BYTES = 5 * 1024 * 1024;
10
11
  var AppPublishValidationService = class {
@@ -16,8 +17,8 @@ var AppPublishValidationService = class {
16
17
  validate = async (params) => {
17
18
  const { appDirectory: inputAppDirectory, metadataPath: inputMetadataPath, mode } = params;
18
19
  const appDirectory = path.resolve(inputAppDirectory);
19
- const distributionMode = mode ?? "source";
20
20
  const bundle = await this.manifestService.load(appDirectory);
21
+ const distributionMode = mode ?? (bundle.manifest.schemaVersion === 2 ? "bundle" : "source");
21
22
  const metadataPath = inputMetadataPath ? path.resolve(inputMetadataPath) : path.join(appDirectory, "marketplace.json");
22
23
  await this.metadataService.load({
23
24
  appDirectory,
@@ -31,9 +32,10 @@ var AppPublishValidationService = class {
31
32
  outputPath: path.join(tempDirectory, `${bundle.manifest.id}-${bundle.manifest.version}.napp`),
32
33
  mode: distributionMode
33
34
  });
34
- const mainEntryStats = await stat(bundle.mainEntryPath);
35
+ const standaloneBundle = isAppStandaloneManifestBundle(bundle) ? bundle : void 0;
36
+ const mainEntryStats = standaloneBundle ? await stat(standaloneBundle.mainEntryPath) : void 0;
35
37
  const warnings = this.buildWarnings({
36
- mainEntrySizeBytes: mainEntryStats.size,
38
+ mainEntrySizeBytes: mainEntryStats?.size,
37
39
  bundleSizeBytes: packResult.sizeBytes
38
40
  });
39
41
  return {
@@ -43,9 +45,11 @@ var AppPublishValidationService = class {
43
45
  appId: bundle.manifest.id,
44
46
  version: bundle.manifest.version,
45
47
  distributionMode,
46
- mainKind: bundle.manifest.main.kind,
47
- mainEntryPath: bundle.mainEntryPath,
48
- mainEntrySizeBytes: mainEntryStats.size,
48
+ profile: standaloneBundle ? "standalone" : "components",
49
+ mainKind: standaloneBundle?.manifest.main.kind,
50
+ mainEntryPath: standaloneBundle?.mainEntryPath,
51
+ mainEntrySizeBytes: mainEntryStats?.size,
52
+ componentCount: isAppComponentManifestBundle(bundle) ? bundle.components.length : void 0,
49
53
  bundleSizeBytes: packResult.sizeBytes,
50
54
  bundleFilePaths: packResult.filePaths,
51
55
  warnings
@@ -60,7 +64,7 @@ var AppPublishValidationService = class {
60
64
  buildWarnings = (params) => {
61
65
  const { bundleSizeBytes, mainEntrySizeBytes } = params;
62
66
  const warnings = [];
63
- if (mainEntrySizeBytes > MAIN_ENTRY_WARN_BYTES) warnings.push({
67
+ if (mainEntrySizeBytes !== void 0 && mainEntrySizeBytes > MAIN_ENTRY_WARN_BYTES) warnings.push({
64
68
  code: "main-entry-large",
65
69
  message: `main entry is ${this.formatBytes(mainEntrySizeBytes)}, which is larger than the ${this.formatBytes(MAIN_ENTRY_WARN_BYTES)} warning threshold.`
66
70
  });
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-publish-validation.service.js","names":[],"sources":["../../src/services/app-publish-validation.service.ts"],"sourcesContent":["import { stat } from \"node:fs/promises\";\nimport { mkdtemp, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport path from \"node:path\";\nimport { AppBundleService } from \"#app-runtime/services/app-bundle.service.js\";\nimport type { AppDistributionMode } from \"#app-runtime/types/app-bundle.types.js\";\nimport { AppManifestService } from \"#app-runtime/services/app-manifest.service.js\";\nimport {\n isAppComponentManifestBundle,\n isAppStandaloneManifestBundle,\n} from \"#app-runtime/types/app-manifest.types.js\";\nimport { AppMarketplaceMetadataService } from \"./app-marketplace-metadata.service.js\";\n\nconst MAIN_ENTRY_WARN_BYTES = 10 * 1024 * 1024;\nconst BUNDLE_WARN_BYTES = 5 * 1024 * 1024;\n\nexport type AppPublishValidationWarningCode =\n | \"main-entry-large\"\n | \"bundle-large\";\n\nexport type AppPublishValidationWarning = {\n code: AppPublishValidationWarningCode;\n message: string;\n};\n\nexport type AppPublishValidationResult = {\n ok: boolean;\n appDirectory: string;\n metadataPath: string;\n appId: string;\n version: string;\n distributionMode: AppDistributionMode;\n profile: \"standalone\" | \"components\";\n mainKind?: string;\n mainEntryPath?: string;\n mainEntrySizeBytes?: number;\n componentCount?: number;\n bundleSizeBytes: number;\n bundleFilePaths: string[];\n warnings: AppPublishValidationWarning[];\n};\n\nexport class AppPublishValidationService {\n constructor(\n private readonly manifestService: AppManifestService = new AppManifestService(),\n private readonly metadataService: AppMarketplaceMetadataService = new AppMarketplaceMetadataService(),\n private readonly bundleService: AppBundleService = new AppBundleService(),\n ) {}\n\n validate = async (params: {\n appDirectory: string;\n metadataPath?: string;\n mode?: AppDistributionMode;\n }): Promise<AppPublishValidationResult> => {\n const {\n appDirectory: inputAppDirectory,\n metadataPath: inputMetadataPath,\n mode,\n } = params;\n const appDirectory = path.resolve(inputAppDirectory);\n const bundle = await this.manifestService.load(appDirectory);\n const distributionMode = mode ??\n (bundle.manifest.schemaVersion === 2 ? \"bundle\" : \"source\");\n const metadataPath = inputMetadataPath\n ? path.resolve(inputMetadataPath)\n : path.join(appDirectory, \"marketplace.json\");\n await this.metadataService.load({\n appDirectory,\n manifest: bundle.manifest,\n metadataPath,\n });\n\n const tempDirectory = await mkdtemp(path.join(tmpdir(), \"napp-validate-publish-\"));\n try {\n const packResult = await this.bundleService.packAppDirectory({\n appDirectory,\n outputPath: path.join(tempDirectory, `${bundle.manifest.id}-${bundle.manifest.version}.napp`),\n mode: distributionMode,\n });\n const standaloneBundle = isAppStandaloneManifestBundle(bundle) ? bundle : undefined;\n const mainEntryStats = standaloneBundle\n ? await stat(standaloneBundle.mainEntryPath)\n : undefined;\n const warnings = this.buildWarnings({\n mainEntrySizeBytes: mainEntryStats?.size,\n bundleSizeBytes: packResult.sizeBytes,\n });\n return {\n ok: true,\n appDirectory,\n metadataPath,\n appId: bundle.manifest.id,\n version: bundle.manifest.version,\n distributionMode,\n profile: standaloneBundle ? \"standalone\" : \"components\",\n mainKind: standaloneBundle?.manifest.main.kind,\n mainEntryPath: standaloneBundle?.mainEntryPath,\n mainEntrySizeBytes: mainEntryStats?.size,\n componentCount: isAppComponentManifestBundle(bundle)\n ? bundle.components.length\n : undefined,\n bundleSizeBytes: packResult.sizeBytes,\n bundleFilePaths: packResult.filePaths,\n warnings,\n };\n } finally {\n await rm(tempDirectory, { recursive: true, force: true });\n }\n };\n\n private buildWarnings = (params: {\n mainEntrySizeBytes?: number;\n bundleSizeBytes: number;\n }): AppPublishValidationWarning[] => {\n const { bundleSizeBytes, mainEntrySizeBytes } = params;\n const warnings: AppPublishValidationWarning[] = [];\n if (mainEntrySizeBytes !== undefined && mainEntrySizeBytes > MAIN_ENTRY_WARN_BYTES) {\n warnings.push({\n code: \"main-entry-large\",\n message: `main entry is ${this.formatBytes(mainEntrySizeBytes)}, which is larger than the ${this.formatBytes(MAIN_ENTRY_WARN_BYTES)} warning threshold.`,\n });\n }\n if (bundleSizeBytes > BUNDLE_WARN_BYTES) {\n warnings.push({\n code: \"bundle-large\",\n message: `packed .napp is ${this.formatBytes(bundleSizeBytes)}, which is larger than the ${this.formatBytes(BUNDLE_WARN_BYTES)} warning threshold.`,\n });\n }\n return warnings;\n };\n\n private formatBytes = (value: number): string => {\n if (value < 1024) {\n return `${value} B`;\n }\n if (value < 1024 * 1024) {\n return `${(value / 1024).toFixed(1)} KB`;\n }\n return `${(value / (1024 * 1024)).toFixed(1)} MB`;\n };\n}\n"],"mappings":";;;;;;;;AAaA,MAAM,wBAAwB,KAAK,OAAO;AAC1C,MAAM,oBAAoB,IAAI,OAAO;AA4BrC,IAAa,8BAAb,MAAyC;CACvC,YACE,kBAAuD,IAAI,oBAAoB,EAC/E,kBAAkE,IAAI,+BAA+B,EACrG,gBAAmD,IAAI,kBAAkB,EACzE;AAHiB,OAAA,kBAAA;AACA,OAAA,kBAAA;AACA,OAAA,gBAAA;;CAGnB,WAAW,OAAO,WAIyB;EACzC,MAAM,EACJ,cAAc,mBACd,cAAc,mBACd,SACE;EACJ,MAAM,eAAe,KAAK,QAAQ,kBAAkB;EACpD,MAAM,SAAS,MAAM,KAAK,gBAAgB,KAAK,aAAa;EAC5D,MAAM,mBAAmB,SACtB,OAAO,SAAS,kBAAkB,IAAI,WAAW;EACpD,MAAM,eAAe,oBACjB,KAAK,QAAQ,kBAAkB,GAC/B,KAAK,KAAK,cAAc,mBAAmB;AAC/C,QAAM,KAAK,gBAAgB,KAAK;GAC9B;GACA,UAAU,OAAO;GACjB;GACD,CAAC;EAEF,MAAM,gBAAgB,MAAM,QAAQ,KAAK,KAAK,QAAQ,EAAE,yBAAyB,CAAC;AAClF,MAAI;GACF,MAAM,aAAa,MAAM,KAAK,cAAc,iBAAiB;IAC3D;IACA,YAAY,KAAK,KAAK,eAAe,GAAG,OAAO,SAAS,GAAG,GAAG,OAAO,SAAS,QAAQ,OAAO;IAC7F,MAAM;IACP,CAAC;GACF,MAAM,mBAAmB,8BAA8B,OAAO,GAAG,SAAS,KAAA;GAC1E,MAAM,iBAAiB,mBACnB,MAAM,KAAK,iBAAiB,cAAc,GAC1C,KAAA;GACJ,MAAM,WAAW,KAAK,cAAc;IAClC,oBAAoB,gBAAgB;IACpC,iBAAiB,WAAW;IAC7B,CAAC;AACF,UAAO;IACL,IAAI;IACJ;IACA;IACA,OAAO,OAAO,SAAS;IACvB,SAAS,OAAO,SAAS;IACzB;IACA,SAAS,mBAAmB,eAAe;IAC3C,UAAU,kBAAkB,SAAS,KAAK;IAC1C,eAAe,kBAAkB;IACjC,oBAAoB,gBAAgB;IACpC,gBAAgB,6BAA6B,OAAO,GAChD,OAAO,WAAW,SAClB,KAAA;IACJ,iBAAiB,WAAW;IAC5B,iBAAiB,WAAW;IAC5B;IACD;YACO;AACR,SAAM,GAAG,eAAe;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;;;CAI7D,iBAAyB,WAGY;EACnC,MAAM,EAAE,iBAAiB,uBAAuB;EAChD,MAAM,WAA0C,EAAE;AAClD,MAAI,uBAAuB,KAAA,KAAa,qBAAqB,sBAC3D,UAAS,KAAK;GACZ,MAAM;GACN,SAAS,iBAAiB,KAAK,YAAY,mBAAmB,CAAC,6BAA6B,KAAK,YAAY,sBAAsB,CAAC;GACrI,CAAC;AAEJ,MAAI,kBAAkB,kBACpB,UAAS,KAAK;GACZ,MAAM;GACN,SAAS,mBAAmB,KAAK,YAAY,gBAAgB,CAAC,6BAA6B,KAAK,YAAY,kBAAkB,CAAC;GAChI,CAAC;AAEJ,SAAO;;CAGT,eAAuB,UAA0B;AAC/C,MAAI,QAAQ,KACV,QAAO,GAAG,MAAM;AAElB,MAAI,QAAQ,OAAO,KACjB,QAAO,IAAI,QAAQ,MAAM,QAAQ,EAAE,CAAC;AAEtC,SAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,EAAE,CAAC"}
@@ -1,12 +1,12 @@
1
- import { AppManifestService } from "../manifest/app-manifest.service.js";
2
- import { AppDistributionMode } from "../bundle/app-bundle.types.js";
3
- import { AppBundleService } from "../bundle/app-bundle.service.js";
4
- import { AppPublishResult } from "./app-publish.types.js";
1
+ import { AppManifestService } from "./app-manifest.service.js";
2
+ import { AppDistributionMode } from "../types/app-bundle.types.js";
3
+ import { AppBundleService } from "./app-bundle.service.js";
4
+ import { AppPublishResult } from "../types/app-publish.types.js";
5
5
  import { AppMarketplaceClientService } from "./app-marketplace-client.service.js";
6
6
  import { AppMarketplaceMetadataService } from "./app-marketplace-metadata.service.js";
7
7
  import { PlatformAuthStateService } from "./platform-auth-state.service.js";
8
8
 
9
- //#region src/publish/app-publish.service.d.ts
9
+ //#region src/services/app-publish.service.d.ts
10
10
  declare class AppPublishService {
11
11
  private readonly manifestService;
12
12
  private readonly bundleService;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-publish.service.d.ts","names":[],"sources":["../../src/services/app-publish.service.ts"],"mappings":";;;;;;;;;cAkBa,iBAAA;EAAA,iBAEQ,eAAA;EAAA,iBACA,aAAA;EAAA,iBACA,eAAA;EAAA,iBACA,iBAAA;EAAA,iBACA,gBAAA;cAJA,eAAA,GAAiB,kBAAA,EACjB,aAAA,GAAe,gBAAA,EACf,eAAA,GAAiB,6BAAA,EACjB,iBAAA,GAAmB,2BAAA,EACnB,gBAAA,GAAkB,wBAAA;EAGrC,OAAA,GAAiB,MAAA;IACf,YAAA;IACA,YAAA;IACA,UAAA;IACA,KAAA;IACA,IAAA,GAAO,mBAAA;EAAA,MACL,OAAA,CAAQ,gBAAA;EAAA,QAoEJ,mBAAA;EAAA,QA6CA,wBAAA;EAAA,QA6CA,sBAAA;EAAA,QAOA,kBAAA;EAAA,QAkBA,sBAAA;AAAA"}