@akanjs/cli 3.1.0-rc.1 → 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 (74) hide show
  1. package/.build-stamp +1 -1
  2. package/{CodeAgent-kyprmy06.js → CodeAgent-q50k4s45.js} +2 -2
  3. package/{CodeTui-21mtze3j.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-5s780vnz.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-yj6xb2a7.js → cloud.command-k2fhaape.js} +57 -65
  11. package/cloud.script-z8p5dz7e.js +23 -0
  12. package/{code.command-3wkn4ja5.js → code.command-kt5zgcc2.js} +6 -6
  13. package/{context.command-9jjn3gcw.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 +28 -15
  17. package/guidelines/cssRule/cssRule.instruction.md +12 -6
  18. package/guidelines/mcpRule/mcpRule.instruction.md +27 -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-1w2qaee2.js → index-0909wckt.js} +361 -291
  23. package/{index-jx4bzvwg.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-8ggztp8k.js → index-3reaaa1h.js} +42 -177
  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-rtct7d43.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-rc5rwyps.js → index-fjsv10hd.js} +71 -60
  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-ae5pwhgs.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-56d2g8ms.js → index-sby8fe1p.js} +1 -1
  47. package/{index-ctanya41.js → index-sqfdmb5b.js} +4 -4
  48. package/{index-krq7btbt.js → index-t7nws9mx.js} +3 -3
  49. package/{index-8r4d7cmt.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-vsreyy42.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-md2teygq.js → subspace.command-51n0ykbx.js} +421 -362
  67. package/{tunnel.command-jx3tdm2d.js → tunnel.command-7820vtxq.js} +7 -4
  68. package/{workflow.command-jx0wag5r.js → workflow.command-n5sv4wqz.js} +10 -10
  69. package/{workspace.command-yxd7rr7g.js → workspace.command-zdy60jh8.js} +33 -30
  70. package/TunnelShare-q4jq08qg.js +0 -9
  71. package/cloud.script-h6pvcpa2.js +0 -20
  72. package/context.runner-atcrzz5b.js +0 -21
  73. package/index-6w0rbr9d.js +0 -68
  74. package/index-pgj2rt78.js +0 -404
@@ -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,26 +1,29 @@
1
1
  // @bun
2
2
  import {
3
3
  GlobalConfig,
4
- CloudApi
5
- } from "./index-pgj2rt78.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";
12
11
  import {
13
- NativeApp
14
- } from "./index-1w2qaee2.js";
12
+ NativePublicEnv,
13
+ UpdatePackFolder
14
+ } from "./index-0909wckt.js";
15
+ import {
16
+ script
17
+ } from "./index-31ce9vhg.js";
15
18
  import {
16
19
  ApplicationScript
17
- } from "./index-jx4bzvwg.js";
20
+ } from "./index-20cebtth.js";
18
21
  import {
19
22
  PackageScript
20
- } from "./index-gnyf1fqy.js";
23
+ } from "./index-tz5evhdr.js";
21
24
  import {
22
25
  CloudRunner
23
- } from "./index-8ggztp8k.js";
26
+ } from "./index-3reaaa1h.js";
24
27
 
25
28
  // pkgs/@akanjs/cli/cloud/cloud.script.ts
26
29
  import { Logger } from "akanjs/common";
