@akanjs/cli 3.0.0-alpha.71 → 3.0.0-alpha.72

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 (65) hide show
  1. package/.build-stamp +1 -1
  2. package/{abstractCompactor-20e0cwbs.js → abstractCompactor-8yjc9sj4.js} +1 -1
  3. package/{agent.command-xdvw642m.js → agent.command-z0cam80t.js} +6 -6
  4. package/{application.command-g3f7xj25.js → application.command-2dct57za.js} +11 -12
  5. package/{applicationBuildRunner-af0wtspv.js → applicationBuildRunner-ds8acdfz.js} +3 -3
  6. package/{applicationReleasePackager-93nzdfsy.js → applicationReleasePackager-0jf6ejr4.js} +2 -2
  7. package/buildBatch.proc.js +4 -4
  8. package/{capacitorApp-b0ppke3m.js → capacitorApp-md7dnt25.js} +2 -2
  9. package/{cloud.command-0hmsv44q.js → cloud.command-8j7xrxsm.js} +10 -10
  10. package/{context.command-x92afrnf.js → context.command-xjf4y7em.js} +14 -14
  11. package/{dependencyScanner-rbs2407b.js → dependencyScanner-aqg3dkks.js} +1 -1
  12. package/{guideline.command-hpq08q66.js → guideline.command-yzm0qevv.js} +4 -4
  13. package/guidelines/conventions/conventions.instruction.md +17 -9
  14. package/guidelines/ssrRule/ssrRule.instruction.md +49 -5
  15. package/incrementalBuilder.proc.js +5 -5
  16. package/{index-737aj4fm.js → index-116w1dap.js} +4 -4
  17. package/{index-cp00yns2.js → index-5r4e65hb.js} +65 -62
  18. package/{index-abyjt72y.js → index-61x7qthy.js} +17 -21
  19. package/{index-m5gfc86a.js → index-763h7h9g.js} +1 -1
  20. package/{index-wnp7hwq7.js → index-94hdqqka.js} +1 -1
  21. package/{index-r691v756.js → index-9gqzgfsd.js} +4 -4
  22. package/{index-pehn44hr.js → index-a341yqdh.js} +3 -3
  23. package/{index-gvq17wqn.js → index-akz5xvyw.js} +17 -5
  24. package/{index-6d5r8q6k.js → index-bmz9crym.js} +13 -6
  25. package/{index-nq3avsf6.js → index-eed7vc38.js} +66 -33
  26. package/{index-46tjzh6s.js → index-h5sr2nnj.js} +24 -24
  27. package/{index-5f4gnt4c.js → index-h9cybjep.js} +91 -19
  28. package/{index-sqsfv8wg.js → index-hvbdre8z.js} +4 -10
  29. package/{index-qnv0aqmm.js → index-jcm6zr20.js} +3 -1
  30. package/{index-j37qq1f2.js → index-k7731a4v.js} +4 -4
  31. package/{index-8besc14m.js → index-q0s2dp3y.js} +1 -1
  32. package/{index-ety6takb.js → index-q13s3e01.js} +3 -3
  33. package/{index-jybbmwed.js → index-qge1hc70.js} +5 -5
  34. package/{index-sh01r3pm.js → index-safgeq9a.js} +3 -2
  35. package/{index-xjd3rqzj.js → index-scemmfpj.js} +6 -15
  36. package/{index-wbbswwqt.js → index-te6r1b79.js} +5 -5
  37. package/{index-p27h7535.js → index-vrra4ttx.js} +6 -6
  38. package/{index-hs70d8ed.js → index-y3wyqcsp.js} +6 -6
  39. package/{index-cbfp5wyp.js → index-ym9g9ggs.js} +21 -21
  40. package/{index-fgc8r6dj.js → index-ynf37b66.js} +3 -1
  41. package/{index-wybbcgxn.js → index-z52nhkjs.js} +4 -4
  42. package/index.js +18 -18
  43. package/{library.command-8vgrdtwy.js → library.command-w8b53vtt.js} +4 -4
  44. package/{localRegistry.command-0gtqj0r0.js → localRegistry.command-ymrgda7e.js} +9 -9
  45. package/{module.command-rama4zya.js → module.command-7pje37dv.js} +7 -7
  46. package/{package.command-6jxapdsg.js → package.command-jg4qk8ts.js} +4 -4
  47. package/package.json +3 -4
  48. package/{page.command-hxy7x525.js → page.command-abbpj96j.js} +3 -3
  49. package/{primitive.command-4bf6xcc3.js → primitive.command-jw4yv918.js} +8 -8
  50. package/{quality.command-h5edwegz.js → quality.command-06j6qy6n.js} +34 -4
  51. package/{repair.command-rgqf6px6.js → repair.command-x6resn10.js} +5 -5
  52. package/{scalar.command-6krkz6tw.js → scalar.command-mj2vx6rj.js} +6 -6
  53. package/templates/appSample/lib/task/task.signal.ts +11 -6
  54. package/templates/crudPages/[__model__Id]/edit/page.tsx +5 -5
  55. package/templates/crudPages/[__model__Id]/page.tsx +10 -13
  56. package/templates/crudPages/new/page.tsx +5 -5
  57. package/templates/crudPages/page.tsx +9 -9
  58. package/templates/crudSinglePage/page.tsx +11 -7
  59. package/templates/module/__model__.dictionary.ts +4 -1
  60. package/templates/module/__model__.signal.ts +2 -3
  61. package/templates/module/__model__.store.ts +1 -2
  62. package/{typeChecker-g6bh0xfv.js → typeChecker-yhs4eht8.js} +1 -1
  63. package/typecheck.proc.js +1 -1
  64. package/{workflow.command-dwhwrqhd.js → workflow.command-pmw2tere.js} +11 -11
  65. package/{workspace.command-f5h11gjn.js → workspace.command-x32k2vma.js} +29 -26
