@akanjs/cli 3.0.0-beta.3 → 3.0.0-beta.30

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 (194) hide show
  1. package/.build-stamp +1 -1
  2. package/CodeAgent-xnfyyz8h.js +9 -0
  3. package/CodeAgentRpcHost-p7h6n2hp.js +7 -0
  4. package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
  5. package/CodeTui-h66xb1fh.js +1457 -0
  6. package/README.md +3 -0
  7. package/TunnelShare-cwh9ezsm.js +9 -0
  8. package/{agent.command-d2gfxfck.js → agent.command-c4v7kjff.js} +8 -9
  9. package/akanCode.js +102 -0
  10. package/application.command-yzsswrz6.js +241 -0
  11. package/{applicationBuildRunner-kxwbssgn.js → applicationBuildRunner-qkt6spd5.js} +121 -77
  12. package/buildBatch.proc.js +120 -32
  13. package/cloud.command-v8h688jc.js +95 -0
  14. package/cloud.script-yct1sk4k.js +20 -0
  15. package/code.command-jff3tw7y.js +154 -0
  16. package/commandManifest.json +1 -1
  17. package/consoleToStderr-h5bryj94.js +7 -0
  18. package/context.command-y5sevk3c.js +48 -0
  19. package/context.runner-90hsmacr.js +21 -0
  20. package/{dependencyScanner-shs82ynp.js → dependencyScanner-06z2dmrr.js} +2 -2
  21. package/{devTui-40ggmd99.js → devTui-q7k7bakd.js} +122 -40
  22. package/fileSys-wzzrntkw.js +9 -0
  23. package/guideline.command-11cndccb.js +42 -0
  24. package/guidelines/agentRule/agentRule.instruction.md +209 -33
  25. package/guidelines/conventions/conventions.instruction.md +143 -41
  26. package/guidelines/fieldRule/fieldRule.instruction.md +1 -0
  27. package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
  28. package/guidelines/queryRule/queryRule.instruction.md +21 -7
  29. package/guidelines/runtimeRule/runtimeRule.instruction.md +268 -6
  30. package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
  31. package/guidelines/transportRule/transportRule.instruction.md +51 -0
  32. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +20 -0
  33. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +66 -3
  34. package/incrementalBuilder.proc.js +564 -109
  35. package/{index-fz5q3gd7.js → index-0ncc0mbk.js} +10 -17
  36. package/index-167c77aq.js +69 -0
  37. package/{index-kcxmv48c.js → index-2ahj896a.js} +45 -79
  38. package/index-2wc41k5w.js +49 -0
  39. package/{index-j9yhg404.js → index-35mmm9ca.js} +4 -7
  40. package/{index-a64esmtb.js → index-376gpdds.js} +523 -1022
  41. package/index-3hx1z96c.js +87 -0
  42. package/{index-v0qh106m.js → index-3rh7thcx.js} +961 -892
  43. package/{index-hwkygn9s.js → index-48k96p55.js} +325 -36
  44. package/{index-q0y2jq9j.js → index-52w0fvh8.js} +21 -4
  45. package/index-5rp0h6na.js +1119 -0
  46. package/index-6x9p8dpb.js +4300 -0
  47. package/index-7md2g9vw.js +6 -0
  48. package/index-8tv7356t.js +700 -0
  49. package/index-94s080qm.js +266 -0
  50. package/index-9dp031by.js +12 -0
  51. package/{index-ws5e0j51.js → index-a4s954kq.js} +43 -26
  52. package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
  53. package/{index-ne2qy0nk.js → index-bxmejydw.js} +12 -12
  54. package/index-c6eggbee.js +123 -0
  55. package/index-d2242ksy.js +99 -0
  56. package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
  57. package/{index-259dsnz3.js → index-gxamdf18.js} +5 -8
  58. package/{index-4edzf1gr.js → index-hf6f4xnb.js} +77 -150
  59. package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
  60. package/{index-gyd220p2.js → index-hmdq5pqm.js} +554 -577
  61. package/{index-600zhnve.js → index-hqd0h1pb.js} +75 -203
  62. package/index-kb16nzyt.js +997 -0
  63. package/index-mk3b9rk1.js +2729 -0
  64. package/{index-2tv3fdx4.js → index-n3jk2501.js} +1205 -1458
  65. package/index-p6pbz9n5.js +25 -0
  66. package/{index-zry5nz81.js → index-qcejqgts.js} +51 -30
  67. package/{index-7737gxcp.js → index-rtwhw4aq.js} +107 -241
  68. package/{index-pnqbkf5p.js → index-se643zvp.js} +6 -2
  69. package/index-tsb0f8ya.js +53 -0
  70. package/{index-ktb5njgy.js → index-tzc1gtrg.js} +49 -99
  71. package/index-wa5jbxj1.js +760 -0
  72. package/index-wfwgcnyc.js +187 -0
  73. package/{index-mak3cd28.js → index-xb7qhxa8.js} +137 -255
  74. package/{index-h7yw2z9n.js → index-zzvvc845.js} +8 -14
  75. package/index.js +23 -22
  76. package/{library.command-nbsky672.js → library.command-n9kp7yms.js} +4 -5
  77. package/{localRegistry.command-yeq57wjr.js → localRegistry.command-jx6kxt2x.js} +23 -42
  78. package/{module.command-29vqzrh8.js → module.command-q2xjf6cx.js} +8 -11
  79. package/{package.command-axv0abmn.js → package.command-q5a3nsw5.js} +6 -7
  80. package/package.json +15 -7
  81. package/{page.command-vs9s3zrh.js → page.command-ppenrxjn.js} +4 -5
  82. package/{primitive.command-cbxmqbtc.js → primitive.command-dvgg8nem.js} +9 -22
  83. package/prompter-76k56b37.js +8 -0
  84. package/{quality.command-gmbs7nws.js → quality.command-pz7kg3pc.js} +205 -377
  85. package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
  86. package/{repair.command-bqsjptsj.js → repair.command-a6py9xvz.js} +11 -35
  87. package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
  88. package/{scalar.command-6k1vhe9s.js → scalar.command-7f3xfpen.js} +7 -10
  89. package/skills/akan-code/SKILL.md +130 -0
  90. package/skills/akan-debug/SKILL.md +42 -0
  91. package/skills/akan-deps/SKILL.md +50 -0
  92. package/skills/akan-err/SKILL.md +39 -0
  93. package/skills/akan-module/SKILL.md +45 -0
  94. package/skills/akan-scaffold/SKILL.md +76 -0
  95. package/skills/akan-scalar/SKILL.md +52 -0
  96. package/skills/akan-service/SKILL.md +34 -0
  97. package/skills/akan-store/SKILL.md +67 -0
  98. package/skills/akan-ui/SKILL.md +63 -0
  99. package/skills/akan-validate/SKILL.md +44 -0
  100. package/{subspace.command-fwjfcts7.js → subspace.command-z7nqs508.js} +138 -67
  101. package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
  102. package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
  103. package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
  104. package/templates/appSample/lib/task/task.abstract.ts +12 -32
  105. package/templates/appSample/lib/task/task.signal.spec.ts +15 -18
  106. package/templates/appSample/lib/task/task.signal.test.ts +15 -1
  107. package/templates/appSample/lib/task/task.signal.ts +1 -1
  108. package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +7 -4
  109. package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +6 -4
  110. package/templates/client.ts +7 -30
  111. package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
  112. package/templates/crudPages/[__model__Id]/page.tsx +2 -1
  113. package/templates/crudPages/new/page.tsx +2 -1
  114. package/templates/crudPages/page.tsx +2 -1
  115. package/templates/crudSinglePage/page.tsx +2 -1
  116. package/templates/lib/__lib/lib.dictionary.ts +0 -2
  117. package/templates/lib/__lib/lib.document.ts +0 -2
  118. package/templates/lib/sig.ts +8 -30
  119. package/templates/localDev/docker-compose.yaml.template +3 -14
  120. package/templates/module/__model__.signal.ts +12 -4
  121. package/templates/pkgRoot/tsconfig.json.template +2 -7
  122. package/templates/server.ts +1 -3
  123. package/templates/service/__model__.abstract.md.template +8 -0
  124. package/templates/workspaceRoot/.gitignore.template +0 -1
  125. package/templates/workspaceRoot/package.json.template +1 -3
  126. package/tunnel.command-zy4wbcgt.js +129 -0
  127. package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
  128. package/typecheck.proc.js +1 -1
  129. package/workflow.command-f142t17s.js +79 -0
  130. package/{workspace.command-8s050m0h.js → workspace.command-gpk1149x.js} +77 -109
  131. package/abstractCompactor-mjh5ppsq.js +0 -101
  132. package/application.command-pj2m7584.js +0 -204
  133. package/applicationReleasePackager-4yasxwv9.js +0 -244
  134. package/capacitorApp-36rbr858.js +0 -12
  135. package/cloud.command-jshwdq22.js +0 -93
  136. package/context.command-ez8a0zyz.js +0 -80
  137. package/devTuiView-c08ccbat.js +0 -9
  138. package/getDirname-dr3jz1xg.js +0 -7
  139. package/guideline.command-xmqwx8zm.js +0 -359
  140. package/guidelines/agentRule/agentRule.generate.json +0 -31
  141. package/guidelines/componentRule/componentRule.generate.json +0 -31
  142. package/guidelines/conventions/conventions.generate.json +0 -25
  143. package/guidelines/cssRule/cssRule.generate.json +0 -31
  144. package/guidelines/docPageRule/docPageRule.generate.json +0 -31
  145. package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
  146. package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
  147. package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
  148. package/guidelines/enumConstant/enumConstant.generate.json +0 -31
  149. package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
  150. package/guidelines/fieldRule/fieldRule.generate.json +0 -31
  151. package/guidelines/framework/framework.generate.json +0 -32
  152. package/guidelines/mcpRule/mcpRule.generate.json +0 -35
  153. package/guidelines/modelConstant/modelConstant.generate.json +0 -32
  154. package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
  155. package/guidelines/modelDocument/modelDocument.generate.json +0 -31
  156. package/guidelines/modelService/modelService.generate.json +0 -31
  157. package/guidelines/modelSignal/modelSignal.generate.json +0 -31
  158. package/guidelines/modelStore/modelStore.generate.json +0 -31
  159. package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
  160. package/guidelines/modelUnit/modelUnit.generate.json +0 -31
  161. package/guidelines/modelUtil/modelUtil.generate.json +0 -31
  162. package/guidelines/modelView/modelView.generate.json +0 -31
  163. package/guidelines/modelZone/modelZone.generate.json +0 -31
  164. package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
  165. package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
  166. package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
  167. package/guidelines/queryRule/queryRule.generate.json +0 -31
  168. package/guidelines/recipeRule/recipeRule.generate.json +0 -31
  169. package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
  170. package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
  171. package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
  172. package/guidelines/scalarModule/scalarModule.generate.json +0 -31
  173. package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
  174. package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
  175. package/guidelines/ssrRule/ssrRule.generate.json +0 -31
  176. package/guidelines/transportRule/transportRule.generate.json +0 -31
  177. package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
  178. package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
  179. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
  180. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -33
  181. package/index-2hq52jq3.js +0 -465
  182. package/index-47pj3aee.js +0 -76
  183. package/index-6wwzs1bc.js +0 -7
  184. package/index-8pm30m73.js +0 -841
  185. package/index-kn1h7p1x.js +0 -560
  186. package/index-meh558jy.js +0 -65
  187. package/index-rwg2aa4f.js +0 -229
  188. package/index-w8kmx1b6.js +0 -2176
  189. package/index-wt7qrtd4.js +0 -1516
  190. package/templates/__scalar/__model__/__model__.abstract.md +0 -28
  191. package/templates/module/__model__.abstract.md +0 -28
  192. package/templates/service/__model__.abstract.md +0 -28
  193. package/templates/workspaceRoot/patches/react-dom@19.2.7.patch.template +0 -62
  194. package/workflow.command-nwpcdc8p.js +0 -107
