@akanjs/cli 3.0.0-alpha.64 → 3.0.0-alpha.66
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.
- package/.build-stamp +1 -1
- package/{agent.command-tsx1nsdj.js → agent.command-7vr15vkn.js} +5 -5
- package/{application.command-n8ex8g9h.js → application.command-nrq6qvkh.js} +4 -4
- package/{applicationBuildRunner-x8h12rp0.js → applicationBuildRunner-jnjag4ay.js} +10 -8
- package/buildBatch.proc.js +2 -2
- package/{capacitorApp-8mv9e537.js → capacitorApp-w1ryppdw.js} +2 -2
- package/{cloud.command-f0rhw014.js → cloud.command-crwf7emx.js} +7 -7
- package/{context.command-s7a41qjs.js → context.command-xbsgta4f.js} +12 -12
- package/{guideline.command-qrw84ttb.js → guideline.command-mm19n009.js} +2 -2
- package/guidelines/conventions/conventions.instruction.md +107 -5
- package/incrementalBuilder.proc.js +1 -1
- package/{index-h0mnt0b0.js → index-0jn016vv.js} +3 -3
- package/{index-ckpwq052.js → index-1f34snpd.js} +1 -1
- package/{index-4mtyaqj2.js → index-639mgtfm.js} +2 -2
- package/{index-x1dbhd80.js → index-6s8snbb8.js} +2 -2
- package/{index-kkya2ped.js → index-7kxz2z5t.js} +1 -1
- package/{index-g44fykfw.js → index-8vv6xtm5.js} +1 -1
- package/{index-dvg362vq.js → index-8xeg8ehr.js} +3 -3
- package/{index-cc1mgv1f.js → index-9ppq2sx0.js} +4 -4
- package/{index-r8z20vnj.js → index-a6k0b1b5.js} +5 -5
- package/{index-0g9ajdz8.js → index-bzthvy50.js} +5 -5
- package/{index-8md8zszv.js → index-cnyeq88g.js} +3 -3
- package/{index-tn46rr6w.js → index-d5ef8n21.js} +4 -4
- package/{index-ek4mkwxp.js → index-gkg6e6cx.js} +10 -10
- package/{index-ryns915y.js → index-hpbf1b1e.js} +3 -3
- package/{index-ce9755av.js → index-jbhecvr9.js} +1 -1
- package/{index-f0t3wjyr.js → index-k8k45qfk.js} +2 -2
- package/{index-681sx6nt.js → index-w008bx1p.js} +69 -36
- package/{index-wc19q8mb.js → index-xda7qe2j.js} +2 -2
- package/{index-xj5b8c0w.js → index-xesyg6bc.js} +1 -0
- package/index.js +18 -18
- package/{library.command-p3jgf5h2.js → library.command-afjd6ex4.js} +3 -3
- package/{localRegistry.command-bms0qn6t.js → localRegistry.command-6zadvx6z.js} +6 -6
- package/{module.command-hb3xm07r.js → module.command-rh01pbz3.js} +5 -5
- package/{package.command-fbpa6r4w.js → package.command-g4s1y1wn.js} +3 -3
- package/package.json +2 -2
- package/{page.command-92vrmw96.js → page.command-9bw6sz1r.js} +3 -3
- package/{primitive.command-k6b9jfxr.js → primitive.command-pg1j3gm3.js} +6 -6
- package/{quality.command-89vwmjvf.js → quality.command-rt1z7je9.js} +2 -2
- package/{repair.command-nh9jn8rh.js → repair.command-pg54yhgc.js} +5 -5
- package/{scalar.command-zcsjgvax.js → scalar.command-t0akqh1r.js} +4 -4
- package/templates/app/main.ts +3 -1
- package/{workflow.command-jj0cphfm.js → workflow.command-se886yew.js} +9 -9
- package/{workspace.command-ma3g994j.js → workspace.command-q17atzha.js} +18 -18
package/.build-stamp
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
9aa6bbc9a3c9ef9ff25aa95015f54834f3a9f39d7f76d5b9cc7704a55a0f57b8
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
AgentScript
|
|
4
|
-
} from "./index-
|
|
5
|
-
import"./index-
|
|
6
|
-
import"./index-
|
|
4
|
+
} from "./index-0jn016vv.js";
|
|
5
|
+
import"./index-xda7qe2j.js";
|
|
6
|
+
import"./index-8vv6xtm5.js";
|
|
7
7
|
import"./index-j37qq1f2.js";
|
|
8
8
|
import {
|
|
9
9
|
Workspace,
|
|
10
10
|
command
|
|
11
|
-
} from "./index-
|
|
12
|
-
import"./index-
|
|
11
|
+
} from "./index-1f34snpd.js";
|
|
12
|
+
import"./index-w008bx1p.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-
|
|
8
|
-
import"./index-
|
|
7
|
+
} from "./index-a6k0b1b5.js";
|
|
8
|
+
import"./index-k8k45qfk.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-
|
|
18
|
+
} from "./index-1f34snpd.js";
|
|
19
19
|
import"./index-fgc8r6dj.js";
|
|
20
20
|
import"./index-5vy2jzar.js";
|
|
21
|
-
import"./index-
|
|
21
|
+
import"./index-w008bx1p.js";
|
|
22
22
|
import"./index-f39512t6.js";
|
|
23
23
|
import"./index-mxvakhsm.js";
|
|
24
24
|
import"./index-1577bej2.js";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
CsrArtifactBuilder,
|
|
5
5
|
SsrBaseArtifactBuilder,
|
|
6
6
|
precompressArtifacts
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-xesyg6bc.js";
|
|
8
8
|
import"./index-xjd3rqzj.js";
|
|
9
9
|
import"./index-qnv0aqmm.js";
|
|
10
10
|
import"./index-5vy2jzar.js";
|
|
@@ -58,14 +58,15 @@ class ApplicationBuildRunner {
|
|
|
58
58
|
}
|
|
59
59
|
async build({ spinner = false } = {}) {
|
|
60
60
|
const phaseOptions = { spinner };
|
|
61
|
+
const { web } = await this.#app.getConfig();
|
|
61
62
|
await this.#runPhase("prepare", "Preparing output directory", () => this.#app.prepareCommand("build"), undefined, {
|
|
62
63
|
spinner
|
|
63
64
|
});
|
|
64
65
|
if (!this.#fast)
|
|
65
66
|
await this.#runPhase("typecheck", "Typechecking", () => this.typecheck(), undefined, phaseOptions);
|
|
66
67
|
await this.#runPhase("backend", "Compiling backend", () => this.#buildBackend(), (result) => `${result.entrypoints} entrypoints, ${result.outputs} outputs`, phaseOptions);
|
|
67
|
-
await this.#runPhase("ssr", "Building SSR route artifacts", () => this.#buildSsr(), (result) => result ? `${result.allRoutes.manifest.routeIds.length} routes, ${result.allRoutes.manifest.knownEntries.length} entries` : "skipped", phaseOptions);
|
|
68
|
-
await this.#runPhase("csr", "Building CSR assets", () => this.#buildCsr(), (result) => result?.outputDir ?? "skipped", phaseOptions);
|
|
68
|
+
await this.#runPhase("ssr", "Building SSR route artifacts", async () => web.ssr ? await this.#buildSsr() : null, (result) => result ? `${result.allRoutes.manifest.routeIds.length} routes, ${result.allRoutes.manifest.knownEntries.length} entries` : web.ssr ? "skipped" : "disabled by akan.config.ts web.ssr", phaseOptions);
|
|
69
|
+
await this.#runPhase("csr", "Building CSR assets", async () => web.csr ? await this.#buildCsr() : null, (result) => result?.outputDir ?? (web.csr ? "skipped" : "disabled by akan.config.ts web.csr"), phaseOptions);
|
|
69
70
|
await this.#runPhase("compress", "Compressing static assets", () => precompressArtifacts(this.#app), (result) => result.files > 0 ? `${result.files} files, ${ApplicationBuildRunner.formatBytes(result.inputBytes)} -> gzip ${ApplicationBuildRunner.formatBytes(result.outputBytes)} / br ${ApplicationBuildRunner.formatBytes(result.brotliBytes)}` : "no files", phaseOptions);
|
|
70
71
|
await this.#runPhase("metadata", "Writing production metadata", () => this.#buildAppMeta(), undefined, {
|
|
71
72
|
spinner
|
|
@@ -107,7 +108,7 @@ class ApplicationBuildRunner {
|
|
|
107
108
|
const akanConfig = await this.#app.getConfig();
|
|
108
109
|
await Promise.all([
|
|
109
110
|
this.#app.dist.writeJson("package.json", akanConfig.getProductionPackageJson()),
|
|
110
|
-
this.#app.dist.writeFile(`${this.#app.dist.cwdPath}/Dockerfile`, akanConfig.
|
|
111
|
+
this.#app.dist.writeFile(`${this.#app.dist.cwdPath}/Dockerfile`, akanConfig.dockerfile)
|
|
111
112
|
]);
|
|
112
113
|
}
|
|
113
114
|
async#buildBackend() {
|
|
@@ -115,6 +116,7 @@ class ApplicationBuildRunner {
|
|
|
115
116
|
const backendExternals = [
|
|
116
117
|
...new Set([...akanConfig.externalLibs, ...SSR_RENDER_EXTERNALS, ...AKAN_OPTIONAL_BACKEND_EXTERNALS])
|
|
117
118
|
];
|
|
119
|
+
const { web } = akanConfig;
|
|
118
120
|
const backendEntryPoints = [`${this.#app.cwdPath}/main.ts`, `${this.#app.cwdPath}/server.ts`];
|
|
119
121
|
for (const entrypoint of backendEntryPoints) {
|
|
120
122
|
if (!await Bun.file(entrypoint).exists())
|
|
@@ -129,7 +131,7 @@ class ApplicationBuildRunner {
|
|
|
129
131
|
define: { "process.env.NODE_ENV": JSON.stringify("production") },
|
|
130
132
|
plugins: backendExternals.length > 0 ? [this.#createExternalSpecifiersPlugin(backendExternals)] : []
|
|
131
133
|
});
|
|
132
|
-
const rscWorkerResult = await this.#buildOrThrow("rsc-worker", {
|
|
134
|
+
const rscWorkerResult = web.ssr ? await this.#buildOrThrow("rsc-worker", {
|
|
133
135
|
entrypoints: [this.#resolveRscWorkerBuildEntry()],
|
|
134
136
|
outdir: this.#app.dist.cwdPath,
|
|
135
137
|
target: "bun",
|
|
@@ -138,7 +140,7 @@ class ApplicationBuildRunner {
|
|
|
138
140
|
conditions: ["react-server"],
|
|
139
141
|
define: { "process.env.NODE_ENV": JSON.stringify("production") },
|
|
140
142
|
plugins: backendExternals.length > 0 ? [this.#createExternalSpecifiersPlugin(backendExternals)] : []
|
|
141
|
-
});
|
|
143
|
+
}) : null;
|
|
142
144
|
const consoleRuntimeResult = await this.#buildOrThrow("console-runtime", {
|
|
143
145
|
entrypoints: [this.#resolveConsoleRuntimeBuildEntry()],
|
|
144
146
|
outdir: this.#app.dist.cwdPath,
|
|
@@ -149,8 +151,8 @@ class ApplicationBuildRunner {
|
|
|
149
151
|
});
|
|
150
152
|
await this.#writeConsoleShim();
|
|
151
153
|
return {
|
|
152
|
-
entrypoints: backendEntryPoints.length + 2,
|
|
153
|
-
outputs: backendResult.outputs.length + rscWorkerResult
|
|
154
|
+
entrypoints: backendEntryPoints.length + (rscWorkerResult ? 2 : 1),
|
|
155
|
+
outputs: backendResult.outputs.length + (rscWorkerResult?.outputs.length ?? 0) + consoleRuntimeResult.outputs.length + 1
|
|
154
156
|
};
|
|
155
157
|
}
|
|
156
158
|
async#writeConsoleShim() {
|
package/buildBatch.proc.js
CHANGED
|
@@ -5,14 +5,14 @@ import {
|
|
|
5
5
|
FontOptimizer,
|
|
6
6
|
PagesBundleBuilder,
|
|
7
7
|
SsrBaseArtifactBuilder
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-xesyg6bc.js";
|
|
9
9
|
import"./index-xjd3rqzj.js";
|
|
10
10
|
import"./index-qnv0aqmm.js";
|
|
11
11
|
import"./index-5vy2jzar.js";
|
|
12
12
|
import {
|
|
13
13
|
AppExecutor,
|
|
14
14
|
WorkspaceExecutor
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-w008bx1p.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-
|
|
28
|
+
} from "./index-jbhecvr9.js";
|
|
29
29
|
import"./index-76rn3g2c.js";
|
|
30
|
-
import"./index-
|
|
30
|
+
import"./index-w008bx1p.js";
|
|
31
31
|
import"./index-f39512t6.js";
|
|
32
32
|
import"./index-mxvakhsm.js";
|
|
33
33
|
import"./index-1577bej2.js";
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
CloudScript
|
|
4
|
-
} from "./index-
|
|
5
|
-
import"./index-
|
|
6
|
-
import"./index-
|
|
4
|
+
} from "./index-bzthvy50.js";
|
|
5
|
+
import"./index-cnyeq88g.js";
|
|
6
|
+
import"./index-6s8snbb8.js";
|
|
7
7
|
import {
|
|
8
8
|
GlobalConfig
|
|
9
9
|
} from "./index-sh01r3pm.js";
|
|
10
|
-
import"./index-
|
|
11
|
-
import"./index-
|
|
10
|
+
import"./index-a6k0b1b5.js";
|
|
11
|
+
import"./index-k8k45qfk.js";
|
|
12
12
|
import"./index-76rn3g2c.js";
|
|
13
13
|
import {
|
|
14
14
|
Workspace,
|
|
15
15
|
command
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-1f34snpd.js";
|
|
17
17
|
import"./index-fgc8r6dj.js";
|
|
18
18
|
import"./index-5vy2jzar.js";
|
|
19
|
-
import"./index-
|
|
19
|
+
import"./index-w008bx1p.js";
|
|
20
20
|
import"./index-f39512t6.js";
|
|
21
21
|
import"./index-mxvakhsm.js";
|
|
22
22
|
import"./index-1577bej2.js";
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
ContextScript
|
|
4
|
-
} from "./index-
|
|
5
|
-
import"./index-
|
|
6
|
-
import"./index-
|
|
7
|
-
import"./index-
|
|
8
|
-
import"./index-
|
|
9
|
-
import"./index-
|
|
4
|
+
} from "./index-gkg6e6cx.js";
|
|
5
|
+
import"./index-hpbf1b1e.js";
|
|
6
|
+
import"./index-8xeg8ehr.js";
|
|
7
|
+
import"./index-639mgtfm.js";
|
|
8
|
+
import"./index-9ppq2sx0.js";
|
|
9
|
+
import"./index-d5ef8n21.js";
|
|
10
10
|
import"./index-ss469dec.js";
|
|
11
|
-
import"./index-
|
|
12
|
-
import"./index-
|
|
11
|
+
import"./index-7kxz2z5t.js";
|
|
12
|
+
import"./index-jbhecvr9.js";
|
|
13
13
|
import"./index-sh01r3pm.js";
|
|
14
|
-
import"./index-
|
|
15
|
-
import"./index-
|
|
14
|
+
import"./index-xda7qe2j.js";
|
|
15
|
+
import"./index-8vv6xtm5.js";
|
|
16
16
|
import"./index-j37qq1f2.js";
|
|
17
17
|
import"./index-76rn3g2c.js";
|
|
18
18
|
import {
|
|
19
19
|
Workspace,
|
|
20
20
|
command
|
|
21
|
-
} from "./index-
|
|
22
|
-
import"./index-
|
|
21
|
+
} from "./index-1f34snpd.js";
|
|
22
|
+
import"./index-w008bx1p.js";
|
|
23
23
|
import"./index-f39512t6.js";
|
|
24
24
|
import"./index-mxvakhsm.js";
|
|
25
25
|
import"./index-xys926f2.js";
|
|
@@ -271,6 +271,101 @@ are, because those are the ones the server could have done.
|
|
|
271
271
|
Full version with code, the `Tab` composition example, and a review checklist: `get_guideline` with `ssrRule`, or
|
|
272
272
|
`akan guideline show ssrRule`.
|
|
273
273
|
|
|
274
|
+
## Web Surfaces — Building And Serving Without SSR/CSR
|
|
275
|
+
|
|
276
|
+
An app serves three things: the API, the SSR/RSC web renderer, and the CSR single-file bundle. The API is always
|
|
277
|
+
on; the other two are declared in `akan.config.ts` as **`web: true | false | { csr: boolean }`** and can be
|
|
278
|
+
narrowed again per deployment.
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
const config: AppConfig = { web: { csr: false } }; // web without the mobile bundle
|
|
282
|
+
const config: AppConfig = { web: false }; // api only
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
- **`web: { csr: false }`** drops the CSR build phase and the `/__csr` + `?csr=true` routes. The CSR bundle is
|
|
286
|
+
what the Capacitor mobile build ships, so a web-only deployment never needs it — and an app that declares a
|
|
287
|
+
`mobile` section is refused, because `akan build-ios` copies `dist/apps/<app>/csr/<target>.html` into the
|
|
288
|
+
native project.
|
|
289
|
+
- **`web: false`** is an API-only build: no base artifact, no pages or client bundles, no RSC worker
|
|
290
|
+
entrypoint, and no `public/` in the image (the web router's catch-all is its only reader). Nothing under
|
|
291
|
+
`page/` is served, including routes a lib contributed through `syncPageLibs`.
|
|
292
|
+
- **There is no CSR-without-SSR option, by type.** The CSR bundle inlines the stylesheet the SSR base artifact
|
|
293
|
+
compiles, so it would ship an unstyled app — the object form therefore carries only `csr`, and SSR goes off
|
|
294
|
+
only through the whole-surface `false`.
|
|
295
|
+
- **At runtime, `AKAN_SSR` and `AKAN_CSR` narrow further and never widen** — `false` or `0` turns one off, and
|
|
296
|
+
`AKAN_SSR=false` takes CSR with it for the same reason the option has no such pair. A surface the build left
|
|
297
|
+
out cannot be switched back on, and the boot log names what the process ended up serving. The generated
|
|
298
|
+
Dockerfile writes the build's own answer as the image default.
|
|
299
|
+
- **A build with no web artifact boots the API instead of crashing.** `WebRouter.create` returns `null` when
|
|
300
|
+
`.akan/artifact/base-artifact.json` is absent — an api-only build, or a workspace with no `page/` at all.
|
|
301
|
+
- `akan start` ignores `web` and keeps the whole dev surface: the incremental builder is also the file watcher,
|
|
302
|
+
so switching it off would take server-code HMR with it. It warns once when the config and the dev server
|
|
303
|
+
disagree.
|
|
304
|
+
- The saving is mostly the RSC worker, which is a **separate process per web-serving replica**. Measured on
|
|
305
|
+
`apps/akan` at boot plus one render: 350MB across 3 processes with SSR on, 120MB across 2 with
|
|
306
|
+
`AKAN_SSR=false`, and the built image goes 86MB → 6.2MB when the artifacts are left out of it too.
|
|
307
|
+
- **The generated image installs `ca-certificates` and `tzdata` and nothing else.** It used to carry the whole
|
|
308
|
+
Chromium runtime, ffmpeg, `build-essential`, `python3` and `redis` in every app's image whether or not the app
|
|
309
|
+
reached for any of them. An app that needs one declares it in `docker.preRuns` / `docker.postRuns`, which are
|
|
310
|
+
emitted around the `bun install` — that is the migration for a `puppeteer` or `ffmpeg` app.
|
|
311
|
+
|
|
312
|
+
## The Process Model — Gateway And Solo
|
|
313
|
+
|
|
314
|
+
A container runs one process per replica, a gateway in front of them when there is more than one, and one RSC
|
|
315
|
+
worker per web-serving replica.
|
|
316
|
+
|
|
317
|
+
- **One traffic replica runs in the container's only process.** `AKAN_REPLICA=0,0,1` — the default, and what
|
|
318
|
+
every environment in `infra/app/values` sets — means there is nothing to balance and nothing to fan pubsub out
|
|
319
|
+
to, so `AkanApp` starts that replica in-process rather than spawning it. Measured on `apps/akan`: 28MB less RSS
|
|
320
|
+
and twice the requests per second, because every request used to cross a unix-socket proxy hop. Declare two or
|
|
321
|
+
more and the gateway is back, spawning and proxying them.
|
|
322
|
+
- **`AKAN_SOLO=false` forces the gateway** for a single replica. Like `AKAN_SSR`, the env only narrows — it
|
|
323
|
+
cannot fold a real gateway's replicas into one process. Passing `replica` to `new AkanApp(...)` also keeps the
|
|
324
|
+
gateway: code that states a topology is asking for the thing that serves it.
|
|
325
|
+
- **`akan start` always runs the gateway**, whatever the replica count. It is also the dev host's builder relay,
|
|
326
|
+
its crash page, and what holds the port across a child restart.
|
|
327
|
+
- **A batch-only replica (`0,1,0`) keeps the gateway too**, because a batch server never listens and the gateway
|
|
328
|
+
is then the only thing bound to answer `/_akan/app/health`.
|
|
329
|
+
- **The RSC worker is never folded in.** It runs under `--conditions react-server`, which resolves the same
|
|
330
|
+
module graph differently, so it cannot share a process with the server that renders client components.
|
|
331
|
+
- **A solo process answers `/_akan/app/health`, `/_akan/app/metrics` and `/_akan/bench/ping` itself**, in the
|
|
332
|
+
gateway's own shape — a `children` array with one entry — so a probe reads one contract either way. It owns the
|
|
333
|
+
rotating log file the gateway would otherwise write, in the same `runtime/logs` directory.
|
|
334
|
+
- **Nothing supervises a solo process but the orchestrator**, since the gateway's crash-restart-with-backoff went
|
|
335
|
+
with it. `infra/app/templates/app.yaml` carries the liveness, readiness and startup probes that replace it.
|
|
336
|
+
- **`main.ts` imports `AkanApp` from `akanjs/server/akanApp`, not the barrel.** The barrel re-exports
|
|
337
|
+
`AkanServer`, whose graph the gateway never runs; through it the process evaluated 35MB of SSR renderer and
|
|
338
|
+
SQLite driver to spawn children and relay bytes. Keep entrypoint imports at the leaf.
|
|
339
|
+
|
|
340
|
+
## The Generated Image — `docker` In `akan.config.ts`
|
|
341
|
+
|
|
342
|
+
**`docker` is `string | { image, preRuns, postRuns, command }`** — a whole Dockerfile, or the parts Akan
|
|
343
|
+
assembles one from. There is no `content` field; the string *is* the content.
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
const config: AppConfig = {
|
|
347
|
+
docker: { preRuns: ["apt-get update && apt-get install -y --no-install-recommends ffmpeg"] },
|
|
348
|
+
};
|
|
349
|
+
const config: AppConfig = { docker: "FROM oven/bun:1-slim\n…" }; // verbatim, nothing merged in
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
- `image` and each run entry take `string | { amd64?, arm64? }`; the object form compiles to a
|
|
353
|
+
`RUN if [ "$TARGETARCH" = "<arch>" ]` guard, so a multi-arch build runs it on one leg only. `preRuns` land
|
|
354
|
+
before `bun install --production` (where a native dependency's build tools have to be), `postRuns` after it
|
|
355
|
+
and before the app files are copied.
|
|
356
|
+
- **A lib declares the steps its own runtime needs**, and every app that mounts it inherits them:
|
|
357
|
+
`libs/<lib>/akan.config.ts` takes `docker: { preRuns, postRuns }` and nothing else — the base image and the
|
|
358
|
+
command belong to the app. Lib steps are emitted before the app's own, and an identical step declared twice
|
|
359
|
+
becomes one layer.
|
|
360
|
+
- **The string form takes no contributions.** A Dockerfile handed over whole is used exactly as written, so a
|
|
361
|
+
lib's `preRuns` are dropped rather than spliced into a file Akan does not own. An app that needs both writes
|
|
362
|
+
the parts instead.
|
|
363
|
+
- Like `externalLibs`, lib steps are collected from **every lib in the workspace**, not just this app's
|
|
364
|
+
dependency closure — narrowing that set needs the dependency scan, and this config is re-read on every file
|
|
365
|
+
change in dev. Keep a lib's steps to what its runtime genuinely requires.
|
|
366
|
+
- `AkanAppConfig.docker` is the resolved declaration; `AkanAppConfig.dockerfile` is the text `akan build` writes
|
|
367
|
+
to `dist/apps/<app>/Dockerfile`.
|
|
368
|
+
|
|
274
369
|
## React Components And Styling (`**/*.tsx`)
|
|
275
370
|
|
|
276
371
|
- Components are `export const X = ({ … }: XProps) => { return (…); };` — arrow const with a block body. `export default` is reserved for pages, layouts, and `lazy()` targets.
|
|
@@ -369,17 +464,24 @@ workflow changes.
|
|
|
369
464
|
- Slice-level `guards` only reach the generated query/mutation endpoints. A `pubsub`/`message` endpoint is unguarded unless it declares its own `guards` in its signal option.
|
|
370
465
|
- A pubsub room is authorized once, at subscribe. When a socket's credential changes the framework re-runs each room's guards and unsubscribes the ones that now fail (`SignalResolver.revalidateWsRooms`), so guards must stay side-effect free and safe to re-run.
|
|
371
466
|
- A websocket carries its credential in the handshake snapshot on `ws.data` (`AppWsData`); clients that hold the token in memory send it with `fetch.setJwt(...)`, which forwards an auth frame over the socket.
|
|
372
|
-
- **Never read the caller's IP off the socket or the request peer — take `.with(Ip)`.**
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
467
|
+
- **Never read the caller's IP off the socket or the request peer — take `.with(Ip)`.** Whenever a federation
|
|
468
|
+
gateway is in front, `ws.remoteAddress` and the child's own peer are the *gateway* (`127.0.0.1`) for every
|
|
469
|
+
caller and for the whole life of every socket. `Ip` reads what a proxy recorded (`x-real-ip`, then the first
|
|
470
|
+
`x-forwarded-for` entry) and falls back to the peer only when nothing proxied the call — which is the answer
|
|
471
|
+
for a solo process behind an ingress that sets neither; `context.getClientIp()` is the same answer inside a
|
|
472
|
+
guard or middleware. It arrives unwrapped from
|
|
377
473
|
its `::ffff:` IPv4-mapped form, so it can address a `udp4` socket as well as identify a caller, and it is
|
|
378
474
|
`null` rather than a placeholder when genuinely unknown — a loopback-looking address for an unknown caller
|
|
379
475
|
is the failure this replaced. The gateway also forwards the client port (`x-forwarded-port`, read with
|
|
380
476
|
`context.getClientPort()`) along with host and protocol.
|
|
381
477
|
- **Every socket carries a `socketId`, and only the framework mints one.** `AppWsData` assigns it at the handshake, and a `message` / `pubsub` handler reads it off the `Ws` internal arg — `.with(Ws)` hands `{ ws, socketId, subscribe, on, off }`. Never mint your own from `ws.data`: the room bookkeeping keys on the framework's id, and a second one fails to match it silently. It identifies a **connection**, not a caller — a reconnect gets a new id and the federation gateway's own socket is a different one — so per-user state keys on the account, never on this.
|
|
382
478
|
|
|
479
|
+
- **A cleanup registered with `ws.on("disconnect" | "unsubscribe", fn)` is scoped to the call that registered it.**
|
|
480
|
+
From a `pubsub` subscribe it belongs to that room — `unsubscribe` runs when the client leaves it or a credential
|
|
481
|
+
change revokes it, `disconnect` when the socket closes while still subscribed — so a room already left runs
|
|
482
|
+
neither again, and cleanup that must happen either way registers for both. From a `message` handler it belongs to
|
|
483
|
+
the socket and runs at close. A handler that throws is logged and never blocks the rest of the teardown.
|
|
484
|
+
|
|
383
485
|
### Authorization Defaults
|
|
384
486
|
|
|
385
487
|
- **Every `slice()` takes an explicit `{ guards: {…} }` second argument, and `root:` is always `Admin`.**
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
AkanContextAnalyzer
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-xda7qe2j.js";
|
|
5
5
|
import {
|
|
6
6
|
Prompter
|
|
7
7
|
} from "./index-j37qq1f2.js";
|
|
8
8
|
import {
|
|
9
9
|
runner,
|
|
10
10
|
script
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-1f34snpd.js";
|
|
12
12
|
import {
|
|
13
13
|
AGENT_BLOCK_END,
|
|
14
14
|
AGENT_BLOCK_START,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
renderRecipeEntries,
|
|
20
20
|
stampBlockVersion,
|
|
21
21
|
upsertAgentBlock
|
|
22
|
-
} from "./index-
|
|
22
|
+
} from "./index-w008bx1p.js";
|
|
23
23
|
import {
|
|
24
24
|
collectRecipeSources,
|
|
25
25
|
scanRecipes
|
|
@@ -9,14 +9,14 @@ import {
|
|
|
9
9
|
createPassedPrimitiveReport,
|
|
10
10
|
generatedFilesForSync,
|
|
11
11
|
scalarChangedFiles
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-8vv6xtm5.js";
|
|
13
13
|
import {
|
|
14
14
|
Prompter
|
|
15
15
|
} from "./index-j37qq1f2.js";
|
|
16
16
|
import {
|
|
17
17
|
runner,
|
|
18
18
|
script
|
|
19
|
-
} from "./index-
|
|
19
|
+
} from "./index-1f34snpd.js";
|
|
20
20
|
|
|
21
21
|
// pkgs/@akanjs/cli/scalar/scalar.prompt.ts
|
|
22
22
|
import { input } from "@inquirer/prompts";
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runner,
|
|
4
4
|
script
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-1f34snpd.js";
|
|
6
6
|
import {
|
|
7
7
|
PkgExecutor
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-w008bx1p.js";
|
|
9
9
|
import {
|
|
10
10
|
TypeScriptDependencyScanner
|
|
11
11
|
} from "./index-46tjzh6s.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
AkanContextAnalyzer
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-xda7qe2j.js";
|
|
5
5
|
import {
|
|
6
6
|
WorkflowExecutor,
|
|
7
7
|
compactWorkflowInputs,
|
|
@@ -23,10 +23,10 @@ import {
|
|
|
23
23
|
workflowCommandsForPlan,
|
|
24
24
|
workflowPlanApproval,
|
|
25
25
|
writeWorkflowRunArtifact
|
|
26
|
-
} from "./index-
|
|
26
|
+
} from "./index-8vv6xtm5.js";
|
|
27
27
|
import {
|
|
28
28
|
runner
|
|
29
|
-
} from "./index-
|
|
29
|
+
} from "./index-1f34snpd.js";
|
|
30
30
|
|
|
31
31
|
// pkgs/@akanjs/cli/workflow/workflow.runner.ts
|
|
32
32
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
ModuleScript
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-d5ef8n21.js";
|
|
5
5
|
import {
|
|
6
6
|
addFieldUiPolicyForType,
|
|
7
7
|
coerceFieldDefault,
|
|
@@ -34,15 +34,15 @@ import {
|
|
|
34
34
|
sourceFile,
|
|
35
35
|
validationCommandsForTarget,
|
|
36
36
|
viaBuilderParameterName
|
|
37
|
-
} from "./index-
|
|
37
|
+
} from "./index-8vv6xtm5.js";
|
|
38
38
|
import {
|
|
39
39
|
script
|
|
40
|
-
} from "./index-
|
|
40
|
+
} from "./index-1f34snpd.js";
|
|
41
41
|
import {
|
|
42
42
|
AppExecutor,
|
|
43
43
|
LibExecutor,
|
|
44
44
|
ModuleExecutor
|
|
45
|
-
} from "./index-
|
|
45
|
+
} from "./index-w008bx1p.js";
|
|
46
46
|
|
|
47
47
|
// pkgs/@akanjs/cli/primitive/primitive.script.ts
|
|
48
48
|
import { capitalize } from "akanjs/common";
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
LibraryScript
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-k8k45qfk.js";
|
|
5
5
|
import {
|
|
6
6
|
resolveMobileTargets
|
|
7
7
|
} from "./index-76rn3g2c.js";
|
|
8
8
|
import {
|
|
9
9
|
runner,
|
|
10
10
|
script
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-1f34snpd.js";
|
|
12
12
|
import {
|
|
13
13
|
HmrWatcher,
|
|
14
14
|
WatchRootResolver
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
LibExecutor,
|
|
19
19
|
PkgExecutor,
|
|
20
20
|
WorkspaceExecutor
|
|
21
|
-
} from "./index-
|
|
21
|
+
} from "./index-w008bx1p.js";
|
|
22
22
|
import {
|
|
23
23
|
__require
|
|
24
24
|
} from "./index-yb2wsc7f.js";
|
|
@@ -1898,9 +1898,9 @@ function openBrowser(url) {
|
|
|
1898
1898
|
}
|
|
1899
1899
|
|
|
1900
1900
|
// pkgs/@akanjs/cli/application/application.runner.ts
|
|
1901
|
-
var loadBuildRunner = async () => (await import("./applicationBuildRunner-
|
|
1901
|
+
var loadBuildRunner = async () => (await import("./applicationBuildRunner-jnjag4ay.js")).ApplicationBuildRunner;
|
|
1902
1902
|
var loadReleasePackager = async () => (await import("./applicationReleasePackager-93nzdfsy.js")).ApplicationReleasePackager;
|
|
1903
|
-
var loadCapacitorApp = async () => (await import("./capacitorApp-
|
|
1903
|
+
var loadCapacitorApp = async () => (await import("./capacitorApp-w1ryppdw.js")).CapacitorApp;
|
|
1904
1904
|
var loadAbstractCompactor = async () => (await import("./abstractCompactor-20e0cwbs.js")).AbstractCompactor;
|
|
1905
1905
|
var loadPrompts = async () => await import("@inquirer/prompts");
|
|
1906
1906
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
CloudRunner
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-cnyeq88g.js";
|
|
5
5
|
import {
|
|
6
6
|
PackageScript
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-6s8snbb8.js";
|
|
8
8
|
import {
|
|
9
9
|
AiSession,
|
|
10
10
|
CloudApi,
|
|
@@ -12,13 +12,13 @@ import {
|
|
|
12
12
|
} from "./index-sh01r3pm.js";
|
|
13
13
|
import {
|
|
14
14
|
ApplicationScript
|
|
15
|
-
} from "./index-
|
|
15
|
+
} from "./index-a6k0b1b5.js";
|
|
16
16
|
import {
|
|
17
17
|
script
|
|
18
|
-
} from "./index-
|
|
18
|
+
} from "./index-1f34snpd.js";
|
|
19
19
|
import {
|
|
20
20
|
PkgExecutor
|
|
21
|
-
} from "./index-
|
|
21
|
+
} from "./index-w008bx1p.js";
|
|
22
22
|
|
|
23
23
|
// pkgs/@akanjs/cli/cloud/cloud.script.ts
|
|
24
24
|
import { Logger } from "akanjs/common";
|
|
@@ -7,14 +7,14 @@ import {
|
|
|
7
7
|
} from "./index-sh01r3pm.js";
|
|
8
8
|
import {
|
|
9
9
|
openBrowser
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-a6k0b1b5.js";
|
|
11
11
|
import {
|
|
12
12
|
runner
|
|
13
|
-
} from "./index-
|
|
13
|
+
} from "./index-1f34snpd.js";
|
|
14
14
|
import {
|
|
15
15
|
AppExecutor,
|
|
16
16
|
WorkspaceExecutor
|
|
17
|
-
} from "./index-
|
|
17
|
+
} from "./index-w008bx1p.js";
|
|
18
18
|
|
|
19
19
|
// pkgs/@akanjs/cli/npmRegistry.ts
|
|
20
20
|
var defaultNpmRegistry = "https://registry.npmjs.org";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./index-ss469dec.js";
|
|
5
5
|
import {
|
|
6
6
|
PageScript
|
|
7
|
-
} from "./index-
|
|
7
|
+
} from "./index-7kxz2z5t.js";
|
|
8
8
|
import {
|
|
9
9
|
AiSession
|
|
10
10
|
} from "./index-sh01r3pm.js";
|
|
@@ -15,17 +15,17 @@ import {
|
|
|
15
15
|
generatedFilesForSync,
|
|
16
16
|
moduleSourcePaths,
|
|
17
17
|
sourceFile
|
|
18
|
-
} from "./index-
|
|
18
|
+
} from "./index-8vv6xtm5.js";
|
|
19
19
|
import {
|
|
20
20
|
Prompter
|
|
21
21
|
} from "./index-j37qq1f2.js";
|
|
22
22
|
import {
|
|
23
23
|
runner,
|
|
24
24
|
script
|
|
25
|
-
} from "./index-
|
|
25
|
+
} from "./index-1f34snpd.js";
|
|
26
26
|
import {
|
|
27
27
|
ModuleExecutor
|
|
28
|
-
} from "./index-
|
|
28
|
+
} from "./index-w008bx1p.js";
|
|
29
29
|
import {
|
|
30
30
|
FileSys
|
|
31
31
|
} from "./index-67546d0j.js";
|