package/.build-stamp CHANGED
@@ -1 +1 @@
1
- c08012757b2708a1699f9196c5c763ff7548b2c2eee46b18086317b4d1be2eef
1
+ 3e4467a64347b464d13f0e4e50b29becbd56eef56f18d2d954d96881cb55f9a9
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  AiSession
4
- } from "./index-sh01r3pm.js";
4
+ } from "./index-safgeq9a.js";
5
5
  import {
6
6
  AbstractDoc
7
7
  } from "./index-0wae5ebk.js";
@@ -1,15 +1,15 @@
1
1
  // @bun
2
2
  import {
3
3
  AgentScript
4
- } from "./index-wbbswwqt.js";
5
- import"./index-6d5r8q6k.js";
6
- import"./index-8besc14m.js";
7
- import"./index-j37qq1f2.js";
4
+ } from "./index-te6r1b79.js";
5
+ import"./index-bmz9crym.js";
6
+ import"./index-q0s2dp3y.js";
7
+ import"./index-k7731a4v.js";
8
8
  import {
9
9
  Workspace,
10
10
  command
11
- } from "./index-gvq17wqn.js";
12
- import"./index-5f4gnt4c.js";
11
+ } from "./index-akz5xvyw.js";
12
+ import"./index-h9cybjep.js";
13
13
  import"./index-f39512t6.js";
14
14
  import"./index-mxvakhsm.js";
15
15
  import"./index-xys926f2.js";
@@ -4,8 +4,8 @@ import {
4
4
  } from "./index-0wae5ebk.js";
5
5
  import {
6
6
  ApplicationScript
7
- } from "./index-cp00yns2.js";
8
- import"./index-sqsfv8wg.js";
7
+ } from "./index-5r4e65hb.js";
8
+ import"./index-hvbdre8z.js";
9
9
  import {
10
10
  getMobileTargetChoices
11
11
  } from "./index-76rn3g2c.js";
@@ -15,10 +15,10 @@ import {
15
15
  Sys,
16
16
  Workspace,
17
17
  command
18
- } from "./index-gvq17wqn.js";
19
- import"./index-fgc8r6dj.js";
18
+ } from "./index-akz5xvyw.js";
19
+ import"./index-ynf37b66.js";
20
20
  import"./index-5vy2jzar.js";
21
- import"./index-5f4gnt4c.js";
21
+ import"./index-h9cybjep.js";
22
22
  import"./index-f39512t6.js";
23
23
  import"./index-mxvakhsm.js";
24
24
  import"./index-1577bej2.js";
@@ -27,7 +27,6 @@ import"./index-yb2wsc7f.js";
27
27
 
28
28
  // pkgs/@akanjs/cli/application/application.command.ts
29
29
  import { select } from "@inquirer/prompts";
