@akanjs/cli 3.1.0-rc.0 → 3.1.0-rc.2

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 (76) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-q7a4srt6.js → CodeAgent-q50k4s45.js} +2 -2
  3. package/{CodeTui-ak23dxc9.js → CodeTui-62g35ztk.js} +1 -1
  4. package/TunnelShare-f1egrktx.js +13 -0
  5. package/{agent.command-f3gsc1gd.js → agent.command-adfd5299.js} +5 -5
  6. package/akanCode.js +2 -2
  7. package/{application.command-3v2d53gd.js → application.command-hj3gv1rx.js} +52 -41
  8. package/{applicationBuildRunner-1yaqsrdq.js → applicationBuildRunner-by10r9gf.js} +16 -30
  9. package/buildBatch.proc.js +22 -13
  10. package/{cloud.command-kk2rwkvw.js → cloud.command-k2fhaape.js} +60 -63
  11. package/cloud.script-z8p5dz7e.js +23 -0
  12. package/{code.command-30sca09d.js → code.command-kt5zgcc2.js} +6 -6
  13. package/{context.command-k7eqacq6.js → context.command-8fgn42jw.js} +16 -13
  14. package/context.runner-hnh0rg7m.js +24 -0
  15. package/{guideline.command-dtczrqpf.js → guideline.command-3yxxr2mm.js} +2 -2
  16. package/guidelines/conventions/conventions.instruction.md +30 -15
  17. package/guidelines/cssRule/cssRule.instruction.md +12 -6
  18. package/guidelines/mcpRule/mcpRule.instruction.md +32 -11
  19. package/guidelines/runtimeRule/runtimeRule.instruction.md +24 -15
  20. package/guidelines/transportRule/transportRule.instruction.md +28 -5
  21. package/incrementalBuilder.proc.js +9 -6
  22. package/{index-kjvrq3nc.js → index-0909wckt.js} +361 -282
  23. package/{index-p9ystjrp.js → index-20cebtth.js} +92 -52
  24. package/{index-55mynnqs.js → index-2etqq75t.js} +455 -206
  25. package/{index-6jjtnhkw.js → index-31ce9vhg.js} +51 -9
  26. package/{index-y8q31011.js → index-3reaaa1h.js} +42 -153
  27. package/{index-ww9bhp67.js → index-4pf8g7ff.js} +1 -1
  28. package/{index-qt22xstj.js → index-58vvz603.js} +5 -3
  29. package/index-6726qr1m.js +668 -0
  30. package/index-8935h3n1.js +33 -0
  31. package/{index-nz15k0b6.js → index-8zdwpxef.js} +1 -1
  32. package/{index-c2yrsxdh.js → index-azh29dc8.js} +96 -320
  33. package/{index-c1x0be5j.js → index-bea2gwc6.js} +2 -2
  34. package/{index-v29746vb.js → index-e9prnmyt.js} +3 -3
  35. package/{index-tn4rpqp1.js → index-fjsv10hd.js} +73 -49
  36. package/index-g0vwzy9m.js +241 -0
  37. package/{index-c76k723e.js → index-h85cxfkg.js} +2 -2
  38. package/{index-rwq3ekqc.js → index-hnby7p9n.js} +7 -7
  39. package/{index-2etcv0sc.js → index-jwqtchha.js} +1 -1
  40. package/index-kc8z134d.js +248 -0
  41. package/index-nq045px5.js +1124 -0
  42. package/{index-fm46xrf1.js → index-nq2ja5e0.js} +3 -3
  43. package/{index-0bm04n5g.js → index-pyxn1b53.js} +10 -8
  44. package/{index-05g3jayg.js → index-rhbabmja.js} +1 -1
  45. package/{index-2mx692qq.js → index-rk9sdys3.js} +2 -2
  46. package/{index-7bymavqk.js → index-sby8fe1p.js} +1 -1
  47. package/{index-ctanya41.js → index-sqfdmb5b.js} +4 -4
  48. package/{index-2t4tqd1c.js → index-t7nws9mx.js} +3 -3
  49. package/{index-jyv387qw.js → index-tv8fjaba.js} +4 -4
  50. package/{index-gnyf1fqy.js → index-tz5evhdr.js} +2 -2
  51. package/{index-aprt7pkz.js → index-xpdgxsj5.js} +229 -1327
  52. package/{index-e0cvze1s.js → index-z507nzhg.js} +4 -4
  53. package/index.js +22 -22
  54. package/{library.command-gaga5bmq.js → library.command-8tw59xzj.js} +3 -3
  55. package/{localRegistry.command-9e84e32q.js → localRegistry.command-tf3dmznd.js} +12 -9
  56. package/{module.command-7vpf6db4.js → module.command-9vm8hffy.js} +5 -5
  57. package/{package.command-twmvvf69.js → package.command-erbxe2tz.js} +3 -3
  58. package/package.json +2 -2
  59. package/{page.command-5asq7fdf.js → page.command-jpavcj0p.js} +3 -3
  60. package/{pipeline.command-d0v38572.js → pipeline.command-b8rzvjvv.js} +220 -219
  61. package/{primitive.command-dyrs2fm8.js → primitive.command-sm32chzk.js} +6 -6
  62. package/{projectTypecheck-cvtkrzp2.js → projectTypecheck-jamtx95x.js} +1 -1
  63. package/{quality.command-6emsqpbg.js → quality.command-pkd17n6y.js} +2 -2
  64. package/{repair.command-8t6aegv5.js → repair.command-8y4mq6hs.js} +5 -5
  65. package/{scalar.command-bnggy1x7.js → scalar.command-q8khmyx5.js} +4 -4
  66. package/{subspace.command-f02j5tge.js → subspace.command-51n0ykbx.js} +421 -362
  67. package/templates/app/env/env.client.type.ts +2 -3
  68. package/templates/app/page/styles.css.template +8 -0
  69. package/{tunnel.command-9x8nfn75.js → tunnel.command-7820vtxq.js} +7 -4
  70. package/{workflow.command-jx0wag5r.js → workflow.command-n5sv4wqz.js} +10 -10
  71. package/{workspace.command-cmj6mqyk.js → workspace.command-zdy60jh8.js} +33 -30
  72. package/TunnelShare-21mm6dr5.js +0 -9
  73. package/cloud.script-r7eyfey4.js +0 -20
  74. package/context.runner-hqd1ppqe.js +0 -21
  75. package/index-6w0rbr9d.js +0 -68
  76. package/index-r2tpeb3n.js +0 -392
