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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-q7a4srt6.js → CodeAgent-q50k4s45.js} +2 -2
  3. package/{CodeTui-ak23dxc9.js → CodeTui-62g35ztk.js} +1 -1
  4. package/TunnelShare-f1egrktx.js +13 -0
  5. package/{agent.command-f3gsc1gd.js → agent.command-adfd5299.js} +5 -5
  6. package/akanCode.js +2 -2
  7. package/{application.command-3v2d53gd.js → application.command-hj3gv1rx.js} +52 -41
  8. package/{applicationBuildRunner-1yaqsrdq.js → applicationBuildRunner-by10r9gf.js} +16 -30
  9. package/buildBatch.proc.js +22 -13
  10. package/{cloud.command-kk2rwkvw.js → cloud.command-k2fhaape.js} +60 -63
  11. package/cloud.script-z8p5dz7e.js +23 -0
  12. package/{code.command-30sca09d.js → code.command-kt5zgcc2.js} +6 -6
  13. package/{context.command-k7eqacq6.js → context.command-8fgn42jw.js} +16 -13
  14. package/context.runner-hnh0rg7m.js +24 -0
  15. package/{guideline.command-dtczrqpf.js → guideline.command-3yxxr2mm.js} +2 -2
  16. package/guidelines/conventions/conventions.instruction.md +30 -15
  17. package/guidelines/cssRule/cssRule.instruction.md +12 -6
  18. package/guidelines/mcpRule/mcpRule.instruction.md +32 -11
  19. package/guidelines/runtimeRule/runtimeRule.instruction.md +24 -15
  20. package/guidelines/transportRule/transportRule.instruction.md +28 -5
  21. package/incrementalBuilder.proc.js +9 -6
  22. package/{index-kjvrq3nc.js → index-0909wckt.js} +361 -282
  23. package/{index-p9ystjrp.js → index-20cebtth.js} +92 -52
  24. package/{index-55mynnqs.js → index-2etqq75t.js} +455 -206
  25. package/{index-6jjtnhkw.js → index-31ce9vhg.js} +51 -9
  26. package/{index-y8q31011.js → index-3reaaa1h.js} +42 -153
  27. package/{index-ww9bhp67.js → index-4pf8g7ff.js} +1 -1
  28. package/{index-qt22xstj.js → index-58vvz603.js} +5 -3
  29. package/index-6726qr1m.js +668 -0
  30. package/index-8935h3n1.js +33 -0
  31. package/{index-nz15k0b6.js → index-8zdwpxef.js} +1 -1
  32. package/{index-c2yrsxdh.js → index-azh29dc8.js} +96 -320
  33. package/{index-c1x0be5j.js → index-bea2gwc6.js} +2 -2
  34. package/{index-v29746vb.js → index-e9prnmyt.js} +3 -3
  35. package/{index-tn4rpqp1.js → index-fjsv10hd.js} +73 -49
  36. package/index-g0vwzy9m.js +241 -0
  37. package/{index-c76k723e.js → index-h85cxfkg.js} +2 -2
  38. package/{index-rwq3ekqc.js → index-hnby7p9n.js} +7 -7
  39. package/{index-2etcv0sc.js → index-jwqtchha.js} +1 -1
  40. package/index-kc8z134d.js +248 -0
  41. package/index-nq045px5.js +1124 -0
  42. package/{index-fm46xrf1.js → index-nq2ja5e0.js} +3 -3
  43. package/{index-0bm04n5g.js → index-pyxn1b53.js} +10 -8
  44. package/{index-05g3jayg.js → index-rhbabmja.js} +1 -1
  45. package/{index-2mx692qq.js → index-rk9sdys3.js} +2 -2
  46. package/{index-7bymavqk.js → index-sby8fe1p.js} +1 -1
  47. package/{index-ctanya41.js → index-sqfdmb5b.js} +4 -4
  48. package/{index-2t4tqd1c.js → index-t7nws9mx.js} +3 -3
  49. package/{index-jyv387qw.js → index-tv8fjaba.js} +4 -4
  50. package/{index-gnyf1fqy.js → index-tz5evhdr.js} +2 -2
  51. package/{index-aprt7pkz.js → index-xpdgxsj5.js} +229 -1327
  52. package/{index-e0cvze1s.js → index-z507nzhg.js} +4 -4
  53. package/index.js +22 -22
  54. package/{library.command-gaga5bmq.js → library.command-8tw59xzj.js} +3 -3
  55. package/{localRegistry.command-9e84e32q.js → localRegistry.command-tf3dmznd.js} +12 -9
  56. package/{module.command-7vpf6db4.js → module.command-9vm8hffy.js} +5 -5
  57. package/{package.command-twmvvf69.js → package.command-erbxe2tz.js} +3 -3
  58. package/package.json +2 -2
  59. package/{page.command-5asq7fdf.js → page.command-jpavcj0p.js} +3 -3
  60. package/{pipeline.command-d0v38572.js → pipeline.command-b8rzvjvv.js} +220 -219
  61. package/{primitive.command-dyrs2fm8.js → primitive.command-sm32chzk.js} +6 -6
  62. package/{projectTypecheck-cvtkrzp2.js → projectTypecheck-jamtx95x.js} +1 -1
  63. package/{quality.command-6emsqpbg.js → quality.command-pkd17n6y.js} +2 -2
  64. package/{repair.command-8t6aegv5.js → repair.command-8y4mq6hs.js} +5 -5
  65. package/{scalar.command-bnggy1x7.js → scalar.command-q8khmyx5.js} +4 -4
  66. package/{subspace.command-f02j5tge.js → subspace.command-51n0ykbx.js} +421 -362
  67. package/templates/app/env/env.client.type.ts +2 -3
  68. package/templates/app/page/styles.css.template +8 -0
  69. package/{tunnel.command-9x8nfn75.js → tunnel.command-7820vtxq.js} +7 -4
  70. package/{workflow.command-jx0wag5r.js → workflow.command-n5sv4wqz.js} +10 -10
  71. package/{workspace.command-cmj6mqyk.js → workspace.command-zdy60jh8.js} +33 -30
  72. package/TunnelShare-21mm6dr5.js +0 -9
  73. package/cloud.script-r7eyfey4.js +0 -20
  74. package/context.runner-hqd1ppqe.js +0 -21
  75. package/index-6w0rbr9d.js +0 -68
  76. package/index-r2tpeb3n.js +0 -392
