@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,1124 @@
1
+ // @bun
2
+ import {
3
+ FileSys2
4
+ } from "./index-52w0fvh8.js";
5
+ import {
6
+ AsyncDefaultExportDetector,
7
+ resolveSsrPageEntriesForApp
8
+ } from "./index-2etqq75t.js";
9
+
10
+ // pkgs/@akanjs/devkit/frontendBuild/serverGraphFile.ts
11
+ import fs2 from "fs";
12
+ import path3 from "path";
13
+
14
+ // pkgs/@akanjs/devkit/transforms/rscUseClientTransform.ts
15
+ import path from "path";
16
+ import ts from "typescript";
17
+
18
+ // pkgs/@akanjs/devkit/transforms/moduleSyntax.ts
19
+ var loaderFor = (absPath) => {
20
+ if (absPath.endsWith(".tsx"))
21
+ return "tsx";
22
+ if (absPath.endsWith(".jsx"))
23
+ return "jsx";
24
+ if (absPath.endsWith(".ts"))
25
+ return "ts";
26
+ return "js";
27
+ };
28
+ var parseNamedList = (listBody) => {
29
+ const out = [];
30
+ for (const raw of listBody.split(",")) {
31
+ let rest = raw.trim();
32
+ if (!rest)
33
+ continue;
34
+ let isType = false;
35
+ if (rest.startsWith("type ")) {
36
+ isType = true;
37
+ rest = rest.slice(5).trim();
38
+ }
39
+ const asMatch = /^(\w+)\s+as\s+(\w+)$/.exec(rest);
40
+ if (asMatch) {
41
+ out.push({ imported: asMatch[1] ?? "", local: asMatch[2] ?? "", isType });
42
+ continue;
43
+ }
44
+ if (/^\w+$/.test(rest))
45
+ out.push({ imported: rest, local: rest, isType });
46
+ }
47
+ return out;
48
+ };
49
+
50
+ // pkgs/@akanjs/devkit/transforms/rscUseClientTransform.ts
51
+ var USE_CLIENT_RE = /^\s*(?:\/\*[\s\S]*?\*\/\s*|\/\/[^\n]*\n\s*)*["']use client["']/;
52
+ var IMPLICIT_ROOT_LAYOUT_RE = /[/\\]\.akan[/\\]generated[/\\](?:implicit-root-layout|root-layouts[/\\].*__root_layout)\.(tsx|ts|jsx|js)$/;
53
+ var STAR_REEXPORT_HINT_RE = /\bexport\s*\*\s*from\b/;
54
+ var hasUseClientDirective = (source) => USE_CLIENT_RE.test(source);
55
+ function toClientReferencePath(absPath, workspaceRoot) {
56
+ return path.relative(path.resolve(workspaceRoot), path.resolve(absPath)).split(path.sep).join("/");
57
+ }
58
+ var starReexportSpecifiers = (source, filePath) => ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest).statements.filter((statement) => ts.isExportDeclaration(statement) && !statement.exportClause && !statement.isTypeOnly && !!statement.moduleSpecifier && ts.isStringLiteral(statement.moduleSpecifier)).map((statement) => statement.moduleSpecifier.text);
59
+ var scanUseClientExports = (source, filePath, workspaceRoot) => {
60
+ const stars = USE_CLIENT_RE.test(source) && STAR_REEXPORT_HINT_RE.test(source) ? starReexportSpecifiers(source, filePath) : [];
61
+ if (stars.length) {
62
+ const file = workspaceRoot ? toClientReferencePath(filePath, workspaceRoot) : filePath;
63
+ const listed = stars.slice(0, 3).map((specifier) => `\`export * from ${JSON.stringify(specifier)}\``);
64
+ const written = stars.length > 3 ? `${listed.join(", ")} (and ${stars.length - 3} more)` : listed.join(", ");
65
+ throw new Error(`${file} is a "use client" module, so it cannot ${written}: the server sees only the names a client module ` + `declares, and a star re-export declares none. Re-export them by name \u2014 \`export { \u2026 } from ${JSON.stringify(stars[0])}\`.`);
66
+ }
67
+ return new Bun.Transpiler({ loader: loaderFor(filePath) }).scan(source).exports;
68
+ };
69
+ function transformUseClient(source, args) {
70
+ if (!USE_CLIENT_RE.test(source))
71
+ return null;
72
+ if (IMPLICIT_ROOT_LAYOUT_RE.test(args.path))
73
+ return null;
74
+ const exports = scanUseClientExports(source, args.path, args.workspaceRoot);
75
+ if (exports.length === 0)
76
+ return null;
77
+ args.onClientModule?.(args.path, exports);
78
+ const referencePath = args.workspaceRoot ? toClientReferencePath(args.path, args.workspaceRoot) : args.path;
79
+ const filePathLit = JSON.stringify(referencePath);
80
+ const lines = [`import { registerClientReference } from "react-server-dom-webpack/server.node";`];
81
+ for (const name of exports) {
82
+ const nameLit = JSON.stringify(name);
83
+ const errMsg = JSON.stringify(`Attempted to call '${name}' from '${referencePath}' on the server, but it is a client-only export.`);
84
+ const proxy = `() => { throw new Error(${errMsg}); }`;
85
+ const binding = name === "default" ? `export default registerClientReference(${proxy}, ${filePathLit}, ${nameLit});` : `export const ${name} = registerClientReference(${proxy}, ${filePathLit}, ${nameLit});`;
86
+ lines.push(binding);
87
+ }
88
+ return lines.join(`
89
+ `);
90
+ }
91
+
92
+ // pkgs/@akanjs/devkit/frontendBuild/csrDevPaths.ts
93
+ import fs from "fs";
94
+ import path2 from "path";
95
+
96
+ class CsrDevPaths {
97
+ static modulePrefix = "akan-module:";
98
+ static stubPrefix = "stub:";
99
+ static emptyStubPrefix = "stub:empty:";
100
+ static vendorPrefix = "vendor:";
101
+ root;
102
+ constructor(workspaceRoot) {
103
+ this.root = CsrDevPaths.realpath(workspaceRoot);
104
+ }
105
+ idOf(file) {
106
+ const real = CsrDevPaths.realpath(file);
107
+ const relative = path2.relative(this.root, real);
108
+ const id = relative.startsWith("..") || path2.isAbsolute(relative) ? real : relative;
109
+ return id.split(path2.sep).join("/");
110
+ }
111
+ fileOf(id) {
112
+ return path2.isAbsolute(id) ? id : path2.join(this.root, id);
113
+ }
114
+ static isStub(target) {
115
+ return target.startsWith(CsrDevPaths.stubPrefix);
116
+ }
117
+ static isVendorFile(file) {
118
+ return file.includes(`${path2.sep}node_modules${path2.sep}`);
119
+ }
120
+ static isScript(file) {
121
+ return /\.[cm]?[jt]sx?$/.test(file);
122
+ }
123
+ static mtimeOf(file) {
124
+ return fs.statSync(file, { throwIfNoEntry: false })?.mtimeMs ?? -1;
125
+ }
126
+ static async hashOf(file) {
127
+ const source = Bun.file(file);
128
+ return await source.exists() ? Bun.hash(await source.arrayBuffer()).toString(36) : "";
129
+ }
130
+ static realpath(file) {
131
+ return fs.existsSync(file) ? fs.realpathSync.native(file) : path2.resolve(file);
132
+ }
133
+ static isNamed(file) {
134
+ try {
135
+ return fs.realpathSync.native(file) === file;
136
+ } catch {
137
+ return false;
138
+ }
139
+ }
140
+ static #extensions = {
141
+ import: [".tsx", ".jsx", ".mts", ".ts", ".mjs", ".js", ".cts", ".cjs"],
142
+ require: [".tsx", ".ts", ".jsx", ".cts", ".cjs", ".js", ".mjs", ".mts"]
143
+ };
144
+ static resolveOnDisk(base, kind = "import") {
145
+ return CsrDevPaths.#asFile(base, kind) ?? CsrDevPaths.#asFolder(base, kind);
146
+ }
147
+ static resolveRelative(dir, specifier, kind = "import") {
148
+ const base = path2.resolve(dir, specifier);
149
+ const folder = /(^|[\\/])\.\.?$|[\\/]$/.test(specifier);
150
+ return folder ? CsrDevPaths.#asFolder(base, kind) : CsrDevPaths.resolveOnDisk(base, kind);
151
+ }
152
+ static #asFile(base, kind) {
153
+ const isFile = (candidate) => fs.statSync(candidate, { throwIfNoEntry: false })?.isFile() ?? false;
154
+ return [base, ...CsrDevPaths.#extensions[kind].map((extension) => `${base}${extension}`)].find(isFile) ?? null;
155
+ }
156
+ static #asFolder(dir, kind) {
157
+ const entry = CsrDevPaths.#packageEntryOf(dir, kind);
158
+ const named = entry ? CsrDevPaths.#asFile(path2.join(dir, entry), kind) ?? CsrDevPaths.#indexOf(path2.join(dir, entry), kind) : null;
159
+ return named ?? CsrDevPaths.#indexOf(dir, kind);
160
+ }
161
+ static #indexOf(dir, kind) {
162
+ return CsrDevPaths.#asFile(path2.join(dir, "index"), kind);
163
+ }
164
+ static #packageEntryOf(dir, kind) {
165
+ try {
166
+ const pkg = JSON.parse(fs.readFileSync(path2.join(dir, "package.json"), "utf8"));
167
+ const fields = kind === "require" ? [pkg.browser, pkg.main] : [pkg.browser, pkg.module, pkg.main];
168
+ const entry = fields.find((field) => typeof field === "string");
169
+ return typeof entry === "string" ? entry : null;
170
+ } catch {
171
+ return null;
172
+ }
173
+ }
174
+ static installedSince(specifier, from, since) {
175
+ const [first = "", second = ""] = specifier.split("/");
176
+ const name = first.startsWith("@") ? `${first}/${second}` : first;
177
+ if (!name || name.startsWith("."))
178
+ return false;
179
+ for (let dir = path2.resolve(from);; dir = path2.dirname(dir)) {
180
+ const pkgDir = path2.join(dir, "node_modules", name);
181
+ if (fs.existsSync(path2.join(pkgDir, "package.json")))
182
+ return (fs.statSync(pkgDir, { throwIfNoEntry: false })?.ctimeMs ?? 0) > since;
183
+ if (path2.dirname(dir) === dir)
184
+ return false;
185
+ }
186
+ }
187
+ static tryResolve(specifier, from) {
188
+ try {
189
+ return Bun.resolveSync(specifier, from);
190
+ } catch {
191
+ return null;
192
+ }
193
+ }
194
+ static lineCount(text) {
195
+ let count = 0;
196
+ for (let index = text.indexOf(`
197
+ `);index !== -1; index = text.indexOf(`
198
+ `, index + 1))
199
+ count += 1;
200
+ return count;
201
+ }
202
+ }
203
+
204
+ // pkgs/@akanjs/devkit/frontendBuild/serverGraphFile.ts
205
+ class ServerGraphFile {
206
+ static fileName = "server-graph.json";
207
+ static #cache = null;
208
+ static async read(artifactDir) {
209
+ const file = path3.join(artifactDir, ServerGraphFile.fileName);
210
+ const stat = fs2.statSync(file, { throwIfNoEntry: false });
211
+ if (!stat)
212
+ return null;
213
+ const stamp = `${stat.ino}:${stat.size}:${stat.mtimeMs}`;
214
+ const cached = ServerGraphFile.#cache;
215
+ if (cached?.file === file && cached.stamp === stamp)
216
+ return cached.graph;
217
+ const graph = await Bun.file(file).json().catch(() => null);
218
+ if (graph)
219
+ ServerGraphFile.#cache = { file, stamp, graph };
220
+ return graph;
221
+ }
222
+ static async write(artifactDir, graph) {
223
+ const file = path3.join(artifactDir, ServerGraphFile.fileName);
224
+ const temp = `${file}.${process.pid}.tmp`;
225
+ await Bun.write(temp, JSON.stringify(graph));
226
+ await FileSys2.replace(temp, file);
227
+ }
228
+ static async carry(artifactDir, files) {
229
+ const graph = await ServerGraphFile.read(artifactDir);
230
+ if (!graph || files.length === 0)
231
+ return;
232
+ const carried = [...new Set([...graph.carried ?? [], ...files.map((file) => CsrDevPaths.realpath(file))])];
233
+ await ServerGraphFile.write(artifactDir, { ...graph, carried });
234
+ }
235
+ static async touches(graph, files, exportsNow, next) {
236
+ if (!graph)
237
+ return true;
238
+ const inputs = new Set(graph.inputs);
239
+ const joined = new Set((next?.inputs ?? []).filter((input) => !inputs.has(input)));
240
+ for (const rawFile of files) {
241
+ const file = CsrDevPaths.realpath(rawFile);
242
+ if (joined.has(file))
243
+ return true;
244
+ if (!inputs.has(file))
245
+ continue;
246
+ const before = graph.clientExports[file];
247
+ if (!before)
248
+ return true;
249
+ const now = await exportsNow(file);
250
+ if (!now || ServerGraphFile.#names(now) !== ServerGraphFile.#names(before))
251
+ return true;
252
+ }
253
+ return false;
254
+ }
255
+ static async clientExportsOf(file) {
256
+ const source = await Bun.file(file).text().catch(() => null);
257
+ if (source === null || !hasUseClientDirective(source))
258
+ return null;
259
+ try {
260
+ return scanUseClientExports(source, file);
261
+ } catch {
262
+ return null;
263
+ }
264
+ }
265
+ static #names(exports) {
266
+ return [...exports].sort().join(",");
267
+ }
268
+ }
269
+
270
+ // pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
271
+ import fs3 from "fs";
272
+ import path8 from "path";
273
+
274
+ // pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
275
+ import path5 from "path";
276
+ import ts2 from "typescript";
277
+
278
+ // pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
279
+ import path4 from "path";
280
+ import { Logger } from "akanjs/common";
281
+ var REEXPORT_RE = /(?:^|\n)\s*export\s+(?:type\s+)?(?:(\*)(?:\s+as\s+(\w+))?|\{\s*([^}]*?)\s*\})\s+from\s+(["'])([^"']+)\4;?/g;
282
+ var LOCAL_NAMED_RE = /(?:^|\n)\s*export\s+\{\s*([^}]*?)\s*\}(?!\s*from)/g;
283
+ var CANDIDATE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
284
+
285
+ class BarrelAnalyzer {
286
+ #logger = new Logger("BarrelAnalyzer");
287
+ #opts;
288
+ #cache = new Map;
289
+ #tsTranspiler = new Bun.Transpiler({ loader: "ts" });
290
+ #tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
291
+ constructor(opts) {
292
+ this.#opts = opts;
293
+ }
294
+ analyze(pkgName) {
295
+ const cached = this.#cache.get(pkgName);
296
+ if (cached)
297
+ return cached;
298
+ const promise = this.#analyzeSafe(pkgName);
299
+ this.#cache.set(pkgName, promise);
300
+ return promise;
301
+ }
302
+ async#analyzeSafe(pkgName) {
303
+ try {
304
+ const pkg = await this.#opts.resolvePackage(pkgName);
305
+ if (!pkg)
306
+ return null;
307
+ const map = new Map;
308
+ await this.#walk(pkg.entryFile, pkg, map, new Set);
309
+ return map;
310
+ } catch (err) {
311
+ this.#logger.error(`analyze failed for ${pkgName}: ${err.message}`);
312
+ return null;
313
+ }
314
+ }
315
+ async#walk(absFile, pkg, map, visited) {
316
+ if (visited.has(absFile))
317
+ return;
318
+ visited.add(absFile);
319
+ const file = Bun.file(absFile);
320
+ if (!await file.exists())
321
+ return;
322
+ const source = await file.text();
323
+ const currentSubpath = this.#subpathFor(pkg, absFile);
324
+ if (!currentSubpath)
325
+ return;
326
+ const authoritative = this.#scanExports(source, absFile);
327
+ authoritative.delete("default");
328
+ const attributed = new Set;
329
+ const attribute = (listBody, subpath) => {
330
+ for (const item of parseNamedList(listBody)) {
331
+ if (item.isType || item.imported === "default" || !authoritative.has(item.local))
332
+ continue;
333
+ attributed.add(item.local);
334
+ if (!map.has(item.local))
335
+ map.set(item.local, { subpath, originalName: item.imported });
336
+ }
337
+ };
338
+ const starSpecs = [];
339
+ for (const m of source.matchAll(REEXPORT_RE)) {
340
+ const star = m[1];
341
+ const nsAs = m[2];
342
+ const namedList = m[3];
343
+ const spec = m[5] ?? "";
344
+ if (!isRelative(spec))
345
+ continue;
346
+ if (star) {
347
+ if (nsAs)
348
+ authoritative.delete(nsAs);
349
+ else
350
+ starSpecs.push(spec);
351
+ continue;
352
+ }
353
+ if (namedList !== undefined) {
354
+ const targetAbs = await this.#resolveRel(absFile, spec);
355
+ if (!targetAbs)
356
+ continue;
357
+ const targetSubpath = this.#subpathFor(pkg, targetAbs);
358
+ if (targetSubpath)
359
+ attribute(namedList, targetSubpath);
360
+ }
361
+ }
362
+ LOCAL_NAMED_RE.lastIndex = 0;
363
+ let n = LOCAL_NAMED_RE.exec(source);
364
+ while (n !== null) {
365
+ const body = n[1] ?? "";
366
+ n = LOCAL_NAMED_RE.exec(source);
367
+ attribute(body, currentSubpath);
368
+ }
369
+ for (const name of authoritative) {
370
+ if (attributed.has(name))
371
+ continue;
372
+ if (map.has(name))
373
+ continue;
374
+ map.set(name, { subpath: currentSubpath, originalName: name });
375
+ }
376
+ for (const spec of starSpecs) {
377
+ const targetAbs = await this.#resolveRel(absFile, spec);
378
+ if (targetAbs)
379
+ await this.#walk(targetAbs, pkg, map, visited);
380
+ }
381
+ }
382
+ #scanExports(source, absFile) {
383
+ try {
384
+ const transpiler = [".tsx", ".jsx"].includes(path4.extname(absFile)) ? this.#tsxTranspiler : this.#tsTranspiler;
385
+ const { exports } = transpiler.scan(source);
386
+ return new Set(exports);
387
+ } catch (err) {
388
+ this.#logger.error(`scan failed: ${err.message}`);
389
+ return new Set;
390
+ }
391
+ }
392
+ #subpathFor(pkg, absFile) {
393
+ const rel = path4.relative(pkg.pkgDir, absFile);
394
+ if (!rel || rel.startsWith("..") || path4.isAbsolute(rel))
395
+ return null;
396
+ if (pkg.preserveFilePath)
397
+ return `${pkg.pkgName}/${rel.split(path4.sep).join("/")}`;
398
+ const ext = CANDIDATE_EXTS.find((candidate) => rel.endsWith(candidate));
399
+ const parts = (ext ? rel.slice(0, -ext.length) : rel).split(path4.sep);
400
+ if (parts[parts.length - 1] === "index")
401
+ parts.pop();
402
+ const tail = parts.join("/");
403
+ return tail === "" ? pkg.pkgName : `${pkg.pkgName}/${tail}`;
404
+ }
405
+ async#resolveRel(fromFile, relSpec) {
406
+ if (this.#opts.resolveRelative)
407
+ return this.#opts.resolveRelative(fromFile, relSpec);
408
+ return defaultResolveRelative(fromFile, relSpec);
409
+ }
410
+ }
411
+ var isRelative = (spec) => {
412
+ return spec.startsWith("./") || spec.startsWith("../") || spec === "." || spec === "..";
413
+ };
414
+ var defaultResolveRelative = async (fromFile, relSpec) => {
415
+ const baseDir = path4.dirname(fromFile);
416
+ const joined = path4.resolve(baseDir, relSpec);
417
+ if (path4.extname(joined)) {
418
+ if (await Bun.file(joined).exists())
419
+ return joined;
420
+ return null;
421
+ }
422
+ for (const ext of CANDIDATE_EXTS) {
423
+ const cand = joined + ext;
424
+ if (await Bun.file(cand).exists())
425
+ return cand;
426
+ }
427
+ for (const ext of CANDIDATE_EXTS) {
428
+ const cand = path4.join(joined, `index${ext}`);
429
+ if (await Bun.file(cand).exists())
430
+ return cand;
431
+ }
432
+ return null;
433
+ };
434
+
435
+ // pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
436
+ var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
437
+ const akanConfig = await app.getConfig();
438
+ const barrels = [...new Set(akanConfig.barrelImports)].filter(Boolean);
439
+ const analyzer = new BarrelAnalyzer({
440
+ resolvePackage: await createTsconfigPackageResolver(app)
441
+ });
442
+ return {
443
+ name: "barrel-imports",
444
+ setup(build) {
445
+ build.onLoad({
446
+ filter: /^(?:(?!.*[\\/]node_modules[\\/]).*|.*[\\/]node_modules[\\/]akanjs[\\/].*)\.(tsx|ts|jsx|js)(\?v=\d+)?$/
447
+ }, async (args) => {
448
+ const realPath = args.path.replace(/\?v=\d+$/, "");
449
+ const loader = loaderFor(realPath);
450
+ let source = await Bun.file(realPath).text();
451
+ if (skipPath(realPath))
452
+ return { contents: source, loader };
453
+ if (!MACRO_ATTR_RE.test(source) && barrels.length > 0) {
454
+ const rewritten = await rewriteBarrelImports(source, barrels, analyzer);
455
+ if (rewritten !== null)
456
+ source = rewritten;
457
+ }
458
+ if (pipeAfter) {
459
+ const piped = await pipeAfter(source, { path: realPath });
460
+ if (piped !== null)
461
+ source = piped;
462
+ }
463
+ return { contents: source, loader };
464
+ });
465
+ }
466
+ };
467
+ };
468
+ var createTsconfigPackageResolver = async (app) => {
469
+ const tsconfig = await app.getTsConfig();
470
+ const tsconfigPaths = tsconfig.compilerOptions.paths ?? {};
471
+ const wildcardEntries = Object.entries(tsconfigPaths).filter(([k]) => k.endsWith("/*")).map(([k, v]) => ({ prefix: k.slice(0, -1), replacements: v })).sort((a, b) => b.prefix.length - a.prefix.length);
472
+ return async (pkgName) => {
473
+ const exact = tsconfigPaths[pkgName];
474
+ if (exact && exact.length > 0) {
475
+ const raw = exact[0];
476
+ if (!raw)
477
+ return null;
478
+ const entryFile = path5.resolve(app.workspace.workspaceRoot, raw);
479
+ if (!await Bun.file(entryFile).exists())
480
+ return null;
481
+ const parsed = path5.parse(entryFile);
482
+ const lastSlash = pkgName.lastIndexOf("/");
483
+ if (parsed.name !== "index" && lastSlash > 0 && pkgName.slice(lastSlash + 1) === parsed.name)
484
+ return { pkgName: pkgName.slice(0, lastSlash), entryFile, pkgDir: parsed.dir };
485
+ return { pkgName, entryFile, pkgDir: path5.dirname(entryFile) };
486
+ }
487
+ for (const { prefix, replacements } of wildcardEntries) {
488
+ if (!pkgName.startsWith(prefix))
489
+ continue;
490
+ const suffix = pkgName.slice(prefix.length);
491
+ for (const repl of replacements) {
492
+ if (!repl)
493
+ continue;
494
+ const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
495
+ const candidate = path5.resolve(app.workspace.workspaceRoot, replPath + suffix);
496
+ for (const ext of CANDIDATE_EXTS2) {
497
+ const file = `${candidate}${ext}`;
498
+ if (await Bun.file(file).exists()) {
499
+ const lastSlash = pkgName.lastIndexOf("/");
500
+ const parentSpec = lastSlash > 0 ? pkgName.slice(0, lastSlash) : pkgName;
501
+ return { pkgName: parentSpec, entryFile: file, pkgDir: path5.dirname(file) };
502
+ }
503
+ }
504
+ for (const ext of CANDIDATE_EXTS2) {
505
+ const file = path5.join(candidate, `index${ext}`);
506
+ if (await Bun.file(file).exists())
507
+ return { pkgName, entryFile: file, pkgDir: candidate };
508
+ }
509
+ }
510
+ return null;
511
+ }
512
+ const exported = await resolveNodePackageExport(app.workspace.workspaceRoot, pkgName);
513
+ if (exported)
514
+ return exported;
515
+ const pkgJsonPath = path5.join(app.workspace.workspaceRoot, "node_modules", pkgName, "package.json");
516
+ if (!await Bun.file(pkgJsonPath).exists())
517
+ return null;
518
+ try {
519
+ const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
520
+ const rel = pkgJson.module ?? pkgJson.main ?? "index.js";
521
+ const entryFile = path5.resolve(path5.dirname(pkgJsonPath), rel);
522
+ if (!await Bun.file(entryFile).exists())
523
+ return null;
524
+ return { pkgName, entryFile, pkgDir: path5.dirname(pkgJsonPath) };
525
+ } catch {
526
+ return null;
527
+ }
528
+ };
529
+ };
530
+ var CANDIDATE_EXTS2 = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
531
+ var NODE_MODULES_RE = /[\\/]node_modules[\\/]/;
532
+ var AKANJS_NODE_MODULE_RE = /[\\/]node_modules[\\/]akanjs[\\/]/;
533
+ var defaultSkipPath = (absPath) => NODE_MODULES_RE.test(absPath) && !AKANJS_NODE_MODULE_RE.test(absPath);
534
+ var resolveNodePackageExport = async (workspaceRoot, specifier) => {
535
+ const packageName = getPackageName(specifier);
536
+ if (!packageName)
537
+ return null;
538
+ const pkgJsonPath = path5.join(workspaceRoot, "node_modules", packageName, "package.json");
539
+ if (!await Bun.file(pkgJsonPath).exists())
540
+ return null;
541
+ try {
542
+ const pkgDir = path5.dirname(pkgJsonPath);
543
+ const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
544
+ const subpath = specifier === packageName ? "." : `.${specifier.slice(packageName.length)}`;
545
+ const exported = resolvePackageExport(pkgJson.exports, subpath);
546
+ const rel = exported ?? (subpath === "." ? pkgJson.module ?? pkgJson.main ?? "index.js" : null);
547
+ if (!rel?.startsWith("."))
548
+ return null;
549
+ const entryFile = await resolveFileCandidate(path5.resolve(pkgDir, rel));
550
+ if (!entryFile)
551
+ return null;
552
+ return { pkgName: specifier, entryFile, pkgDir: path5.dirname(entryFile), preserveFilePath: true };
553
+ } catch {
554
+ return null;
555
+ }
556
+ };
557
+ var resolveExportValue = (value) => {
558
+ if (!value)
559
+ return null;
560
+ if (typeof value === "string")
561
+ return value;
562
+ if (Array.isArray(value)) {
563
+ for (const item of value) {
564
+ const resolved = resolveExportValue(item);
565
+ if (resolved)
566
+ return resolved;
567
+ }
568
+ return null;
569
+ }
570
+ for (const condition of ["source", "import", "default", "types"]) {
571
+ const resolved = resolveExportValue(value[condition]);
572
+ if (resolved)
573
+ return resolved;
574
+ }
575
+ return null;
576
+ };
577
+ var resolvePackageExport = (exportsMap, subpath) => {
578
+ if (!exportsMap)
579
+ return null;
580
+ const exact = resolveExportValue(exportsMap[subpath]);
581
+ if (exact)
582
+ return exact;
583
+ for (const [key, value] of Object.entries(exportsMap)) {
584
+ const starIdx = key.indexOf("*");
585
+ if (starIdx === -1)
586
+ continue;
587
+ const prefix = key.slice(0, starIdx);
588
+ const suffix = key.slice(starIdx + 1);
589
+ if (!subpath.startsWith(prefix) || !subpath.endsWith(suffix))
590
+ continue;
591
+ const wildcard = subpath.slice(prefix.length, subpath.length - suffix.length);
592
+ const resolved = resolveExportValue(value);
593
+ if (resolved)
594
+ return resolved.replace("*", wildcard);
595
+ }
596
+ return null;
597
+ };
598
+ var getPackageName = (specifier) => {
599
+ const parts = specifier.split("/");
600
+ if (!parts[0])
601
+ return null;
602
+ if (specifier.startsWith("@"))
603
+ return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null;
604
+ return parts[0];
605
+ };
606
+ var resolveFileCandidate = async (candidate) => {
607
+ if (await Bun.file(candidate).exists())
608
+ return candidate;
609
+ if (path5.extname(candidate))
610
+ return null;
611
+ for (const ext of CANDIDATE_EXTS2) {
612
+ const file = `${candidate}${ext}`;
613
+ if (await Bun.file(file).exists())
614
+ return file;
615
+ }
616
+ for (const ext of CANDIDATE_EXTS2) {
617
+ const file = path5.join(candidate, `index${ext}`);
618
+ if (await Bun.file(file).exists())
619
+ return file;
620
+ }
621
+ return null;
622
+ };
623
+ var MACRO_ATTR_RE = /with\s*\{\s*type\s*:\s*["']macro["']\s*\}/;
624
+ var rewriteBarrelImports = async (source, barrels, analyzer) => {
625
+ if (!barrels.some((barrel) => source.includes(barrel)))
626
+ return null;
627
+ const statements = findImportStatements(source);
628
+ if (statements.length === 0)
629
+ return null;
630
+ let changed = false;
631
+ let out = source;
632
+ for (let i = statements.length - 1;i >= 0; i--) {
633
+ const stmt = statements[i];
634
+ if (!stmt)
635
+ continue;
636
+ if (!barrels.includes(stmt.specifier))
637
+ continue;
638
+ const map = await analyzer.analyze(stmt.specifier);
639
+ if (!map || map.size === 0)
640
+ continue;
641
+ const replacement = rewriteSingleStatement(stmt, map);
642
+ if (replacement === null)
643
+ continue;
644
+ out = out.slice(0, stmt.start) + replacement + out.slice(stmt.end);
645
+ changed = true;
646
+ }
647
+ return changed ? out : null;
648
+ };
649
+ var findImportStatements = (source) => {
650
+ const statements = [];
651
+ const sourceFile = ts2.createSourceFile("barrel-imports.tsx", source, ts2.ScriptTarget.Latest, false, ts2.ScriptKind.TSX);
652
+ for (const statement of sourceFile.statements) {
653
+ if (!ts2.isImportDeclaration(statement))
654
+ continue;
655
+ if (!ts2.isStringLiteral(statement.moduleSpecifier))
656
+ continue;
657
+ const importClause = statement.importClause;
658
+ if (!importClause)
659
+ continue;
660
+ statements.push({
661
+ start: statement.getStart(sourceFile),
662
+ end: statement.end,
663
+ clause: source.slice(importClause.getStart(sourceFile), importClause.end).trim(),
664
+ specifier: statement.moduleSpecifier.text
665
+ });
666
+ }
667
+ return statements;
668
+ };
669
+ var parseImportClause = (clause) => {
670
+ let rest = clause.trim();
671
+ let typeOnly = false;
672
+ if (rest.startsWith("type ")) {
673
+ typeOnly = true;
674
+ rest = rest.slice(5).trim();
675
+ }
676
+ const parsed = { typeOnly };
677
+ const commaMatch = /^(\w+)\s*,\s*(.+)$/.exec(rest);
678
+ if (commaMatch) {
679
+ parsed.defaultImport = commaMatch[1];
680
+ rest = commaMatch[2] ?? "";
681
+ } else if (/^\w+$/.test(rest)) {
682
+ parsed.defaultImport = rest;
683
+ return parsed;
684
+ }
685
+ if (rest.startsWith("*")) {
686
+ const ns = /^\*\s+as\s+(\w+)$/.exec(rest);
687
+ if (!ns)
688
+ return null;
689
+ parsed.namespaceImport = ns[1];
690
+ return parsed;
691
+ }
692
+ if (rest.startsWith("{")) {
693
+ const close = rest.indexOf("}");
694
+ if (close === -1)
695
+ return null;
696
+ parsed.named = parseNamedList(rest.slice(1, close));
697
+ }
698
+ return parsed;
699
+ };
700
+ var rewriteSingleStatement = (stmt, map) => {
701
+ const clause = parseImportClause(stmt.clause);
702
+ if (!clause)
703
+ return null;
704
+ if (clause.namespaceImport)
705
+ return null;
706
+ if (clause.typeOnly && !clause.defaultImport)
707
+ return null;
708
+ if (!clause.named?.length)
709
+ return null;
710
+ const remaining = [];
711
+ const rewrites = new Map;
712
+ for (const item of clause.named) {
713
+ if (item.isType) {
714
+ remaining.push(item);
715
+ continue;
716
+ }
717
+ const target = map.get(item.imported);
718
+ if (!target) {
719
+ remaining.push(item);
720
+ continue;
721
+ }
722
+ const list = rewrites.get(target.subpath) ?? [];
723
+ list.push({ imported: target.originalName, local: item.local, isType: false });
724
+ rewrites.set(target.subpath, list);
725
+ }
726
+ if (rewrites.size === 0)
727
+ return null;
728
+ const lines = [];
729
+ if (shouldPreserveBarrelSideEffects(stmt.specifier))
730
+ lines.push(`import "${stmt.specifier}";`);
731
+ if (clause.defaultImport || remaining.length > 0) {
732
+ const parts = [];
733
+ if (clause.defaultImport)
734
+ parts.push(clause.defaultImport);
735
+ if (remaining.length > 0)
736
+ parts.push(`{ ${remaining.map(serializeNamedItem).join(", ")} }`);
737
+ lines.push(`import ${parts.join(", ")} from "${stmt.specifier}";`);
738
+ }
739
+ for (const [subpath, items] of rewrites) {
740
+ lines.push(`import { ${items.map(serializeNamedItem).join(", ")} } from "${subpath}";`);
741
+ }
742
+ return lines.join(`
743
+ `);
744
+ };
745
+ var shouldPreserveBarrelSideEffects = (specifier) => /^@(apps|libs)\/[^/]+\/client$/.test(specifier);
746
+ var serializeNamedItem = (item) => {
747
+ const prefix = item.isType ? "type " : "";
748
+ if (item.imported === item.local)
749
+ return `${prefix}${item.imported}`;
750
+ return `${prefix}${item.imported} as ${item.local}`;
751
+ };
752
+
753
+ // pkgs/@akanjs/devkit/transforms/externalizeFrameworkPlugin.ts
754
+ import path6 from "path";
755
+ var DEFAULT_INCLUDE = ["akanjs/", "@apps/", "@libs/"];
756
+ var DEFAULT_EXCLUDE_EXACT = new Set(["akanjs/webkit", "@akanjs/cli", "@akanjs/devkit"]);
757
+ var DEFAULT_EXCLUDE_PREFIX = ["@akanjs/cli/", "@akanjs/devkit/"];
758
+ var OPTIONAL_BACKEND_EXTERNAL_EXACT = new Set(["bullmq", "ioredis", "postgres", "protobufjs"]);
759
+ var RUNTIME_EXTERNAL_EXACT = new Set([
760
+ "react",
761
+ "react-dom",
762
+ "react/jsx-runtime",
763
+ "react/jsx-dev-runtime",
764
+ "react-server-dom-webpack",
765
+ "react-server-dom-webpack/server.node",
766
+ "react-server-dom-webpack/client.node",
767
+ "react-server-dom-webpack/client.browser"
768
+ ]);
769
+ var RUNTIME_EXTERNAL_PREFIX = ["react-dom/", "react-server-dom-webpack/"];
770
+ var CANDIDATE_EXTS3 = [".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"];
771
+ async function createExternalizeFrameworkPlugin(options) {
772
+ const tsconfig = await options.app.getTsConfig();
773
+ const includePrefixes = options.include ?? DEFAULT_INCLUDE;
774
+ const extraExact = new Set(options.extra ?? []);
775
+ const workspaceRoot = options.app.workspace.workspaceRoot;
776
+ const tsconfigPaths = tsconfig.compilerOptions.paths ?? {};
777
+ const rootEntries = Object.entries(tsconfigPaths).filter(([k]) => !k.endsWith("/*")).map(([k, v]) => ({ pkg: k, entryFile: v[0] ?? null })).filter((e) => e.entryFile !== null);
778
+ const wildcardEntries = Object.entries(tsconfigPaths).filter(([k]) => k.endsWith("/*")).map(([k, v]) => ({ prefix: k.slice(0, -1), replacements: v })).sort((a, b) => b.prefix.length - a.prefix.length);
779
+ async function resolveWorkspaceSubpath(spec) {
780
+ if (!workspaceRoot)
781
+ return null;
782
+ for (const { prefix, replacements } of wildcardEntries) {
783
+ if (!spec.startsWith(prefix))
784
+ continue;
785
+ const suffix = spec.slice(prefix.length);
786
+ for (const repl of replacements) {
787
+ const replPath = repl?.endsWith("/*") ? repl.slice(0, -1) : repl ?? "";
788
+ if (!replPath)
789
+ continue;
790
+ const candidate = path6.resolve(workspaceRoot, replPath + suffix);
791
+ const hit = await firstExisting(candidate);
792
+ if (hit)
793
+ return hit;
794
+ }
795
+ }
796
+ for (const { pkg, entryFile } of rootEntries) {
797
+ if (!spec.startsWith(`${pkg}/`))
798
+ continue;
799
+ const suffix = spec.slice(pkg.length + 1);
800
+ const pkgDir = path6.dirname(path6.resolve(workspaceRoot, entryFile));
801
+ const candidate = path6.join(pkgDir, suffix);
802
+ const hit = await firstExisting(candidate);
803
+ if (hit)
804
+ return hit;
805
+ }
806
+ return null;
807
+ }
808
+ return {
809
+ name: "akan-externalize-framework",
810
+ setup(build) {
811
+ build.onResolve({ filter: /.*/ }, async (args) => {
812
+ const spec = args.path;
813
+ if (spec === "." || spec === ".." || spec.startsWith("./") || spec.startsWith("../") || spec.startsWith("/"))
814
+ return;
815
+ if (extraExact.has(spec) || DEFAULT_EXCLUDE_EXACT.has(spec))
816
+ return { path: spec, external: true };
817
+ for (const prefix of DEFAULT_EXCLUDE_PREFIX) {
818
+ if (spec.startsWith(prefix))
819
+ return { path: spec, external: true };
820
+ }
821
+ if (OPTIONAL_BACKEND_EXTERNAL_EXACT.has(spec))
822
+ return { path: spec, external: true };
823
+ if (RUNTIME_EXTERNAL_EXACT.has(spec))
824
+ return { path: spec, external: true };
825
+ for (const prefix of RUNTIME_EXTERNAL_PREFIX) {
826
+ if (spec.startsWith(prefix))
827
+ return { path: spec, external: true };
828
+ }
829
+ if (!includePrefixes.some((prefix) => spec.startsWith(prefix)))
830
+ return;
831
+ const resolved = await resolveWorkspaceSubpath(spec);
832
+ return resolved ? { path: resolved } : undefined;
833
+ });
834
+ }
835
+ };
836
+ }
837
+ async function firstExisting(basePath) {
838
+ if (await Bun.file(basePath).exists())
839
+ return basePath;
840
+ for (const ext of CANDIDATE_EXTS3) {
841
+ const candidate = `${basePath}${ext}`;
842
+ if (await Bun.file(candidate).exists())
843
+ return candidate;
844
+ }
845
+ for (const ext of CANDIDATE_EXTS3) {
846
+ const candidate = path6.join(basePath, `index${ext}`);
847
+ if (await Bun.file(candidate).exists())
848
+ return candidate;
849
+ }
850
+ return null;
851
+ }
852
+
853
+ // pkgs/@akanjs/devkit/transforms/useClientBundlePlugin.ts
854
+ function createUseClientBundlePlugin(options = {}) {
855
+ return {
856
+ name: "akan-use-client-bundle",
857
+ setup(build) {
858
+ build.onLoad({ filter: /\.(tsx|ts|jsx|js)$/ }, async (args) => {
859
+ if (args.path.includes("/node_modules/"))
860
+ return;
861
+ let source;
862
+ try {
863
+ source = await Bun.file(args.path).text();
864
+ } catch {
865
+ return;
866
+ }
867
+ const stubbed = transformUseClient(source, {
868
+ path: args.path,
869
+ workspaceRoot: options.workspaceRoot,
870
+ onClientModule: options.onClientModule
871
+ });
872
+ if (stubbed === null)
873
+ return;
874
+ return { contents: stubbed, loader: loaderFor(args.path) };
875
+ });
876
+ }
877
+ };
878
+ }
879
+
880
+ // pkgs/@akanjs/devkit/frontendBuild/bundleDefine.ts
881
+ var bundleDefine = (app, command, renderEnv) => {
882
+ const nodeEnv = command === "build" ? "production" : "development";
883
+ return {
884
+ "process.env.NODE_ENV": JSON.stringify(nodeEnv),
885
+ "process.env.AKAN_PUBLIC_RENDER_ENV": JSON.stringify(renderEnv),
886
+ ...Object.fromEntries(Object.entries(app.getPublicEnv()).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, value]) => [`process.env.${key}`, JSON.stringify(value)]))
887
+ };
888
+ };
889
+
890
+ // pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
891
+ import path7 from "path";
892
+ class PagesEntrySourceGenerator {
893
+ #pageEntries;
894
+ #asyncDefaults = new Map;
895
+ #detect;
896
+ constructor(pageEntries, { isAsyncDefault } = {}) {
897
+ this.#pageEntries = pageEntries;
898
+ this.#detect = isAsyncDefault ?? ((moduleAbsPath) => AsyncDefaultExportDetector.detect(moduleAbsPath));
899
+ }
900
+ static generate(pageEntries) {
901
+ return new PagesEntrySourceGenerator(pageEntries).generate();
902
+ }
903
+ generate() {
904
+ const lines = this.#pageEntries.map(({ key, moduleAbsPath }) => {
905
+ const specifier = PagesEntrySourceGenerator.#toImportSpecifier(moduleAbsPath);
906
+ return ` ${JSON.stringify(key)}: () => import(${JSON.stringify(specifier)}),`;
907
+ });
908
+ return `export const pages = {
909
+ ${lines.join(`
910
+ `)}
911
+ };
912
+ `;
913
+ }
914
+ static async generateStatic(pageEntries, { fromDir } = {}) {
915
+ return await new PagesEntrySourceGenerator(pageEntries).generateStatic({ fromDir });
916
+ }
917
+ async generateStatic({ fromDir } = {}) {
918
+ const imports = this.#pageEntries.map(({ moduleAbsPath }, index) => {
919
+ const specifier = fromDir ? PagesEntrySourceGenerator.#toRelativeSpecifier(fromDir, moduleAbsPath) : PagesEntrySourceGenerator.#toImportSpecifier(moduleAbsPath);
920
+ return `import * as page${index} from ${JSON.stringify(specifier)};`;
921
+ });
922
+ const entries = await Promise.all(this.#pageEntries.map(async ({ key, moduleAbsPath }, index) => {
923
+ const isAsyncDefault = await this.#isAsyncDefault(moduleAbsPath);
924
+ return ` ${JSON.stringify(key)}: { loader: async () => page${index}, isAsyncDefault: ${isAsyncDefault} },`;
925
+ }));
926
+ return `${imports.join(`
927
+ `)}
928
+ export const pages = {
929
+ ${entries.join(`
930
+ `)}
931
+ };
932
+ `;
933
+ }
934
+ async generateHotReplace({
935
+ fromDir,
936
+ ownerId,
937
+ moduleIds
938
+ }) {
939
+ const entries = await Promise.all(this.#pageEntries.map(async ({ key, moduleAbsPath }) => {
940
+ const specifier = PagesEntrySourceGenerator.#toRelativeSpecifier(fromDir, moduleAbsPath);
941
+ const isAsyncDefault = await this.#isAsyncDefault(moduleAbsPath);
942
+ return ` ${JSON.stringify(key)}: { loader: async () => require(${JSON.stringify(specifier)}), isAsyncDefault: ${isAsyncDefault} },`;
943
+ }));
944
+ return `__akan.accept(${JSON.stringify(ownerId)}, ${JSON.stringify(moduleIds)}, async () => {
945
+ const replaced = await akanWebkit.replacePages({
946
+ ${entries.join(`
947
+ `)}
948
+ });
949
+ if (!replaced) throw new Error("the route table no longer matches the pages it was built from");
950
+ });
951
+ `;
952
+ }
953
+ #isAsyncDefault(moduleAbsPath) {
954
+ const known = this.#asyncDefaults.get(moduleAbsPath);
955
+ if (known)
956
+ return known;
957
+ const detected = this.#detect(moduleAbsPath);
958
+ this.#asyncDefaults.set(moduleAbsPath, detected);
959
+ return detected;
960
+ }
961
+ static #toImportSpecifier(moduleAbsPath) {
962
+ return path7.resolve(moduleAbsPath).split(path7.sep).join("/");
963
+ }
964
+ static #toRelativeSpecifier(fromDir, moduleAbsPath) {
965
+ const relative = path7.relative(fromDir, path7.resolve(moduleAbsPath)).split(path7.sep).join("/");
966
+ return relative.startsWith(".") ? relative : `./${relative}`;
967
+ }
968
+ }
969
+
970
+ // pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
971
+ var VIRTUAL_PAGES_ENTRY = "akan-pages-entry";
972
+
973
+ class PagesBundleBuilder {
974
+ #app;
975
+ #command;
976
+ #pageEntries;
977
+ #started = Date.now();
978
+ #serverEnv;
979
+ constructor(app, command = "start", pageEntries, serverEnv) {
980
+ this.#app = app;
981
+ this.#command = command;
982
+ this.#pageEntries = pageEntries;
983
+ this.#serverEnv = serverEnv;
984
+ }
985
+ async build() {
986
+ const akanConfig = await this.#app.getConfig();
987
+ const resolvedEntries = this.#pageEntries ?? await resolveSsrPageEntriesForApp(this.#app, await this.#app.getPageKeys());
988
+ const entrySource = PagesEntrySourceGenerator.generate(resolvedEntries);
989
+ const workspaceRoot = this.#app.workspace.workspaceRoot;
990
+ const dev = this.#command === "start";
991
+ const clientExports = {};
992
+ const onClientModule = dev ? (file, exports) => {
993
+ clientExports[CsrDevPaths.realpath(file)] = exports;
994
+ } : undefined;
995
+ const result = await Bun.build({
996
+ entrypoints: [VIRTUAL_PAGES_ENTRY],
997
+ outdir: `${this.#artifactDir}/server`,
998
+ target: "bun",
999
+ format: "esm",
1000
+ splitting: this.#splitting,
1001
+ minify: this.#command === "build",
1002
+ naming: {
1003
+ entry: "pages-[hash].[ext]",
1004
+ chunk: "chunks/[name]-[hash].[ext]",
1005
+ asset: "assets/[name]-[hash].[ext]"
1006
+ },
1007
+ define: bundleDefine(this.#app, this.#command, "ssr"),
1008
+ metafile: dev,
1009
+ plugins: [
1010
+ ...this.#serverEnv ? [this.#serverEnv] : [],
1011
+ PagesBundleBuilder.createPagesEntryPlugin(entrySource),
1012
+ PagesBundleBuilder.createCssStubPlugin(),
1013
+ PagesBundleBuilder.createServerUseClientFetchPlugin(),
1014
+ await createExternalizeFrameworkPlugin({ app: this.#app, extra: akanConfig.externalLibs }),
1015
+ akanConfig.barrelImports.length > 0 ? await createBarrelImportsPlugin(this.#app, {
1016
+ pipeAfter: (source, args) => transformUseClient(source, {
1017
+ path: args.path,
1018
+ workspaceRoot,
1019
+ onClientModule
1020
+ })
1021
+ }) : createUseClientBundlePlugin({ workspaceRoot, onClientModule })
1022
+ ]
1023
+ });
1024
+ if (!result.success)
1025
+ throw new AggregateError(result.logs, "[PagesBundleBuilder] Bun.build failed");
1026
+ const entryArtifact = result.outputs.find((a) => a.kind === "entry-point");
1027
+ if (!entryArtifact)
1028
+ throw new Error("[PagesBundleBuilder] Bun.build emitted no entry-point artifact");
1029
+ const bundlePath = path8.resolve(entryArtifact.path);
1030
+ const buildId = Date.now();
1031
+ if (dev && result.metafile)
1032
+ await ServerGraphFile.write(this.#artifactDir, this.#serverGraph(result.metafile, clientExports));
1033
+ const outputBytes = result.outputs.reduce((sum, output) => sum + output.size, 0);
1034
+ const chunkCount = result.outputs.filter((output) => output.kind === "chunk").length;
1035
+ this.#app.verbose(`[PagesBundleBuilder] ${path8.basename(bundlePath)} emitted in ${Date.now() - this.#started}ms splitting=${this.#splitting} entry=${entryArtifact.size} bytes outputs=${result.outputs.length} chunks=${chunkCount} total=${outputBytes} bytes`);
1036
+ return {
1037
+ bundlePath,
1038
+ buildId,
1039
+ splitting: this.#splitting,
1040
+ entryBytes: entryArtifact.size,
1041
+ outputBytes,
1042
+ outputCount: result.outputs.length,
1043
+ chunkCount
1044
+ };
1045
+ }
1046
+ #serverGraph(metafile, clientExports) {
1047
+ const inputs = Object.keys(metafile.inputs).filter((input) => !input.includes("node_modules")).map((input) => path8.resolve(input)).filter((input) => fs3.existsSync(input)).map((input) => CsrDevPaths.realpath(input));
1048
+ return { inputs, clientExports };
1049
+ }
1050
+ get #artifactDir() {
1051
+ return `${this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath}/.akan/artifact`;
1052
+ }
1053
+ get #splitting() {
1054
+ return process.env.AKAN_SERVER_PAGES_SPLITTING === "1";
1055
+ }
1056
+ static createPagesEntryPlugin(source) {
1057
+ return {
1058
+ name: "akan-pages-entry",
1059
+ setup(build) {
1060
+ build.onResolve({ filter: /^akan-pages-entry$/ }, () => ({
1061
+ path: VIRTUAL_PAGES_ENTRY,
1062
+ namespace: "akan-virtual"
1063
+ }));
1064
+ build.onLoad({ filter: /^akan-pages-entry$/, namespace: "akan-virtual" }, () => ({
1065
+ contents: source,
1066
+ loader: "tsx"
1067
+ }));
1068
+ }
1069
+ };
1070
+ }
1071
+ static createCssStubPlugin() {
1072
+ return {
1073
+ name: "akan-css-stub",
1074
+ setup(build) {
1075
+ build.onLoad({ filter: /\.css$/ }, () => ({
1076
+ contents: "",
1077
+ loader: "js"
1078
+ }));
1079
+ }
1080
+ };
1081
+ }
1082
+ static createServerUseClientFetchPlugin() {
1083
+ return {
1084
+ name: "akan-server-use-client-fetch",
1085
+ setup(build) {
1086
+ build.onLoad({ filter: /[/\\]lib[/\\]useClient\.(ts|tsx|js|jsx)$/ }, async (args) => {
1087
+ const source = await Bun.file(args.path).text();
1088
+ const transformed = PagesBundleBuilder.transformServerUseClientFetchSource(source);
1089
+ if (transformed === source)
1090
+ return;
1091
+ return { contents: transformed, loader: loaderFor(args.path) };
1092
+ });
1093
+ }
1094
+ };
1095
+ }
1096
+ static transformServerUseClientFetchSource(source) {
1097
+ if (!source.includes(`with { type: "macro" }`) || !source.includes("FetchClient.build"))
1098
+ return source;
1099
+ return source.replace(/import\s+\{\s*getSerializedSignal\s*\}\s+from\s+["']\.\/sig["']\s+with\s+\{\s*type\s*:\s*["']macro["']\s*\};/, `import { fetch as serverFetch } from "./sig";`).replace(/const\s+fetchProto\s*=\s*FetchClient\.build<[^;]+;/, "const fetchProto = FetchClient.build<typeof signal>(cnst, serverFetch.serializedSignal, { Err: pageProto.Err, base: serverFetch });");
1100
+ }
1101
+ }
1102
+
1103
+ // pkgs/@akanjs/devkit/frontendBuild/csrEntryFiles.ts
1104
+ import path9 from "path";
1105
+
1106
+ class CsrEntryFiles {
1107
+ static entryFilename(basePath) {
1108
+ return `${basePath || "index"}.csr.tsx`;
1109
+ }
1110
+ static pageEntriesForBasePath(pageEntries, basePath, basePaths) {
1111
+ return pageEntries.filter((entry) => {
1112
+ const entryBasePath = CsrEntryFiles.basePathOfPageKey(entry.key, basePaths);
1113
+ return entryBasePath === null || entryBasePath === basePath;
1114
+ });
1115
+ }
1116
+ static basePathOfPageKey(pageKey, basePaths) {
1117
+ const normalized = pageKey.split(path9.sep).join("/").replace(/^\.\//, "");
1118
+ const segments = normalized.split("/");
1119
+ const firstPublicSegment = segments.find((segment) => segment !== "[lang]" && !/^\(.+\)$/.test(segment));
1120
+ return firstPublicSegment && basePaths.includes(firstPublicSegment) ? firstPublicSegment : null;
1121
+ }
1122
+ }
1123
+
1124
+ export { bundleDefine, CsrEntryFiles, loaderFor, BarrelAnalyzer, createBarrelImportsPlugin, createTsconfigPackageResolver, rewriteBarrelImports, toClientReferencePath, scanUseClientExports, CsrDevPaths, PagesEntrySourceGenerator, ServerGraphFile, PagesBundleBuilder };