@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
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-6jjtnhkw.js";
5
+ } from "./index-31ce9vhg.js";
6
6
  import {
7
7
  LibSource,
8
8
  formatLibStatuses,
9
9
  LibExecutor
10
- } from "./index-55mynnqs.js";
10
+ } from "./index-2etqq75t.js";
11
11
 
12
12
  // pkgs/@akanjs/cli/library/library.script.ts
13
13
  import { Logger } from "akanjs/common";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-6jjtnhkw.js";
5
+ } from "./index-31ce9vhg.js";
6
6
  import {
7
7
  AGENT_BLOCK_START,
8
8
  AGENT_BLOCK_END,
@@ -13,14 +13,14 @@ import {
13
13
  CLAUDE_COMMENT_RULE,
14
14
  AppExecutor,
15
15
  LibExecutor
16
- } from "./index-55mynnqs.js";
16
+ } from "./index-2etqq75t.js";
17
17
  import {
18
18
  collectRecipeSources2,
19
19
  scanRecipes2
20
20
  } from "./index-hj6w4ka1.js";
21
21
  import {
22
22
  AkanContextAnalyzer
23
- } from "./index-2mx692qq.js";
23
+ } from "./index-rk9sdys3.js";
24
24
  import {
25
25
  Prompter2
26
26
  } from "./index-zzvvc845.js";
@@ -1,23 +1,29 @@
1
1
  // @bun
2
2
  import {
3
3
  GlobalConfig,
4
- CloudApi
5
- } from "./index-r2tpeb3n.js";
6
- import {
7
- script
8
- } from "./index-6jjtnhkw.js";
4
+ CloudApi,
5
+ CloudUpdates,
6
+ PipelineSecrets
7
+ } from "./index-6726qr1m.js";
9
8
  import {
10
9
  PkgExecutor
11
- } from "./index-55mynnqs.js";
10
+ } from "./index-2etqq75t.js";
11
+ import {
12
+ NativePublicEnv,
13
+ UpdatePackFolder
14
+ } from "./index-0909wckt.js";
15
+ import {
16
+ script
17
+ } from "./index-31ce9vhg.js";
12
18
  import {
13
19
  ApplicationScript
14
- } from "./index-p9ystjrp.js";
20
+ } from "./index-20cebtth.js";
15
21
  import {
16
22
  PackageScript
17
- } from "./index-gnyf1fqy.js";
23
+ } from "./index-tz5evhdr.js";
18
24
  import {
19
25
  CloudRunner
20
- } from "./index-y8q31011.js";
26
+ } from "./index-3reaaa1h.js";
21
27
 
22
28
  // pkgs/@akanjs/cli/cloud/cloud.script.ts
23
29
  import { Logger } from "akanjs/common";
@@ -28,12 +34,14 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
28
34
  async logout(workspace, host) {
29
35
  await this.cloudRunner.logout(await GlobalConfig.hostFor(workspace, host));
30
36
  }
