@akanjs/cli 2.4.0 → 2.4.1-rc.0
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/agent.command-h4afc69n.js +26 -0
- package/application.command-4ctkfdan.js +165 -0
- package/applicationBuildRunner-esa1kj7v.js +284 -0
- package/applicationReleasePackager-brvth6rs.js +245 -0
- package/capacitorApp-y0h6cgft.js +58 -0
- package/cloud.command-rpztn4fh.js +94 -0
- package/commandManifest.json +1 -0
- package/context.command-nqbtak4f.js +82 -0
- package/dependencyScanner-m4x5maek.js +9 -0
- package/guideline.command-ya0dh44f.js +356 -0
- package/incrementalBuilder.proc.js +89 -17394
- package/index-1xdrsbry.js +1447 -0
- package/index-45aj5ry0.js +990 -0
- package/index-5vvwc0cz.js +559 -0
- package/index-61keag0s.js +40 -0
- package/index-6pz1j0zj.js +62 -0
- package/index-73pr2cmy.js +534 -0
- package/index-76rn3g2c.js +76 -0
- package/index-85msc0wg.js +161 -0
- package/index-8pkbzj26.js +840 -0
- package/index-8rc0bm04.js +514 -0
- package/index-9sp6fsc5.js +1884 -0
- package/index-a6sbyy0b.js +2769 -0
- package/index-b0brjbp3.js +83 -0
- package/index-fgc8r6dj.js +33 -0
- package/index-h6ca6qg0.js +2777 -0
- package/index-hdqztm58.js +758 -0
- package/index-hwzpw9c1.js +202 -0
- package/index-pmm9e2jf.js +120 -0
- package/index-qaq13qk3.js +80 -0
- package/index-qhtr07v8.js +1072 -0
- package/index-r24hmh0q.js +4 -0
- package/index-ss469dec.js +11 -0
- package/index-swf4bmbg.js +25 -0
- package/index-w7fyqjrw.js +462 -0
- package/index-wnp7hwq7.js +193 -0
- package/index-wq8jwx8z.js +224 -0
- package/index-x53a5nya.js +301 -0
- package/index-xmc2w32q.js +4359 -0
- package/index-y3hdhy4p.js +229 -0
- package/index.js +54 -23340
- package/library.command-r15zdqvp.js +33 -0
- package/localRegistry.command-5tcahs3f.js +178 -0
- package/module.command-qrj3kmyz.js +54 -0
- package/package.command-r8sq5kzp.js +43 -0
- package/package.json +2 -2
- package/page.command-c6xdx0xm.js +24 -0
- package/primitive.command-pv9ssmtf.js +62 -0
- package/quality.command-es67wvdp.js +809 -0
- package/repair.command-677675vw.js +67 -0
- package/routeSourceValidator-wbhmbwpj.js +132 -0
- package/scalar.command-kabkd6wd.js +35 -0
- package/templates/facetIndex/index.ts +1 -1
- package/typeChecker-kravn7ns.js +8 -0
- package/typecheck.proc.js +4 -194
- package/workflow.command-64r6cw0w.js +108 -0
- package/workspace.command-vrws0rgx.js +435 -0
- package/README.ko.md +0 -72
- package/README.md +0 -85
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
AgentScript
|
|
4
|
+
} from "./index-hwzpw9c1.js";
|
|
5
|
+
import"./index-8rc0bm04.js";
|
|
6
|
+
import"./index-qaq13qk3.js";
|
|
7
|
+
import"./index-h6ca6qg0.js";
|
|
8
|
+
import {
|
|
9
|
+
Workspace,
|
|
10
|
+
command
|
|
11
|
+
} from "./index-hdqztm58.js";
|
|
12
|
+
import"./index-a6sbyy0b.js";
|
|
13
|
+
import"./index-61keag0s.js";
|
|
14
|
+
import"./index-6pz1j0zj.js";
|
|
15
|
+
import"./index-r24hmh0q.js";
|
|
16
|
+
|
|
17
|
+
// pkgs/@akanjs/cli/agent/agent.command.ts
|
|
18
|
+
class AgentCommand extends command("agent", [AgentScript], ({ public: target }) => ({
|
|
19
|
+
agent: target({ desc: "Install Akan agent rules for editors and coding agents" }).arg("action", String, { desc: "install" }).arg("target", String, { desc: "cursor, agents-md, claude, or all", nullable: true }).option("force", Boolean, { desc: "overwrite existing rule files", default: false }).with(Workspace).exec(async function(action, targetName, force, workspace) {
|
|
20
|
+
await this.agentScript.agent(workspace, action, targetName, { force });
|
|
21
|
+
})
|
|
22
|
+
})) {
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
AgentCommand
|
|
26
|
+
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
ApplicationScript
|
|
4
|
+
} from "./index-9sp6fsc5.js";
|
|
5
|
+
import {
|
|
6
|
+
getMobileTargetChoices
|
|
7
|
+
} from "./index-76rn3g2c.js";
|
|
8
|
+
import"./index-pmm9e2jf.js";
|
|
9
|
+
import {
|
|
10
|
+
App,
|
|
11
|
+
Exec,
|
|
12
|
+
Sys,
|
|
13
|
+
Workspace,
|
|
14
|
+
command
|
|
15
|
+
} from "./index-hdqztm58.js";
|
|
16
|
+
import"./index-fgc8r6dj.js";
|
|
17
|
+
import"./index-a6sbyy0b.js";
|
|
18
|
+
import"./index-61keag0s.js";
|
|
19
|
+
import"./index-6pz1j0zj.js";
|
|
20
|
+
import"./index-r24hmh0q.js";
|
|
21
|
+
|
|
22
|
+
// pkgs/@akanjs/cli/application/application.command.ts
|
|
23
|
+
import { select } from "@inquirer/prompts";
|
|
24
|
+
var asMobileEnv = (env) => env;
|
|
25
|
+
var mobileTargetOption = {
|
|
26
|
+
desc: "mobile target name or all",
|
|
27
|
+
ask: "Select mobile target",
|
|
28
|
+
enum: async ({ app }) => await getMobileTargetChoices(app)
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
class ApplicationCommand extends command("application", [ApplicationScript], ({ public: target }) => ({
|
|
32
|
+
createApplication: target({ desc: "Create a new application in the workspace" }).arg("appName", String, { desc: "name of application" }).option("start", Boolean, { desc: "start application", default: false }).with(Workspace).exec(async function(appName, start, workspace) {
|
|
33
|
+
await this.applicationScript.createApplication(appName.toLowerCase().replace(/ /g, "-"), workspace, { start });
|
|
34
|
+
}),
|
|
35
|
+
removeApplication: target({ desc: "Remove an application from the workspace" }).with(App).exec(async function(app) {
|
|
36
|
+
await this.applicationScript.removeApplication(app);
|
|
37
|
+
}),
|
|
38
|
+
sync: target({ desc: "Sync dependencies and configuration for an app or library" }).with(Sys).exec(async function(sys) {
|
|
39
|
+
await this.applicationScript.sync(sys);
|
|
40
|
+
}),
|
|
41
|
+
script: target({ desc: "Run a custom script in the application" }).with(App).arg("filename", String, { desc: "name of script", nullable: true }).exec(async function(app, filename) {
|
|
42
|
+
await this.applicationScript.script(app, filename);
|
|
43
|
+
}),
|
|
44
|
+
console: target({ desc: "Open an interactive server console for the application" }).with(App).exec(async function(app) {
|
|
45
|
+
await this.applicationScript.console(app);
|
|
46
|
+
}),
|
|
47
|
+
build: target({ short: true, desc: "Build the application for production (frontend + backend)" }).with(App).option("write", Boolean, { desc: "write code generation", default: true }).option("fast", Boolean, { desc: "fast build", default: false }).option("quiet", Boolean, { desc: "hide build progress output", default: false }).exec(async function(app, write, fast, quiet) {
|
|
48
|
+
await this.applicationScript.build(app, { write, fast, quiet });
|
|
49
|
+
}),
|
|
50
|
+
typecheck: target({ short: true, desc: "Typecheck the application" }).with(App).option("write", Boolean, { desc: "write code generation", default: true }).option("clean", Boolean, { desc: "clear typecheck cache before running", default: false }).option("incremental", Boolean, { desc: "reuse TypeScript incremental cache", default: true }).exec(async function(app, write, clean, incremental) {
|
|
51
|
+
await this.applicationScript.typecheck(app, { write, clean, incremental });
|
|
52
|
+
}),
|
|
53
|
+
test: target({ desc: "Prepare and test an app, library, or package" }).with(Exec).option("write", Boolean, { desc: "write code generation", default: true }).exec(async function(exec, write) {
|
|
54
|
+
await this.applicationScript.test(exec, { write });
|
|
55
|
+
}),
|
|
56
|
+
buildIos: target({ short: true, desc: "Build iOS app with Capacitor" }).with(App).option("target", String, mobileTargetOption).option("env", String, {
|
|
57
|
+
enum: ["local", "debug", "develop", "main"],
|
|
58
|
+
desc: "backend environment",
|
|
59
|
+
default: "debug"
|
|
60
|
+
}).option("write", Boolean, { desc: "write code generation", default: true }).option("regenerate", Boolean, { flag: "g", desc: "delete and regenerate native project", default: false }).exec(async function(app, target2, env, write, regenerate) {
|
|
61
|
+
await this.applicationScript.buildIos(app, { target: target2, env: asMobileEnv(env), write, regenerate });
|
|
62
|
+
}),
|
|
63
|
+
buildAndroid: target({ short: true, desc: "Build Android app with Capacitor" }).with(App).option("target", String, mobileTargetOption).option("env", String, {
|
|
64
|
+
enum: ["local", "debug", "develop", "main"],
|
|
65
|
+
desc: "backend environment",
|
|
66
|
+
default: "debug"
|
|
67
|
+
}).option("write", Boolean, { desc: "write code generation", default: true }).option("regenerate", Boolean, { flag: "g", desc: "delete and regenerate native project", default: false }).exec(async function(app, target2, env, write, regenerate) {
|
|
68
|
+
await this.applicationScript.buildAndroid(app, { target: target2, env: asMobileEnv(env), write, regenerate });
|
|
69
|
+
}),
|
|
70
|
+
start: target({ short: true, desc: "Start development server (frontend SSR + backend)" }).with(App).option("open", Boolean, { desc: "open web browser?", default: false }).option("write", Boolean, { desc: "write code generation", default: true }).exec(async function(app, open, write) {
|
|
71
|
+
await this.applicationScript.start(app, { open, write });
|
|
72
|
+
}),
|
|
73
|
+
startIos: target({ short: true, desc: "Start iOS app in simulator or device" }).with(App).option("target", String, mobileTargetOption).option("env", String, {
|
|
74
|
+
enum: ["local", "debug", "develop", "main"],
|
|
75
|
+
desc: "backend environment",
|
|
76
|
+
default: "local"
|
|
77
|
+
}).option("open", Boolean, { desc: "open ios simulator", default: false }).option("release", Boolean, { desc: "release mode", default: false }).option("write", Boolean, { desc: "write code generation", default: true }).option("regenerate", Boolean, { flag: "g", desc: "delete and regenerate native project", default: false }).option("noAllowProvisioningUpdates", Boolean, {
|
|
78
|
+
desc: "disable automatic iOS provisioning updates for physical devices",
|
|
79
|
+
default: false
|
|
80
|
+
}).option("device", String, {
|
|
81
|
+
desc: "run target to select non-interactively: udid, device name, or runtime (e.g. 'iPhone 16' or 'iOS 18')",
|
|
82
|
+
default: ""
|
|
83
|
+
}).exec(async function(app, target2, env, open, release, write, regenerate, noAllowProvisioningUpdates, device) {
|
|
84
|
+
await this.applicationScript.startIos(app, {
|
|
85
|
+
target: target2,
|
|
86
|
+
env: asMobileEnv(env),
|
|
87
|
+
open,
|
|
88
|
+
operation: release ? "release" : "local",
|
|
89
|
+
write,
|
|
90
|
+
regenerate,
|
|
91
|
+
noAllowProvisioningUpdates,
|
|
92
|
+
device: device || undefined
|
|
93
|
+
});
|
|
94
|
+
}),
|
|
95
|
+
startAndroid: target({ short: true, desc: "Start Android app in emulator or device" }).with(App).option("target", String, mobileTargetOption).option("env", String, {
|
|
96
|
+
enum: ["local", "debug", "develop", "main"],
|
|
97
|
+
desc: "backend environment",
|
|
98
|
+
default: "local"
|
|
99
|
+
}).option("release", Boolean, { desc: "release mode", default: false }).option("open", Boolean, { desc: "open android simulator", default: false }).option("write", Boolean, { desc: "write code generation", default: true }).option("regenerate", Boolean, { flag: "g", desc: "delete and regenerate native project", default: false }).exec(async function(app, target2, env, release, open, write, regenerate) {
|
|
100
|
+
await this.applicationScript.startAndroid(app, {
|
|
101
|
+
target: target2,
|
|
102
|
+
env: asMobileEnv(env),
|
|
103
|
+
open,
|
|
104
|
+
operation: release ? "release" : "local",
|
|
105
|
+
write,
|
|
106
|
+
regenerate
|
|
107
|
+
});
|
|
108
|
+
}),
|
|
109
|
+
releaseIos: target({ desc: "Build and package iOS app for release (App Store)" }).with(App).option("target", String, mobileTargetOption).option("env", String, {
|
|
110
|
+
enum: ["debug", "develop", "main", "local"],
|
|
111
|
+
desc: "backend environment",
|
|
112
|
+
default: "main"
|
|
113
|
+
}).option("write", Boolean, { desc: "write code generation", default: true }).option("regenerate", Boolean, { flag: "g", desc: "delete and regenerate native project", default: false }).option("allowLocalRelease", Boolean, { flag: "l", desc: "allow release with --env local", default: false }).exec(async function(app, target2, env, write, regenerate, allowLocalRelease) {
|
|
114
|
+
await this.applicationScript.releaseIos(app, {
|
|
115
|
+
target: target2,
|
|
116
|
+
env: asMobileEnv(env),
|
|
117
|
+
write,
|
|
118
|
+
regenerate,
|
|
119
|
+
allowLocalRelease
|
|
120
|
+
});
|
|
121
|
+
}),
|
|
122
|
+
releaseAndroid: target({ desc: "Build and package Android app for release (Play Store)" }).with(App).option("assembleType", String, { enum: ["apk", "aab"], default: "apk" }).option("target", String, mobileTargetOption).option("env", String, {
|
|
123
|
+
enum: ["debug", "develop", "main", "local"],
|
|
124
|
+
desc: "backend environment",
|
|
125
|
+
default: "main"
|
|
126
|
+
}).option("write", Boolean, { desc: "write code generation", default: true }).option("regenerate", Boolean, { flag: "g", desc: "delete and regenerate native project", default: false }).option("allowLocalRelease", Boolean, { flag: "l", desc: "allow release with --env local", default: false }).exec(async function(app, assembleType, target2, env, write, regenerate, allowLocalRelease) {
|
|
127
|
+
await this.applicationScript.releaseAndroid(app, assembleType, {
|
|
128
|
+
target: target2,
|
|
129
|
+
env: asMobileEnv(env),
|
|
130
|
+
write,
|
|
131
|
+
regenerate,
|
|
132
|
+
allowLocalRelease
|
|
133
|
+
});
|
|
134
|
+
}),
|
|
135
|
+
releaseSource: target({ desc: "Release app source code with OTA update support" }).with(App).option("rebuild", Boolean, { desc: "rebuild", default: false }).option("buildNum", Number, { desc: "build number", default: 0 }).option("environment", String, { desc: "environment", default: "debug" }).option("local", Boolean, { desc: "local", default: true }).exec(async function(app, rebuild, buildNum, environment, local) {
|
|
136
|
+
await this.applicationScript.releaseSource(app, { rebuild, buildNum, environment, local });
|
|
137
|
+
}),
|
|
138
|
+
codepush: target({ desc: "Deploy over-the-air (OTA) update for mobile app" }).with(App).exec(async function(app) {
|
|
139
|
+
const os = await select({
|
|
140
|
+
message: "Select os",
|
|
141
|
+
choices: [
|
|
142
|
+
{ value: "ios", name: "ios", description: "ios" },
|
|
143
|
+
{ value: "android", name: "android", description: "android" }
|
|
144
|
+
]
|
|
145
|
+
});
|
|
146
|
+
await this.applicationScript.codepush(app, os);
|
|
147
|
+
}),
|
|
148
|
+
dbup: target({ desc: "Start local database services for a database mode" }).with(Workspace).option("mode", String, {
|
|
149
|
+
desc: "database mode",
|
|
150
|
+
default: "multiple",
|
|
151
|
+
enum: ["single", "multiple", "cluster"]
|
|
152
|
+
}).exec(async function(workspace, mode) {
|
|
153
|
+
await this.applicationScript.dbup(workspace, mode);
|
|
154
|
+
}),
|
|
155
|
+
dbdown: target({ desc: "Stop local database services" }).with(Workspace).exec(async function(workspace) {
|
|
156
|
+
await this.applicationScript.dbdown(workspace);
|
|
157
|
+
}),
|
|
158
|
+
configureApp: target({ desc: "Configure application settings interactively" }).with(App).exec(async function(app) {
|
|
159
|
+
await this.applicationScript.configureApp(app);
|
|
160
|
+
})
|
|
161
|
+
})) {
|
|
162
|
+
}
|
|
163
|
+
export {
|
|
164
|
+
ApplicationCommand
|
|
165
|
+
};
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
AllRoutesBuilder,
|
|
4
|
+
CsrArtifactBuilder,
|
|
5
|
+
SsrBaseArtifactBuilder,
|
|
6
|
+
precompressArtifacts
|
|
7
|
+
} from "./index-xmc2w32q.js";
|
|
8
|
+
import {
|
|
9
|
+
Spinner
|
|
10
|
+
} from "./index-6pz1j0zj.js";
|
|
11
|
+
import"./index-r24hmh0q.js";
|
|
12
|
+
|
|
13
|
+
// pkgs/@akanjs/devkit/applicationBuildRunner.ts
|
|
14
|
+
import { mkdir, rm } from "fs/promises";
|
|
15
|
+
import path from "path";
|
|
16
|
+
var BUILD_PHASE_EMOJIS = {
|
|
17
|
+
prepare: "\uD83E\uDDF9",
|
|
18
|
+
typecheck: "\uD83D\uDD0E",
|
|
19
|
+
backend: "\uD83D\uDCE6",
|
|
20
|
+
ssr: "\uD83E\uDDED",
|
|
21
|
+
csr: "\uD83C\uDFA8",
|
|
22
|
+
compress: "\uD83D\uDDDC\uFE0F",
|
|
23
|
+
metadata: "\uD83D\uDCDD"
|
|
24
|
+
};
|
|
25
|
+
var SSR_RENDER_EXTERNALS = [
|
|
26
|
+
"react",
|
|
27
|
+
"react/jsx-runtime",
|
|
28
|
+
"react/jsx-dev-runtime",
|
|
29
|
+
"react-dom",
|
|
30
|
+
"react-dom/server.browser",
|
|
31
|
+
"react-server-dom-webpack",
|
|
32
|
+
"react-server-dom-webpack/server.node",
|
|
33
|
+
"react-server-dom-webpack/client.node",
|
|
34
|
+
"react-server-dom-webpack/client.browser"
|
|
35
|
+
];
|
|
36
|
+
var AKAN_OPTIONAL_BACKEND_EXTERNALS = [
|
|
37
|
+
"@libsql/client",
|
|
38
|
+
"bullmq",
|
|
39
|
+
"croner",
|
|
40
|
+
"ioredis",
|
|
41
|
+
"postgres",
|
|
42
|
+
"protobufjs"
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
class ApplicationBuildRunner {
|
|
46
|
+
#app;
|
|
47
|
+
#fast;
|
|
48
|
+
#reporter;
|
|
49
|
+
#startedAt = Date.now();
|
|
50
|
+
#phases = [];
|
|
51
|
+
constructor(app, { fast = false, reporter } = {}) {
|
|
52
|
+
this.#app = app;
|
|
53
|
+
this.#fast = fast;
|
|
54
|
+
this.#reporter = reporter;
|
|
55
|
+
}
|
|
56
|
+
async build({ spinner = false } = {}) {
|
|
57
|
+
const phaseOptions = { spinner };
|
|
58
|
+
await this.#runPhase("prepare", "Preparing output directory", () => this.#app.prepareCommand("build"), undefined, {
|
|
59
|
+
spinner
|
|
60
|
+
});
|
|
61
|
+
if (!this.#fast)
|
|
62
|
+
await this.#runPhase("typecheck", "Typechecking", () => this.typecheck(), undefined, phaseOptions);
|
|
63
|
+
await this.#runPhase("backend", "Compiling backend", () => this.#buildBackend(), (result) => `${result.entrypoints} entrypoints, ${result.outputs} outputs`, phaseOptions);
|
|
64
|
+
await this.#runPhase("ssr", "Building SSR route artifacts", () => this.#buildSsr(), (result) => result ? `${result.allRoutes.manifest.routeIds.length} routes, ${result.allRoutes.manifest.knownEntries.length} entries` : "skipped", phaseOptions);
|
|
65
|
+
await this.#runPhase("csr", "Building CSR assets", () => this.#buildCsr(), (result) => result?.outputDir ?? "skipped", phaseOptions);
|
|
66
|
+
await this.#runPhase("compress", "Compressing static assets", () => precompressArtifacts(this.#app), (result) => result.files > 0 ? `${result.files} files, ${ApplicationBuildRunner.formatBytes(result.inputBytes)} -> ${ApplicationBuildRunner.formatBytes(result.outputBytes)}` : "no files", phaseOptions);
|
|
67
|
+
await this.#runPhase("metadata", "Writing production metadata", () => this.#buildAppMeta(), undefined, {
|
|
68
|
+
spinner
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
phases: this.#phases,
|
|
72
|
+
durationMs: Date.now() - this.#startedAt,
|
|
73
|
+
outputDir: this.#app.dist.cwdPath,
|
|
74
|
+
artifactDir: path.join(this.#app.dist.cwdPath, ".akan/artifact")
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
async typecheck(options = {}) {
|
|
78
|
+
const { clean = false, incremental = true } = options;
|
|
79
|
+
await this.#app.getPageKeys({ refresh: true });
|
|
80
|
+
const { typecheckDir, tsconfigPath } = await this.#writeTypecheckTsconfig({ incremental });
|
|
81
|
+
if (clean)
|
|
82
|
+
await rm(path.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
|
|
83
|
+
await this.#checkProjectInChildProcess(tsconfigPath);
|
|
84
|
+
}
|
|
85
|
+
async#runPhase(id, label, task, summarize, options = {}) {
|
|
86
|
+
this.#reporter?.phaseStart?.({ id, label });
|
|
87
|
+
const phaseStartedAt = Date.now();
|
|
88
|
+
const spinner = options.spinner ? new Spinner(label, { prefix: `${BUILD_PHASE_EMOJIS[id]} ${id}` }).start() : undefined;
|
|
89
|
+
try {
|
|
90
|
+
const result = await task();
|
|
91
|
+
const phase = { id, label, durationMs: Date.now() - phaseStartedAt, summary: summarize?.(result) };
|
|
92
|
+
this.#phases.push(phase);
|
|
93
|
+
const summary = phase.summary ? `: ${phase.summary}` : "";
|
|
94
|
+
spinner?.succeed(`${label}${summary}`);
|
|
95
|
+
this.#reporter?.phaseDone?.(phase);
|
|
96
|
+
return result;
|
|
97
|
+
} catch (error) {
|
|
98
|
+
spinner?.fail(`${label} failed`);
|
|
99
|
+
this.#reporter?.phaseFail?.({ id, label }, error);
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async#buildAppMeta() {
|
|
104
|
+
const akanConfig = await this.#app.getConfig();
|
|
105
|
+
await Promise.all([
|
|
106
|
+
this.#app.dist.writeJson("package.json", akanConfig.getProductionPackageJson()),
|
|
107
|
+
this.#app.dist.writeFile(`${this.#app.dist.cwdPath}/Dockerfile`, akanConfig.docker.content)
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
110
|
+
async#buildBackend() {
|
|
111
|
+
const akanConfig = await this.#app.getConfig();
|
|
112
|
+
const backendExternals = [
|
|
113
|
+
...new Set([...akanConfig.externalLibs, ...SSR_RENDER_EXTERNALS, ...AKAN_OPTIONAL_BACKEND_EXTERNALS])
|
|
114
|
+
];
|
|
115
|
+
const backendEntryPoints = [`${this.#app.cwdPath}/main.ts`, `${this.#app.cwdPath}/server.ts`];
|
|
116
|
+
for (const entrypoint of backendEntryPoints) {
|
|
117
|
+
if (!await Bun.file(entrypoint).exists())
|
|
118
|
+
throw new Error(`Backend entrypoint not found: ${entrypoint}`);
|
|
119
|
+
}
|
|
120
|
+
const backendResult = await this.#buildOrThrow("backend", {
|
|
121
|
+
entrypoints: backendEntryPoints,
|
|
122
|
+
outdir: this.#app.dist.cwdPath,
|
|
123
|
+
target: "bun",
|
|
124
|
+
minify: true,
|
|
125
|
+
naming: { entry: "[name].[ext]", chunk: "chunk-[hash].[ext]" },
|
|
126
|
+
define: { "process.env.NODE_ENV": JSON.stringify("production") },
|
|
127
|
+
plugins: backendExternals.length > 0 ? [this.#createExternalSpecifiersPlugin(backendExternals)] : []
|
|
128
|
+
});
|
|
129
|
+
const rscWorkerResult = await this.#buildOrThrow("rsc-worker", {
|
|
130
|
+
entrypoints: [this.#resolveRscWorkerBuildEntry()],
|
|
131
|
+
outdir: this.#app.dist.cwdPath,
|
|
132
|
+
target: "bun",
|
|
133
|
+
minify: true,
|
|
134
|
+
naming: { entry: "[name].[ext]", chunk: "chunk-[hash].[ext]" },
|
|
135
|
+
conditions: ["react-server"],
|
|
136
|
+
define: { "process.env.NODE_ENV": JSON.stringify("production") },
|
|
137
|
+
plugins: backendExternals.length > 0 ? [this.#createExternalSpecifiersPlugin(backendExternals)] : []
|
|
138
|
+
});
|
|
139
|
+
const consoleRuntimeResult = await this.#buildOrThrow("console-runtime", {
|
|
140
|
+
entrypoints: [this.#resolveConsoleRuntimeBuildEntry()],
|
|
141
|
+
outdir: this.#app.dist.cwdPath,
|
|
142
|
+
target: "bun",
|
|
143
|
+
minify: true,
|
|
144
|
+
naming: { entry: "console-runtime.[ext]", chunk: "chunk-[hash].[ext]" },
|
|
145
|
+
define: { "process.env.NODE_ENV": JSON.stringify("production") }
|
|
146
|
+
});
|
|
147
|
+
await this.#writeConsoleShim();
|
|
148
|
+
return {
|
|
149
|
+
entrypoints: backendEntryPoints.length + 2,
|
|
150
|
+
outputs: backendResult.outputs.length + rscWorkerResult.outputs.length + consoleRuntimeResult.outputs.length + 1
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async#writeConsoleShim() {
|
|
154
|
+
await Bun.write(path.join(this.#app.dist.cwdPath, "console.js"), `import { cnst, db, dict, option, server, sig, srv } from "./server.js";
|
|
155
|
+
import { assertAkanConsoleAllowed, startAkanConsole } from "./console-runtime.js";
|
|
156
|
+
|
|
157
|
+
const run = async () => {
|
|
158
|
+
assertAkanConsoleAllowed(server.env);
|
|
159
|
+
await server.start({ listen: false, web: false });
|
|
160
|
+
try {
|
|
161
|
+
await startAkanConsole(server, { globals: { cnst, db, dict, option, sig, srv } });
|
|
162
|
+
} finally {
|
|
163
|
+
await server.stop();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
void run().catch((error) => {
|
|
168
|
+
console.error(error);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
});
|
|
171
|
+
`);
|
|
172
|
+
}
|
|
173
|
+
#resolveRscWorkerBuildEntry() {
|
|
174
|
+
try {
|
|
175
|
+
return Bun.resolveSync("akanjs/server/rsc-worker", import.meta.dir);
|
|
176
|
+
} catch {
|
|
177
|
+
return path.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/rscWorker.tsx");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
#resolveConsoleRuntimeBuildEntry() {
|
|
181
|
+
try {
|
|
182
|
+
return path.join(path.dirname(Bun.resolveSync("akanjs/server", import.meta.dir)), "console.ts");
|
|
183
|
+
} catch {
|
|
184
|
+
return path.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/console.ts");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async#buildCsr() {
|
|
188
|
+
return await new CsrArtifactBuilder(this.#app, "build").build();
|
|
189
|
+
}
|
|
190
|
+
async#buildSsr() {
|
|
191
|
+
const pageKeys = await this.#app.getPageKeys();
|
|
192
|
+
if (pageKeys.length === 0) {
|
|
193
|
+
this.#app.log(`[cli] no route files under ${this.#app.cwdPath}/page \u2014 skipping SSR build`);
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
const base = await new SsrBaseArtifactBuilder(this.#app, "build").build();
|
|
197
|
+
const allRoutes = await new AllRoutesBuilder(this.#app, base.artifact, "build").build();
|
|
198
|
+
return { base, allRoutes };
|
|
199
|
+
}
|
|
200
|
+
async#writeTypecheckTsconfig({ incremental = true } = {}) {
|
|
201
|
+
const typecheckDir = path.join(this.#app.cwdPath, ".akan", "typecheck");
|
|
202
|
+
await mkdir(typecheckDir, { recursive: true });
|
|
203
|
+
const tsconfig = {
|
|
204
|
+
extends: "../../tsconfig.json",
|
|
205
|
+
compilerOptions: {
|
|
206
|
+
noEmit: true,
|
|
207
|
+
incremental,
|
|
208
|
+
tsBuildInfoFile: "./tsconfig.tsbuildinfo"
|
|
209
|
+
},
|
|
210
|
+
include: [
|
|
211
|
+
"../../main.ts",
|
|
212
|
+
"../../server.ts",
|
|
213
|
+
"../../client.ts",
|
|
214
|
+
"../../page/**/*.ts",
|
|
215
|
+
"../../page/**/*.tsx",
|
|
216
|
+
"../../../../pkgs/akanjs/*/types/**/*.d.ts"
|
|
217
|
+
],
|
|
218
|
+
references: []
|
|
219
|
+
};
|
|
220
|
+
const tsconfigPath = path.join(typecheckDir, "tsconfig.json");
|
|
221
|
+
await Bun.write(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
|
|
222
|
+
`);
|
|
223
|
+
return { typecheckDir, tsconfigPath };
|
|
224
|
+
}
|
|
225
|
+
async#checkProjectInChildProcess(tsconfigPath) {
|
|
226
|
+
const entry = await this.#resolveTypecheckWorkerEntry();
|
|
227
|
+
const proc = Bun.spawn([process.execPath, entry], {
|
|
228
|
+
cwd: this.#app.workspace.workspaceRoot,
|
|
229
|
+
env: this.#app.getCommandEnv({
|
|
230
|
+
AKAN_COMMAND_TYPE: "typecheck",
|
|
231
|
+
AKAN_TYPECHECK_TSCONFIG: tsconfigPath
|
|
232
|
+
}),
|
|
233
|
+
stdout: "pipe",
|
|
234
|
+
stderr: "pipe"
|
|
235
|
+
});
|
|
236
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
237
|
+
new Response(proc.stdout).text(),
|
|
238
|
+
new Response(proc.stderr).text(),
|
|
239
|
+
proc.exited
|
|
240
|
+
]);
|
|
241
|
+
if (exitCode !== 0)
|
|
242
|
+
throw new Error((stderr || stdout).trim() || `Typecheck failed with exit code ${exitCode}`);
|
|
243
|
+
}
|
|
244
|
+
async#resolveTypecheckWorkerEntry() {
|
|
245
|
+
const candidates = [
|
|
246
|
+
path.join(this.#app.workspace.workspaceRoot, "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
247
|
+
path.join(this.#app.workspace.workspaceRoot, "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
248
|
+
path.join(import.meta.dir, "typecheck.proc.js"),
|
|
249
|
+
path.join(import.meta.dir, "typecheck.proc.ts")
|
|
250
|
+
];
|
|
251
|
+
for (const candidate of candidates)
|
|
252
|
+
if (await Bun.file(candidate).exists())
|
|
253
|
+
return candidate;
|
|
254
|
+
throw new Error(`[cli] typecheck worker entry not found; looked in: ${candidates.join(", ")}`);
|
|
255
|
+
}
|
|
256
|
+
async#buildOrThrow(label, config) {
|
|
257
|
+
const result = await Bun.build(config);
|
|
258
|
+
if (!result.success)
|
|
259
|
+
throw new AggregateError(result.logs, `[${label}] Bun.build failed`);
|
|
260
|
+
return result;
|
|
261
|
+
}
|
|
262
|
+
#createExternalSpecifiersPlugin(specifiers) {
|
|
263
|
+
const uniqueSpecifiers = [...new Set(specifiers)];
|
|
264
|
+
const escaped = uniqueSpecifiers.map((specifier) => specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
265
|
+
const filter = new RegExp(`^(${escaped.join("|")})(?:/.*)?$`);
|
|
266
|
+
return {
|
|
267
|
+
name: "akan-backend-externalize-specifiers",
|
|
268
|
+
setup(build) {
|
|
269
|
+
build.onResolve({ filter }, (args) => ({ path: args.path, external: true }));
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
static formatBytes(bytes) {
|
|
274
|
+
if (bytes < 1024)
|
|
275
|
+
return `${bytes}B`;
|
|
276
|
+
if (bytes < 1024 * 1024)
|
|
277
|
+
return `${(bytes / 1024).toFixed(1)}KB`;
|
|
278
|
+
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
export {
|
|
282
|
+
ApplicationBuildRunner,
|
|
283
|
+
AKAN_OPTIONAL_BACKEND_EXTERNALS
|
|
284
|
+
};
|