@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
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
GlobalConfig,
|
|
4
|
-
CloudApi
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "./index-6jjtnhkw.js";
|
|
4
|
+
CloudApi,
|
|
5
|
+
CloudUpdates,
|
|
6
|
+
PipelineSecrets
|
|
7
|
+
} from "./index-wjqbc7sf.js";
|
|
9
8
|
import {
|
|
10
9
|
PkgExecutor
|
|
11
|
-
} from "./index-
|
|
10
|
+
} from "./index-bv210r6t.js";
|
|
12
11
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
NativePublicEnv,
|
|
13
|
+
UpdatePackFolder
|
|
14
|
+
} from "./index-qf8g88j9.js";
|
|
15
|
+
import {
|
|
16
|
+
script
|
|
17
|
+
} from "./index-3x7yeecy.js";
|
|
15
18
|
import {
|
|
16
19
|
ApplicationScript
|
|
17
|
-
} from "./index-
|
|
20
|
+
} from "./index-1a7nhq56.js";
|
|
18
21
|
import {
|
|
19
22
|
PackageScript
|
|
20
|
-
} from "./index-
|
|
23
|
+
} from "./index-qvghfv6v.js";
|
|
21
24
|
import {
|
|
22
25
|
CloudRunner
|
|
23
|
-
} from "./index-
|
|
26
|
+
} from "./index-wanhh011.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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
79
|
-
const
|
|
80
|
-
await this.
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
await this.
|
|
93
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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.
|
|
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
|
-
|
|
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-qf8g88j9.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 };
|
|
@@ -5,13 +5,13 @@ import {
|
|
|
5
5
|
writeGeneratedSyncState,
|
|
6
6
|
createRepairReport,
|
|
7
7
|
renderRepairReport
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-wdze51wz.js";
|
|
9
9
|
import {
|
|
10
10
|
AkanContextAnalyzer
|
|
11
|
-
} from "./index-
|
|
11
|
+
} from "./index-vhfjzda3.js";
|
|
12
12
|
import {
|
|
13
13
|
runner
|
|
14
|
-
} from "./index-
|
|
14
|
+
} from "./index-3x7yeecy.js";
|
|
15
15
|
|
|
16
16
|
// pkgs/@akanjs/cli/repair/repair.runner.ts
|
|
17
17
|
var spawnShell = async (workspace, command) => await workspace.spawn("bash", ["-lc", command.startsWith("akan ") ? `bun run ${command}` : command], {
|