37
+ async#cloudApi(workspace, given) {
38
+ const host = await GlobalConfig.hostFor(workspace, given);
39
+ await this.login(workspace, host);
40
+ return await CloudApi.fromHost(workspace, host);
41
+ }
31
42
  async downloadEnv(workspace, workspaceId = workspace.getWorkspaceId({ allowEmpty: true }), { host: given } = {}) {
32
43
  if (workspaceId) {
33
- const host = await GlobalConfig.hostFor(workspace, given);
34
- await this.login(workspace, host);
35
- const cloudApi = await CloudApi.fromHost(workspace, host);
36
- await this.cloudRunner.downloadEnv(cloudApi, workspace, workspaceId);
44
+ await this.cloudRunner.downloadEnv(await this.#cloudApi(workspace, given), workspace, workspaceId);
37
45
  return;
38
46
  }
39
47
  await this.cloudRunner.downloadEnvByScp(workspace);
@@ -48,10 +56,7 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
48
56
  throw new Error("A scoped env upload needs a cloud workspace id \u2014 the scp target is workspace-wide.");
49
57
  const { files, path } = await this.cloudRunner.gatherEnvFiles(workspace, { scope, archivePath });
50
58
  if (workspaceId) {
51
- const host = await GlobalConfig.hostFor(workspace, given);
52
- await this.login(workspace, host);
53
- const cloudApi = await CloudApi.fromHost(workspace, host);
54
- await this.cloudRunner.uploadEnv(cloudApi, workspaceId, path);
59
+ await this.cloudRunner.uploadEnv(await this.#cloudApi(workspace, given), workspaceId, path);
55
60
  return { workspaceId, files };
56
61
  }
57
62
  await this.cloudRunner.uploadEnvByScp(workspace, path);
@@ -64,19 +69,16 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
64
69
  subspace,
65
70
  host: given
66
71
  }) {
67
- const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
72
+ PipelineSecrets.assertName(name);
73
+ PipelineSecrets.assertBranch(branch);
74
+ const devProjectId = await this.cloudRunner.projectOf(workspace, subspace);
68
75
  const value = await this.cloudRunner.readSecretValue(name, file);
69
- const host = await GlobalConfig.hostFor(workspace, given);
70
- await this.login(workspace, host);
71
- const cloudApi = await CloudApi.fromHost(workspace, host);
72
- await this.cloudRunner.uploadSecret(cloudApi, devProjectId, { name, branch, value });
76
+ await this.cloudRunner.uploadSecret(await this.#cloudApi(workspace, given), devProjectId, { name, branch, value });
73
77
  }
74
78
  async listSecrets(workspace, { branch, subspace, host: given }) {
75
- const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
76
- const host = await GlobalConfig.hostFor(workspace, given);
77
- await this.login(workspace, host);
78
- const cloudApi = await CloudApi.fromHost(workspace, host);
79
- await this.cloudRunner.listSecrets(cloudApi, devProjectId, branch);
79
+ PipelineSecrets.assertBranch(branch);
80
+ const devProjectId = await this.cloudRunner.projectOf(workspace, subspace);
81
+ await this.cloudRunner.listSecrets(await this.#cloudApi(workspace, given), devProjectId, branch);
80
82
  }
81
83
  async removeSecret(workspace, {
82
84
  name,
@@ -84,11 +86,10 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
84
86
  subspace,
85
87
  host: given
86
88
  }) {
87
- const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
88
- const host = await GlobalConfig.hostFor(workspace, given);
89
- await this.login(workspace, host);
90
- const cloudApi = await CloudApi.fromHost(workspace, host);
91
- await this.cloudRunner.removeSecret(cloudApi, devProjectId, { name, branch });
89
+ PipelineSecrets.assertName(name);
90
+ PipelineSecrets.assertBranch(branch);
91
+ const devProjectId = await this.cloudRunner.projectOf(workspace, subspace);
92
+ await this.cloudRunner.removeSecret(await this.#cloudApi(workspace, given), devProjectId, { name, branch });
92
93
  }
93
94
  async pushUpdate(workspace, app, {
94
95
  platform,
@@ -99,22 +100,43 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
99
100
  subspace,
100
101
  host: given,
101
102
  write,
102
- allowLocalRelease
103
+ allowLocalRelease,
104
+ pack: packDir,
105
+ publicEnv
103
106
  }) {
104
- const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
105
- const pack = await this.applicationScript.packUpdate(app, platform, {
106
- target,
107
- env,
108
- write,
109
- allowLocalRelease
110
- });
111
- const host = await GlobalConfig.hostFor(workspace, given);
112
- await this.login(workspace, host);
113
- return await this.cloudRunner.pushUpdate(await CloudApi.fromHost(workspace, host), devProjectId, pack, {
107
+ if (packDir && publicEnv)
108
+ throw new Error("--public-env picks what a pack is built with, and --pack uploads one already built: give one.");
109
+ const devProjectId = await this.cloudRunner.projectOf(workspace, subspace, app.name);
110
+ const pack = await this.#packToPush(app, { platform, target, env, write, allowLocalRelease, packDir, publicEnv });
111
+ const verdict = UpdatePackFolder.storeBuildVerdict(pack);
112
+ if (verdict)
113
+ throw verdict;
114
+ return await this.cloudRunner.pushUpdate(await this.#cloudApi(workspace, given), devProjectId, pack, {
114
115
  channel,
115
116
  notes
116
117
  });
117
118
  }
119
+ async#packToPush(app, {
120
+ platform,
121
+ target,
122
+ env,
123
+ write,
124
+ allowLocalRelease,
125
+ packDir,
126
+ publicEnv
127
+ }) {
128
+ if (packDir)
129
+ return await this.cloudRunner.readPack(app, packDir, { platform, target, env, allowLocalRelease });
130
+ if (!platform)
131
+ throw new Error("push-update needs --platform ios or android to pack, or --pack <dir> to upload what `akan pack-update` wrote.");
132
+ return await this.applicationScript.packUpdate(app, platform, {
133
+ target: target ?? undefined,
134
+ env: env ?? "main",
135
+ write,
136
+ allowLocalRelease,
137
+ publicEnv: publicEnv ?? undefined
138
+ });
139
+ }
118
140
  async registerBinary(workspace, app, {
119
141
  platform,
120
142
  distribution,
@@ -123,18 +145,20 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
123
145
  subspace,
124
146
  host: given,
125
147
  write,
126
- allowLocalRelease
148
+ allowLocalRelease,
149
+ publicEnv
127
150
  }) {
128
- const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
151
+ const devProjectId = await this.cloudRunner.projectOf(workspace, subspace, app.name);
152
+ const storeBundle = await CloudUpdates.storeBundlePath(app, target, platform);
153
+ const recorded = !publicEnv && await NativePublicEnv.recordedIn(storeBundle);
129
154
  const pack = await this.applicationScript.packUpdate(app, platform, {
130
155
  target,
131
156
  env,
132
157
  write,
133
- allowLocalRelease
158
+ allowLocalRelease,
159
+ publicEnv: publicEnv ?? (recorded ? storeBundle : undefined)
134
160
  });
135
- const host = await GlobalConfig.hostFor(workspace, given);
136
- await this.login(workspace, host);
137
- return await this.cloudRunner.registerBinary(await CloudApi.fromHost(workspace, host), devProjectId, app, pack, {
161
+ return await this.cloudRunner.registerBinary(await this.#cloudApi(workspace, given), devProjectId, app, pack, {
138
162
  distribution,
139
163
  env
140
164
  });
@@ -0,0 +1,241 @@
1
+ // @bun
2
+ import {
3
+ DesktopBin,
4
+ UpdatePackFolder
5
+ } from "./index-0909wckt.js";
6
+
7
+ // pkgs/@akanjs/devkit/mobile/placeholderAppId.ts
8
+ var PLACEHOLDER_APP_IDS = [
9
+ "com.myapp.app",
10
+ "com.myorg.myapp",
11
+ "com.example.app",
12
+ "com.example.myapp"
13
+ ];
14
+ var placeholderAppIdSegment = /^(example|examples|myorg|myapp|mycompany|myorganization|changeme|todo|sample|test)$/;
15
+ var isPlaceholderAppId = (appId) => {
16
+ const normalized = appId?.trim().toLowerCase() ?? "";
17
+ if (!normalized)
18
+ return true;
19
+ if (PLACEHOLDER_APP_IDS.includes(normalized))
20
+ return true;
21
+ return normalized.split(".").some((segment) => placeholderAppIdSegment.test(segment));
22
+ };
23
+ // pkgs/@akanjs/devkit/mobile/desktopServerStage.ts
24
+ import { cp, mkdir, readdir, rm, writeFile } from "fs/promises";
25
+ import path from "path";
26
+ import { toError } from "akanjs/common";
27
+ class DesktopServerStage {
28
+ app;
29
+ static uncarried = new Set([
30
+ "Dockerfile",
31
+ "package.json",
32
+ "rscWorker.js",
33
+ "console.js",
34
+ "console-runtime.js",
35
+ "csr",
36
+ "public",
37
+ ".akan"
38
+ ]);
39
+ static rscRenderer = "react-server-dom-webpack";
40
+ dir;
41
+ constructor(app) {
42
+ this.app = app;
43
+ this.dir = path.join(app.cwdPath, ".akan", "desktop", "server");
44
+ }
45
+ static assertCarriable(config) {
46
+ if (!config.database.modes.includes("single"))
47
+ throw new Error(`desktop.server in native puts the server in the app, where only database mode single runs (no Redis or Postgres); apps/${config.app.name}/akan.config.ts declares ${config.database.modes.join(", ")}.`);
48
+ }
49
+ static env(config, environment, { modules = [], env = {} } = {}) {
50
+ const { PORT: _port, AKAN_LOG_TO_FILE: _fileLog, ...image } = config.getProductionEnv(environment);
51
+ return {
52
+ ...image,
53
+ ...env,
54
+ AKAN_PUBLIC_OPERATION_MODE: "edge",
55
+ AKAN_DATABASE_MODE: "single",
56
+ AKAN_DATABASE_MODES: "single",
57
+ AKAN_SSR: "false",
58
+ AKAN_CSR: "false",
59
+ AKAN_MCP: "false",
60
+ AKAN_SHUTDOWN_TIMEOUT_MS: "1000",
61
+ ...modules.length ? { AKAN_MODULES: modules.join(",") } : {}
62
+ };
63
+ }
64
+ static imageStepsNotice(config, carried) {
65
+ const steps = typeof config.docker === "string" ? null : config.docker.preRuns.length + config.docker.postRuns.length;
66
+ if (steps === 0)
67
+ return null;
68
+ const image = steps === null ? `apps/${config.app.name}/akan.config.ts writes its own Dockerfile` : `The image runs ${steps} docker step${steps === 1 ? "" : "s"} from the app and its libs`;
69
+ return carried.length ? {
70
+ level: "info",
71
+ message: `${image}; the desktop app's server runs none of them and carries only bin: ${carried.join(", ")}.`
72
+ } : {
73
+ level: "warn",
74
+ message: `${image}, and a desktop app's server runs none of them: declare in bin the executables its code spawns, or those calls fail on the user's computer.`
75
+ };
76
+ }
77
+ static packageJson(config, built, omit = []) {
78
+ const otherDrivers = new Set(config.database.modes.filter((mode) => mode !== "single").flatMap((mode) => config.getDatabaseModeRuntimePackages(mode)));
79
+ const dependencies = Object.entries(built.dependencies ?? {}).filter(([name]) => !omit.includes(name) && (config.externalLibs.includes(name) || name !== DesktopServerStage.rscRenderer && !otherDrivers.has(name)));
80
+ return { ...built, dependencies: Object.fromEntries(dependencies) };
81
+ }
82
+ static async dependentsOf(nodeModules, name) {
83
+ const dependents = new Set;
84
+ for await (const manifest of new Bun.Glob("**/package.json").scan({ cwd: nodeModules, onlyFiles: true })) {
85
+ const json = await Bun.file(path.join(nodeModules, manifest)).json().catch(() => null);
86
+ if (!json?.name || json.name === name)
87
+ continue;
88
+ const declared = { ...json.dependencies, ...json.optionalDependencies, ...json.peerDependencies };
89
+ if (name in declared)
90
+ dependents.add(json.name);
91
+ }
92
+ return [...dependents].sort();
93
+ }
94
+ static installArgs(arch) {
95
+ return ["install", "--production", "--prefer-offline", ...arch && arch !== process.arch ? [`--cpu=${arch}`] : []];
96
+ }
97
+ async install(arch, omit = []) {
98
+ const config = await this.app.getConfig();
99
+ DesktopServerStage.assertCarriable(config);
100
+ await rm(this.dir, { recursive: true, force: true });
101
+ await mkdir(this.dir, { recursive: true });
102
+ const built = config.getProductionPackageJson();
103
+ for (const name of omit.filter((name) => !(name in (built.dependencies ?? {}))))
104
+ this.app.logger.warn(`desktop.server.omit names ${name}, which the server does not depend on directly.`);
105
+ await writeFile(path.join(this.dir, "package.json"), JSON.stringify(DesktopServerStage.packageJson(config, built, omit), null, 2));
106
+ try {
107
+ await this.app.spawn(process.execPath, DesktopServerStage.installArgs(arch), { cwd: this.dir });
108
+ } catch (error) {
109
+ throw new Error(`The desktop app's server could not install its packages in ${this.dir}: it needs the npm registry, or a Bun cache that already holds every one of them.
110
+ ${toError(error).message}`, { cause: error });
111
+ }
112
+ await rm(path.join(this.dir, "node_modules", ".bin"), { recursive: true, force: true });
113
+ await this.#assertOmitted(omit);
114
+ }
115
+ async#assertOmitted(omit) {
116
+ const nodeModules = path.join(this.dir, "node_modules");
117
+ const kept = [];
118
+ for (const name of omit) {
119
+ if (!await Bun.file(path.join(nodeModules, name, "package.json")).exists())
120
+ continue;
121
+ const dependents = await DesktopServerStage.dependentsOf(nodeModules, name);
122
+ kept.push(`${name} (needed by ${dependents.join(", ") || "a package that names it"})`);
123
+ }
124
+ if (kept.length)
125
+ throw new Error(`desktop.server.omit leaves out packages another dependency still installs: ${kept.join("; ")}. Omit those too, or keep the package.`);
126
+ }
127
+ async prepare(environment, run = {}) {
128
+ const config = await this.app.getConfig();
129
+ const dist = this.app.dist.cwdPath;
130
+ await mkdir(this.dir, { recursive: true });
131
+ for (const name of await readdir(dist))
132
+ if (!DesktopServerStage.uncarried.has(name))
133
+ await cp(path.join(dist, name), path.join(this.dir, name), { recursive: true });
134
+ const scanInfo = this.app.getScanInfo({ allowEmpty: true }) ?? await this.app.scan({ write: false });
135
+ const carried = [...DesktopBin.select(config, scanInfo.getLibs()).keys()];
136
+ const notice = DesktopServerStage.imageStepsNotice(config, carried);
137
+ if (notice)
138
+ this.app.logger[notice.level](notice.message);
139
+ return {
140
+ dir: this.dir,
141
+ entry: "main.js",
142
+ env: DesktopServerStage.env(config, environment, run),
143
+ ...run.restart !== undefined ? { restart: run.restart } : {},
144
+ ...run.watchdog ? { watchdog: run.watchdog } : {}
145
+ };
146
+ }
147
+ }
148
+ // pkgs/@akanjs/devkit/mobile/updateUploader.ts
149
+ import { readdir as readdir2 } from "fs/promises";
150
+ import path2 from "path";
151
+ import { isRecord } from "akanjs/common";
152
+ class UpdateUploader {
153
+ bucket;
154
+ prefix;
155
+ static #manifest = /\.json(?:\.sig)?$/;
156
+ static parseTarget(target) {
157
+ const match = /^s3:\/\/([^/]+)\/?(.*)$/.exec(target.trim());
158
+ if (!match?.[1])
159
+ throw new Error(`--upload takes s3://<bucket>/<prefix>, not ${JSON.stringify(target)}.`);
160
+ return { bucket: match[1], prefix: (match[2] ?? "").replace(/\/+$/, "") };
161
+ }
162
+ static order(files) {
163
+ const manifests = files.filter((file) => UpdateUploader.#manifest.test(file));
164
+ return {
165
+ releases: files.filter((file) => !UpdateUploader.#manifest.test(file)).sort((a, b) => a.localeCompare(b)),
166
+ manifests: manifests.sort((a, b) => Number(a.endsWith(".json")) - Number(b.endsWith(".json")) || a.localeCompare(b))
167
+ };
168
+ }
169
+ static async releaseFiles(updatesDir, { dir, channel, bundle }) {
170
+ const keyOf = (file) => UpdateUploader.#keyOf(updatesDir, dir, file);
171
+ const desktop = await UpdateUploader.#read(path2.join(dir, `${channel}.json`));
172
+ if (desktop?.bundle === bundle) {
173
+ const archive = desktop.archive?.url;
174
+ const patches = UpdateUploader.#field(desktop.patches, "url");
175
+ return [archive, ...patches, `${channel}.json.sig`, `${channel}.json`].map(keyOf);
176
+ }
177
+ const names = await readdir2(path2.join(dir, channel)).catch(() => []);
178
+ for (const name of names.filter((name) => name.endsWith(".json"))) {
179
+ const envelope = await UpdateUploader.#read(path2.join(dir, channel, name));
180
+ const manifest = typeof envelope?.manifest === "string" ? UpdateUploader.#parse(Buffer.from(envelope.manifest, "base64").toString("utf8")) : null;
181
+ if (manifest?.bundle !== bundle)
182
+ continue;
183
+ const hashes = [...new Set(UpdateUploader.#field(manifest.files, "sha256"))];
184
+ if (!hashes.every((hash) => typeof hash === "string" && /^[0-9a-f]{64}$/.test(hash)))
185
+ throw new Error(`${path2.join(dir, channel, name)} lists a file whose sha256 is not 64 hex digits; nothing was uploaded.`);
186
+ return [...hashes.map((hash) => `${UpdatePackFolder.filesDir}/${hash}`), `${channel}/${name}`].map(keyOf);
187
+ }
188
+ throw new Error(`${dir} holds no ${channel} manifest of release ${bundle}; nothing was uploaded.`);
189
+ }
190
+ static #keyOf(updatesDir, dir, file) {
191
+ const resolved = typeof file === "string" ? path2.resolve(dir, file) : "";
192
+ const key = path2.relative(updatesDir, resolved);
193
+ if (!resolved.startsWith(`${path2.resolve(dir)}${path2.sep}`) || key.startsWith("..") || path2.isAbsolute(key))
194
+ throw new Error(`The release in ${dir} names ${typeof file === "string" ? JSON.stringify(file) : "a file with no path"}, which is not inside that folder; nothing was uploaded.`);
195
+ return key.split(path2.sep).join("/");
196
+ }
197
+ static #field(list, key) {
198
+ return Array.isArray(list) ? list.map((item) => isRecord(item) ? item[key] : undefined) : [];
199
+ }
200
+ static async#read(file) {
201
+ const text = await Bun.file(file).text().catch(() => "");
202
+ return UpdateUploader.#parse(text);
203
+ }
204
+ static #parse(text) {
205
+ try {
206
+ const value = JSON.parse(text);
207
+ return isRecord(value) ? value : null;
208
+ } catch {
209
+ return null;
210
+ }
211
+ }
212
+ constructor(bucket, prefix) {
213
+ this.bucket = bucket;
214
+ this.prefix = prefix;
215
+ }
216
+ static forTarget(target) {
217
+ const { bucket, prefix } = UpdateUploader.parseTarget(target);
218
+ return new UpdateUploader(new Bun.S3Client({ bucket }), prefix);
219
+ }
220
+ async upload(updatesDir, release) {
221
+ const { releases, manifests } = UpdateUploader.order(await UpdateUploader.releaseFiles(updatesDir, release));
222
+ const keyOf = (file) => this.prefix ? `${this.prefix}/${file}` : file;
223
+ let uploaded = 0;
224
+ let skipped = 0;
225
+ for (const file of releases) {
226
+ if (await this.bucket.exists(keyOf(file))) {
227
+ skipped++;
228
+ continue;
229
+ }
230
+ await this.bucket.write(keyOf(file), Bun.file(path2.join(updatesDir, file)));
231
+ uploaded++;
232
+ }
233
+ for (const file of manifests) {
234
+ const type = file.endsWith(".json") ? "application/json" : "text/plain";
235
+ await this.bucket.write(keyOf(file), Bun.file(path2.join(updatesDir, file)), { type });
236
+ uploaded++;
237
+ }
238
+ return { uploaded, skipped };
239
+ }
240
+ }
241
+ export { DesktopServerStage, isPlaceholderAppId, UpdateUploader };
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-6jjtnhkw.js";
5
+ } from "./index-31ce9vhg.js";
6
6
  import {
7
7
  generatedFilesForSync,
8
8
  createPassedPrimitiveReport,
9
9
  scalarChangedFiles
10
- } from "./index-05g3jayg.js";
10
+ } from "./index-rhbabmja.js";
11
11
  import {
12
12
  pluralizeName
13
13
  } from "./index-nz8prx9g.js";
@@ -22,26 +22,26 @@ import {
22
22
  renderWorkflowApply,
23
23
  renderWorkflowValidation,
24
24
  renderWorkflowRunArtifact
25
- } from "./index-05g3jayg.js";
25
+ } from "./index-rhbabmja.js";
26
26
  import {
27
27
  AkanContextAnalyzer
28
- } from "./index-2mx692qq.js";
28
+ } from "./index-rk9sdys3.js";
29
29
  import {
30
30
  CommandContainer,
31
31
  runner
32
- } from "./index-6jjtnhkw.js";
32
+ } from "./index-31ce9vhg.js";
33
33
  import {
34
34
  ModuleScript
35
- } from "./index-e0cvze1s.js";
35
+ } from "./index-z507nzhg.js";
36
36
  import {
37
37
  PrimitiveScript
38
- } from "./index-ctanya41.js";
38
+ } from "./index-sqfdmb5b.js";
39
39
  import {
40
40
  spawnShell
41
- } from "./index-fm46xrf1.js";
41
+ } from "./index-nq2ja5e0.js";
42
42
  import {
43
43
  ScalarScript
44
- } from "./index-c76k723e.js";
44
+ } from "./index-h85cxfkg.js";
45
45
 
46
46
  // pkgs/@akanjs/cli/workflow/workflow.runner.ts
47
47
  import { mkdir, readFile, writeFile } from "fs/promises";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-6jjtnhkw.js";
5
+ } from "./index-31ce9vhg.js";
6
6
 
7
7
  // pkgs/@akanjs/cli/page/page.runner.ts
8
8
  class PageRunner extends runner("page") {