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

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 (100) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-q50k4s45.js → CodeAgent-n3tzjm91.js} +2 -2
  3. package/{CodeAgentRpcHost-p7h6n2hp.js → CodeAgentRpcHost-9g27hmer.js} +1 -1
  4. package/{CodeTui-62g35ztk.js → CodeTui-fnm9ft4d.js} +47 -4
  5. package/TunnelShare-661cxz5e.js +14 -0
  6. package/{agent.command-adfd5299.js → agent.command-3qxf4xcj.js} +5 -5
  7. package/akanCode.js +7 -5
  8. package/{application.command-hj3gv1rx.js → application.command-zfja7x4r.js} +12 -11
  9. package/{applicationBuildRunner-by10r9gf.js → applicationBuildRunner-vh4j6vdv.js} +16 -9
  10. package/buildBatch.proc.js +7 -7
  11. package/{cloud.command-k2fhaape.js → cloud.command-fcc8e8tp.js} +17 -16
  12. package/cloud.script-1xt3tnts.js +24 -0
  13. package/{code.command-kt5zgcc2.js → code.command-130bdmhe.js} +25 -12
  14. package/{context.command-8fgn42jw.js → context.command-0qx447mb.js} +17 -16
  15. package/context.runner-1vsjztjg.js +25 -0
  16. package/{dependencyScanner-06z2dmrr.js → dependencyScanner-3afj2vt1.js} +1 -1
  17. package/{guideline.command-3yxxr2mm.js → guideline.command-cv5bmrx2.js} +2 -2
  18. package/guidelines/agentRule/agentRule.instruction.md +25 -10
  19. package/guidelines/conventions/conventions.instruction.md +463 -1084
  20. package/guidelines/cssRule/cssRule.instruction.md +16 -1
  21. package/guidelines/fieldRule/fieldRule.instruction.md +74 -0
  22. package/guidelines/framework/framework.instruction.md +4 -7
  23. package/guidelines/mcpRule/mcpRule.instruction.md +16 -9
  24. package/guidelines/modelConstant/modelConstant.instruction.md +2 -1
  25. package/guidelines/modelStore/modelStore.instruction.md +16 -0
  26. package/guidelines/pageRule/pageRule.instruction.md +80 -0
  27. package/guidelines/queryRule/queryRule.instruction.md +47 -12
  28. package/guidelines/runtimeRule/runtimeRule.instruction.md +89 -2
  29. package/guidelines/ssrRule/ssrRule.instruction.md +13 -0
  30. package/guidelines/transportRule/transportRule.instruction.md +107 -8
  31. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +4 -4
  32. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +70 -7
  33. package/incrementalBuilder.proc.js +4 -4
  34. package/{index-nq045px5.js → index-192ha4xh.js} +356 -307
  35. package/{index-t7nws9mx.js → index-1djcjcre.js} +661 -448
  36. package/{index-h85cxfkg.js → index-1p98exm2.js} +2 -2
  37. package/{index-hnby7p9n.js → index-1xj2t7cb.js} +7 -7
  38. package/{index-wa5jbxj1.js → index-2mrn1mrg.js} +1 -0
  39. package/{index-58vvz603.js → index-35hc95h5.js} +1 -1
  40. package/{index-tv8fjaba.js → index-4mhy6qme.js} +4 -4
  41. package/{index-rk9sdys3.js → index-5edzv8fn.js} +5 -5
  42. package/{index-k9rrten6.js → index-5nd1wtkv.js} +92 -94
  43. package/index-62md4dwy.js +260 -0
  44. package/{index-kc8z134d.js → index-665zp9rs.js} +38 -15
  45. package/{index-jwqtchha.js → index-86jt2a0e.js} +1 -1
  46. package/{index-d2242ksy.js → index-at7bz0xq.js} +3 -0
  47. package/{index-sqfdmb5b.js → index-awbdfcf2.js} +4 -4
  48. package/{index-azh29dc8.js → index-axs61rna.js} +19 -14
  49. package/{index-3hx1z96c.js → index-bqbf654f.js} +1 -1
  50. package/{index-6726qr1m.js → index-cpb3nvma.js} +57 -58
  51. package/{index-pyxn1b53.js → index-d72hfmdm.js} +13 -13
  52. package/{index-8zdwpxef.js → index-dye8pnxx.js} +119 -81
  53. package/{index-z507nzhg.js → index-fmzcs8v6.js} +4 -4
  54. package/{index-3reaaa1h.js → index-fyq1z6kt.js} +29 -27
  55. package/{index-0909wckt.js → index-g1mbppa9.js} +238 -236
  56. package/{index-fjsv10hd.js → index-hsadfb6c.js} +7 -7
  57. package/{index-tz5evhdr.js → index-j237xtew.js} +6 -6
  58. package/{index-nq2ja5e0.js → index-j4mkhz93.js} +3 -3
  59. package/{index-31ce9vhg.js → index-jw1zm273.js} +28 -30
  60. package/{index-q958tqqg.js → index-m9jj544v.js} +1 -1
  61. package/{index-8935h3n1.js → index-mdjc93e1.js} +1 -1
  62. package/{index-bea2gwc6.js → index-pydbnfez.js} +2 -2
  63. package/{index-20cebtth.js → index-qtfmtcrw.js} +17 -15
  64. package/{index-sby8fe1p.js → index-qwa5k1j8.js} +1 -1
  65. package/{index-e9prnmyt.js → index-tamvyvj3.js} +3 -3
  66. package/{index-rhbabmja.js → index-trpasv9q.js} +260 -259
  67. package/{index-2ahj896a.js → index-tvehn2sp.js} +1 -1
  68. package/{index-2etqq75t.js → index-va06nr10.js} +1090 -1078
  69. package/{index-g0vwzy9m.js → index-vk0pa0mn.js} +20 -21
  70. package/{index-xpdgxsj5.js → index-w44cy4vs.js} +2216 -2216
  71. package/index.js +22 -22
  72. package/{library.command-8tw59xzj.js → library.command-erp2f56n.js} +3 -3
  73. package/{localRegistry.command-tf3dmznd.js → localRegistry.command-hj3p16p5.js} +15 -14
  74. package/{module.command-9vm8hffy.js → module.command-gs2r615e.js} +5 -5
  75. package/{package.command-erbxe2tz.js → package.command-j10r76ax.js} +4 -4
  76. package/package.json +21 -21
  77. package/{page.command-jpavcj0p.js → page.command-4h4a8pnh.js} +3 -3
  78. package/{pipeline.command-b8rzvjvv.js → pipeline.command-a2nrk26m.js} +3 -3
  79. package/{primitive.command-sm32chzk.js → primitive.command-w6t0asqz.js} +6 -6
  80. package/{projectTypecheck-jamtx95x.js → projectTypecheck-f534enqj.js} +1 -1
  81. package/{quality.command-pkd17n6y.js → quality.command-77x7vbbx.js} +4 -4
  82. package/{repair.command-8y4mq6hs.js → repair.command-y6sstev7.js} +5 -5
  83. package/{scalar.command-q8khmyx5.js → scalar.command-20b8cy0k.js} +4 -4
  84. package/skills/akan-code/SKILL.md +4 -0
  85. package/skills/akan-store/SKILL.md +2 -1
  86. package/{subspace.command-51n0ykbx.js → subspace.command-baz73jpk.js} +11 -10
  87. package/templates/appSample/lib/task/Task.Util.tsx +7 -7
  88. package/templates/appSample/lib/task/Task.Zone.tsx +1 -1
  89. package/templates/appSample/ui/QuantityControl.tsx +2 -2
  90. package/templates/crudSinglePage/page.tsx +1 -1
  91. package/templates/lib/cnst.ts +0 -1
  92. package/templates/workspaceRoot/.gitignore.template +23 -52
  93. package/templates/workspaceRoot/biome.json.template +1 -1
  94. package/{tunnel.command-7820vtxq.js → tunnel.command-2kw8vt9g.js} +8 -7
  95. package/{workflow.command-n5sv4wqz.js → workflow.command-2djwmpqf.js} +10 -10
  96. package/{workspace.command-zdy60jh8.js → workspace.command-jqs7vjhe.js} +29 -28
  97. package/TunnelShare-f1egrktx.js +0 -13
  98. package/cloud.script-z8p5dz7e.js +0 -23
  99. package/context.runner-hnh0rg7m.js +0 -24
  100. package/index-n68jx79w.js +0 -120