@@ -31,12 +34,14 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
31
34
  async logout(workspace, host) {
32
35
  await this.cloudRunner.logout(await GlobalConfig.hostFor(workspace, host));
33
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
+ }
34
42
  async downloadEnv(workspace, workspaceId = workspace.getWorkspaceId({ allowEmpty: true }), { host: given } = {}) {
35
43
  if (workspaceId) {
36
- const host = await GlobalConfig.hostFor(workspace, given);
37
- await this.login(workspace, host);
38
- const cloudApi = await CloudApi.fromHost(workspace, host);
39
- await this.cloudRunner.downloadEnv(cloudApi, workspace, workspaceId);
44
+ await this.cloudRunner.downloadEnv(await this.#cloudApi(workspace, given), workspace, workspaceId);
40
45
  return;
41
46
  }
42
47
  await this.cloudRunner.downloadEnvByScp(workspace);
@@ -51,10 +56,7 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
51
56
  throw new Error("A scoped env upload needs a cloud workspace id \u2014 the scp target is workspace-wide.");
52
57
  const { files, path } = await this.cloudRunner.gatherEnvFiles(workspace, { scope, archivePath });
53
58
  if (workspaceId) {
54
- const host = await GlobalConfig.hostFor(workspace, given);
55
- await this.login(workspace, host);
56
- const cloudApi = await CloudApi.fromHost(workspace, host);
57
- await this.cloudRunner.uploadEnv(cloudApi, workspaceId, path);
59
+ await this.cloudRunner.uploadEnv(await this.#cloudApi(workspace, given), workspaceId, path);
58
60
  return { workspaceId, files };
59
61
  }
60
62
  await this.cloudRunner.uploadEnvByScp(workspace, path);
@@ -67,19 +69,16 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
67
69
  subspace,
68
70
  host: given
69
71
  }) {
70
- 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);
71
75
  const value = await this.cloudRunner.readSecretValue(name, file);
72
- const host = await GlobalConfig.hostFor(workspace, given);
73
- await this.login(workspace, host);
74
- const cloudApi = await CloudApi.fromHost(workspace, host);
75
- await this.cloudRunner.uploadSecret(cloudApi, devProjectId, { name, branch, value });
76
+ await this.cloudRunner.uploadSecret(await this.#cloudApi(workspace, given), devProjectId, { name, branch, value });
76
77
  }
77
78
  async listSecrets(workspace, { branch, subspace, host: given }) {
78
- const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
79
- const host = await GlobalConfig.hostFor(workspace, given);
80
- await this.login(workspace, host);
81
- const cloudApi = await CloudApi.fromHost(workspace, host);
82
- 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);
83
82
  }
84
83
  async removeSecret(workspace, {
85
84
  name,
@@ -87,11 +86,10 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
87
86
  subspace,
88
87
  host: given
89
88
  }) {
90
- const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
91
- const host = await GlobalConfig.hostFor(workspace, given);
92
- await this.login(workspace, host);
93
- const cloudApi = await CloudApi.fromHost(workspace, host);
94
- 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 });
95
93
  }
96
94
  async pushUpdate(workspace, app, {
97
95
  platform,
@@ -103,31 +101,42 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
103
101
  host: given,
104
102
  write,
105
103
  allowLocalRelease,
106
- pack: packDir
104
+ pack: packDir,
105
+ publicEnv
107
106
  }) {
108
- const devProjectId = await this.cloudRunner.secretProject(workspace, subspace);
109
- const pack = packDir ? await NativeApp.readPack(packDir) : await this.applicationScript.packUpdate(app, platform, {
110
- target,
111
- env,
112
- write,
113
- allowLocalRelease
114
- });
115
- if (pack.app !== app.name || pack.platform !== platform || target && pack.target !== target)
116
- throw new Error(`The pack in ${pack.out} is ${pack.app} ${pack.target} ${pack.platform}, not ${app.name} ${target ?? pack.target} ${platform}.`);
117
- if (pack.compat && !pack.compat.compatible) {
118
- Logger.error(`The pack in ${pack.out} needs a new store build; it differs from the one ${pack.compat.against} came from:
119
- - ${pack.compat.problems.join(`
120
- - `)}`);
121
- process.exitCode = 2;
122
- return null;
123
- }
124
- const host = await GlobalConfig.hostFor(workspace, given);
125
- await this.login(workspace, host);
126
- 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, {
127
115
  channel,
128
116
  notes
129
117
  });
130
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
+ }
131
140
  async registerBinary(workspace, app, {
132
141
  platform,
133
142
  distribution,
@@ -136,18 +145,20 @@ class CloudScript2 extends script("cloud", [CloudRunner, ApplicationScript, Pack
136
145
  subspace,
137
146
  host: given,
138
147
  write,
139
- allowLocalRelease
148
+ allowLocalRelease,
149
+ publicEnv
140
150
  }) {
141
- 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);
142
154
  const pack = await this.applicationScript.packUpdate(app, platform, {
143
155
  target,
144
156
  env,
145
157
  write,
146
- allowLocalRelease
158
+ allowLocalRelease,
159
+ publicEnv: publicEnv ?? (recorded ? storeBundle : undefined)
147
160
  });
148
- const host = await GlobalConfig.hostFor(workspace, given);
149
- await this.login(workspace, host);
150
- 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, {
151
162
  distribution,
152
163
  env
153
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") {