@@ -257,9 +257,10 @@ const config: AppConfig = {
257
257
  Intel Macs are not a target, so `--arch x64` on macOS is refused.
258
258
  - **A release is signed only with `--sign` and notarized only with `--notarize`** (`build-desktop`,
259
259
  `publish-update`); the environment names the identity and never decides to use it, so a shell exporting a Developer
260
- ID signs and uploads nothing unasked. Before either, the server the app carries is searched for every secret value
261
- of the workspace's server env files and refused with the paths, and one line names the identity and the service
262
- the app goes to.
260
+ ID signs and uploads nothing unasked. Every release build and every `publish-update` of a target that carries a
261
+ server, signed or not, first searches that server for every secret value of the workspace's server env files and
262
+ refuses with the paths; an env file it cannot evaluate stops the release too, and a debug build is not searched.
263
+ One line then names the identity and the service the app goes to.
263
264
  - **A macOS release for download is signed with a Developer ID and notarized.**
264
265
  `AKAN_NATIVE_MACOS_IDENTITY` names a keychain identity, or `AKAN_NATIVE_MACOS_CERTIFICATE` +
265
266
  `_CERTIFICATE_PASSWORD` a `.p12` the build imports into a keychain of its own (a CI runner);
@@ -280,12 +281,15 @@ const config: AppConfig = {
280
281
  key. List the online signing key first and offline spares after it (up to three): a phone binary trusts all of
281
282
  them, and a key may revoke only the keys listed before it, so a leaked key cannot lock out its spares. A desktop
282
283
  app trusts the first; `publicKey` is the one-key form. `akan publish-update <app>` builds and signs a release
283
- into `updates/`: upload that folder to `url`, the manifests last, or let `--upload s3://<bucket>/<prefix>` do it
284
- (credentials and endpoint from `S3_*` or `AWS_*`; a release file the bucket holds is skipped). A phone reads only
285
- `<url>/<platform>/<channel>/<nativeApi>.json`, so each store generation on a channel takes its own fixes.
284
+ into `updates/`: upload that release's files to `url` and its manifest last, or let
285
+ `--upload s3://<bucket>/<prefix>` do it (credentials and endpoint from `S3_*` or `AWS_*`; a release file the bucket
286
+ holds is skipped), which sends that release alone, and nothing when it is missing or fails a check. Never upload the
287
+ folder whole: a phone's is also where `pack-update` writes by default.
288
+ A phone reads only `<url>/<platform>/<channel>/<nativeApi>.json`, so each store generation on a channel takes its
289
+ own fixes.
286
290
  `akan pack-update` writes an unsigned phone bundle for whoever holds the key to sign and records it in
287
291
  `<out>/pack.json`, exiting 2 when `--against` says it needs a new store build; `akan push-update` packs and uploads to
288
- an akasys project that holds the key, and `akan register-binary` registers a store build after `release-*`. A
292
+ the Akan Cloud project that holds the key, and `akan register-binary` registers a store build after `release-*`. A
289
293
  release that hangs is rolled back while the app runs, and `report: { url }` has a phone post what became of each
290
294
  release (applied, confirmed, rolled back and why) at its next launch, so rollback rates are visible. `devtools: true`
291
295
  opens the web inspector of a release build for an internal test target. The channel is the backend env the binary was built for unless `channel` names one;
@@ -307,10 +311,11 @@ const config: AppConfig = {
307
311
  their page paints, so a dark board never flashes white, and `desktop.publisher` names who publishes a Windows app in
308
312
  Apps & features and its executable's company (the app name when unset, never Bun's own).
309
313
  - **A third-party page shown first-party** — a scoreboard, a menu board — is the `external-view` plugin, listed in
310
- `native.plugins`: a webview over the window with a browser profile of its own, held to the origins it was opened
311
- for, with an init script, `evaluate`, a trusted `sendKey`, `capture`, and `loadFailed` / `gone` (it reloads, or is
312
- rebuilt, by itself) / `consoleMessage` events. Every method on Windows; macOS 14+ lacks `sendKey`, `setMuted` and
313
- `capture`.
314
+ `native.plugins`: a webview over the window with a browser profile of its own, its top level held to the origins it
315
+ was opened for while its frames load web content from anywhere, with an init script that runs in the top document
316
+ only, `evaluate`, a trusted `sendKey`, `capture`, and `loadFailed` / `gone` (it reloads, or is rebuilt, by itself;
317
+ the reason is `terminated` on macOS, and `rebuildFailed` when a rebuild failed and the view is closed, to be opened
318
+ again) / `consoleMessage` events. Every method on Windows; macOS 14+ lacks `sendKey`, `setMuted` and `capture`.
314
319
 
315
320
  ## A Desktop App's Server — `bin` And `trustedDependencies`
316
321
 
@@ -416,10 +421,14 @@ in those alone, and `modules: ["@edge"]` (or `AKAN_MODULES=@edge`) names every m
416
421
  inject, cascade to and hold a relation to. `desktop: { server: { profile: "edge", modules: ["@edge"] } }` builds the
417
422
  carried server that way: `env/env.server.<env>.edge.ts` is bundled in place of `env/env.server.<env>.ts`, which never
418
423
  enters it, and the build evaluates the profile file with no app env and refuses one whose secret-named keys hold a
419
- value — a `process.env.X ?? "literal"` counts as the literal. Each lib's env defaults (`env.server.testing.ts`) are
424
+ value — a `process.env.X ?? "literal"` counts as the literal. Signing, encryption, master and session keys, `pwd`, a
425
+ `…dsn` and a connection string are secret-named, and a URL holding a password or a secret-named query parameter is a
426
+ secret under any key. The profile may spread `libEnv`, and the lib defaults it reaches are checked as the bundle
427
+ carries them; a profile that imports the file it replaces is refused. Each lib's env defaults (`env.server.testing.ts`) are
420
428
  swapped the same way: for the lib's `env/env.server.testing.edge.ts`, held to the same check, or for the defaults with
421
- every secret-named value left out, which the build names in a warning. `akan build <app> --profile edge` does the
422
- same for an image. A module listing only edge does not mount under `akan start` (local): list `local` too to develop
429
+ every secret-named value left out, which the build names in a warning — and a default a JSON snapshot cannot carry (a
430
+ function, Map, Set, Date, class instance, bigint or non-finite number) is refused unless the lib has its profile file.
431
+ `akan build <app> --profile edge` does the same for an image. A module listing only edge does not mount under `akan start` (local): list `local` too to develop
423
432
  it there.
424
433
 
425
434
  **A file the user picks reaches the server as a grant, never as a copy or a path.** With `"file-picker"` in
@@ -556,7 +565,7 @@ const config: AppConfig = { assets: { pruneFonts: false } }; // emergency valve,
556
565
 
557
566
  Akan Cloud builds and deploys each app as `build` → `docker` → `deploy`, and `ota` after them when asked. **An app's own stages go in
558
567
  `apps/<app>/akan.config.ts` under `pipeline`; stages around every app go in the workspace root's
559
- `akan.config.ts`**, typed `WorkspaceConfig` (`before`, `after`, `post`, `env`, `timeout`). Both are `import type`
568
+ `akan.config.ts`**, typed `WorkspaceConfig`, under its own `pipeline` (`before`, `after`, `post`, `env`, `timeout`). Both are `import type`
560
569
  objects (or `(ctx) => …`), and `akan pipeline dry-run | validate | plan` turns them into the plan Akan Cloud runs —
561
570
  locally, running nothing.
562
571
 
@@ -47,14 +47,17 @@ mutation is mounted under. `conventions` carries the invariants — this is the
47
47
  change revokes it, `disconnect` when the socket closes while still subscribed — so a room already left runs
48
48
  neither again, and cleanup that must happen either way registers for both. From a `message` handler it belongs to
49
49
  the socket and runs at close. A handler that throws is logged and never blocks the rest of the teardown.
50
+ - **A subscribe the client leaves before it finishes joins nothing.** When an `unsubscribe` for the room, or the
51
+ socket's close, arrives while the subscribe is still running, the subscribe answers `subscribe: false` and runs its
52
+ `unsubscribe` cleanup (and its `disconnect` one when the socket closed) instead of joining the room.
50
53
 
51
54
  ## Request Deadlines
52
55
 
53
56
  - **`{ timeout: <ms> }` in an endpoint's signal option is the whole configuration surface**, and it reaches both
54
57
  ends of the call. Server side, the `Timeout` middleware races the handler against it and answers
55
58
  `base.error.gatewayTimeout` (504) once it is spent. Client side, `FetchSerializer` ships the value on the
56
- serialized endpoint and `fetch.<endpoint>()` uses it as that request's `AbortSignal.timeout` budget, so the
57
- browser does not abandon a call the server is still allowed to be working on.
59
+ serialized endpoint and `fetch.<endpoint>()` uses it as that call's deadline — every retry of the call and every
60
+ wait between them included — so the browser does not abandon a call the server is still allowed to be working on.
58
61
  - **The middleware is registered by default and has no default of its own.** An endpoint that declares no
59
62
  `timeout` is passed straight through — a default here would put a deadline on every endpoint in the app that
60
63
  nobody asked for, which is why the middleware used to be opt-in and, being opt-in, made the declared value
@@ -92,6 +95,11 @@ mutation is mounted under. `conventions` carries the invariants — this is the
92
95
  - **The entry is the handler's result, not the response.** The lookup wraps the handler only, so `resolveReturn`
93
96
  still runs per call on the cached value — field masking, `hidden`/`secret` stripping and relation resolution are
94
97
  never cached, and a relation still costs its own load. The cache saves the handler, not the serialization.
98
+ - **A hit hands `resolveReturn` an instance of the declared return model**, rebuilt from an entry that keeps its
99
+ `Map`s, bytes and dates, so a `resolveField` reads the same methods and `Dayjs` values on a hit as on a miss. It is
100
+ the declared model, not the service's document: a method only the document has is not there on a hit, and a return
101
+ declared as a `Light` model shows `resolveField` its light fields only. The entry still holds `hidden` and `secret`
102
+ values for its TTL, as the handler returned them.
95
103
  - **A cache backend that is down does not take the endpoint down.** A failed read is warned and the call runs
96
104
  uncached; a failed write is warned and dropped.
97
105
  - The default middleware chain is `Logging → Timeout → <lib middlewares>`, and the call inside it runs an
@@ -99,6 +107,21 @@ mutation is mounted under. `conventions` carries the invariants — this is the
99
107
  handler: a hung cache backend is bounded by the same deadline as the handler it stands in for. **`Retry` was removed** — an automatic re-run of an endpoint
100
108
  whose failure it cannot classify replays whatever the first attempt already did.
101
109
 
110
+ ## Repeated Mutations
111
+
112
+ - **A mutation sent again under the same `Idempotency-Key` header runs once.** The key is checked after the
113
+ resource guards and the internal arguments, and it is scoped to the endpoint, the caller and a digest of the
114
+ arguments, so one caller's key never hands another caller its answer. A repeat while the first run is still going
115
+ answers 409 `base.error.idempotencyInFlight`.
116
+ - **A repeat answers the first response as it was sent** — resolved, masked and serialized — for 24 hours. What
117
+ is kept is that wire form, never the handler's result, so no `hidden` or `secret` field reaches the cache.
118
+ - A handler that throws frees the key, so a repeat runs it again. A failure after the handler returned is kept and
119
+ replayed instead, for the same 24 hours and a transient one (a relation read during a database blip) included:
120
+ the handler's writes stand, so running it again would repeat them.
121
+ - **Only an HTTP call is deduplicated.** A signed-out call, one whose handler returns a `Response` (whose headers,
122
+ such as a session's `Set-Cookie`, cannot be replayed), a websocket call, and a call through MCP all run every
123
+ time.
124
+
102
125
  ## Rate Limits
103
126
 
104
127
  - **`{ rateLimit: { calls, windowMs?, by? } }` in an endpoint's signal option** counts calls per caller per window
@@ -107,9 +130,9 @@ mutation is mounted under. `conventions` carries the invariants — this is the
107
130
  checked after the middlewares and before the guards, keyed by `accountKey(account)`; a caller it names nothing
108
131
  for — an anonymous one — is counted by address. Leaving a pubsub room is never counted.
109
132
  - **The answer is 429 `base.error.tooManyRequests` with `data: { seconds }`** and a `Retry-After` header; a WS
110
- call gets the same payload as its error frame, and the HTTP client restores a proxy's own non-JSON 429 under the
111
- same key (seconds from its `Retry-After`, else 60). The first refusal per endpoint per process is warned once;
112
- later ones log at `debug`, so a flood does not become a log flood.
133
+ call gets the same payload as its error frame, and the HTTP client restores a proxy's own 429 — a page, or JSON
134
+ naming no error key of ours — under the same key (seconds from its `Retry-After`, `0` included, else 60). The first
135
+ refusal per endpoint per process is warned once; later ones log at `debug`, so a flood does not become a log flood.
113
136
  - **Keys and addresses.** The address is `context.getClientIp()` — the trusted-proxy answer, never a raw header
114
137
  from an untrusted peer. Callers whose address is unknown share one `unknown` budget (fail closed), and the first
115
138
  such call is warned about, since it usually means the proxy in front records no `X-Real-IP`/`X-Forwarded-For`
@@ -8,19 +8,21 @@ import {
8
8
  CodegenLock,
9
9
  WorkspaceExecutor,
10
10
  AppExecutor
11
- } from "./index-55mynnqs.js";
11
+ } from "./index-2etqq75t.js";
12
12
  import"./index-52w0fvh8.js";
13
13
  import {
14
14
  GraphClientEntryDiscovery,
15
15
  RouteClientBuilder,
16
16
  AutoImportSync,
17
- ServerGraphFile,
18
17
  CsrDevPatcher,
19
18
  CsrDevBundler,
20
19
  DevChangePlanner,
21
20
  DevGeneratedIndexSync,
22
21
  SsrDevBundler
23
- } from "./index-aprt7pkz.js";
22
+ } from "./index-xpdgxsj5.js";
23
+ import {
24
+ ServerGraphFile
25
+ } from "./index-nq045px5.js";
24
26
  import {
25
27
  prepareDevWatchBatch
26
28
  } from "./index-a5vmm6x4.js";
@@ -235,7 +237,7 @@ class IncrementalBuilder {
235
237
  #autoImportSync;
236
238
  #watcher = null;
237
239
  #generation = 0;
238
- #shellGeneration = null;
240
+ #shellKey = null;
239
241
  #discoveredThrough = 0;
240
242
  #csrActive = IncrementalBuilder.#csrArmedByEnv();
241
243
  #csrBundler;
@@ -948,13 +950,14 @@ class IncrementalBuilder {
948
950
  async#buildShell(msg) {
949
951
  await this.#workQueue.enqueue("build-shell", async () => {
950
952
  const generation = this.#generation;
953
+ const shellKey = `${generation}:${JSON.stringify(this.#artifact.cssAssets)}`;
951
954
  let error;
952
- if (this.#shellGeneration !== generation)
955
+ if (this.#shellKey !== shellKey)
953
956
  try {
954
957
  const result = await this.#batchRunner.run(await this.#batchRequest({ generation, needs: ["shell"], changedFiles: [] }));
955
958
  error = result.errors.shell;
956
959
  if (!error)
957
- this.#shellGeneration = generation;
960
+ this.#shellKey = shellKey;
958
961
  } catch (err) {
959
962
  error = ApplicationBuildReporter.formatError(err, this.#app.workspace.workspaceRoot);
960
963
  }