@@ -0,0 +1,248 @@
1
+ // @bun
2
+ import {
3
+ resolveSsrPageEntriesForApp
4
+ } from "./index-2etqq75t.js";
5
+ import {
6
+ bundleDefine,
7
+ CsrEntryFiles,
8
+ PagesEntrySourceGenerator,
9
+ PagesBundleBuilder
10
+ } from "./index-nq045px5.js";
11
+
12
+ // pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
13
+ import { mkdir, rm, unlink } from "fs/promises";
14
+ import path from "path";
15
+ class CsrArtifactBuilder {
16
+ #app;
17
+ #command;
18
+ #lang;
19
+ #cssAssets;
20
+ constructor(app, command = "start", lang = "en", { cssAssets = null } = {}) {
21
+ this.#app = app;
22
+ this.#command = command;
23
+ this.#lang = lang;
24
+ this.#cssAssets = cssAssets;
25
+ }
26
+ async build() {
27
+ const pageKeys = await this.#app.getPageKeys();
28
+ if (pageKeys.length === 0) {
29
+ this.#app.log(`[cli] no route files under ${this.#app.cwdPath}/page \u2014 skipping CSR build`);
30
+ return null;
31
+ }
32
+ const pageEntries = await resolveSsrPageEntriesForApp(this.#app, pageKeys);
33
+ const akanConfig = await this.#app.getConfig();
34
+ const cssAssets = await this.#loadCssAssets();
35
+ const basePaths = [...akanConfig.basePaths];
36
+ const htmlBasePaths = basePaths.length > 0 ? basePaths : [""];
37
+ await rm(this.#outputDir, { recursive: true, force: true });
38
+ await mkdir(this.#generatedDir, { recursive: true });
39
+ const generatedFiles = Object.fromEntries((await Promise.all(htmlBasePaths.map(async (basePath) => [
40
+ this.#createHtmlFile(basePath),
41
+ await this.#createEntryFile(basePath, CsrArtifactBuilder.pageEntriesForBasePath(pageEntries, basePath, basePaths))
42
+ ]))).flat());
43
+ const options = CsrArtifactBuilder.bundleOptions(this.#app, this.#command, akanConfig.optimizeImports);
44
+ const result = await Bun.build({
45
+ ...options,
46
+ entrypoints: htmlBasePaths.map((basePath) => this.#generatedPath(CsrArtifactBuilder.htmlFilename(basePath))),
47
+ files: generatedFiles,
48
+ root: this.#generatedDir,
49
+ outdir: this.#outputDir
50
+ });
51
+ if (!result.success) {
52
+ const logs = result.logs.map((log) => log.message).join(`
53
+ `);
54
+ throw new Error(`[csr-build] failed${logs ? `
55
+ ${logs}` : ""}`);
56
+ }
57
+ await this.#inlineCsrArtifacts(cssAssets);
58
+ if (this.#command === "build")
59
+ await CsrArtifactBuilder.writePublicEnv(this.#app, options.define);
60
+ this.#app.verbose(`[csr-build] output -> ${this.#outputDir}`);
61
+ return { outputDir: this.#outputDir };
62
+ }
63
+ static bundleOptions(app, command, optimizeImports = []) {
64
+ return {
65
+ target: "browser",
66
+ splitting: false,
67
+ minify: true,
68
+ define: bundleDefine(app, command, "csr"),
69
+ optimizeImports,
70
+ plugins: [PagesBundleBuilder.createCssStubPlugin()]
71
+ };
72
+ }
73
+ static publicEnvPath(app) {
74
+ return path.join(app.dist.cwdPath, ".akan", "artifact", "csr-public-env.json");
75
+ }
76
+ static async writePublicEnv(app, define) {
77
+ const prefix = "process.env.";
78
+ const publicEnv = Object.fromEntries(Object.entries(define).filter(([key]) => key.startsWith(`${prefix}AKAN_PUBLIC_`)).map(([key, value]) => [key.slice(prefix.length), JSON.parse(value)]));
79
+ await Bun.write(CsrArtifactBuilder.publicEnvPath(app), `${JSON.stringify(publicEnv, null, 2)}
80
+ `);
81
+ }
82
+ static pageEntriesForBasePath(pageEntries, basePath, basePaths) {
83
+ return CsrEntryFiles.pageEntriesForBasePath(pageEntries, basePath, basePaths);
84
+ }
85
+ static htmlFilename(basePath) {
86
+ return `${basePath || "index"}.html`;
87
+ }
88
+ static entryFilename(basePath) {
89
+ return CsrEntryFiles.entryFilename(basePath);
90
+ }
91
+ static basePathOfHtml(htmlPath) {
92
+ const name = path.basename(htmlPath, ".html");
93
+ return name === "index" ? "" : name;
94
+ }
95
+ get #outputDir() {
96
+ return path.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, this.#command === "build" ? "csr" : ".akan/artifact/csr");
97
+ }
98
+ get #generatedDir() {
99
+ return path.join(this.#app.cwdPath, ".akan/generated/csr");
100
+ }
101
+ get #artifactDir() {
102
+ return path.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact");
103
+ }
104
+ #generatedPath(filename) {
105
+ return path.join(this.#generatedDir, filename);
106
+ }
107
+ async#createEntryFile(basePath, pageEntries) {
108
+ return [
109
+ this.#generatedPath(CsrArtifactBuilder.entryFilename(basePath)),
110
+ `import { bootCsr } from "akanjs/webkit";
111
+ ${await PagesEntrySourceGenerator.generateStatic(pageEntries)}
112
+ void bootCsr(pages);
113
+ `
114
+ ];
115
+ }
116
+ #createHtmlFile(basePath) {
117
+ return [
118
+ this.#generatedPath(CsrArtifactBuilder.htmlFilename(basePath)),
119
+ `<!doctype html>
120
+ <html lang="${this.#lang}">
121
+ <head>
122
+ <meta charset="utf-8" />
123
+ <title>${this.#app.name}</title>
124
+ <base href="/" />
125
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
126
+ </head>
127
+ <body>
128
+ <div id="root"></div>
129
+ <script type="module" src="./${CsrArtifactBuilder.entryFilename(basePath)}"></script>
130
+ </body>
131
+ </html>
132
+ `
133
+ ];
134
+ }
135
+ async#loadCssAssets() {
136
+ if (this.#cssAssets)
137
+ return this.#cssAssets;
138
+ const artifactFile = Bun.file(path.join(this.#artifactDir, "base-artifact.json"));
139
+ if (!await artifactFile.exists())
140
+ return {};
141
+ const artifact = await artifactFile.json();
142
+ return artifact.cssAssets ?? {};
143
+ }
144
+ async#inlineCsrArtifacts(cssAssets) {
145
+ const jsFiles = new Set;
146
+ for (const htmlPath of await this.#listOutputFiles((filePath) => filePath.endsWith(".html"))) {
147
+ const htmlFile = Bun.file(htmlPath);
148
+ if (!await htmlFile.exists())
149
+ continue;
150
+ const basePath = CsrArtifactBuilder.basePathOfHtml(htmlPath);
151
+ const cssAsset = cssAssets[basePath];
152
+ if (!cssAsset) {
153
+ this.#app.logger.warn(`[csr-build] base-artifact.json has no compiled stylesheet for ${basePath || "root"}; ${path.basename(htmlPath)} ships without CSS`);
154
+ }
155
+ const inlined = await this.#inlineHtmlAssets(await htmlFile.text(), htmlPath, cssAsset);
156
+ for (const filePath of inlined.jsFiles)
157
+ jsFiles.add(filePath);
158
+ await Bun.write(htmlPath, inlined.html);
159
+ }
160
+ for (const filePath of jsFiles)
161
+ await unlink(filePath).catch(() => {
162
+ return;
163
+ });
164
+ const remainingAssets = await this.#listOutputFiles((filePath) => filePath.endsWith(".js") || filePath.endsWith(".css"));
165
+ if (remainingAssets.length > 0) {
166
+ throw new Error(`[csr-build] expected single-file HTML, but CSR assets remain:
167
+ ${remainingAssets.join(`
168
+ `)}`);
169
+ }
170
+ }
171
+ async#inlineHtmlAssets(html, htmlPath, cssAsset) {
172
+ let next = html;
173
+ if (cssAsset) {
174
+ const css = await Bun.file(path.join(this.#artifactDir, cssAsset.cssRelPath)).text();
175
+ next = CsrArtifactBuilder.injectBeforeHeadEnd(next, CsrArtifactBuilder.createInlineStyle(css));
176
+ }
177
+ const jsFiles = [];
178
+ next = await CsrArtifactBuilder.replaceModuleScriptSrc(next, async (src) => {
179
+ const jsPath = CsrArtifactBuilder.resolveHtmlAssetPath(htmlPath, src);
180
+ jsFiles.push(jsPath);
181
+ return await Bun.file(jsPath).text();
182
+ });
183
+ return { html: next, jsFiles };
184
+ }
185
+ async#listOutputFiles(predicate) {
186
+ const glob = new Bun.Glob("**/*");
187
+ const files = [];
188
+ for await (const filePath of glob.scan({ cwd: this.#outputDir, absolute: true })) {
189
+ if (predicate(filePath))
190
+ files.push(filePath);
191
+ }
192
+ return files.sort();
193
+ }
194
+ static injectBeforeHeadEnd(html, snippet) {
195
+ const scannable = CsrArtifactBuilder.blankEmbeddedContent(html);
196
+ const headEnd = scannable.search(/<\/head\s*>/i);
197
+ if (headEnd !== -1)
198
+ return `${html.slice(0, headEnd)}${snippet}
199
+ ${html.slice(headEnd)}`;
200
+ const bodyStart = scannable.search(/<body(?:\s|>)/i);
201
+ if (bodyStart !== -1)
202
+ return `${html.slice(0, bodyStart)}${snippet}
203
+ ${html.slice(bodyStart)}`;
204
+ return `${html}
205
+ ${snippet}`;
206
+ }
207
+ static blankEmbeddedContent(html) {
208
+ return html.replace(/<script\b[^>]*>[\s\S]*?<\/script\s*>|<style\b[^>]*>[\s\S]*?<\/style\s*>|<!--[\s\S]*?-->/gi, (match) => " ".repeat(match.length));
209
+ }
210
+ static createInlineStyle(css) {
211
+ return `<style data-akan-css="active">
212
+ ${css.replace(/<\/style/gi, "<\\/style")}
213
+ </style>`;
214
+ }
215
+ static async replaceModuleScriptSrc(html, loadScript) {
216
+ const scriptRe = /<script\b(?=[^>]*\btype=["']module["'])(?=[^>]*\bsrc=["']([^"']+)["'])[^>]*>\s*<\/script>/gi;
217
+ let result = "";
218
+ let lastIndex = 0;
219
+ let matched = false;
220
+ for (const match of html.matchAll(scriptRe)) {
221
+ const full = match[0];
222
+ const src = match[1];
223
+ if (match.index === undefined || !src)
224
+ continue;
225
+ matched = true;
226
+ result += html.slice(lastIndex, match.index);
227
+ result += `<script type="module">
228
+ ${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
229
+ </script>`;
230
+ lastIndex = match.index + full.length;
231
+ }
232
+ if (!matched)
233
+ return html;
234
+ return result + html.slice(lastIndex);
235
+ }
236
+ static escapeInlineScript(source) {
237
+ return source.replace(/<\/script/gi, "<\\/script");
238
+ }
239
+ static resolveHtmlAssetPath(htmlPath, src) {
240
+ if (/^[a-z][a-z0-9+.-]*:/i.test(src) || src.startsWith("//")) {
241
+ throw new Error(`[csr-build] cannot inline external script: ${src}`);
242
+ }
243
+ const normalized = src.startsWith("/") ? src.slice(1) : src;
244
+ return path.resolve(path.dirname(htmlPath), normalized);
245
+ }
246
+ }
247
+
248
+ export { CsrArtifactBuilder };