@@ -1,22 +1,55 @@
1
1
  // @bun
2
2
  import {
3
3
  Spinner
4
- } from "./index-2tv3fdx4.js";
4
+ } from "./index-n3jk2501.js";
5
+ import"./index-6x9p8dpb.js";
5
6
  import {
6
7
  AllRoutesBuilder,
7
8
  CsrArtifactBuilder,
8
9
  FontPruner,
9
10
  precompressArtifacts,
10
11
  SsrBaseArtifactBuilder
11
- } from "./index-a64esmtb.js";
12
- import"./index-w8kmx1b6.js";
13
- import"./index-q0y2jq9j.js";
14
- import"./index-hwkygn9s.js";
12
+ } from "./index-376gpdds.js";
13
+ import"./index-52w0fvh8.js";
15
14
  import"./index-n68jx79w.js";
16
15
 
17
16
  // pkgs/@akanjs/devkit/applicationBuildRunner.ts
18
17
  import { mkdir, rm } from "fs/promises";
18
+ import path2 from "path";
19
+
20
+ // pkgs/@akanjs/devkit/transforms/serverEnvPlugin.ts
21
+ import { existsSync, realpathSync } from "fs";
19
22
  import path from "path";
23
+ var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
24
+ var createServerEnvPlugin = ({ envDir, environment, environments }) => {
25
+ const others = [...new Set(environments)].filter((name) => name !== environment);
26
+ const dirs = new Set([path.resolve(envDir), existsSync(envDir) ? realpathSync.native(envDir) : envDir]);
27
+ const names = others.map(escapeRegExp).join("|");
28
+ const filter = new RegExp(`^(?:${[...dirs].map(escapeRegExp).join("|")})[\\\\/]env\\.server\\.(?:${names})\\.ts$`);
29
+ return {
30
+ name: "akan-server-env",
31
+ setup(build) {
32
+ if (!others.length)
33
+ return;
34
+ build.onLoad({ filter }, async (args) => {
35
+ const name = path.basename(args.path, ".ts").slice("env.server.".length);
36
+ const { exports } = new Bun.Transpiler({ loader: "ts" }).scan(await Bun.file(args.path).text());
37
+ const message = `env/env.server.${name}.ts is not in this build: \`akan build\` bundles the server env of AKAN_PUBLIC_ENV=${environment} alone, the environment its image runs. To run ${name}, build for it: AKAN_PUBLIC_ENV=${name} in the workspace's .env, which outranks the shell, or --env ${name} on a desktop or mobile build.`;
38
+ return {
39
+ loader: "js",
40
+ contents: [
41
+ `const refuse = () => { throw new Error(${JSON.stringify(message)}); };`,
42
+ "const unbuilt = new Proxy({}, { get: refuse, has: refuse, ownKeys: refuse, getOwnPropertyDescriptor: refuse });",
43
+ `export { ${exports.map((exported) => `unbuilt as ${JSON.stringify(exported)}`).join(", ")} };`
44
+ ].join(`
45
+ `)
46
+ };
47
+ });
48
+ }
49
+ };
50
+ };
51
+
52
+ // pkgs/@akanjs/devkit/applicationBuildRunner.ts
20
53
  var BUILD_PHASE_EMOJIS = {
21
54
  prepare: "\uD83E\uDDF9",
22
55
  typecheck: "\uD83D\uDD0E",
@@ -51,54 +84,52 @@ class ApplicationBuildRunner {
51
84
  #app;
52
85
  #fast;
53
86
  #reporter;
87
+ #environment;
88
+ #spinner;
54
89
  #startedAt = Date.now();
55
90
  #phases = [];
56
- constructor(app, { fast = false, reporter } = {}) {
91
+ constructor(app, { fast = false, reporter, environment } = {}) {
57
92
  this.#app = app;
58
93
  this.#fast = fast;
59
94
  this.#reporter = reporter;
95
+ this.#environment = environment;
60
96
  }
61
97
  async build({ spinner = false } = {}) {
62
- const phaseOptions = { spinner };
98
+ this.#spinner = spinner;
63
99
  const { web, assets } = await this.#app.getConfig();
64
- await this.#runPhase("prepare", "Preparing output directory", () => this.#app.prepareCommand("build"), undefined, {
65
- spinner
66
- });
100
+ await this.#runPhase("prepare", "Preparing output directory", () => this.#app.prepareCommand("build"));
67
101
  if (!this.#fast)
68
- await this.#runPhase("typecheck", "Typechecking", () => this.typecheck(), undefined, phaseOptions);
69
- await this.#runPhase("backend", "Compiling backend", () => this.#buildBackend(), (result) => `${result.entrypoints} entrypoints, ${result.outputs} outputs`, phaseOptions);
70
- await this.#runPhase("ssr", "Building SSR route artifacts", async () => web.ssr ? await this.#buildSsr() : null, (result) => result ? `${result.allRoutes.manifest.routeIds.length} routes, ${result.allRoutes.manifest.knownEntries.length} entries` : web.ssr ? "skipped" : "disabled by akan.config.ts web.ssr", phaseOptions);
71
- await this.#runPhase("csr", "Building CSR assets", async () => web.csr ? await this.#buildCsr() : null, (result) => result?.outputDir ?? (web.csr ? "skipped" : "disabled by akan.config.ts web.csr"), phaseOptions);
72
- await this.#runPhase("assets", "Trimming unread static assets", async () => assets.pruneFonts ? await new FontPruner(this.#app, assets).prune() : null, (result) => result ? `${result.removed.length} font file(s) dropped, ${ApplicationBuildRunner.formatBytes(result.freedBytes)} freed; ${result.kept.length} kept` : "disabled by akan.config.ts assets.pruneFonts", phaseOptions);
73
- await this.#runPhase("compress", "Compressing static assets", () => precompressArtifacts(this.#app), (result) => result.files > 0 ? `${result.files} files, ${ApplicationBuildRunner.formatBytes(result.inputBytes)} -> gzip ${ApplicationBuildRunner.formatBytes(result.outputBytes)} / br ${ApplicationBuildRunner.formatBytes(result.brotliBytes)}` : "no files", phaseOptions);
74
- await this.#runPhase("metadata", "Writing production metadata", () => this.#buildAppMeta(), undefined, {
75
- spinner
76
- });
102
+ await this.#runPhase("typecheck", "Typechecking", () => this.typecheck());
103
+ await this.#runPhase("backend", "Compiling backend", () => this.#buildBackend(), (result) => `${result.entrypoints} entrypoints, ${result.outputs} outputs`);
104
+ await this.#runPhase("ssr", "Building SSR route artifacts", async () => web.ssr ? await this.#buildSsr() : null, (result) => result ? `${result.allRoutes.manifest.routeIds.length} routes, ${result.allRoutes.manifest.knownEntries.length} entries` : web.ssr ? "skipped" : "disabled by akan.config.ts web.ssr");
105
+ await this.#runPhase("csr", "Building CSR assets", async () => web.csr ? await new CsrArtifactBuilder(this.#app, "build").build() : null, (result) => result?.outputDir ?? (web.csr ? "skipped" : "disabled by akan.config.ts web.csr"));
106
+ await this.#runPhase("assets", "Trimming unread static assets", async () => assets.pruneFonts ? await new FontPruner(this.#app, assets).prune() : null, (result) => result ? `${result.removed.length} font file(s) dropped, ${ApplicationBuildRunner.formatBytes(result.freedBytes)} freed; ${result.kept.length} kept` : "disabled by akan.config.ts assets.pruneFonts");
107
+ await this.#runPhase("compress", "Compressing static assets", () => precompressArtifacts(this.#app), (result) => result.files > 0 ? `${result.files} files, ${ApplicationBuildRunner.formatBytes(result.inputBytes)} -> gzip ${ApplicationBuildRunner.formatBytes(result.outputBytes)} / br ${ApplicationBuildRunner.formatBytes(result.brotliBytes)}` : "no files");
108
+ await this.#runPhase("metadata", "Writing production metadata", () => this.buildAppMeta());
77
109
  return {
78
110
  phases: this.#phases,
79
111
  durationMs: Date.now() - this.#startedAt,
80
112
  outputDir: this.#app.dist.cwdPath,
81
- artifactDir: path.join(this.#app.dist.cwdPath, ".akan/artifact")
113
+ artifactDir: path2.join(this.#app.dist.cwdPath, ".akan/artifact")
82
114
  };
83
115
  }
84
116
  async typecheck(options = {}) {
85
117
  const { clean = false, incremental = true } = options;
86
118
  await this.#app.getPageKeys({ refresh: true });
87
- const { typecheckDir, tsconfigPath } = await this.#writeTypecheckTsconfig({ incremental });
119
+ const { typecheckDir, tsconfigPath } = await this.#writeTypecheckTsconfig(incremental);
88
120
  if (clean)
89
- await rm(path.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
121
+ await rm(path2.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
90
122
  await this.#checkProjectInChildProcess(tsconfigPath);
91
123
  }
92
- async#runPhase(id, label, task, summarize, options = {}) {
124
+ async#runPhase(id, label, task, summarize) {
93
125
  this.#reporter?.phaseStart?.({ id, label });
94
126
  const phaseStartedAt = Date.now();
95
- const spinner = options.spinner ? new Spinner(label, { prefix: `${BUILD_PHASE_EMOJIS[id]} ${id}` }).start() : undefined;
127
+ const spinner = this.#spinner ? new Spinner(label, { prefix: `${BUILD_PHASE_EMOJIS[id]} ${id}` }).start() : undefined;
96
128
  try {
97
129
  const result = await task();
98
130
  const phase = { id, label, durationMs: Date.now() - phaseStartedAt, summary: summarize?.(result) };
99
131
  this.#phases.push(phase);
100
- const summary = phase.summary ? `: ${phase.summary}` : "";
101
- spinner?.succeed(`${label}${summary}`);
132
+ spinner?.succeed(`${label}${phase.summary ? `: ${phase.summary}` : ""}`);
102
133
  this.#reporter?.phaseDone?.(phase);
103
134
  return result;
104
135
  } catch (error) {
@@ -107,63 +138,85 @@ class ApplicationBuildRunner {
107
138
  throw error;
108
139
  }
109
140
  }
110
- async#buildAppMeta() {
141
+ async buildAppMeta() {
111
142
  const akanConfig = await this.#app.getConfig();
143
+ const dockerfile = akanConfig.dockerfileFor(this.#environment ?? akanConfig.baseDevEnv.env);
112
144
  await Promise.all([
113
145
  this.#app.dist.writeJson("package.json", akanConfig.getProductionPackageJson()),
114
- this.#app.dist.writeFile(`${this.#app.dist.cwdPath}/Dockerfile`, akanConfig.dockerfile)
146
+ this.#app.dist.writeFile(`${this.#app.dist.cwdPath}/Dockerfile`, dockerfile),
147
+ this.#app.dist.writeJson("akan.build.json", {
148
+ buildId: await this.#resolveBuildId(),
149
+ akanVersion: akanConfig.akanVersion,
150
+ builtAt: new Date().toISOString()
151
+ })
115
152
  ]);
116
153
  }
154
+ async#resolveBuildId() {
155
+ const fromEnv = process.env.AKAN_BUILD_ID?.trim();
156
+ if (fromEnv)
157
+ return fromEnv;
158
+ const root = this.#app.workspace.workspaceRoot;
159
+ const sha = Bun.spawnSync(["git", "rev-parse", "--short=12", "HEAD"], { cwd: root, stderr: "ignore" });
160
+ if (sha.exitCode !== 0)
161
+ return null;
162
+ const dirty = Bun.spawnSync(["git", "status", "--porcelain", "--untracked-files=no"], {
163
+ cwd: root,
164
+ stderr: "ignore"
165
+ });
166
+ const suffix = dirty.exitCode === 0 && dirty.stdout.toString().trim() ? "-dirty" : "";
167
+ return `${sha.stdout.toString().trim()}${suffix}`;
168
+ }
117
169
  async#buildBackend() {
118
- const akanConfig = await this.#app.getConfig();
119
- const backendExternals = [
120
- ...new Set([...akanConfig.externalLibs, ...SSR_RENDER_EXTERNALS, ...AKAN_OPTIONAL_BACKEND_EXTERNALS])
121
- ];
122
- const { web } = akanConfig;
170
+ const { externalLibs, web, baseDevEnv, branches } = await this.#app.getConfig();
123
171
  const backendEntryPoints = [`${this.#app.cwdPath}/main.ts`, `${this.#app.cwdPath}/server.ts`];
124
172
  for (const entrypoint of backendEntryPoints) {
125
173
  if (!await Bun.file(entrypoint).exists())
126
174
  throw new Error(`Backend entrypoint not found: ${entrypoint}`);
127
175
  }
128
- const backendResult = await this.#buildOrThrow("backend", {
129
- entrypoints: backendEntryPoints,
176
+ const sharedConfig = {
130
177
  outdir: this.#app.dist.cwdPath,
131
178
  target: "bun",
132
179
  minify: AKAN_BACKEND_MINIFY,
133
180
  naming: { entry: "[name].[ext]", chunk: "chunk-[hash].[ext]" },
134
- define: { "process.env.NODE_ENV": JSON.stringify("production") },
135
- plugins: backendExternals.length > 0 ? [this.#createExternalSpecifiersPlugin(backendExternals)] : []
181
+ define: { "process.env.NODE_ENV": JSON.stringify("production") }
182
+ };
183
+ const serverEnvPlugin = createServerEnvPlugin({
184
+ envDir: path2.join(this.#app.cwdPath, "env"),
185
+ environment: this.#environment ?? baseDevEnv.env,
186
+ environments: ["local", "testing", ...branches]
136
187
  });
188
+ const backendConfig = {
189
+ ...sharedConfig,
190
+ plugins: [this.#createExternalSpecifiersPlugin(externalLibs), serverEnvPlugin]
191
+ };
192
+ const [mainResult, serverResult] = [
193
+ await this.#buildOrThrow("backend", { ...backendConfig, entrypoints: [backendEntryPoints[0]] }),
194
+ await this.#buildOrThrow("backend", { ...backendConfig, entrypoints: [backendEntryPoints[1]], splitting: true })
195
+ ];
137
196
  const rscWorkerResult = web.ssr ? await this.#buildOrThrow("rsc-worker", {
197
+ ...backendConfig,
138
198
  entrypoints: [this.#resolveRscWorkerBuildEntry()],
139
- outdir: this.#app.dist.cwdPath,
140
- target: "bun",
141
- minify: AKAN_BACKEND_MINIFY,
142
- naming: { entry: "[name].[ext]", chunk: "chunk-[hash].[ext]" },
143
- conditions: ["react-server"],
144
- define: { "process.env.NODE_ENV": JSON.stringify("production") },
145
- plugins: backendExternals.length > 0 ? [this.#createExternalSpecifiersPlugin(backendExternals)] : []
199
+ conditions: ["react-server"]
146
200
  }) : null;
147
201
  const consoleRuntimeResult = await this.#buildOrThrow("console-runtime", {
202
+ ...sharedConfig,
148
203
  entrypoints: [this.#resolveConsoleRuntimeBuildEntry()],
149
- outdir: this.#app.dist.cwdPath,
150
- target: "bun",
151
- minify: AKAN_BACKEND_MINIFY,
152
- naming: { entry: "console-runtime.[ext]", chunk: "chunk-[hash].[ext]" },
153
- define: { "process.env.NODE_ENV": JSON.stringify("production") }
204
+ naming: { entry: "console-runtime.[ext]", chunk: "chunk-[hash].[ext]" }
154
205
  });
155
206
  await this.#writeConsoleShim();
207
+ const results = [mainResult, serverResult, rscWorkerResult, consoleRuntimeResult];
156
208
  return {
157
209
  entrypoints: backendEntryPoints.length + (rscWorkerResult ? 2 : 1),
158
- outputs: backendResult.outputs.length + (rscWorkerResult?.outputs.length ?? 0) + consoleRuntimeResult.outputs.length + 1
210
+ outputs: results.reduce((sum, result) => sum + (result?.outputs.length ?? 0), 1)
159
211
  };
160
212
  }
161
213
  async#writeConsoleShim() {
162
- await Bun.write(path.join(this.#app.dist.cwdPath, "console.js"), `import { cnst, db, dict, option, server, sig, srv } from "./server.js";
163
- import { assertAkanConsoleAllowed, startAkanConsole } from "./console-runtime.js";
214
+ await Bun.write(path2.join(this.#app.dist.cwdPath, "console.js"), `process.env.AKAN_COMMAND_TYPE = "console";
215
+ const { cnst, db, dict, option, server, sig, srv } = await import("./server.js");
216
+ const { assertAkanConsoleAllowed, startAkanConsole } = await import("./console-runtime.js");
164
217
 
165
218
  const run = async () => {
166
- assertAkanConsoleAllowed(server.env);
219
+ assertAkanConsoleAllowed();
167
220
  await server.start({ listen: false, web: false });
168
221
  try {
169
222
  await startAkanConsole(server, { globals: { cnst, db, dict, option, sig, srv } });
@@ -182,19 +235,16 @@ void run().catch((error) => {
182
235
  try {
183
236
  return Bun.resolveSync("akanjs/server/rsc-worker", import.meta.dir);
184
237
  } catch {
185
- return path.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/rscWorker.tsx");
238
+ return path2.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/rscWorker.tsx");
186
239
  }
187
240
  }
188
241
  #resolveConsoleRuntimeBuildEntry() {
189
242
  try {
190
- return path.join(path.dirname(Bun.resolveSync("akanjs/server", import.meta.dir)), "console.ts");
243
+ return path2.join(path2.dirname(Bun.resolveSync("akanjs/server", import.meta.dir)), "console.ts");
191
244
  } catch {
192
- return path.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/console.ts");
245
+ return path2.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/console.ts");
193
246
  }
194
247
  }
195
- async#buildCsr() {
196
- return await new CsrArtifactBuilder(this.#app, "build").build();
197
- }
198
248
  async#buildSsr() {
199
249
  const pageKeys = await this.#app.getPageKeys();
200
250
  if (pageKeys.length === 0) {
@@ -205,11 +255,11 @@ void run().catch((error) => {
205
255
  const allRoutes = await new AllRoutesBuilder(this.#app, base.artifact, "build").build();
206
256
  return { base, allRoutes };
207
257
  }
208
- async#writeTypecheckTsconfig({ incremental = true } = {}) {
209
- const typecheckDir = path.join(this.#app.cwdPath, ".akan", "typecheck");
258
+ async#writeTypecheckTsconfig(incremental) {
259
+ const typecheckDir = path2.join(this.#app.cwdPath, ".akan", "typecheck");
210
260
  await mkdir(typecheckDir, { recursive: true });
211
261
  const libPageIncludes = (await this.#app.getPageRoots()).filter((root) => root.keyPrefix).flatMap((root) => {
212
- const rel = path.relative(typecheckDir, root.realDir).split(path.sep).join("/");
262
+ const rel = path2.relative(typecheckDir, root.realDir).split(path2.sep).join("/");
213
263
  return [`${rel}/**/*.ts`, `${rel}/**/*.tsx`];
214
264
  });
215
265
  const tsconfig = {
@@ -230,7 +280,7 @@ void run().catch((error) => {
230
280
  ],
231
281
  references: []
232
282
  };
233
- const tsconfigPath = path.join(typecheckDir, "tsconfig.json");
283
+ const tsconfigPath = path2.join(typecheckDir, "tsconfig.json");
234
284
  await Bun.write(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
235
285
  `);
236
286
  return { typecheckDir, tsconfigPath };
@@ -256,10 +306,10 @@ void run().catch((error) => {
256
306
  }
257
307
  async#resolveTypecheckWorkerEntry() {
258
308
  const candidates = [
259
- path.join(this.#app.workspace.workspaceRoot, "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
260
- path.join(this.#app.workspace.workspaceRoot, "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
261
- path.join(import.meta.dir, "typecheck.proc.js"),
262
- path.join(import.meta.dir, "typecheck.proc.ts")
309
+ path2.join(this.#app.workspace.workspaceRoot, "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
310
+ path2.join(this.#app.workspace.workspaceRoot, "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
311
+ path2.join(import.meta.dir, "typecheck.proc.js"),
312
+ path2.join(import.meta.dir, "typecheck.proc.ts")
263
313
  ];
264
314
  for (const candidate of candidates)
265
315
  if (await Bun.file(candidate).exists())
@@ -272,9 +322,9 @@ void run().catch((error) => {
272
322
  throw new AggregateError(result.logs, `[${label}] Bun.build failed`);
273
323
  return result;
274
324
  }
275
- #createExternalSpecifiersPlugin(specifiers) {
276
- const uniqueSpecifiers = [...new Set(specifiers)];
277
- const escaped = uniqueSpecifiers.map((specifier) => specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
325
+ #createExternalSpecifiersPlugin(externalLibs) {
326
+ const specifiers = new Set([...externalLibs, ...SSR_RENDER_EXTERNALS, ...AKAN_OPTIONAL_BACKEND_EXTERNALS]);
327
+ const escaped = [...specifiers].map((specifier) => specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
278
328
  const filter = new RegExp(`^(${escaped.join("|")})(?:/.*)?$`);
279
329
  return {
280
330
  name: "akan-backend-externalize-specifiers",
@@ -283,13 +333,7 @@ void run().catch((error) => {
283
333
  }
284
334
  };
285
335
  }
286
- static formatBytes(bytes) {
287
- if (bytes < 1024)
288
- return `${bytes}B`;
289
- if (bytes < 1024 * 1024)
290
- return `${(bytes / 1024).toFixed(1)}KB`;
291
- return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
292
- }
336
+ static formatBytes = FontPruner.formatBytes;
293
337
  }
294
338
  export {
295
339
  ApplicationBuildRunner
@@ -1,24 +1,33 @@
1
1
  // @bun
2
2
  import {
3
+ ApplicationBuildReporter
4
+ } from "./index-48k96p55.js";
5
+ import {
6
+ resolveSsrPageEntriesForApp,
3
7
  WorkspaceExecutor,
4
8
  AppExecutor
5
- } from "./index-2tv3fdx4.js";
6
- import"./index-q0y2jq9j.js";
7
- import"./index-6wwzs1bc.js";
9
+ } from "./index-n3jk2501.js";
8
10
  import {
9
- CssCompiler,
11
+ computeRouteSeedIndex,
12
+ saveRouteSeedIndex,
13
+ ServerGraphFile,
10
14
  PagesBundleBuilder,
15
+ CsrDevBundler,
16
+ SsrDevBundler
17
+ } from "./index-6x9p8dpb.js";
18
+ import"./index-52w0fvh8.js";
19
+ import {
11
20
  CsrArtifactBuilder,
21
+ CssCompiler,
12
22
  FontOptimizer,
13
23
  SsrBaseArtifactBuilder
14
- } from "./index-a64esmtb.js";
15
- import"./index-w8kmx1b6.js";
16
- import"./index-hwkygn9s.js";
24
+ } from "./index-376gpdds.js";
17
25
  import"./index-n68jx79w.js";
18
26
 
19
27
  // pkgs/@akanjs/devkit/incrementalBuilder/buildBatch.proc.ts
20
28
  import path from "path";
21
29
  import { Logger } from "akanjs/common";
30
+ import { resolveDevCsrMode } from "akanjs/server/hmr/csrDevManifest";
22
31
 
23
32
  class BuildBatch {
24
33
  #logger = new Logger("BuildBatch");
@@ -35,15 +44,23 @@ class BuildBatch {
35
44
  await this.#buildBase();
36
45
  if (this.#request.needs.includes("csr"))
37
46
  await this.#buildCsr();
38
- if (this.#request.needs.includes("pages"))
39
- await this.#buildPages();
47
+ if (this.#request.needs.includes("ssr"))
48
+ await this.#buildSsrRegistry();
40
49
  if (this.#request.needs.includes("css"))
41
50
  await this.#buildCss();
51
+ if (this.#request.needs.includes("pages"))
52
+ await this.#buildPages();
42
53
  return this.#result;
43
54
  }
44
55
  #emit(message) {
45
56
  process.send?.(message);
46
57
  }
58
+ #sentTrace() {
59
+ if (!this.#request.trace)
60
+ return;
61
+ const now = Date.now();
62
+ return { ...this.#request.trace, patchAt: now, sentAt: now };
63
+ }
47
64
  #emitStatus(phase, message) {
48
65
  this.#emit({
49
66
  type: "build-status",
@@ -56,6 +73,13 @@ class BuildBatch {
56
73
  }
57
74
  });
58
75
  }
76
+ #fail(need, label, err) {
77
+ const message = ApplicationBuildReporter.formatError(err, this.#request.workspaceRoot);
78
+ this.#logger.error(`${label} failed: ${message}`);
79
+ this.#result.errors[need] = message;
80
+ if (need !== "base")
81
+ this.#emitStatus(need, message);
82
+ }
59
83
  async#buildBase() {
60
84
  const started = Date.now();
61
85
  try {
@@ -64,44 +88,106 @@ class BuildBatch {
64
88
  this.#result.optimizedFonts = optimizedFonts;
65
89
  this.#logger.verbose(`base-artifact ok buildId=${artifact.pagesBundleBuildId} (${Date.now() - started}ms)`);
66
90
  } catch (err) {
67
- const message = err instanceof Error ? err.message : String(err);
68
- this.#logger.error(`base-artifact failed: ${message}`);
69
- this.#result.errors.base = message;
91
+ this.#fail("base", "base-artifact", err);
70
92
  }
71
93
  }
72
94
  async#buildCsr() {
73
95
  const started = Date.now();
74
96
  try {
75
- await new CsrArtifactBuilder(this.#app).build();
76
- this.#logger.verbose(`csr-rebundle ok (${Date.now() - started}ms)`);
97
+ if (resolveDevCsrMode() === "registry")
98
+ await this.#updateCsrRegistry(started);
99
+ else
100
+ await this.#rebuildCsrArtifact(started);
77
101
  this.#emitStatus("csr");
78
102
  } catch (err) {
79
- const message = err instanceof Error ? err.message : String(err);
80
- this.#logger.error(`csr-rebundle failed: ${message}`);
81
- this.#result.errors.csr = message;
82
- this.#emitStatus("csr", message);
103
+ this.#fail("csr", "csr-rebundle", err);
104
+ }
105
+ }
106
+ async#rebuildCsrArtifact(started) {
107
+ await new CsrArtifactBuilder(this.#app).build();
108
+ this.#logger.verbose(`csr-rebundle ok (${Date.now() - started}ms)`);
109
+ if (this.#request.changedFiles.length === 0)
110
+ return;
111
+ this.#emit({
112
+ type: "csr-updated",
113
+ data: { generation: Date.now(), mode: "artifact", reload: true, reason: "the CSR artifact was rebuilt" }
114
+ });
115
+ }
116
+ async#updateCsrRegistry(started) {
117
+ const update = await new CsrDevBundler(this.#app).update(this.#request.changedFiles, {
118
+ announce: (announced) => this.#emit({
119
+ type: "csr-updated",
120
+ data: {
121
+ generation: announced.generation,
122
+ mode: "registry",
123
+ reload: announced.reload,
124
+ reason: announced.reason,
125
+ patchUrl: announced.patchUrl,
126
+ changedIds: announced.changedIds,
127
+ trace: this.#sentTrace()
128
+ }
129
+ })
130
+ });
131
+ if (!update) {
132
+ this.#logger.verbose(`csr-dev unchanged (${Date.now() - started}ms)`);
133
+ return;
134
+ }
135
+ this.#logger.verbose(`csr-dev generation=${update.generation} ${update.reload ? `reload (${update.reason})` : `patch modules=${update.changedIds.length}`} graph=${update.moduleCount} (${Date.now() - started}ms)`);
136
+ }
137
+ async#buildSsrRegistry() {
138
+ const started = Date.now();
139
+ try {
140
+ const bundler = new SsrDevBundler(this.#app);
141
+ const hold = await ServerGraphFile.touches(await ServerGraphFile.read(this.#request.artifactDir), this.#request.changedFiles, (file) => ServerGraphFile.clientExportsOf(file));
142
+ const update = await bundler.update(this.#request.changedFiles, {
143
+ roots: await bundler.clientEntries(),
144
+ announce: (announced) => this.#emit({
145
+ type: "ssr-updated",
146
+ data: {
147
+ generation: announced.generation,
148
+ reload: announced.reload,
149
+ reason: announced.reason,
150
+ patchUrl: announced.patchUrl,
151
+ changedIds: announced.changedIds,
152
+ trace: this.#sentTrace(),
153
+ ...announced.epoch !== undefined ? { epoch: announced.epoch } : {},
154
+ ...announced.first ? { first: true } : {},
155
+ ...hold && this.#request.changedFiles.length > 0 ? { hold, batchGeneration: this.#request.generation } : {}
156
+ }
157
+ })
158
+ });
159
+ this.#emitStatus("ssr");
160
+ this.#logger.verbose(update ? `ssr-dev generation=${update.generation} ${update.reload ? `reload (${update.reason})` : `patch modules=${update.changedIds.length}`} graph=${update.moduleCount} (${Date.now() - started}ms)` : `ssr-dev unchanged (${Date.now() - started}ms)`);
161
+ } catch (err) {
162
+ this.#fail("ssr", "ssr-dev", err);
83
163
  }
84
164
  }
85
165
  async#buildPages() {
86
166
  const started = Date.now();
87
167
  try {
88
- const next = await new PagesBundleBuilder(this.#app).build();
168
+ const pageEntries = await resolveSsrPageEntriesForApp(this.#app, await this.#app.getPageKeys());
169
+ const seedIndex = computeRouteSeedIndex(pageEntries);
170
+ const previousGraph = await ServerGraphFile.read(this.#request.artifactDir);
171
+ const next = await new PagesBundleBuilder(this.#app, "start", pageEntries).build();
172
+ await saveRouteSeedIndex(this.#request.artifactDir, seedIndex);
173
+ const nextGraph = await ServerGraphFile.read(this.#request.artifactDir);
174
+ const serverTouched = await ServerGraphFile.touches(previousGraph, [...this.#request.changedFiles, ...previousGraph?.carried ?? []], (file) => nextGraph?.clientExports[file] ?? null, nextGraph);
89
175
  this.#emit({
90
176
  type: "pages-updated",
91
177
  data: {
92
178
  bundlePath: next.bundlePath,
93
179
  buildId: next.buildId,
94
180
  generation: this.#request.generation,
95
- changedFiles: this.#request.changedFiles
181
+ changedFiles: this.#request.changedFiles,
182
+ trace: this.#sentTrace(),
183
+ serverTouched
96
184
  }
97
185
  });
98
186
  this.#emitStatus("pages");
99
187
  this.#logger.verbose(`pages-rebundle ok buildId=${next.buildId} (${Date.now() - started}ms)`);
100
188
  } catch (err) {
101
- const message = err instanceof Error ? err.message : String(err);
102
- this.#logger.error(`pages-rebundle failed: ${message}`);
103
- this.#result.errors.pages = message;
104
- this.#emitStatus("pages", message);
189
+ this.#fail("pages", "pages-rebundle", err);
190
+ await ServerGraphFile.carry(this.#request.artifactDir, this.#request.changedFiles).catch((carryError) => this.#logger.warn(`server graph carry failed; the next save may skip its RSC refresh: ${String(carryError)}`));
105
191
  }
106
192
  }
107
193
  async#buildCss() {
@@ -143,10 +229,7 @@ ${cssText}`).toString(36);
143
229
  });
144
230
  this.#logger.verbose(`css-compile ok assets=${Object.keys(cssAssets).length} (${Date.now() - started}ms)`);
145
231
  } catch (err) {
146
- const message = err instanceof Error ? err.message : String(err);
147
- this.#logger.error(`css-rebuild failed: ${message}`);
148
- this.#result.errors.css = message;
149
- this.#emitStatus("css", message);
232
+ this.#fail("css", "css-rebuild", err);
150
233
  }
151
234
  }
152
235
  async#optimizeFonts() {
@@ -162,8 +245,6 @@ ${cssText}`).toString(36);
162
245
  return optimizedFonts;
163
246
  }
164
247
  static #shouldReoptimizeFonts(previous, changedFiles) {
165
- if (changedFiles.length === 0)
166
- return false;
167
248
  return changedFiles.some((file) => {
168
249
  const normalized = path.resolve(file);
169
250
  if (/\.(woff2?|ttf|otf)$/i.test(normalized))
@@ -175,7 +256,11 @@ ${cssText}`).toString(36);
175
256
  const raw = process.argv[2];
176
257
  if (!raw)
177
258
  throw new Error("[build-batch] missing request argument");
178
- const request = JSON.parse(raw);
259
+ const parsed = JSON.parse(raw);
260
+ const request = parsed.trace ? {
261
+ ...parsed,
262
+ trace: { ...parsed.trace, workerStartAt: Math.round(performance.timeOrigin), workerAt: Date.now() }
263
+ } : parsed;
179
264
  const workspace = WorkspaceExecutor.fromRoot({
180
265
  workspaceRoot: request.workspaceRoot,
181
266
  repoName: request.repoName
@@ -183,11 +268,14 @@ ${cssText}`).toString(36);
183
268
  const app = AppExecutor.from(workspace, request.appName);
184
269
  if (request.pageKeys)
185
270
  app.setPageKeys(request.pageKeys);
271
+ const orphaned = () => process.exit(1);
272
+ process.on("disconnect", orphaned);
186
273
  const result = await new BuildBatch(request, app).run();
187
274
  process.send?.({ type: "build-batch-result", data: result });
275
+ process.off("disconnect", orphaned);
188
276
  }
189
277
  }
190
- BuildBatch.main().catch((err) => {
278
+ await BuildBatch.main().catch((err) => {
191
279
  console.error(err);
192
280
  process.exit(1);
193
281
  });