30
- var asMobileEnv = (env) => env;
31
30
  var mobileTargetOption = {
32
31
  desc: "mobile target name or all",
33
32
  ask: "Select mobile target",
@@ -94,14 +93,14 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
94
93
  desc: "backend environment",
95
94
  default: "debug"
96
95
  }).option("write", Boolean, { desc: "write code generation", default: true }).option("regenerate", Boolean, { flag: "g", desc: "delete and regenerate native project", default: false }).exec(async function(app, target2, env, write, regenerate) {
97
- await this.applicationScript.buildIos(app, { target: target2, env: asMobileEnv(env), write, regenerate });
96
+ await this.applicationScript.buildIos(app, { target: target2, env, write, regenerate });
98
97
  }),
99
98
  buildAndroid: target({ short: true, desc: "Build Android app with Capacitor" }).with(App).option("target", String, mobileTargetOption).option("env", String, {
100
99
  enum: ["local", "debug", "develop", "main"],
101
100
  desc: "backend environment",
102
101
  default: "debug"
103
102
  }).option("write", Boolean, { desc: "write code generation", default: true }).option("regenerate", Boolean, { flag: "g", desc: "delete and regenerate native project", default: false }).exec(async function(app, target2, env, write, regenerate) {
104
- await this.applicationScript.buildAndroid(app, { target: target2, env: asMobileEnv(env), write, regenerate });
103
+ await this.applicationScript.buildAndroid(app, { target: target2, env, write, regenerate });
105
104
  }),
