@akanjs/cli 3.1.0-rc.1 → 3.1.0-rc.3
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/{CodeAgent-kyprmy06.js → CodeAgent-ctk4fh2b.js} +2 -2
- package/{CodeTui-21mtze3j.js → CodeTui-mrxtrdzw.js} +1 -1
- package/TunnelShare-rj74jd6x.js +13 -0
- package/{agent.command-f3gsc1gd.js → agent.command-ncre6kwz.js} +5 -5
- package/akanCode.js +2 -2
- package/{application.command-5s780vnz.js → application.command-54mawreg.js} +52 -41
- package/{applicationBuildRunner-1yaqsrdq.js → applicationBuildRunner-8573zr2w.js} +16 -30
- package/buildBatch.proc.js +22 -13
- package/{cloud.command-yj6xb2a7.js → cloud.command-nyemv0m3.js} +57 -65
- package/cloud.script-ht6yb203.js +23 -0
- package/{code.command-3wkn4ja5.js → code.command-spsrzg63.js} +6 -6
- package/{context.command-9jjn3gcw.js → context.command-768zv7z4.js} +16 -13
- package/context.runner-tf1b53qq.js +24 -0
- package/{guideline.command-dtczrqpf.js → guideline.command-4ycwc51q.js} +2 -2
- package/guidelines/conventions/conventions.instruction.md +28 -15
- package/guidelines/cssRule/cssRule.instruction.md +12 -6
- package/guidelines/mcpRule/mcpRule.instruction.md +27 -11
- package/guidelines/runtimeRule/runtimeRule.instruction.md +24 -15
- package/guidelines/transportRule/transportRule.instruction.md +28 -5
- package/incrementalBuilder.proc.js +9 -6
- package/{index-2etcv0sc.js → index-00seamy5.js} +1 -1
- package/{index-jx4bzvwg.js → index-1a7nhq56.js} +92 -52
- package/{index-e0cvze1s.js → index-1nyxvz8j.js} +4 -4
- package/index-2z3kykvd.js +248 -0
- package/{index-rtct7d43.js → index-3675mvjw.js} +1 -1
- package/{index-56d2g8ms.js → index-3ddt3qjg.js} +1 -1
- package/{index-6jjtnhkw.js → index-3x7yeecy.js} +51 -9
- package/{index-ww9bhp67.js → index-4pf8g7ff.js} +1 -1
- package/index-8935h3n1.js +33 -0
- package/{index-v29746vb.js → index-8eqkxwsx.js} +3 -3
- package/{index-c2yrsxdh.js → index-91rt5bye.js} +96 -320
- package/{index-55mynnqs.js → index-bv210r6t.js} +459 -210
- package/{index-c76k723e.js → index-c4h5b5nq.js} +2 -2
- package/{index-qt22xstj.js → index-c9zjb3tw.js} +5 -3
- package/{index-c1x0be5j.js → index-dmsvd2rv.js} +2 -2
- package/index-ec080x99.js +1124 -0
- package/{index-ctanya41.js → index-fjqvd5mx.js} +4 -4
- package/{index-aprt7pkz.js → index-fvn6f5wx.js} +229 -1327
- package/{index-rc5rwyps.js → index-jj7yapwq.js} +71 -60
- package/index-kmamh5bv.js +241 -0
- package/{index-fm46xrf1.js → index-q5abh0jq.js} +3 -3
- package/{index-1w2qaee2.js → index-qf8g88j9.js} +361 -291
- package/{index-gnyf1fqy.js → index-qvghfv6v.js} +2 -2
- package/{index-ae5pwhgs.js → index-r5d6rq19.js} +10 -8
- package/{index-2mx692qq.js → index-vhfjzda3.js} +2 -2
- package/{index-8r4d7cmt.js → index-w9b71b6y.js} +4 -4
- package/{index-8ggztp8k.js → index-wanhh011.js} +42 -177
- package/{index-05g3jayg.js → index-wdze51wz.js} +1 -1
- package/index-wjqbc7sf.js +668 -0
- package/{index-rwq3ekqc.js → index-xf40a295.js} +7 -7
- package/{index-krq7btbt.js → index-xm5tmpv0.js} +3 -3
- package/index.js +22 -22
- package/{library.command-gaga5bmq.js → library.command-88ahgych.js} +3 -3
- package/{localRegistry.command-vsreyy42.js → localRegistry.command-ykea1m7b.js} +12 -9
- package/{module.command-7vpf6db4.js → module.command-zky4b7m9.js} +5 -5
- package/{package.command-twmvvf69.js → package.command-vh8pcedh.js} +3 -3
- package/package.json +2 -2
- package/{page.command-5asq7fdf.js → page.command-fyqeqxc3.js} +3 -3
- package/{pipeline.command-d0v38572.js → pipeline.command-r5t30py6.js} +220 -219
- package/{primitive.command-dyrs2fm8.js → primitive.command-a0516zfk.js} +6 -6
- package/{projectTypecheck-cvtkrzp2.js → projectTypecheck-7djd4z50.js} +1 -1
- package/{quality.command-6emsqpbg.js → quality.command-k7jcnfn0.js} +2 -2
- package/{repair.command-8t6aegv5.js → repair.command-85zg2an3.js} +5 -5
- package/{scalar.command-bnggy1x7.js → scalar.command-g5vmqwca.js} +4 -4
- package/{subspace.command-md2teygq.js → subspace.command-mp4evgsj.js} +421 -362
- package/{tunnel.command-jx3tdm2d.js → tunnel.command-kbnr99sj.js} +7 -4
- package/{workflow.command-jx0wag5r.js → workflow.command-9y9p1n8y.js} +10 -10
- package/{workspace.command-yxd7rr7g.js → workspace.command-jmec2kjg.js} +33 -30
- package/TunnelShare-q4jq08qg.js +0 -9
- package/cloud.script-h6pvcpa2.js +0 -20
- package/context.runner-atcrzz5b.js +0 -21
- package/index-6w0rbr9d.js +0 -68
- package/index-pgj2rt78.js +0 -404
|
@@ -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.
|
|
261
|
-
|
|
262
|
-
the
|
|
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
|
|
284
|
-
(credentials and endpoint from `S3_*` or `AWS_*`; a release file the bucket
|
|
285
|
-
|
|
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
|
-
|
|
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
|
|
311
|
-
for
|
|
312
|
-
|
|
313
|
-
`
|
|
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.
|
|
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
|
|
422
|
-
|
|
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
|
|
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
|
|
111
|
-
same key (seconds from its `Retry-After`, else 60). The first
|
|
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-
|
|
11
|
+
} from "./index-bv210r6t.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-
|
|
22
|
+
} from "./index-fvn6f5wx.js";
|
|
23
|
+
import {
|
|
24
|
+
ServerGraphFile
|
|
25
|
+
} from "./index-ec080x99.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
|
-
#
|
|
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.#
|
|
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.#
|
|
960
|
+
this.#shellKey = shellKey;
|
|
958
961
|
} catch (err) {
|
|
959
962
|
error = ApplicationBuildReporter.formatError(err, this.#app.workspace.workspaceRoot);
|
|
960
963
|
}
|
|
@@ -38,40 +38,45 @@ import {
|
|
|
38
38
|
} from "./index-k9rrten6.js";
|
|
39
39
|
import {
|
|
40
40
|
runner,
|
|
41
|
-
script
|
|
42
|
-
|
|
41
|
+
script,
|
|
42
|
+
assertPromptable
|
|
43
|
+
} from "./index-3x7yeecy.js";
|
|
43
44
|
import {
|
|
44
45
|
WorkspaceExecutor,
|
|
45
46
|
AppExecutor,
|
|
46
47
|
LibExecutor,
|
|
47
48
|
PkgExecutor
|
|
48
|
-
} from "./index-
|
|
49
|
+
} from "./index-bv210r6t.js";
|
|
49
50
|
import {
|
|
50
51
|
DesktopServerStage,
|
|
51
|
-
NativeApp,
|
|
52
52
|
UpdateUploader
|
|
53
|
-
} from "./index-
|
|
53
|
+
} from "./index-kmamh5bv.js";
|
|
54
|
+
import {
|
|
55
|
+
NativePublicEnv,
|
|
56
|
+
UpdatePackFolder,
|
|
57
|
+
NativeApp
|
|
58
|
+
} from "./index-qf8g88j9.js";
|
|
54
59
|
import {
|
|
55
60
|
LibraryScript
|
|
56
|
-
} from "./index-
|
|
61
|
+
} from "./index-dmsvd2rv.js";
|
|
57
62
|
import {
|
|
58
63
|
stripAnsi
|
|
59
64
|
} from "./index-7md2g9vw.js";
|
|
60
65
|
import {
|
|
61
66
|
SlicePlanner,
|
|
62
67
|
formatSlicePlan
|
|
63
|
-
} from "./index-
|
|
68
|
+
} from "./index-c9zjb3tw.js";
|
|
69
|
+
import {
|
|
70
|
+
openBrowser
|
|
71
|
+
} from "./index-9dp031by.js";
|
|
64
72
|
import {
|
|
65
73
|
resolveMobileTargets,
|
|
66
74
|
resolveAppId
|
|
67
75
|
} from "./index-q958tqqg.js";
|
|
68
|
-
import {
|
|
69
|
-
openBrowser
|
|
70
|
-
} from "./index-9dp031by.js";
|
|
71
76
|
|
|
72
77
|
// pkgs/@akanjs/cli/application/application.script.ts
|
|
73
78
|
import { confirm } from "@inquirer/prompts";
|
|
74
|
-
import { Logger as Logger6 } from "akanjs/common";
|
|
79
|
+
import { Logger as Logger6, toError as toError2 } from "akanjs/common";
|
|
75
80
|
|
|
76
81
|
// pkgs/@akanjs/cli/application/application.runner.ts
|
|
77
82
|
import { realpathSync } from "fs";
|
|
@@ -1888,8 +1893,8 @@ ${uniqueCandidates.map((candidate) => ` - ${candidate}`).join(`
|
|
|
1888
1893
|
}
|
|
1889
1894
|
|
|
1890
1895
|
// pkgs/@akanjs/cli/application/application.runner.ts
|
|
1891
|
-
import { Logger as Logger3 } from "akanjs/common";
|
|
1892
|
-
var loadBuildRunner = async () => (await import("./applicationBuildRunner-
|
|
1896
|
+
import { Logger as Logger3, toError } from "akanjs/common";
|
|
1897
|
+
var loadBuildRunner = async () => (await import("./applicationBuildRunner-8573zr2w.js")).ApplicationBuildRunner;
|
|
1893
1898
|
var loadPrompts = async () => await import("@inquirer/prompts");
|
|
1894
1899
|
|
|
1895
1900
|
class ApplicationRunner extends runner("application") {
|
|
@@ -1914,6 +1919,9 @@ class ApplicationRunner extends runner("application") {
|
|
|
1914
1919
|
throw new Error(`No script files found. make a script file in apps/${app.name}/script folder`);
|
|
1915
1920
|
}
|
|
1916
1921
|
const scriptFiles = (await app.readdir("script")).filter((file) => file.endsWith(".ts"));
|
|
1922
|
+
assertPromptable("Missing argument 'filename'", {
|
|
1923
|
+
choices: scriptFiles.map((file) => file.replace(".ts", ""))
|
|
1924
|
+
});
|
|
1917
1925
|
const scriptFile = await (await loadPrompts()).select({
|
|
1918
1926
|
message: "Select script to run",
|
|
1919
1927
|
choices: scriptFiles.map((file) => ({ name: file, value: file.replace(".ts", "") }))
|
|
@@ -2047,7 +2055,7 @@ try {
|
|
|
2047
2055
|
await new (await loadBuildRunner())(app).typecheck(options);
|
|
2048
2056
|
}
|
|
2049
2057
|
async typecheckLibrary(lib, options = {}) {
|
|
2050
|
-
const { ProjectTypecheck } = await import("./projectTypecheck-
|
|
2058
|
+
const { ProjectTypecheck } = await import("./projectTypecheck-7djd4z50.js");
|
|
2051
2059
|
const root = lib.workspace.workspaceRoot;
|
|
2052
2060
|
await new ProjectTypecheck(lib.cwdPath, root, { ...process.env, AKAN_WORKSPACE_ROOT: root }).run([
|
|
2053
2061
|
"../../server.ts",
|
|
@@ -2078,9 +2086,9 @@ try {
|
|
|
2078
2086
|
fast = false,
|
|
2079
2087
|
reporter,
|
|
2080
2088
|
spinner = false,
|
|
2081
|
-
|
|
2089
|
+
envProfile
|
|
2082
2090
|
} = {}) {
|
|
2083
|
-
return new (await loadBuildRunner())(app, { fast, reporter, profile }).build({ spinner });
|
|
2091
|
+
return new (await loadBuildRunner())(app, { fast, reporter, profile: envProfile }).build({ spinner });
|
|
2084
2092
|
}
|
|
2085
2093
|
async start(app, {
|
|
2086
2094
|
open = false,
|
|
@@ -2189,44 +2197,46 @@ try {
|
|
|
2189
2197
|
};
|
|
2190
2198
|
return canonical(reported) === canonical(own);
|
|
2191
2199
|
}
|
|
2192
|
-
async releaseIos(app, { target, env = "main", teamId, adHoc = false } = {}) {
|
|
2200
|
+
async releaseIos(app, { target, env = "main", teamId, adHoc = false, publicEnv } = {}) {
|
|
2193
2201
|
const targets = await resolveMobileTargets(app, target);
|
|
2194
|
-
await this.#buildMobileCsr(app, env);
|
|
2202
|
+
await this.#buildMobileCsr(app, env, undefined, publicEnv ? await NativePublicEnv.load(publicEnv) : null);
|
|
2195
2203
|
for (const mobileTarget of targets)
|
|
2196
2204
|
this.#reportBuild(app, mobileTarget, await new NativeApp(app, mobileTarget, env).releaseIos({ teamId, adHoc }));
|
|
2197
2205
|
}
|
|
2198
|
-
async releaseAndroid(app, format, { target, env = "main" } = {}) {
|
|
2206
|
+
async releaseAndroid(app, format, { target, env = "main", publicEnv } = {}) {
|
|
2199
2207
|
const targets = await resolveMobileTargets(app, target);
|
|
2200
2208
|
NativeApp.androidSigning();
|
|
2201
|
-
await this.#buildMobileCsr(app, env);
|
|
2209
|
+
await this.#buildMobileCsr(app, env, undefined, publicEnv ? await NativePublicEnv.load(publicEnv) : null);
|
|
2202
2210
|
for (const mobileTarget of targets)
|
|
2203
2211
|
this.#reportBuild(app, mobileTarget, await new NativeApp(app, mobileTarget, env).releaseAndroid({ formats: [format] }));
|
|
2204
2212
|
}
|
|
2205
|
-
async packUpdate(app, platform, { target, env = "main", out, against }) {
|
|
2213
|
+
async packUpdate(app, platform, { target, env = "main", out, against, publicEnv }) {
|
|
2206
2214
|
const targets = await resolveMobileTargets(app, target);
|
|
2207
2215
|
const [mobileTarget] = targets;
|
|
2208
2216
|
if (!mobileTarget || targets.length > 1)
|
|
2209
2217
|
throw new Error("pack-update packs one native target at a time; pass --target <name>.");
|
|
2210
|
-
|
|
2211
|
-
|
|
2218
|
+
const nativeApp = new NativeApp(app, mobileTarget, env);
|
|
2219
|
+
await UpdatePackFolder.clear(path5.resolve(out ?? path5.join(nativeApp.updatesDir, platform)));
|
|
2220
|
+
const pinned = publicEnv ? await NativePublicEnv.load(publicEnv) : against ? await NativePublicEnv.recordedIn(against) : null;
|
|
2221
|
+
await this.#buildMobileCsr(app, env, undefined, pinned);
|
|
2222
|
+
const { pack } = await nativeApp.packUpdate(platform, { out });
|
|
2212
2223
|
app.logger.info(`packed ${mobileTarget.name} ${platform} for channel '${pack.channel}' to ${pack.out}: ${pack.files} files, ${(pack.size / 1024).toFixed(0)} KiB, native API ${pack.nativeApi}`);
|
|
2213
2224
|
if (against) {
|
|
2214
|
-
const
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2225
|
+
const bundle = path5.join(pack.out, UpdatePackFolder.bundleFile);
|
|
2226
|
+
const compat = await NativeApp.compareBundles(app.cwdPath, against, bundle);
|
|
2227
|
+
const envProblem = await NativePublicEnv.problemAgainst(against, bundle);
|
|
2228
|
+
await UpdatePackFolder.writeCompat(pack, {
|
|
2229
|
+
against,
|
|
2230
|
+
compatible: compat.compatible && !envProblem,
|
|
2231
|
+
problems: [...compat.problems, ...envProblem ? [envProblem] : []]
|
|
2232
|
+
});
|
|
2218
2233
|
}
|
|
2219
|
-
await
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2234
|
+
await UpdatePackFolder.write(pack);
|
|
2235
|
+
const verdict = UpdatePackFolder.storeBuildVerdict(pack);
|
|
2236
|
+
if (verdict)
|
|
2237
|
+
throw verdict;
|
|
2238
|
+
if (pack.compat)
|
|
2223
2239
|
app.logger.info(`runs in the store build of ${against}`);
|
|
2224
|
-
return pack;
|
|
2225
|
-
}
|
|
2226
|
-
app.logger.error(`This bundle needs a new store build; it differs from the one ${against} came from:
|
|
2227
|
-
- ${pack.compat.problems.join(`
|
|
2228
|
-
- `)}`);
|
|
2229
|
-
process.exitCode = 2;
|
|
2230
2240
|
return pack;
|
|
2231
2241
|
}
|
|
2232
2242
|
async updateKeygen(app, platform, target) {
|
|
@@ -2237,16 +2247,27 @@ try {
|
|
|
2237
2247
|
if (seen.has(appId))
|
|
2238
2248
|
continue;
|
|
2239
2249
|
seen.add(appId);
|
|
2240
|
-
const { publicKey, keyPath, created } = await new NativeApp(app, mobileTarget).updateKeygen(nativePlatform);
|
|
2250
|
+
const { publicKey, keyId, keyPath, created } = await new NativeApp(app, mobileTarget).updateKeygen(nativePlatform);
|
|
2241
2251
|
app.log(`${appId}: ${created ? "made" : "read"} ${keyPath}${created ? " (keep it private and backed up: without it, installed apps take no more updates)" : ""}`);
|
|
2242
2252
|
app.log(` native: { updates: { url: "https://\u2026/${app.name}", publicKeys: [${JSON.stringify(publicKey)}] } }`);
|
|
2253
|
+
app.log(` keyId ${keyId}: what publish-update --revoke and updates.revokedKeys name this key by`);
|
|
2243
2254
|
const { publicKey: one, publicKeys } = mobileTarget.config.updates ?? {};
|
|
2244
2255
|
const declared = publicKeys ?? (one ? [one] : null);
|
|
2245
2256
|
if (declared && !declared.includes(publicKey))
|
|
2246
2257
|
app.logger.warn(`native.targets.${mobileTarget.name}.updates.publicKeys does not hold this key; releases it signs would not verify.`);
|
|
2247
2258
|
}
|
|
2248
2259
|
}
|
|
2249
|
-
async publishUpdate(app, platform, {
|
|
2260
|
+
async publishUpdate(app, platform, {
|
|
2261
|
+
target,
|
|
2262
|
+
env = "main",
|
|
2263
|
+
channel,
|
|
2264
|
+
upload,
|
|
2265
|
+
arch,
|
|
2266
|
+
sign = false,
|
|
2267
|
+
notarize = false,
|
|
2268
|
+
revoke,
|
|
2269
|
+
resetSequence
|
|
2270
|
+
} = {}) {
|
|
2250
2271
|
if (arch && platform !== "desktop")
|
|
2251
2272
|
throw new Error(`--arch picks a desktop release's CPU; ${platform} publishes its web bundle.`);
|
|
2252
2273
|
const targets = await resolveMobileTargets(app, target);
|
|
@@ -2260,7 +2281,9 @@ try {
|
|
|
2260
2281
|
await new NativeApp(app, mobileTarget, env).assertPublishable(nativePlatform, {
|
|
2261
2282
|
server: ApplicationRunner.carriesServer(mobileTarget, nativePlatform),
|
|
2262
2283
|
...channel ? { channel } : {},
|
|
2263
|
-
...arch ? { arch } : {}
|
|
2284
|
+
...arch ? { arch } : {},
|
|
2285
|
+
revoke,
|
|
2286
|
+
resetSequence
|
|
2264
2287
|
});
|
|
2265
2288
|
const carried = await this.#stageMobile(app, nativePlatform, targets, env, arch);
|
|
2266
2289
|
for (const mobileTarget of targets) {
|
|
@@ -2270,15 +2293,17 @@ try {
|
|
|
2270
2293
|
...arch ? { arch } : {},
|
|
2271
2294
|
sign,
|
|
2272
2295
|
notarize,
|
|
2296
|
+
revoke,
|
|
2297
|
+
resetSequence,
|
|
2273
2298
|
...carried && ApplicationRunner.carriesServer(mobileTarget, nativePlatform) ? { server: carried } : {}
|
|
2274
2299
|
});
|
|
2275
2300
|
this.#reportBuild(app, mobileTarget, published.build);
|
|
2276
2301
|
app.log(`${app.name}/${mobileTarget.name} ${published.bundle}: ${published.dir}/${published.channel}.json, ${published.files} files, ${Math.round(published.size / 1024)} KiB`);
|
|
2277
2302
|
if (!uploader) {
|
|
2278
|
-
app.log(`Upload ${nativeApp.updatesDir} to ${mobileTarget.config.updates?.url}, the manifests last.`);
|
|
2303
|
+
app.log(`Upload ${nativeApp.updatesDir} to ${mobileTarget.config.updates?.url}, the manifests last, without pack-update's records (pack.json, compat.json, manifest.template.json, bundle.json); --upload s3://\u2026 sends just this release.`);
|
|
2279
2304
|
continue;
|
|
2280
2305
|
}
|
|
2281
|
-
const { uploaded, skipped } = await uploader.upload(nativeApp.updatesDir);
|
|
2306
|
+
const { uploaded, skipped } = await uploader.upload(nativeApp.updatesDir, published);
|
|
2282
2307
|
app.log(`Uploaded ${uploaded} file(s) to ${upload}, the manifests last; ${skipped} the bucket already held. Installed apps read ${mobileTarget.config.updates?.url}.`);
|
|
2283
2308
|
}
|
|
2284
2309
|
}
|
|
@@ -2300,13 +2325,14 @@ try {
|
|
|
2300
2325
|
if (typeof server !== "object")
|
|
2301
2326
|
return { omit: [], modules: [] };
|
|
2302
2327
|
const { omit = [], modules = [], profile, env, restart, watchdog } = server;
|
|
2328
|
+
const { intervalMs, failures } = typeof watchdog === "object" ? watchdog : {};
|
|
2303
2329
|
return {
|
|
2304
2330
|
omit,
|
|
2305
2331
|
modules,
|
|
2306
2332
|
...profile ? { profile } : {},
|
|
2307
2333
|
...env ? { env } : {},
|
|
2308
2334
|
...restart !== undefined ? { restart } : {},
|
|
2309
|
-
...
|
|
2335
|
+
...intervalMs && failures ? { watchdog: { intervalMs, failures } } : {}
|
|
2310
2336
|
};
|
|
2311
2337
|
});
|
|
2312
2338
|
const [first = { omit: [], modules: [] }, ...rest] = servers;
|
|
@@ -2318,7 +2344,7 @@ try {
|
|
|
2318
2344
|
agree("omit different packages", ({ omit }) => omit.join(", "));
|
|
2319
2345
|
agree("name different env profiles", ({ profile }) => profile ?? "");
|
|
2320
2346
|
agree("mount different modules", ({ modules }) => modules.join(", "));
|
|
2321
|
-
agree("set a different env", ({ env }) => env ? JSON.stringify(env) : "");
|
|
2347
|
+
agree("set a different env", ({ env }) => env ? JSON.stringify(env, Object.keys(env).sort()) : "");
|
|
2322
2348
|
agree("restart differently", ({ restart }) => String(restart ?? ""));
|
|
2323
2349
|
agree("watch it differently", ({ watchdog }) => watchdog ? JSON.stringify(watchdog) : "");
|
|
2324
2350
|
return first;
|
|
@@ -2331,7 +2357,11 @@ try {
|
|
|
2331
2357
|
const { modules, env: serverEnv, restart, watchdog } = server;
|
|
2332
2358
|
return await stage?.prepare(env, { modules, env: serverEnv, restart, watchdog });
|
|
2333
2359
|
}
|
|
2334
|
-
async#buildMobileCsr(app, env,
|
|
2360
|
+
async#buildMobileCsr(app, env, envProfile, publicEnv = null) {
|
|
2361
|
+
if (publicEnv?.AKAN_PUBLIC_ENV !== undefined && publicEnv.AKAN_PUBLIC_ENV !== env)
|
|
2362
|
+
throw new Error(`--env ${env} differs from the public env's AKAN_PUBLIC_ENV ${publicEnv.AKAN_PUBLIC_ENV}.`);
|
|
2363
|
+
if (publicEnv)
|
|
2364
|
+
NativePublicEnv.pin(publicEnv);
|
|
2335
2365
|
const prevEnv = {
|
|
2336
2366
|
AKAN_PUBLIC_ENV: process.env.AKAN_PUBLIC_ENV,
|
|
2337
2367
|
AKAN_PUBLIC_OPERATION_MODE: process.env.AKAN_PUBLIC_OPERATION_MODE,
|
|
@@ -2343,7 +2373,7 @@ try {
|
|
|
2343
2373
|
APP_OPERATION_MODE: "release"
|
|
2344
2374
|
});
|
|
2345
2375
|
try {
|
|
2346
|
-
await new (await loadBuildRunner())(app, { environment: env, profile }).build({ spinner: true });
|
|
2376
|
+
await new (await loadBuildRunner())(app, { environment: env, profile: envProfile }).build({ spinner: true });
|
|
2347
2377
|
} finally {
|
|
2348
2378
|
for (const [key, value] of Object.entries(prevEnv)) {
|
|
2349
2379
|
if (value === undefined)
|
|
@@ -2352,6 +2382,11 @@ try {
|
|
|
2352
2382
|
process.env[key] = value;
|
|
2353
2383
|
}
|
|
2354
2384
|
}
|
|
2385
|
+
if (!publicEnv)
|
|
2386
|
+
return;
|
|
2387
|
+
const differs = NativePublicEnv.diff(publicEnv, await NativePublicEnv.built(app) ?? {});
|
|
2388
|
+
if (differs.length)
|
|
2389
|
+
throw new Error(`The web build inlined other values than --public-env gave for ${differs.join(", ")}.`);
|
|
2355
2390
|
}
|
|
2356
2391
|
async#runMobileTargets(targets, task) {
|
|
2357
2392
|
const results = [];
|
|
@@ -2367,7 +2402,7 @@ try {
|
|
|
2367
2402
|
if (failures.length === 0)
|
|
2368
2403
|
return;
|
|
2369
2404
|
for (const failure of failures) {
|
|
2370
|
-
const message = failure.error
|
|
2405
|
+
const message = toError(failure.error).message;
|
|
2371
2406
|
Logger3.rawLog(`Native target ${failure.target} failed: ${message}`, undefined, "error");
|
|
2372
2407
|
}
|
|
2373
2408
|
throw new Error(`${failures.length}/${results.length} native targets failed`);
|
|
@@ -3240,6 +3275,9 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3240
3275
|
static devServerReadyTimeoutMs = DevSupervisor.bootTimeoutMs;
|
|
3241
3276
|
#interrupt = new InterruptTeardown;
|
|
3242
3277
|
async confirmDatabaseModeDependencyInstall(databaseMode, installSpecs) {
|
|
3278
|
+
assertPromptable(`Database mode '${databaseMode}' requires missing dependencies: ${installSpecs.join(", ")}`, {
|
|
3279
|
+
remedy: `install them first with \`bun add ${installSpecs.join(" ")}\``
|
|
3280
|
+
});
|
|
3243
3281
|
return await confirm({
|
|
3244
3282
|
message: `Database mode '${databaseMode}' requires missing dependencies: ${installSpecs.join(", ")}. Install them now?`,
|
|
3245
3283
|
default: true
|
|
@@ -3312,7 +3350,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3312
3350
|
if (!quiet)
|
|
3313
3351
|
Logger6.rawLog(`Creating an optimized production build for ${app.name}...`);
|
|
3314
3352
|
try {
|
|
3315
|
-
const result = await this.applicationRunner.build(app, { fast, spinner: !quiet, profile });
|
|
3353
|
+
const result = await this.applicationRunner.build(app, { fast, spinner: !quiet, envProfile: profile });
|
|
3316
3354
|
Logger6.rawLog(`${app.name} built in dist/apps/${app.name}`);
|
|
3317
3355
|
if (!quiet)
|
|
3318
3356
|
ApplicationBuildReporter.printSummary(result);
|
|
@@ -3325,10 +3363,12 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3325
3363
|
async typecheck(exec, { write = true, clean = false, incremental = true, tests = false } = {}) {
|
|
3326
3364
|
if (!(exec instanceof AppExecutor) && !(exec instanceof LibExecutor))
|
|
3327
3365
|
throw new Error(`akan typecheck takes an app or a library; ${exec.name} is a package, checked by its own tsconfig.`);
|
|
3328
|
-
if (exec instanceof
|
|
3366
|
+
if (exec instanceof AppExecutor)
|
|
3367
|
+
await exec.scanSync({ write });
|
|
3368
|
+
else if (write)
|
|
3329
3369
|
await this.libraryScript.syncLibrary(exec);
|
|
3330
3370
|
else
|
|
3331
|
-
await exec.
|
|
3371
|
+
await exec.scan({ write: false });
|
|
3332
3372
|
const spinner = exec.spinning(`Typechecking ${exec.name}${tests ? " with its tests" : ""}...`);
|
|
3333
3373
|
try {
|
|
3334
3374
|
if (exec instanceof LibExecutor)
|
|
@@ -3593,13 +3633,13 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
|
|
|
3593
3633
|
await Promise.all(shares.map(async (share) => await share.close()));
|
|
3594
3634
|
}, "Abandoning the tunnel release; the shares expire on their own.");
|
|
3595
3635
|
await Promise.all(apps.map(async (app) => {
|
|
3596
|
-
const { TunnelShare } = await import("./TunnelShare-
|
|
3636
|
+
const { TunnelShare } = await import("./TunnelShare-rj74jd6x.js");
|
|
3597
3637
|
const share = await TunnelShare.open(app, { workspace: app.workspace });
|
|
3598
3638
|
shares.push(share);
|
|
3599
3639
|
urls.set(app.name, share.url);
|
|
3600
3640
|
Logger6.rawLog(`${app.name} is shared at ${share.url}`);
|
|
3601
3641
|
})).catch((error) => {
|
|
3602
|
-
Logger6.rawLog(`Could not open the tunnel: ${error
|
|
3642
|
+
Logger6.rawLog(`Could not open the tunnel: ${toError2(error).message}`, undefined, "error");
|
|
3603
3643
|
});
|
|
3604
3644
|
return urls;
|
|
3605
3645
|
}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
runner,
|
|
4
4
|
script
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-3x7yeecy.js";
|
|
6
6
|
import {
|
|
7
7
|
ModuleExecutor
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-bv210r6t.js";
|
|
9
9
|
import {
|
|
10
10
|
sourceFile,
|
|
11
11
|
moduleSourcePaths,
|
|
@@ -13,10 +13,10 @@ import {
|
|
|
13
13
|
createPassedPrimitiveReport,
|
|
14
14
|
bilingualLabelForField,
|
|
15
15
|
bilingualDescriptionForField
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-wdze51wz.js";
|
|
17
17
|
import {
|
|
18
18
|
PageScript
|
|
19
|
-
} from "./index-
|
|
19
|
+
} from "./index-00seamy5.js";
|
|
20
20
|
import {
|
|
21
21
|
pluralizeName
|
|
22
22
|
} from "./index-nz8prx9g.js";
|