@@ -1,19 +1,15 @@
1
1
  // @bun
2
- import {
3
- FileSys2
4
- } from "./index-52w0fvh8.js";
5
2
  import {
6
3
  AsyncDefaultExportDetector,
7
4
  resolveSsrPageEntriesForApp
8
- } from "./index-2etqq75t.js";
9
-
10
- // pkgs/@akanjs/devkit/frontendBuild/serverGraphFile.ts
11
- import fs2 from "fs";
12
- import path3 from "path";
5
+ } from "./index-va06nr10.js";
6
+ import {
7
+ FileSys2
8
+ } from "./index-52w0fvh8.js";
13
9
 
14
- // pkgs/@akanjs/devkit/transforms/rscUseClientTransform.ts
10
+ // pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
15
11
  import path from "path";
16
- import ts from "typescript";
12
+ import { Logger } from "akanjs/common";
17
13
 
18
14
  // pkgs/@akanjs/devkit/transforms/moduleSyntax.ts
19
15
  var loaderFor = (absPath) => {
@@ -47,237 +43,7 @@ var parseNamedList = (listBody) => {
47
43
  return out;
48
44
  };
49
45
 
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
46
  // pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
279
- import path4 from "path";
280
- import { Logger } from "akanjs/common";
281
47
  var REEXPORT_RE = /(?:^|\n)\s*export\s+(?:type\s+)?(?:(\*)(?:\s+as\s+(\w+))?|\{\s*([^}]*?)\s*\})\s+from\s+(["'])([^"']+)\4;?/g;
282
48
  var LOCAL_NAMED_RE = /(?:^|\n)\s*export\s+\{\s*([^}]*?)\s*\}(?!\s*from)/g;
283
49
  var CANDIDATE_EXTS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
@@ -381,7 +147,7 @@ class BarrelAnalyzer {
381
147
  }
382
148
  #scanExports(source, absFile) {
383
149
  try {
384
- const transpiler = [".tsx", ".jsx"].includes(path4.extname(absFile)) ? this.#tsxTranspiler : this.#tsTranspiler;
150
+ const transpiler = [".tsx", ".jsx"].includes(path.extname(absFile)) ? this.#tsxTranspiler : this.#tsTranspiler;
385
151
  const { exports } = transpiler.scan(source);
386
152
  return new Set(exports);
387
153
  } catch (err) {
@@ -390,13 +156,13 @@ class BarrelAnalyzer {
390
156
  }
391
157
  }
392
158
  #subpathFor(pkg, absFile) {
393
- const rel = path4.relative(pkg.pkgDir, absFile);
394
- if (!rel || rel.startsWith("..") || path4.isAbsolute(rel))
159
+ const rel = path.relative(pkg.pkgDir, absFile);
160
+ if (!rel || rel.startsWith("..") || path.isAbsolute(rel))
395
161
  return null;
396
162
  if (pkg.preserveFilePath)
397
- return `${pkg.pkgName}/${rel.split(path4.sep).join("/")}`;
163
+ return `${pkg.pkgName}/${rel.split(path.sep).join("/")}`;
398
164
  const ext = CANDIDATE_EXTS.find((candidate) => rel.endsWith(candidate));
399
- const parts = (ext ? rel.slice(0, -ext.length) : rel).split(path4.sep);
165
+ const parts = (ext ? rel.slice(0, -ext.length) : rel).split(path.sep);
400
166
  if (parts[parts.length - 1] === "index")
401
167
  parts.pop();
402
168
  const tail = parts.join("/");
@@ -412,9 +178,9 @@ var isRelative = (spec) => {
412
178
  return spec.startsWith("./") || spec.startsWith("../") || spec === "." || spec === "..";
413
179
  };
414
180
  var defaultResolveRelative = async (fromFile, relSpec) => {
415
- const baseDir = path4.dirname(fromFile);
416
- const joined = path4.resolve(baseDir, relSpec);
417
- if (path4.extname(joined)) {
181
+ const baseDir = path.dirname(fromFile);
182
+ const joined = path.resolve(baseDir, relSpec);
183
+ if (path.extname(joined)) {
418
184
  if (await Bun.file(joined).exists())
419
185
  return joined;
420
186
  return null;
@@ -425,7 +191,7 @@ var defaultResolveRelative = async (fromFile, relSpec) => {
425
191
  return cand;
426
192
  }
427
193
  for (const ext of CANDIDATE_EXTS) {
428
- const cand = path4.join(joined, `index${ext}`);
194
+ const cand = path.join(joined, `index${ext}`);
429
195
  if (await Bun.file(cand).exists())
430
196
  return cand;
431
197
  }
@@ -433,6 +199,8 @@ var defaultResolveRelative = async (fromFile, relSpec) => {
433
199
  };
434
200
 
435
201
  // pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
202
+ import path2 from "path";
203
+ import ts from "typescript";
436
204
  var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
437
205
  const akanConfig = await app.getConfig();
438
206
  const barrels = [...new Set(akanConfig.barrelImports)].filter(Boolean);
@@ -475,14 +243,14 @@ var createTsconfigPackageResolver = async (app) => {
475
243
  const raw = exact[0];
476
244
  if (!raw)
477
245
  return null;
478
- const entryFile = path5.resolve(app.workspace.workspaceRoot, raw);
246
+ const entryFile = path2.resolve(app.workspace.workspaceRoot, raw);
479
247
  if (!await Bun.file(entryFile).exists())
480
248
  return null;
481
- const parsed = path5.parse(entryFile);
249
+ const parsed = path2.parse(entryFile);
482
250
  const lastSlash = pkgName.lastIndexOf("/");
483
251
  if (parsed.name !== "index" && lastSlash > 0 && pkgName.slice(lastSlash + 1) === parsed.name)
484
252
  return { pkgName: pkgName.slice(0, lastSlash), entryFile, pkgDir: parsed.dir };
485
- return { pkgName, entryFile, pkgDir: path5.dirname(entryFile) };
253
+ return { pkgName, entryFile, pkgDir: path2.dirname(entryFile) };
486
254
  }
487
255
  for (const { prefix, replacements } of wildcardEntries) {
488
256
  if (!pkgName.startsWith(prefix))
@@ -492,17 +260,17 @@ var createTsconfigPackageResolver = async (app) => {
492
260
  if (!repl)
493
261
  continue;
494
262
  const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
495
- const candidate = path5.resolve(app.workspace.workspaceRoot, replPath + suffix);
263
+ const candidate = path2.resolve(app.workspace.workspaceRoot, replPath + suffix);
496
264
  for (const ext of CANDIDATE_EXTS2) {
497
265
  const file = `${candidate}${ext}`;
498
266
  if (await Bun.file(file).exists()) {
499
267
  const lastSlash = pkgName.lastIndexOf("/");
500
268
  const parentSpec = lastSlash > 0 ? pkgName.slice(0, lastSlash) : pkgName;
501
- return { pkgName: parentSpec, entryFile: file, pkgDir: path5.dirname(file) };
269
+ return { pkgName: parentSpec, entryFile: file, pkgDir: path2.dirname(file) };
502
270
  }
503
271
  }
504
272
  for (const ext of CANDIDATE_EXTS2) {
505
- const file = path5.join(candidate, `index${ext}`);
273
+ const file = path2.join(candidate, `index${ext}`);
506
274
  if (await Bun.file(file).exists())
507
275
  return { pkgName, entryFile: file, pkgDir: candidate };
508
276
  }
@@ -512,16 +280,16 @@ var createTsconfigPackageResolver = async (app) => {
512
280
  const exported = await resolveNodePackageExport(app.workspace.workspaceRoot, pkgName);
513
281
  if (exported)
514
282
  return exported;
515
- const pkgJsonPath = path5.join(app.workspace.workspaceRoot, "node_modules", pkgName, "package.json");
283
+ const pkgJsonPath = path2.join(app.workspace.workspaceRoot, "node_modules", pkgName, "package.json");
516
284
  if (!await Bun.file(pkgJsonPath).exists())
517
285
  return null;
518
286
  try {
519
287
  const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
520
288
  const rel = pkgJson.module ?? pkgJson.main ?? "index.js";
521
- const entryFile = path5.resolve(path5.dirname(pkgJsonPath), rel);
289
+ const entryFile = path2.resolve(path2.dirname(pkgJsonPath), rel);
522
290
  if (!await Bun.file(entryFile).exists())
523
291
  return null;
524
- return { pkgName, entryFile, pkgDir: path5.dirname(pkgJsonPath) };
292
+ return { pkgName, entryFile, pkgDir: path2.dirname(pkgJsonPath) };
525
293
  } catch {
526
294
  return null;
527
295
  }
@@ -535,21 +303,21 @@ var resolveNodePackageExport = async (workspaceRoot, specifier) => {
535
303
  const packageName = getPackageName(specifier);
536
304
  if (!packageName)
537
305
  return null;
538
- const pkgJsonPath = path5.join(workspaceRoot, "node_modules", packageName, "package.json");
306
+ const pkgJsonPath = path2.join(workspaceRoot, "node_modules", packageName, "package.json");
539
307
  if (!await Bun.file(pkgJsonPath).exists())
540
308
  return null;
541
309
  try {
542
- const pkgDir = path5.dirname(pkgJsonPath);
310
+ const pkgDir = path2.dirname(pkgJsonPath);
543
311
  const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
544
312
  const subpath = specifier === packageName ? "." : `.${specifier.slice(packageName.length)}`;
545
313
  const exported = resolvePackageExport(pkgJson.exports, subpath);
546
314
  const rel = exported ?? (subpath === "." ? pkgJson.module ?? pkgJson.main ?? "index.js" : null);
547
315
  if (!rel?.startsWith("."))
548
316
  return null;
549
- const entryFile = await resolveFileCandidate(path5.resolve(pkgDir, rel));
317
+ const entryFile = await resolveFileCandidate(path2.resolve(pkgDir, rel));
550
318
  if (!entryFile)
551
319
  return null;
552
- return { pkgName: specifier, entryFile, pkgDir: path5.dirname(entryFile), preserveFilePath: true };
320
+ return { pkgName: specifier, entryFile, pkgDir: path2.dirname(entryFile), preserveFilePath: true };
553
321
  } catch {
554
322
  return null;
555
323
  }
@@ -591,7 +359,7 @@ var resolvePackageExport = (exportsMap, subpath) => {
591
359
  const wildcard = subpath.slice(prefix.length, subpath.length - suffix.length);
592
360
  const resolved = resolveExportValue(value);
593
361
  if (resolved)
594
- return resolved.replace("*", wildcard);
362
+ return resolved.split("*").join(wildcard);
595
363
  }
596
364
  return null;
597
365
  };
@@ -606,7 +374,7 @@ var getPackageName = (specifier) => {
606
374
  var resolveFileCandidate = async (candidate) => {
607
375
  if (await Bun.file(candidate).exists())
608
376
  return candidate;
609
- if (path5.extname(candidate))
377
+ if (path2.extname(candidate))
610
378
  return null;
611
379
  for (const ext of CANDIDATE_EXTS2) {
612
380
  const file = `${candidate}${ext}`;
@@ -614,7 +382,7 @@ var resolveFileCandidate = async (candidate) => {
614
382
  return file;
615
383
  }
616
384
  for (const ext of CANDIDATE_EXTS2) {
617
- const file = path5.join(candidate, `index${ext}`);
385
+ const file = path2.join(candidate, `index${ext}`);
618
386
  if (await Bun.file(file).exists())
619
387
  return file;
620
388
  }
@@ -648,11 +416,11 @@ var rewriteBarrelImports = async (source, barrels, analyzer) => {
648
416
  };
649
417
  var findImportStatements = (source) => {
650
418
  const statements = [];
651
- const sourceFile = ts2.createSourceFile("barrel-imports.tsx", source, ts2.ScriptTarget.Latest, false, ts2.ScriptKind.TSX);
419
+ const sourceFile = ts.createSourceFile("barrel-imports.tsx", source, ts.ScriptTarget.Latest, false, ts.ScriptKind.TSX);
652
420
  for (const statement of sourceFile.statements) {
653
- if (!ts2.isImportDeclaration(statement))
421
+ if (!ts.isImportDeclaration(statement))
654
422
  continue;
655
- if (!ts2.isStringLiteral(statement.moduleSpecifier))
423
+ if (!ts.isStringLiteral(statement.moduleSpecifier))
656
424
  continue;
657
425
  const importClause = statement.importClause;
658
426
  if (!importClause)
@@ -750,8 +518,156 @@ var serializeNamedItem = (item) => {
750
518
  return `${prefix}${item.imported} as ${item.local}`;
751
519
  };
752
520
 
521
+ // pkgs/@akanjs/devkit/frontendBuild/bundleDefine.ts
522
+ var bundleDefine = (app, command, renderEnv) => {
523
+ const nodeEnv = command === "build" ? "production" : "development";
524
+ return {
525
+ "process.env.NODE_ENV": JSON.stringify(nodeEnv),
526
+ "process.env.AKAN_PUBLIC_RENDER_ENV": JSON.stringify(renderEnv),
527
+ ...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)]))
528
+ };
529
+ };
530
+
531
+ // pkgs/@akanjs/devkit/frontendBuild/csrDevPaths.ts
532
+ import fs from "fs";
533
+ import path3 from "path";
534
+
535
+ class CsrDevPaths {
536
+ static modulePrefix = "akan-module:";
537
+ static stubPrefix = "stub:";
538
+ static emptyStubPrefix = "stub:empty:";
539
+ static vendorPrefix = "vendor:";
540
+ root;
541
+ constructor(workspaceRoot) {
542
+ this.root = CsrDevPaths.realpath(workspaceRoot);
543
+ }
544
+ idOf(file) {
545
+ const real = CsrDevPaths.realpath(file);
546
+ const relative = path3.relative(this.root, real);
547
+ const id = relative.startsWith("..") || path3.isAbsolute(relative) ? real : relative;
548
+ return id.split(path3.sep).join("/");
549
+ }
550
+ fileOf(id) {
551
+ return path3.isAbsolute(id) ? id : path3.join(this.root, id);
552
+ }
553
+ static isStub(target) {
554
+ return target.startsWith(CsrDevPaths.stubPrefix);
555
+ }
556
+ static isVendorFile(file) {
557
+ return file.includes(`${path3.sep}node_modules${path3.sep}`);
558
+ }
559
+ static isScript(file) {
560
+ return /\.[cm]?[jt]sx?$/.test(file);
561
+ }
562
+ static mtimeOf(file) {
563
+ return fs.statSync(file, { throwIfNoEntry: false })?.mtimeMs ?? -1;
564
+ }
565
+ static async hashOf(file) {
566
+ const source = Bun.file(file);
567
+ return await source.exists() ? Bun.hash(await source.arrayBuffer()).toString(36) : "";
568
+ }
569
+ static realpath(file) {
570
+ return fs.existsSync(file) ? fs.realpathSync.native(file) : path3.resolve(file);
571
+ }
572
+ static isNamed(file) {
573
+ try {
574
+ return fs.realpathSync.native(file) === file;
575
+ } catch {
576
+ return false;
577
+ }
578
+ }
579
+ static #extensions = {
580
+ import: [".tsx", ".jsx", ".mts", ".ts", ".mjs", ".js", ".cts", ".cjs"],
581
+ require: [".tsx", ".ts", ".jsx", ".cts", ".cjs", ".js", ".mjs", ".mts"]
582
+ };
583
+ static resolveOnDisk(base, kind = "import") {
584
+ return CsrDevPaths.#asFile(base, kind) ?? CsrDevPaths.#asFolder(base, kind);
585
+ }
586
+ static resolveRelative(dir, specifier, kind = "import") {
587
+ const base = path3.resolve(dir, specifier);
588
+ const folder = /(^|[\\/])\.\.?$|[\\/]$/.test(specifier);
589
+ return folder ? CsrDevPaths.#asFolder(base, kind) : CsrDevPaths.resolveOnDisk(base, kind);
590
+ }
591
+ static #asFile(base, kind) {
592
+ const isFile = (candidate) => fs.statSync(candidate, { throwIfNoEntry: false })?.isFile() ?? false;
593
+ return [base, ...CsrDevPaths.#extensions[kind].map((extension) => `${base}${extension}`)].find(isFile) ?? null;
594
+ }
595
+ static #asFolder(dir, kind) {
596
+ const entry = CsrDevPaths.#packageEntryOf(dir, kind);
597
+ const named = entry ? CsrDevPaths.#asFile(path3.join(dir, entry), kind) ?? CsrDevPaths.#indexOf(path3.join(dir, entry), kind) : null;
598
+ return named ?? CsrDevPaths.#indexOf(dir, kind);
599
+ }
600
+ static #indexOf(dir, kind) {
601
+ return CsrDevPaths.#asFile(path3.join(dir, "index"), kind);
602
+ }
603
+ static #packageEntryOf(dir, kind) {
604
+ try {
605
+ const pkg = JSON.parse(fs.readFileSync(path3.join(dir, "package.json"), "utf8"));
606
+ const fields = kind === "require" ? [pkg.browser, pkg.main] : [pkg.browser, pkg.module, pkg.main];
607
+ const entry = fields.find((field) => typeof field === "string");
608
+ return typeof entry === "string" ? entry : null;
609
+ } catch {
610
+ return null;
611
+ }
612
+ }
613
+ static installedSince(specifier, from, since) {
614
+ const [first = "", second = ""] = specifier.split("/");
615
+ const name = first.startsWith("@") ? `${first}/${second}` : first;
616
+ if (!name || name.startsWith("."))
617
+ return false;
618
+ for (let dir = path3.resolve(from);; dir = path3.dirname(dir)) {
619
+ const pkgDir = path3.join(dir, "node_modules", name);
620
+ if (fs.existsSync(path3.join(pkgDir, "package.json")))
621
+ return (fs.statSync(pkgDir, { throwIfNoEntry: false })?.ctimeMs ?? 0) > since;
622
+ if (path3.dirname(dir) === dir)
623
+ return false;
624
+ }
625
+ }
626
+ static tryResolve(specifier, from) {
627
+ try {
628
+ return Bun.resolveSync(specifier, from);
629
+ } catch {
630
+ return null;
631
+ }
632
+ }
633
+ static lineCount(text) {
634
+ let count = 0;
635
+ for (let index = text.indexOf(`
636
+ `);index !== -1; index = text.indexOf(`
637
+ `, index + 1))
638
+ count += 1;
639
+ return count;
640
+ }
641
+ }
642
+
643
+ // pkgs/@akanjs/devkit/frontendBuild/csrEntryFiles.ts
644
+ import path4 from "path";
645
+
646
+ class CsrEntryFiles {
647
+ static entryFilename(basePath) {
648
+ return `${basePath || "index"}.csr.tsx`;
649
+ }
650
+ static pageEntriesForBasePath(pageEntries, basePath, basePaths) {
651
+ return pageEntries.filter((entry) => {
652
+ const entryBasePath = CsrEntryFiles.basePathOfPageKey(entry.key, basePaths);
653
+ return entryBasePath === null || entryBasePath === basePath;
654
+ });
655
+ }
656
+ static basePathOfPageKey(pageKey, basePaths) {
657
+ const normalized = pageKey.split(path4.sep).join("/").replace(/^\.\//, "");
658
+ const segments = normalized.split("/");
659
+ const firstPublicSegment = segments.find((segment) => segment !== "[lang]" && !/^\(.+\)$/.test(segment));
660
+ return firstPublicSegment && basePaths.includes(firstPublicSegment) ? firstPublicSegment : null;
661
+ }
662
+ }
663
+
664
+ // pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
665
+ import fs3 from "fs";
666
+ import path9 from "path";
667
+ import ts3 from "typescript";
668
+
753
669
  // pkgs/@akanjs/devkit/transforms/externalizeFrameworkPlugin.ts
754
- import path6 from "path";
670
+ import path5 from "path";
755
671
  var DEFAULT_INCLUDE = ["akanjs/", "@apps/", "@libs/"];
756
672
  var DEFAULT_EXCLUDE_EXACT = new Set(["akanjs/webkit", "@akanjs/cli", "@akanjs/devkit"]);
757
673
  var DEFAULT_EXCLUDE_PREFIX = ["@akanjs/cli/", "@akanjs/devkit/"];
@@ -787,7 +703,7 @@ async function createExternalizeFrameworkPlugin(options) {
787
703
  const replPath = repl?.endsWith("/*") ? repl.slice(0, -1) : repl ?? "";
788
704
  if (!replPath)
789
705
  continue;
790
- const candidate = path6.resolve(workspaceRoot, replPath + suffix);
706
+ const candidate = path5.resolve(workspaceRoot, replPath + suffix);
791
707
  const hit = await firstExisting(candidate);
792
708
  if (hit)
793
709
  return hit;
@@ -797,8 +713,8 @@ async function createExternalizeFrameworkPlugin(options) {
797
713
  if (!spec.startsWith(`${pkg}/`))
798
714
  continue;
799
715
  const suffix = spec.slice(pkg.length + 1);
800
- const pkgDir = path6.dirname(path6.resolve(workspaceRoot, entryFile));
801
- const candidate = path6.join(pkgDir, suffix);
716
+ const pkgDir = path5.dirname(path5.resolve(workspaceRoot, entryFile));
717
+ const candidate = path5.join(pkgDir, suffix);
802
718
  const hit = await firstExisting(candidate);
803
719
  if (hit)
804
720
  return hit;
@@ -843,13 +759,57 @@ async function firstExisting(basePath) {
843
759
  return candidate;
844
760
  }
845
761
  for (const ext of CANDIDATE_EXTS3) {
846
- const candidate = path6.join(basePath, `index${ext}`);
762
+ const candidate = path5.join(basePath, `index${ext}`);
847
763
  if (await Bun.file(candidate).exists())
848
764
  return candidate;
849
765
  }
850
766
  return null;
851
767
  }
852
768
 
769
+ // pkgs/@akanjs/devkit/transforms/rscUseClientTransform.ts
770
+ import path6 from "path";
771
+ import ts2 from "typescript";
772
+ var USE_CLIENT_RE = /^\s*(?:\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\/\s*|\/\/[^\n]*\n\s*)*["']use client["']/;
773
+ var IMPLICIT_ROOT_LAYOUT_RE = /[/\\]\.akan[/\\]generated[/\\](?:implicit-root-layout|root-layouts[/\\][^/\\]*__root_layout)\.(tsx|ts|jsx|js)$/;
774
+ var STAR_REEXPORT_HINT_RE = /\bexport\s*\*\s*from\b/;
775
+ var hasUseClientDirective = (source) => USE_CLIENT_RE.test(source);
776
+ function toClientReferencePath(absPath, workspaceRoot) {
777
+ return path6.relative(path6.resolve(workspaceRoot), path6.resolve(absPath)).split(path6.sep).join("/");
778
+ }
779
+ var starReexportSpecifiers = (source, filePath) => ts2.createSourceFile(filePath, source, ts2.ScriptTarget.Latest).statements.filter((statement) => ts2.isExportDeclaration(statement) && !statement.exportClause && !statement.isTypeOnly && !!statement.moduleSpecifier && ts2.isStringLiteral(statement.moduleSpecifier)).map((statement) => statement.moduleSpecifier.text);
780
+ var scanUseClientExports = (source, filePath, workspaceRoot) => {
781
+ const stars = USE_CLIENT_RE.test(source) && STAR_REEXPORT_HINT_RE.test(source) ? starReexportSpecifiers(source, filePath) : [];
782
+ if (stars.length) {
783
+ const file = workspaceRoot ? toClientReferencePath(filePath, workspaceRoot) : filePath;
784
+ const listed = stars.slice(0, 3).map((specifier) => `\`export * from ${JSON.stringify(specifier)}\``);
785
+ const written = stars.length > 3 ? `${listed.join(", ")} (and ${stars.length - 3} more)` : listed.join(", ");
786
+ 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])}\`.`);
787
+ }
788
+ return new Bun.Transpiler({ loader: loaderFor(filePath) }).scan(source).exports;
789
+ };
790
+ function transformUseClient(source, args) {
791
+ if (!USE_CLIENT_RE.test(source))
792
+ return null;
793
+ if (IMPLICIT_ROOT_LAYOUT_RE.test(args.path))
794
+ return null;
795
+ const exports = scanUseClientExports(source, args.path, args.workspaceRoot);
796
+ if (exports.length === 0)
797
+ return null;
798
+ args.onClientModule?.(args.path, exports);
799
+ const referencePath = args.workspaceRoot ? toClientReferencePath(args.path, args.workspaceRoot) : args.path;
800
+ const filePathLit = JSON.stringify(referencePath);
801
+ const lines = [`import { registerClientReference } from "react-server-dom-webpack/server.node";`];
802
+ for (const name of exports) {
803
+ const nameLit = JSON.stringify(name);
804
+ const errMsg = JSON.stringify(`Attempted to call '${name}' from '${referencePath}' on the server, but it is a client-only export.`);
805
+ const proxy = `() => { throw new Error(${errMsg}); }`;
806
+ const binding = name === "default" ? `export default registerClientReference(${proxy}, ${filePathLit}, ${nameLit});` : `export const ${name} = registerClientReference(${proxy}, ${filePathLit}, ${nameLit});`;
807
+ lines.push(binding);
808
+ }
809
+ return lines.join(`
810
+ `);
811
+ }
812
+
853
813
  // pkgs/@akanjs/devkit/transforms/useClientBundlePlugin.ts
854
814
  function createUseClientBundlePlugin(options = {}) {
855
815
  return {
@@ -877,16 +837,6 @@ function createUseClientBundlePlugin(options = {}) {
877
837
  };
878
838
  }
879
839
 
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
840
  // pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
891
841
  import path7 from "path";
892
842
  class PagesEntrySourceGenerator {
@@ -967,6 +917,74 @@ ${entries.join(`
967
917
  }
968
918
  }
969
919
 
920
+ // pkgs/@akanjs/devkit/frontendBuild/serverGraphFile.ts
921
+ import fs2 from "fs";
922
+ import path8 from "path";
923
+ class ServerGraphFile {
924
+ static fileName = "server-graph.json";
925
+ static #cache = null;
926
+ static async read(artifactDir) {
927
+ const file = path8.join(artifactDir, ServerGraphFile.fileName);
928
+ const stat = fs2.statSync(file, { throwIfNoEntry: false });
929
+ if (!stat)
930
+ return null;
931
+ const stamp = `${stat.ino}:${stat.size}:${stat.mtimeMs}`;
932
+ const cached = ServerGraphFile.#cache;
933
+ if (cached?.file === file && cached.stamp === stamp)
934
+ return cached.graph;
935
+ const graph = await Bun.file(file).json().catch(() => null);
936
+ if (graph)
937
+ ServerGraphFile.#cache = { file, stamp, graph };
938
+ return graph;
939
+ }
940
+ static async write(artifactDir, graph) {
941
+ const file = path8.join(artifactDir, ServerGraphFile.fileName);
942
+ const temp = `${file}.${process.pid}.tmp`;
943
+ await Bun.write(temp, JSON.stringify(graph));
944
+ await FileSys2.replace(temp, file);
945
+ }
946
+ static async carry(artifactDir, files) {
947
+ const graph = await ServerGraphFile.read(artifactDir);
948
+ if (!graph || files.length === 0)
949
+ return;
950
+ const carried = [...new Set([...graph.carried ?? [], ...files.map((file) => CsrDevPaths.realpath(file))])];
951
+ await ServerGraphFile.write(artifactDir, { ...graph, carried });
952
+ }
953
+ static async touches(graph, files, exportsNow, next) {
954
+ if (!graph)
955
+ return true;
956
+ const inputs = new Set(graph.inputs);
957
+ const joined = new Set((next?.inputs ?? []).filter((input) => !inputs.has(input)));
958
+ for (const rawFile of files) {
959
+ const file = CsrDevPaths.realpath(rawFile);
960
+ if (joined.has(file))
961
+ return true;
962
+ if (!inputs.has(file))
963
+ continue;
964
+ const before = graph.clientExports[file];
965
+ if (!before)
966
+ return true;
967
+ const now = await exportsNow(file);
968
+ if (!now || ServerGraphFile.#names(now) !== ServerGraphFile.#names(before))
969
+ return true;
970
+ }
971
+ return false;
972
+ }
973
+ static async clientExportsOf(file) {
974
+ const source = await Bun.file(file).text().catch(() => null);
975
+ if (source === null || !hasUseClientDirective(source))
976
+ return null;
977
+ try {
978
+ return scanUseClientExports(source, file);
979
+ } catch {
980
+ return null;
981
+ }
982
+ }
983
+ static #names(exports) {
984
+ return [...exports].sort().join(",");
985
+ }
986
+ }
987
+
970
988
  // pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
971
989
  var VIRTUAL_PAGES_ENTRY = "akan-pages-entry";
972
990
 
@@ -1026,13 +1044,13 @@ class PagesBundleBuilder {
1026
1044
  const entryArtifact = result.outputs.find((a) => a.kind === "entry-point");
1027
1045
  if (!entryArtifact)
1028
1046
  throw new Error("[PagesBundleBuilder] Bun.build emitted no entry-point artifact");
1029
- const bundlePath = path8.resolve(entryArtifact.path);
1047
+ const bundlePath = path9.resolve(entryArtifact.path);
1030
1048
  const buildId = Date.now();
1031
1049
  if (dev && result.metafile)
1032
1050
  await ServerGraphFile.write(this.#artifactDir, this.#serverGraph(result.metafile, clientExports));
1033
1051
  const outputBytes = result.outputs.reduce((sum, output) => sum + output.size, 0);
1034
1052
  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`);
1053
+ this.#app.verbose(`[PagesBundleBuilder] ${path9.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
1054
  return {
1037
1055
  bundlePath,
1038
1056
  buildId,
@@ -1044,7 +1062,7 @@ class PagesBundleBuilder {
1044
1062
  };
1045
1063
  }
1046
1064
  #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));
1065
+ const inputs = Object.keys(metafile.inputs).filter((input) => !input.includes("node_modules")).map((input) => path9.resolve(input)).filter((input) => fs3.existsSync(input)).map((input) => CsrDevPaths.realpath(input));
1048
1066
  return { inputs, clientExports };
1049
1067
  }
1050
1068
  get #artifactDir() {
@@ -1096,28 +1114,59 @@ class PagesBundleBuilder {
1096
1114
  static transformServerUseClientFetchSource(source) {
1097
1115
  if (!source.includes(`with { type: "macro" }`) || !source.includes("FetchClient.build"))
1098
1116
  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
- });
1117
+ const tokens = PagesBundleBuilder.#tokenize(source);
1118
+ const edits = [];
1119
+ const importAt = PagesBundleBuilder.#indexOfTokens(tokens, PagesBundleBuilder.#macroImportTokens);
1120
+ if (importAt !== -1)
1121
+ edits.push({
1122
+ start: tokens[importAt].start,
1123
+ end: tokens[importAt + PagesBundleBuilder.#macroImportTokens.length - 1].end,
1124
+ text: `import { fetch as serverFetch } from "./sig";`
1125
+ });
1126
+ const fetchProtoAt = PagesBundleBuilder.#indexOfTokens(tokens, PagesBundleBuilder.#fetchProtoTokens);
1127
+ const fetchProtoEnd = fetchProtoAt === -1 ? undefined : tokens.slice(fetchProtoAt).find(({ text }) => text === ";");
1128
+ if (fetchProtoEnd)
1129
+ edits.push({
1130
+ start: tokens[fetchProtoAt].start,
1131
+ end: fetchProtoEnd.end,
1132
+ text: "const fetchProto = FetchClient.build<typeof signal>(cnst, serverFetch.serializedSignal, { Err: pageProto.Err, base: serverFetch });"
1133
+ });
1134
+ let transformed = source;
1135
+ for (const { start, end, text } of edits.sort((a, b) => b.start - a.start))
1136
+ transformed = transformed.slice(0, start) + text + transformed.slice(end);
1137
+ return transformed;
1138
+ }
1139
+ static #macroImportTokens = [
1140
+ "import",
1141
+ "{",
1142
+ "getSerializedSignal",
1143
+ "}",
1144
+ "from",
1145
+ '"./sig"',
1146
+ "with",
1147
+ "{",
1148
+ "type",
1149
+ ":",
1150
+ '"macro"',
1151
+ "}",
1152
+ ";"
1153
+ ];
1154
+ static #fetchProtoTokens = ["const", "fetchProto", "=", "FetchClient", ".", "build", "<"];
1155
+ static #tokenize(source) {
1156
+ const scanner = ts3.createScanner(ts3.ScriptTarget.Latest, true, ts3.LanguageVariant.Standard, source);
1157
+ const tokens = [];
1158
+ for (let kind = scanner.scan();kind !== ts3.SyntaxKind.EndOfFileToken; kind = scanner.scan()) {
1159
+ const text = kind === ts3.SyntaxKind.StringLiteral ? JSON.stringify(scanner.getTokenValue()) : scanner.getTokenText();
1160
+ tokens.push({ text, start: scanner.getTokenStart(), end: scanner.getTokenEnd() });
1161
+ }
1162
+ return tokens;
1115
1163
  }
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;
1164
+ static #indexOfTokens(tokens, pattern) {
1165
+ for (let idx = 0;idx + pattern.length <= tokens.length; idx += 1) {
1166
+ if (pattern.every((text, offset) => tokens[idx + offset].text === text))
1167
+ return idx;
1168
+ }
1169
+ return -1;
1121
1170
  }
1122
1171
  }
1123
1172