106
105
  start: target({ short: true, desc: "Start development server (frontend SSR + backend)" }).with(App).option("open", Boolean, { desc: "open web browser?", default: false }).option("write", Boolean, { desc: "write code generation", default: true }).exec(async function(app, open, write) {
107
106
  await this.applicationScript.start(app, { open, write });
@@ -119,7 +118,7 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
119
118
  }).exec(async function(app, target2, env, open, release, write, regenerate, noAllowProvisioningUpdates, device) {
120
119
  await this.applicationScript.startIos(app, {
121
120
  target: target2,
122
- env: asMobileEnv(env),
121
+ env,
123
122
  open,
124
123
  operation: release ? "release" : "local",
125
124
  write,
@@ -135,7 +134,7 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
135
134
  }).option("release", Boolean, { desc: "release mode", default: false }).option("open", Boolean, { desc: "open android simulator", default: false }).option("write", Boolean, { desc: "write code generation", default: true }).option("regenerate", Boolean, { flag: "g", desc: "delete and regenerate native project", default: false }).exec(async function(app, target2, env, release, open, write, regenerate) {
136
135
  await this.applicationScript.startAndroid(app, {
137
136
  target: target2,
138
- env: asMobileEnv(env),
137
+ env,
139
138
  open,
140
139
  operation: release ? "release" : "local",
141
140
  write,
@@ -149,7 +148,7 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
149
148
  }).option("write", Boolean, { desc: "write code generation", default: true }).option("regenerate", Boolean, { flag: "g", desc: "delete and regenerate native project", default: false }).option("allowLocalRelease", Boolean, { flag: "l", desc: "allow release with --env local", default: false }).exec(async function(app, target2, env, write, regenerate, allowLocalRelease) {
150
149
  await this.applicationScript.releaseIos(app, {
151
150
  target: target2,
152
- env: asMobileEnv(env),
151
+ env,
153
152
  write,
154
153
  regenerate,
155
154
  allowLocalRelease
@@ -162,7 +161,7 @@ class ApplicationCommand extends command("application", [ApplicationScript], ({
162
161
  }).option("write", Boolean, { desc: "write code generation", default: true }).option("regenerate", Boolean, { flag: "g", desc: "delete and regenerate native project", default: false }).option("allowLocalRelease", Boolean, { flag: "l", desc: "allow release with --env local", default: false }).exec(async function(app, assembleType, target2, env, write, regenerate, allowLocalRelease) {
163
162
  await this.applicationScript.releaseAndroid(app, assembleType, {
164
163
  target: target2,
165
- env: asMobileEnv(env),
164
+ env,
166
165
  write,
167
166
  regenerate,
168
167
  allowLocalRelease
@@ -5,9 +5,9 @@ import {
5
5
  FontPruner,
6
6
  SsrBaseArtifactBuilder,
7
7
  precompressArtifacts
8
- } from "./index-abyjt72y.js";
9
- import"./index-xjd3rqzj.js";
10
- import"./index-qnv0aqmm.js";
8
+ } from "./index-61x7qthy.js";
9
+ import"./index-scemmfpj.js";
10
+ import"./index-jcm6zr20.js";
11
11
  import"./index-5vy2jzar.js";
12
12
  import"./index-f39512t6.js";
13
13
  import {
@@ -12,7 +12,7 @@ import { cp, mkdir, rm } from "fs/promises";
12
12
  import path from "path";
13
13
 
14
14
  // pkgs/@akanjs/devkit/uploadRelease.ts
15
- import { HttpClient, Logger } from "akanjs/common";
15
+ import { Logger, RestClient } from "akanjs/common";
16
16
  var spinning = (message) => {
17
17
  const spinner = new Spinner(message, { prefix: message, enableSpin: true }).start();
18
18
  return spinner;
@@ -27,7 +27,7 @@ var uploadRelease = async (appName, {
27
27
  }) => {
28
28
  const logger = new Logger("uploadRelease");
29
29
  const basePath = local ? "http://localhost:8282/backend" : "https://cloud.akanjs.com/backend";
30
- const httpClient = new HttpClient(basePath);
30
+ const httpClient = new RestClient(basePath);
31
31
  const buildPath = `${workspaceRoot}/releases/builds/${appName}-release.tar.gz`;
32
32
  const appBuildPath = `${workspaceRoot}/releases/builds/${appName}-appBuild.zip`;
33
33
  const sourcePath = `${workspaceRoot}/releases/sources/${appName}-source.tar.gz`;
@@ -5,14 +5,14 @@ import {
5
5
  FontOptimizer,
6
6
  PagesBundleBuilder,
7
7
  SsrBaseArtifactBuilder
8
- } from "./index-abyjt72y.js";
9
- import"./index-xjd3rqzj.js";
10
- import"./index-qnv0aqmm.js";
8
+ } from "./index-61x7qthy.js";
9
+ import"./index-scemmfpj.js";
10
+ import"./index-jcm6zr20.js";
11
11
  import"./index-5vy2jzar.js";
12
12
  import {
13
13
  AppExecutor,
14
14
  WorkspaceExecutor
15
- } from "./index-5f4gnt4c.js";
15
+ } from "./index-h9cybjep.js";
16
16
  import"./index-f39512t6.js";
17
17
  import"./index-mxvakhsm.js";
18
18
  import"./index-1577bej2.js";
@@ -25,9 +25,9 @@ import {
25
25
  selectLocalDevHost,
26
26
  sortIosRunTargets,
27
27
  writeRootCapacitorConfig
28
- } from "./index-cbfp5wyp.js";
28
+ } from "./index-ym9g9ggs.js";
29
29
  import"./index-76rn3g2c.js";
30
- import"./index-5f4gnt4c.js";
30
+ import"./index-h9cybjep.js";
31
31
  import"./index-f39512t6.js";
32
32
  import"./index-mxvakhsm.js";
33
33
  import"./index-1577bej2.js";
@@ -1,26 +1,26 @@
1
1
  // @bun
2
2
  import {
3
3
  CloudScript
4
- } from "./index-hs70d8ed.js";
5
- import"./index-737aj4fm.js";
6
- import"./index-jybbmwed.js";
4
+ } from "./index-y3wyqcsp.js";
5
+ import"./index-116w1dap.js";
6
+ import"./index-qge1hc70.js";
7
7
  import {
8
8
  GlobalConfig
9
- } from "./index-sh01r3pm.js";
10
- import"./index-cp00yns2.js";
11
- import"./index-sqsfv8wg.js";
9
+ } from "./index-safgeq9a.js";
10
+ import"./index-5r4e65hb.js";
11
+ import"./index-hvbdre8z.js";
12
12
  import"./index-76rn3g2c.js";
13
13
  import {
14
14
  Workspace,
15
15
  command
16
- } from "./index-gvq17wqn.js";
17
- import"./index-fgc8r6dj.js";
16
+ } from "./index-akz5xvyw.js";
17
+ import"./index-ynf37b66.js";
18
18
  import"./index-5vy2jzar.js";
19
- import"./index-5f4gnt4c.js";
19
+ import"./index-h9cybjep.js";
20
20
  import"./index-f39512t6.js";
21
21
  import"./index-mxvakhsm.js";
22
22
  import"./index-1577bej2.js";
23
- import"./index-46tjzh6s.js";
23
+ import"./index-h5sr2nnj.js";
24
24
  import"./index-67546d0j.js";
25
25
  import"./index-yb2wsc7f.js";
26
26
 
@@ -1,25 +1,25 @@
1
1
  // @bun
2
2
  import {
3
3
  ContextScript
4
- } from "./index-nq3avsf6.js";
5
- import"./index-ety6takb.js";
6
- import"./index-pehn44hr.js";
7
- import"./index-r691v756.js";
8
- import"./index-wybbcgxn.js";
9
- import"./index-p27h7535.js";
4
+ } from "./index-eed7vc38.js";
5
+ import"./index-q13s3e01.js";
6
+ import"./index-a341yqdh.js";
7
+ import"./index-9gqzgfsd.js";
8
+ import"./index-z52nhkjs.js";
9
+ import"./index-vrra4ttx.js";
10
10
  import"./index-ss469dec.js";
11
- import"./index-m5gfc86a.js";
12
- import"./index-cbfp5wyp.js";
13
- import"./index-sh01r3pm.js";
14
- import"./index-6d5r8q6k.js";
15
- import"./index-8besc14m.js";
16
- import"./index-j37qq1f2.js";
11
+ import"./index-763h7h9g.js";
12
+ import"./index-ym9g9ggs.js";
13
+ import"./index-safgeq9a.js";
14
+ import"./index-bmz9crym.js";
15
+ import"./index-q0s2dp3y.js";
16
+ import"./index-k7731a4v.js";
17
17
  import"./index-76rn3g2c.js";
18
18
  import {
19
19
  Workspace,
20
20
  command
21
- } from "./index-gvq17wqn.js";
22
- import"./index-5f4gnt4c.js";
21
+ } from "./index-akz5xvyw.js";
22
+ import"./index-h9cybjep.js";
23
23
  import"./index-f39512t6.js";
24
24
  import"./index-mxvakhsm.js";
25
25
  import"./index-xys926f2.js";
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  TypeScriptDependencyScanner
4
- } from "./index-46tjzh6s.js";
4
+ } from "./index-h5sr2nnj.js";
5
5
  import"./index-67546d0j.js";
6
6
  import"./index-yb2wsc7f.js";
7
7
  export {
@@ -1,17 +1,17 @@
1
1
  // @bun
2
2
  import {
3
3
  AiSession
4
- } from "./index-sh01r3pm.js";
4
+ } from "./index-safgeq9a.js";
5
5
  import {
6
6
  Prompter
7
- } from "./index-j37qq1f2.js";
7
+ } from "./index-k7731a4v.js";
8
8
  import {
9
9
  Workspace,
10
10
  command,
11
11
  runner,
12
12
  script
13
- } from "./index-gvq17wqn.js";
14
- import"./index-5f4gnt4c.js";
13
+ } from "./index-akz5xvyw.js";
14
+ import"./index-h9cybjep.js";
15
15
  import"./index-f39512t6.js";
16
16
  import"./index-mxvakhsm.js";
17
17
  import {
@@ -108,16 +108,18 @@ back.
108
108
  - **Never write an async component outside `page/`** (`no-async-component-in-ui.grit`, scoped to
109
109
  `{apps,libs}/**/ui/**/*.tsx`). React has no async client component, so a `ui/` component that awaits breaks as
110
110
  soon as a client parent renders it, and the load drops below the route, which could have started it before the
111
- first byte. Await in the page — or hand an unawaited `fetch.*` to a `Zone` as an `init` / `view` prop — and take
112
- the resolved data as a prop. Only a PascalCase binding whose own initializer is `async` is matched, so an async
113
- handler inside a synchronous component and `lazy(async () => import(…))` are untouched.
111
+ first byte. Await in the page — or hand an unawaited `fetch.*` field to a `Zone` as an `init` / `view` prop, or
112
+ to a `<Load.Stream of={…}>` that awaits it behind a boundary of its own — and take the resolved data as a prop.
113
+ Only a PascalCase binding whose own initializer is `async` is matched, so an async handler inside a synchronous
114
+ component and `lazy(async () => import(…))` are untouched.
114
115
  - **Never call `fetch.init*` from a client file** (`no-init-fetch-in-client.grit`). `fetch.init<Model><Suffix>` and
115
116
  `fetch.get<Model>Init<Suffix>` compose the slice's list and insight queries into the hydration snapshot that
116
117
  `Load.Units` / `Load.View` seed the store from. From a route it resolves before the first byte; after hydration
117
118
  it is two extra round-trips for a shell the browser already painted. Load it in the page and pass the result
118
- down as an `init` prop — or hand the unawaited promise across — and reload from the client through the generated
119
- `st.do.init<Model><Suffix>()`. Gated on the real `"use client"` directive plus `*.store.ts`, and matched by shape
120
- (`init` + `Capitalize<refName>` + `Capitalize<suffix>`), so a hand-written `initPayment` is out.
119
+ down as an `init` prop — or hand the unawaited `x<Model>Init<Suffix>` promise across — and reload from the client
120
+ through the generated `st.do.init<Model><Suffix>()`. Gated on the real `"use client"` directive plus
121
+ `*.store.ts`, and matched by shape (`init` + `Capitalize<refName>` + `Capitalize<suffix>`), so a hand-written
122
+ `initPayment` is out.
121
123
  - `noArrayIndexKey` and `useExhaustiveDependencies` are **off** on purpose: `key={idx}` for embedded scalars and
122
124
  short dependency arrays are intentional, not oversights.
123
125
  - **A grit plugin diagnostic is suppressed as `lint/plugin`, not `plugin`** — `// biome-ignore lint/plugin: <reason>`
@@ -263,8 +265,14 @@ are, because those are the ones the server could have done.
263
265
  `useEffect(…, [])` that fetches on mount.
264
266
  4. **Push the boundary down to the leaf that needs it.** A store-reading `Zone` should hold zero markup and
265
267
  delegate to a server `View`.
266
- 5. **Hand the promise across, not the awaited value.** `ClientInit` / `ClientView` are `PromiseOrObject<T>`, so a
267
- route may pass an unawaited `fetch.initX(...)` and `Load.*` resolves it behind a skeleton.
268
+ 5. **Hand each promise across, not the awaited value.** `fetch.init<Model><Suffix>` / `view<Model>` / `edit<Model>`
269
+ are awaitable *and* destructurable: `const { xInitInY, xListInY } = fetch.initXInY(id)` hands out one promise
270
+ per field with both queries already in flight. Give `xInitInY` to a `Zone` and `xListInY` to a
271
+ `<Load.Stream of={…}>`; each renders behind its own boundary as its own data lands, so the page never waits
272
+ for the slowest. `await` still returns the old shape and keeps the whole section in the shell — which is what
273
+ SEO snapshots, prerendering and pre-hydration E2E read, so await what the page needs immediately and stream
274
+ the rest. `xListInY` / `xInsightInY` hold hydrated model instances that React Flight refuses as client props:
275
+ consume them in a server component, never as a `Zone` prop.
268
276
  6. **Use named `ReactNode` slots, not just `children`** — `Layout.Navbar` takes `title`, `back`, `left`, `right`,
269
277
  and `children`, so a client shell composes server content in five places instead of absorbing it.
270
278
  7. **Let the server do the derived work.** Display and predicate logic belongs on `Light<Model>`; enum→class
@@ -326,7 +334,7 @@ Full contract: `get_guideline` with `runtimeRule`, or `akan guideline show runti
326
334
  - Never `React.FC`, never `defaultProps`, never `PropsWithChildren`. Defaults go in the destructuring (`prefix = ""`); children are typed `children: ReactNode`.
327
335
  - `"use client"` on line 1 above the imports is mechanical by file role: every `.Zone.tsx`, `.Template.tsx`, and `.Util.tsx` has it; no `.Unit.tsx` or `.View.tsx` ever does. `usePage()` is legal in server files.
328
336
  - Conditional render is `cond ? <X/> : null`. Never `{cond && <X/>}` — in a `className` context it renders the literal string `"false"`. Early `return null` is for guard clauses only.
329
- - Never hand-roll loading, empty, or list states. Use `Load.Units` / `Load.View` / `Load.Edit` with `renderItem`, `renderList`, `renderView`, and `renderEmpty`; `<Empty />` for a bare placeholder; and `Model.New` / `Model.Edit` / `Model.SureToRemove` for CRUD modals.
337
+ - Never hand-roll loading, empty, or list states. Use `Load.Units` / `Load.View` / `Load.Edit` with `renderItem`, `renderList`, `renderView`, and `renderEmpty`; `<Empty />` for a bare placeholder; and `Model.New` / `Model.Edit` / `Model.SureToRemove` for CRUD modals. For data no `Load.*` covers, `<Load.Stream of={promise} fallback={…}>{(value) => …}</Load.Stream>` awaits one promise behind its own Suspense boundary; a resolved value renders in the shell with no boundary at all, so the same call site works either way.
330
338
  - Avoid hooks. `useState` is for modal-open, tab, draft-input, and drag state only — never for server data. `useEffect` must be a genuine effect such as subscribe-with-cleanup or one-shot init. Prefer `Tab` over a `useState` mode switch. `.Template.tsx` files contain zero `useState`.
331
339
  - Forms are entirely store-driven: `value={xForm.field}` with `onChange={st.do.setFieldOnX}`, the setter passed by reference. Always use `Field.*`, never a bare `<input>` for a model field. Nested rows use `st.do.writeOnX("payments.3.name", v)` plus the generated `add<Field>OnX` / `sub<Field>OnX`. **Passing the setter by reference is also what makes the framework emit `data-akan-action` / `data-akan-state`** on the control — the annotation an in-page agent, an E2E selector, and an external browser agent all read. Wrapping it in an inline arrow (`onChange={(v) => st.do.setFieldOnX(v)}`) silently drops that: a closure the caller wrote says nothing about what it does. Never hand-write a `data-akan-*` attribute.
332
340
  - Read with `st.use.*` and write with `st.do.*`. Client components do not call `fetch.*`.
@@ -71,18 +71,62 @@ Never collapse this into one client file with a mode `useState` and every panel
71
71
 
72
72
  **③ Sync state instead of fetching it.** A server component cannot hold state, so render the initial data on the
73
73
  server and hand it across as a serializable object. The route calls `fetch.initXInY(...)` / `fetch.viewX(...)` and
74
- passes the result into a `Zone`; `Load.Units` / `Load.View` hydrate the store from it. A `useEffect(…, [])` that
75
- fetches on mount renders an empty shell, hydrates, then round-trips for data the server already had.
74
+ passes `xInitInY` / `xView` into a `Zone`; `Load.Units` / `Load.View` hydrate the store from it. A
75
+ `useEffect(…, [])` that fetches on mount renders an empty shell, hydrates, then round-trips for data the server
76
+ already had.
76
77
 
77
78
  **④ Push the boundary down to the leaf that needs it.** A store-reading `Zone` should hold zero markup and delegate
78
79
  to a server `View` — `User.Zone.Self` is one line, `st.use.self()` into `<User.View.General user={self} />`, so the
79
80
  whole detail surface renders server-side wherever a route uses the `View` directly.
80
81
 
81
- **⑤ Hand the promise across, not the awaited value.** `ClientInit` / `ClientView` are `PromiseOrObject<T>`, so a
82
- route may pass an unawaited `fetch.initX(...)` and `Load.*` resolves it behind a skeleton. `await` blocks the shell
83
- for data the page needs immediately; the promise streams the rest. Independent fetches still go through one
82
+ **⑤ Hand each promise across, not the awaited value.** `fetch.init<Model><Suffix>`, `fetch.view<Model>` and
83
+ `fetch.edit<Model>` are awaitable *and* destructurable, so a route can split one call into the promises its
84
+ sections actually need:
85
+
86
+ ```tsx
87
+ export default async function Page({ params: { orgId } }: PageProps) {
88
+ const { taskInitInOrg, taskListInOrg } = fetch.initTaskInOrg(orgId);
89
+ const { orgView } = fetch.viewOrg(orgId);
90
+ return (
91
+ <>
92
+ <Org.Zone.Header view={orgView} />
93
+ <Task.Zone.Card init={taskInitInOrg} />
94
+ <Load.Stream of={taskListInOrg} fallback={<Loading.Skeleton active />}>
95
+ {(taskList) => taskList.map((task) => <Task.Unit.Row key={task.id} task={task} />)}
96
+ </Load.Stream>
97
+ </>
98
+ );
99
+ }
100
+ ```
101
+
102
+ Both queries leave immediately — splitting the result never serializes them — and each section renders behind its
103
+ own boundary as its own data lands, so one slow query no longer holds the page. `x<Slice>List` does not wait for
104
+ the aggregate the way `x<Slice>Init` must.
105
+
106
+ **`await` is still the right call for what the page needs immediately.** It returns the shape the helper always
107
+ gave and keeps that markup in the shell, which is what SEO snapshots, prerendering and pre-hydration E2E read; a
108
+ boundary moves its subtree out of the shell and into the stream. Independent awaited fetches still go through one
84
109
  `Promise.all`.
85
110
 
111
+ Three rules the shape enforces:
112
+
113
+ - **`x<Slice>List` and `x<Slice>Insight` are server-only.** They hold hydrated model instances, which React Flight
114
+ refuses as props to a client component. Consume them in a server component; `x<Slice>Init` (plain data) is the
115
+ one that crosses into a `Zone`.
116
+ - **Never hand the whole handle to a component** — pass the field. `<Zone init={xInitInY} />`, not
117
+ `<Zone init={fetch.initXInY(id)} />`.
118
+ - **Rendering the list on the server costs one extra hydration.** `Load.Stream` builds the model instances on the
119
+ server and `Load.Units` builds them again after hydration, so a large list is still better off going through
120
+ `x<Slice>Init` → `Zone` alone. Reach for `Load.Stream` when the markup is small and static enough that having
121
+ it in the HTML is worth more than the second pass.
122
+
123
+ **A failure now surfaces where it happened.** One `Promise.all` in the page body reports nothing about which of
124
+ eight queries threw; per-section boundaries put each rejection at its own boundary.
125
+
126
+ **Keep the auth gate in the shell.** A redirect thrown after the shell has flushed can only be delivered as a
127
+ soft-redirect script, so `getSelf({ unauthorize: "/signin" })` stays in `_layout.tsx` or the page body — never
128
+ inside a streamed section.
129
+
86
130
  **⑥ Use named `ReactNode` slots, not just `children`.** `Layout.Navbar` accepts `title`, `back`, `left`, `right`,
87
131
  and `children`, so a client shell composes server-rendered content in five places instead of absorbing it.
88
132
 
@@ -1,14 +1,14 @@
1
1
  // @bun
2
2
  import {
3
3
  prepareDevWatchBatch
4
- } from "./index-fgc8r6dj.js";
4
+ } from "./index-ynf37b66.js";
5
5
  import {
6
6
  AutoImportSync,
7
7
  DevChangePlanner,
8
8
  DevGeneratedIndexSync,
9
9
  GraphClientEntryDiscovery,
10
10
  RouteClientBuilder
11
- } from "./index-qnv0aqmm.js";
11
+ } from "./index-jcm6zr20.js";
12
12
  import {
13
13
  HmrWatcher,
14
14
  WatchRootResolver
@@ -16,7 +16,7 @@ import {
16
16
  import {
17
17
  AppExecutor,
18
18
  WorkspaceExecutor
19
- } from "./index-5f4gnt4c.js";
19
+ } from "./index-h9cybjep.js";
20
20
  import"./index-f39512t6.js";
21
21
  import"./index-mxvakhsm.js";
22
22
  import"./index-1577bej2.js";
@@ -252,6 +252,7 @@ class IncrementalBuilder {
252
252
  this.#shuttingDown = true;
253
253
  const started = Date.now();
254
254
  this.#logger.debug(`shutdown requested (${reason}); draining ${this.#inFlight} work item(s)`);
255
+ this.#watcher?.stop();
255
256
  if (this.#cssRebuildTimer) {
256
257
  clearTimeout(this.#cssRebuildTimer);
257
258
  this.#cssRebuildTimer = null;
@@ -361,13 +362,12 @@ class IncrementalBuilder {
361
362
  this.#logger.verbose(`[auto-import] inserted imports into ${autoImport.changedFiles.length} file(s)`);
362
363
  const indexSync = await this.#generatedIndexSync.syncForBatch(batch.files);
363
364
  await this.#watcher?.absorb([...autoImport.changedFiles, ...indexSync.changedFiles]);
364
- const { files, kinds, expandedBatch, event, hasSyncErrors } = prepareDevWatchBatch({
365
+ const { files, kinds, expandedBatch, devPlan, event, hasSyncErrors } = prepareDevWatchBatch({
365
366
  generation,
366
367
  batch,
367
368
  indexSync,
368
369
  changePlanner: this.#changePlanner
369
370
  });
370
- const devPlan = event.devPlan;
371
371
  this.#logger.verbose(`[hmr] batch generation=${generation} kinds=${kinds.join(",")} files=${files.length} generated=${indexSync.changedFiles.length} roles=${devPlan.roles.join(",") || "(none)"} actions=${devPlan.actions.join(",") || "(none)"}`);
372
372
  for (const error of indexSync.errors)
373
373
  this.#logger.error(error);
@@ -4,17 +4,17 @@ import {
4
4
  CloudApi,
5
5
  GlobalConfig,
6
6
  getDefaultHostConfig
7
- } from "./index-sh01r3pm.js";
7
+ } from "./index-safgeq9a.js";
8
8
  import {
9
9
  openBrowser
10
- } from "./index-cp00yns2.js";
10
+ } from "./index-5r4e65hb.js";
11
11
  import {
12
12
  runner
13
- } from "./index-gvq17wqn.js";
13
+ } from "./index-akz5xvyw.js";
14
14
  import {
15
15
  AppExecutor,
16
16
  WorkspaceExecutor
17
- } from "./index-5f4gnt4c.js";
17
+ } from "./index-h9cybjep.js";
18
18
 
19
19
  // pkgs/@akanjs/cli/npmRegistry.ts
20
20
  var defaultNpmRegistry = "https://registry.npmjs.org";