bleam 0.0.5 → 0.0.7
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/dist/ai.cjs +4146 -0
- package/dist/ai.d.cts +535 -0
- package/dist/ai.d.ts +535 -0
- package/dist/ai.js +4102 -0
- package/dist/animated.cjs +286 -0
- package/dist/animated.d.cts +47 -0
- package/dist/animated.d.ts +47 -0
- package/dist/animated.js +281 -0
- package/dist/app.cjs +92 -0
- package/dist/app.d.cts +1 -2
- package/dist/app.d.ts +1 -2
- package/dist/app.js +93 -2
- package/dist/bundler.d.cts +1 -2
- package/dist/bundler.d.ts +1 -2
- package/dist/cli.cjs +1375 -71
- package/dist/cli.d.cts +89 -1
- package/dist/cli.d.ts +89 -1
- package/dist/cli.js +1373 -74
- package/dist/config-Bb6SULnR.cjs +46 -0
- package/dist/config-CfWa3q-k.js +28 -0
- package/dist/config-Cms0rvqg.d.ts +40 -0
- package/dist/config-CufOVJV3.d.cts +40 -0
- package/dist/config.cjs +4 -25
- package/dist/config.d.cts +2 -28
- package/dist/config.d.ts +2 -28
- package/dist/config.js +2 -24
- package/dist/crypto-BB92-Upx.js +7 -0
- package/dist/crypto-CT3VZ7lF.cjs +13 -0
- package/dist/crypto.cjs +2 -2
- package/dist/crypto.d.cts +6 -1
- package/dist/crypto.d.ts +8 -1
- package/dist/crypto.js +2 -2
- package/dist/dev-protocol.d.cts +16 -3
- package/dist/dev-protocol.d.ts +16 -3
- package/dist/dev-protocol.js +1 -2
- package/dist/files-Bo7h9fik.cjs +468 -0
- package/dist/files-Ds1wT8C2.js +445 -0
- package/dist/files-DwA7pzr3.d.cts +99 -0
- package/dist/files-VrkQlKIT.d.ts +99 -0
- package/dist/files.cjs +7 -0
- package/dist/files.d.cts +2 -0
- package/dist/files.d.ts +2 -0
- package/dist/files.js +4 -0
- package/dist/index.cjs +4 -5
- package/dist/index.d.cts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.js +2 -4
- package/dist/native-runtime-C85Nuc4F.js +10 -0
- package/dist/{native-runtime-CdeT0JyQ.cjs → native-runtime-CsXnXkQn.cjs} +1 -14
- package/dist/native-sqlite-xcGdamRD.js +64 -0
- package/dist/native-sqlite-yQLD5s9i.cjs +66 -0
- package/dist/platform.cjs +27 -0
- package/dist/platform.d.cts +39 -0
- package/dist/platform.d.ts +39 -0
- package/dist/platform.js +21 -0
- package/dist/runtime.d.cts +1 -7
- package/dist/runtime.d.ts +1 -7
- package/dist/schema-Bo5Jvqus.js +90 -0
- package/dist/schema-DOOjfXvs.d.ts +58 -0
- package/dist/schema-ENSMX_1t.d.cts +58 -0
- package/dist/schema-rQ13mrpD.cjs +102 -0
- package/dist/schema.cjs +4 -0
- package/dist/schema.d.cts +2 -0
- package/dist/schema.d.ts +2 -0
- package/dist/schema.js +3 -0
- package/dist/state-Bx0VlTlO.cjs +852 -0
- package/dist/state-CAwe-Vw1.js +767 -0
- package/dist/state.cjs +19 -0
- package/dist/state.d.cts +159 -0
- package/dist/state.d.ts +159 -0
- package/dist/state.js +6 -0
- package/dist/styles.cjs +742 -0
- package/dist/styles.d.cts +701 -0
- package/dist/styles.d.ts +701 -0
- package/dist/styles.js +739 -0
- package/dist/ui-1WepaMS4.d.cts +92 -0
- package/dist/ui-234Plg7Z.d.cts +92 -0
- package/dist/ui-BJmXhz9Q.d.ts +92 -0
- package/dist/ui-Dd7SXdbg.d.cts +92 -0
- package/dist/ui-Ds88eETu.d.ts +92 -0
- package/dist/ui-TaqnB5SP.d.ts +92 -0
- package/dist/ui-WQvnXL0W.d.ts +92 -0
- package/dist/ui.cjs +364 -0
- package/dist/ui.d.cts +2 -0
- package/dist/ui.d.ts +2 -0
- package/dist/ui.js +357 -0
- package/dist/window.cjs +596 -0
- package/dist/window.d.cts +63 -0
- package/dist/window.d.ts +63 -0
- package/dist/window.js +589 -0
- package/metro-config.cjs +18 -13
- package/package.json +57 -21
- package/templates/basic/app/index.tsx +133 -12
- package/templates/basic/app.config.ts +4 -2
- package/templates/foundation-models/app/index.tsx +32 -0
- package/templates/foundation-models/app.config.ts +5 -0
- package/templates/image-generation/app/index.tsx +39 -0
- package/templates/image-generation/app.config.ts +5 -0
- package/templates/state/app/index.tsx +30 -0
- package/templates/state/app.config.ts +5 -0
- package/dist/app.d.cts.map +0 -1
- package/dist/app.d.ts.map +0 -1
- package/dist/app.js.map +0 -1
- package/dist/bundler.d.cts.map +0 -1
- package/dist/bundler.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config.d.cts.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/crypto-BNhWeXMj.cjs +0 -15
- package/dist/crypto-Bg8cD8wX.d.cts +0 -8
- package/dist/crypto-Bg8cD8wX.d.cts.map +0 -1
- package/dist/crypto-CCA_hvao.js +0 -11
- package/dist/crypto-CCA_hvao.js.map +0 -1
- package/dist/crypto-IOzbNoJD.d.ts +0 -8
- package/dist/crypto-IOzbNoJD.d.ts.map +0 -1
- package/dist/dev-protocol.d.cts.map +0 -1
- package/dist/dev-protocol.d.ts.map +0 -1
- package/dist/dev-protocol.js.map +0 -1
- package/dist/fs-BK7joD1g.js +0 -13
- package/dist/fs-BK7joD1g.js.map +0 -1
- package/dist/fs-CEhcjuN6.d.ts +0 -9
- package/dist/fs-CEhcjuN6.d.ts.map +0 -1
- package/dist/fs-CfE8CHf_.d.cts +0 -9
- package/dist/fs-CfE8CHf_.d.cts.map +0 -1
- package/dist/fs-DKHYTPua.cjs +0 -18
- package/dist/fs.cjs +0 -3
- package/dist/fs.d.cts +0 -2
- package/dist/fs.d.ts +0 -2
- package/dist/fs.js +0 -3
- package/dist/native-runtime-BoqybBBf.js +0 -18
- package/dist/native-runtime-BoqybBBf.js.map +0 -1
- package/dist/native.cjs +0 -132
- package/dist/native.d.cts +0 -64
- package/dist/native.d.cts.map +0 -1
- package/dist/native.d.ts +0 -64
- package/dist/native.d.ts.map +0 -1
- package/dist/native.js +0 -133
- package/dist/native.js.map +0 -1
- package/dist/runtime.d.cts.map +0 -1
- package/dist/runtime.d.ts.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -16,27 +16,136 @@ let node_path = require("node:path");
|
|
|
16
16
|
node_path = require_chunk.__toESM(node_path);
|
|
17
17
|
let node_url = require("node:url");
|
|
18
18
|
node_url = require_chunk.__toESM(node_url);
|
|
19
|
+
let ws = require("ws");
|
|
20
|
+
ws = require_chunk.__toESM(ws);
|
|
21
|
+
let yocto_spinner = require("yocto-spinner");
|
|
22
|
+
yocto_spinner = require_chunk.__toESM(yocto_spinner);
|
|
23
|
+
let yoctocolors = require("yoctocolors");
|
|
24
|
+
yoctocolors = require_chunk.__toESM(yoctocolors);
|
|
19
25
|
|
|
20
26
|
//#region src/cli.ts
|
|
21
27
|
const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
22
28
|
const packageRoot = node_path.default.dirname((0, node_url.fileURLToPath)(new URL("../package.json", require("url").pathToFileURL(__filename).href)));
|
|
23
29
|
const packageJson = require$1("../package.json");
|
|
24
30
|
const runtimeVersion = packageJson.version;
|
|
25
|
-
const
|
|
31
|
+
const starterAppName = "Bleam Basic";
|
|
32
|
+
function artifactPlatform() {
|
|
33
|
+
return `macos-${process.arch}`;
|
|
34
|
+
}
|
|
35
|
+
function prettyPath(value) {
|
|
36
|
+
const home = node_os.default.homedir();
|
|
37
|
+
return value === home || value.startsWith(`${home}${node_path.default.sep}`) ? `~${value.slice(home.length)}` : value;
|
|
38
|
+
}
|
|
39
|
+
function commandSucceeds(command, args) {
|
|
40
|
+
const result = (0, node_child_process.spawnSync)(command, args, { stdio: "ignore" });
|
|
41
|
+
return !result.error && result.status === 0;
|
|
42
|
+
}
|
|
43
|
+
function commandText(command, args) {
|
|
44
|
+
return [command, ...args].join(" ");
|
|
45
|
+
}
|
|
46
|
+
function doctorHint(projectRoot) {
|
|
47
|
+
return projectRoot ? `Run ${(0, yoctocolors.bold)(`bleam doctor ${projectRoot}`)} for diagnostics.` : `Run ${(0, yoctocolors.bold)("bleam doctor")} for diagnostics.`;
|
|
48
|
+
}
|
|
49
|
+
function appConfigBuildExample() {
|
|
50
|
+
return [
|
|
51
|
+
"Example:",
|
|
52
|
+
"import { appConfig } from 'bleam'",
|
|
53
|
+
"",
|
|
54
|
+
"export default appConfig({",
|
|
55
|
+
" name: 'My App',",
|
|
56
|
+
" bundleIdentifier: 'com.example.myapp',",
|
|
57
|
+
" teamId: 'ABCDE12345',",
|
|
58
|
+
"})"
|
|
59
|
+
].join("\n");
|
|
60
|
+
}
|
|
61
|
+
function missingBuildFieldError(field) {
|
|
62
|
+
return /* @__PURE__ */ new Error(`app.config.ts must define ${field} for bleam build.\n\n${appConfigBuildExample()}`);
|
|
63
|
+
}
|
|
64
|
+
function heading(text) {
|
|
65
|
+
return (0, yoctocolors.bold)(text);
|
|
66
|
+
}
|
|
67
|
+
function muted(text) {
|
|
68
|
+
return (0, yoctocolors.dim)(text);
|
|
69
|
+
}
|
|
70
|
+
function statusLabel(status) {
|
|
71
|
+
if (status === "pass") return (0, yoctocolors.green)("[ok]");
|
|
72
|
+
if (status === "warn") return (0, yoctocolors.yellow)("[warn]");
|
|
73
|
+
return (0, yoctocolors.red)("[fail]");
|
|
74
|
+
}
|
|
75
|
+
function startSpinner(text) {
|
|
76
|
+
if (!process.stderr.isTTY) {
|
|
77
|
+
console.log(text);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
return (0, yocto_spinner.default)({
|
|
81
|
+
text,
|
|
82
|
+
handleSignals: false
|
|
83
|
+
}).start();
|
|
84
|
+
}
|
|
26
85
|
function printUsage() {
|
|
27
86
|
console.log(`Usage: bleam <command>
|
|
28
87
|
|
|
29
88
|
Commands:
|
|
30
|
-
new
|
|
31
|
-
|
|
89
|
+
new <dir> [--template <name>]
|
|
90
|
+
Create and run a Bleam project
|
|
91
|
+
dev [dir] [--port <port>] [--no-run] [--clean]
|
|
92
|
+
Start a Bleam dev server
|
|
93
|
+
build [dir] [--output <dir>] [--clean]
|
|
94
|
+
Export standalone native archives
|
|
95
|
+
install [dir] [--output <dir>] [--clean]
|
|
96
|
+
Build and install a standalone macOS app
|
|
97
|
+
publish ota [dir] [--service-url <url>]
|
|
98
|
+
Publish an OTA update to the local update service
|
|
99
|
+
publish platform [dir] [--service-url <url>]
|
|
100
|
+
Build and publish a platform update locally
|
|
101
|
+
doctor [dir] Check the local Bleam environment
|
|
102
|
+
typecheck [dir] Typecheck project files
|
|
103
|
+
check [dir] [--write] Format, lint, and organize imports
|
|
104
|
+
format [dir] [--check] Format project files
|
|
105
|
+
lint [dir] Lint project files`);
|
|
106
|
+
}
|
|
107
|
+
function parsePublishOtaOptions(argv) {
|
|
108
|
+
const root = invocationRoot();
|
|
109
|
+
let projectRoot = root;
|
|
110
|
+
let hasProjectRootArg = false;
|
|
111
|
+
let serviceUrl = process.env.BLEAM_UPDATE_SERVICE_URL ?? "http://127.0.0.1:8787";
|
|
112
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
113
|
+
const arg = argv[index];
|
|
114
|
+
if (arg === "--service-url") {
|
|
115
|
+
serviceUrl = argv[++index] ?? "";
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (arg.startsWith("--service-url=")) {
|
|
119
|
+
serviceUrl = arg.slice(14);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
|
|
123
|
+
if (hasProjectRootArg) throw new Error("Only one project directory may be specified");
|
|
124
|
+
projectRoot = node_path.default.resolve(root, arg);
|
|
125
|
+
hasProjectRootArg = true;
|
|
126
|
+
}
|
|
127
|
+
const url = new URL(serviceUrl);
|
|
128
|
+
if (url.protocol !== "http:" || !["127.0.0.1", "localhost"].includes(url.hostname)) throw new Error("Local publishing requires an http://localhost service URL");
|
|
129
|
+
if (!hasProjectRootArg && !isBleamProjectRoot(projectRoot)) projectRoot = discoverBleamProjectRoot(projectRoot) ?? projectRoot;
|
|
130
|
+
return {
|
|
131
|
+
projectRoot: canonicalPath(projectRoot),
|
|
132
|
+
serviceUrl: url.origin
|
|
133
|
+
};
|
|
32
134
|
}
|
|
33
135
|
function invocationRoot() {
|
|
34
|
-
|
|
136
|
+
const pwd = process.env.PWD;
|
|
137
|
+
return pwd && node_path.default.isAbsolute(pwd) ? pwd : process.cwd();
|
|
138
|
+
}
|
|
139
|
+
function canonicalPath(value) {
|
|
140
|
+
const resolved = node_path.default.resolve(value);
|
|
141
|
+
return (0, node_fs.existsSync)(resolved) ? node_fs.realpathSync.native(resolved) : resolved;
|
|
35
142
|
}
|
|
36
143
|
function parseDevOptions(argv) {
|
|
37
144
|
const root = invocationRoot();
|
|
38
145
|
let projectRoot = root;
|
|
39
146
|
let port = 8081;
|
|
147
|
+
let run = true;
|
|
148
|
+
let clean = false;
|
|
40
149
|
let hasProjectRootArg = false;
|
|
41
150
|
for (let index = 0; index < argv.length; index += 1) {
|
|
42
151
|
const arg = argv[index];
|
|
@@ -49,6 +158,18 @@ function parseDevOptions(argv) {
|
|
|
49
158
|
port = Number(arg.slice(7));
|
|
50
159
|
continue;
|
|
51
160
|
}
|
|
161
|
+
if (arg === "--run") {
|
|
162
|
+
run = true;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (arg === "--no-run") {
|
|
166
|
+
run = false;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (arg === "--clean" || arg === "-c") {
|
|
170
|
+
clean = true;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
52
173
|
if (arg === "--help" || arg === "-h") {
|
|
53
174
|
printUsage();
|
|
54
175
|
process.exit(0);
|
|
@@ -60,17 +181,121 @@ function parseDevOptions(argv) {
|
|
|
60
181
|
if (!Number.isInteger(port) || port <= 0) throw new Error(`Invalid port: ${port}`);
|
|
61
182
|
if (!hasProjectRootArg && !isBleamProjectRoot(projectRoot)) projectRoot = discoverBleamProjectRoot(projectRoot) ?? projectRoot;
|
|
62
183
|
return {
|
|
63
|
-
projectRoot:
|
|
64
|
-
port
|
|
184
|
+
projectRoot: canonicalPath(projectRoot),
|
|
185
|
+
port,
|
|
186
|
+
run,
|
|
187
|
+
clean
|
|
65
188
|
};
|
|
66
189
|
}
|
|
67
190
|
function parseNewOptions(argv) {
|
|
191
|
+
const root = invocationRoot();
|
|
192
|
+
let projectRoot;
|
|
193
|
+
let template = "basic";
|
|
194
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
195
|
+
const arg = argv[index];
|
|
196
|
+
if (arg === "--help" || arg === "-h") {
|
|
197
|
+
printUsage();
|
|
198
|
+
process.exit(0);
|
|
199
|
+
}
|
|
200
|
+
if (arg === "--template") {
|
|
201
|
+
template = projectTemplate(argv[++index] ?? "");
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (arg.startsWith("--template=")) {
|
|
205
|
+
template = projectTemplate(arg.slice(11));
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
|
|
209
|
+
if (projectRoot) throw new Error("Only one project directory may be specified");
|
|
210
|
+
projectRoot = node_path.default.resolve(root, arg);
|
|
211
|
+
}
|
|
212
|
+
if (!projectRoot) throw new Error("Usage: bleam new <dir>");
|
|
213
|
+
return {
|
|
214
|
+
projectRoot: canonicalPath(projectRoot),
|
|
215
|
+
template
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const projectTemplates = [
|
|
219
|
+
"basic",
|
|
220
|
+
"state",
|
|
221
|
+
"foundation-models",
|
|
222
|
+
"image-generation"
|
|
223
|
+
];
|
|
224
|
+
function projectTemplate(value) {
|
|
225
|
+
if (projectTemplates.includes(value)) return value;
|
|
226
|
+
throw new Error(`Unknown template: ${value}. Expected ${projectTemplates.join(", ")}`);
|
|
227
|
+
}
|
|
228
|
+
function parseBuildOptions(argv) {
|
|
229
|
+
const root = invocationRoot();
|
|
230
|
+
let projectRoot = root;
|
|
231
|
+
let hasProjectRootArg = false;
|
|
232
|
+
let output;
|
|
233
|
+
let configuration = "Release";
|
|
234
|
+
let clean = false;
|
|
235
|
+
let exportOptionsPlist;
|
|
236
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
237
|
+
const arg = argv[index];
|
|
238
|
+
if (arg === "--output" || arg === "-o") {
|
|
239
|
+
output = argv[++index];
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (arg.startsWith("--output=")) {
|
|
243
|
+
output = arg.slice(9);
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (arg === "--configuration") {
|
|
247
|
+
const value = argv[++index];
|
|
248
|
+
if (!value) throw new Error("Missing --configuration value");
|
|
249
|
+
configuration = value;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (arg.startsWith("--configuration=")) {
|
|
253
|
+
configuration = arg.slice(16);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (arg === "--clean") {
|
|
257
|
+
clean = true;
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
if (arg === "--export-options-plist") {
|
|
261
|
+
exportOptionsPlist = argv[++index];
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (arg.startsWith("--export-options-plist=")) {
|
|
265
|
+
exportOptionsPlist = arg.slice(23);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (arg === "--help" || arg === "-h") {
|
|
269
|
+
printUsage();
|
|
270
|
+
process.exit(0);
|
|
271
|
+
}
|
|
272
|
+
if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
|
|
273
|
+
projectRoot = node_path.default.resolve(root, arg);
|
|
274
|
+
hasProjectRootArg = true;
|
|
275
|
+
}
|
|
276
|
+
if (!hasProjectRootArg && !isBleamProjectRoot(projectRoot)) projectRoot = discoverBleamProjectRoot(projectRoot) ?? projectRoot;
|
|
277
|
+
const resolvedProjectRoot = canonicalPath(projectRoot);
|
|
278
|
+
return {
|
|
279
|
+
projectRoot: resolvedProjectRoot,
|
|
280
|
+
output: node_path.default.resolve(resolvedProjectRoot, output ?? "dist"),
|
|
281
|
+
configuration,
|
|
282
|
+
clean,
|
|
283
|
+
exportOptionsPlist: exportOptionsPlist ? node_path.default.resolve(root, exportOptionsPlist) : void 0
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function parseProjectToolOptions(argv) {
|
|
68
287
|
const root = invocationRoot();
|
|
69
288
|
let projectRoot = root;
|
|
70
|
-
let
|
|
289
|
+
let hasProjectRootArg = false;
|
|
290
|
+
let write = false;
|
|
291
|
+
let formatCheck = false;
|
|
71
292
|
for (const arg of argv) {
|
|
72
|
-
if (arg === "--
|
|
73
|
-
|
|
293
|
+
if (arg === "--write") {
|
|
294
|
+
write = true;
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
if (arg === "--check") {
|
|
298
|
+
formatCheck = true;
|
|
74
299
|
continue;
|
|
75
300
|
}
|
|
76
301
|
if (arg === "--help" || arg === "-h") {
|
|
@@ -79,15 +304,35 @@ function parseNewOptions(argv) {
|
|
|
79
304
|
}
|
|
80
305
|
if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
|
|
81
306
|
projectRoot = node_path.default.resolve(root, arg);
|
|
307
|
+
hasProjectRootArg = true;
|
|
82
308
|
}
|
|
309
|
+
if (!hasProjectRootArg && !isBleamProjectRoot(projectRoot)) projectRoot = discoverBleamProjectRoot(projectRoot) ?? projectRoot;
|
|
83
310
|
return {
|
|
84
|
-
projectRoot,
|
|
85
|
-
|
|
311
|
+
projectRoot: canonicalPath(projectRoot),
|
|
312
|
+
write,
|
|
313
|
+
formatCheck
|
|
86
314
|
};
|
|
87
315
|
}
|
|
316
|
+
function parseDoctorOptions(argv) {
|
|
317
|
+
const root = invocationRoot();
|
|
318
|
+
let projectRoot = root;
|
|
319
|
+
let hasProjectRootArg = false;
|
|
320
|
+
for (const arg of argv) {
|
|
321
|
+
if (arg === "--help" || arg === "-h") {
|
|
322
|
+
printUsage();
|
|
323
|
+
process.exit(0);
|
|
324
|
+
}
|
|
325
|
+
if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
|
|
326
|
+
projectRoot = node_path.default.resolve(root, arg);
|
|
327
|
+
hasProjectRootArg = true;
|
|
328
|
+
}
|
|
329
|
+
if (!hasProjectRootArg && !isBleamProjectRoot(projectRoot)) projectRoot = discoverBleamProjectRoot(projectRoot) ?? projectRoot;
|
|
330
|
+
return { projectRoot: canonicalPath(projectRoot) };
|
|
331
|
+
}
|
|
88
332
|
function parseInternalMetroOptions(argv) {
|
|
89
333
|
let workspaceRoot;
|
|
90
334
|
let port = 8081;
|
|
335
|
+
let resetCache = false;
|
|
91
336
|
for (let index = 0; index < argv.length; index += 1) {
|
|
92
337
|
const arg = argv[index];
|
|
93
338
|
if (arg === "--workspace-root") {
|
|
@@ -102,13 +347,18 @@ function parseInternalMetroOptions(argv) {
|
|
|
102
347
|
port = Number(arg.slice(7));
|
|
103
348
|
continue;
|
|
104
349
|
}
|
|
350
|
+
if (arg === "--reset-cache") {
|
|
351
|
+
resetCache = true;
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
105
354
|
throw new Error(`Unknown internal option: ${arg}`);
|
|
106
355
|
}
|
|
107
356
|
if (!workspaceRoot) throw new Error("Missing --workspace-root");
|
|
108
357
|
if (!Number.isInteger(port) || port <= 0) throw new Error(`Invalid port: ${port}`);
|
|
109
358
|
return {
|
|
110
359
|
workspaceRoot,
|
|
111
|
-
port
|
|
360
|
+
port,
|
|
361
|
+
resetCache
|
|
112
362
|
};
|
|
113
363
|
}
|
|
114
364
|
function isBleamProjectRoot(projectRoot) {
|
|
@@ -148,6 +398,28 @@ function assertStringField(value, field) {
|
|
|
148
398
|
if (typeof value !== "string" || value.trim() === "") throw new Error(`app.config.ts must define ${field}`);
|
|
149
399
|
return value;
|
|
150
400
|
}
|
|
401
|
+
function normalizeAppGroups(value, bundleIdentifier) {
|
|
402
|
+
const configured = Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
403
|
+
if (configured.length > 0) return configured;
|
|
404
|
+
return bundleIdentifier ? [`group.${bundleIdentifier}`] : [];
|
|
405
|
+
}
|
|
406
|
+
function isHexColor(value) {
|
|
407
|
+
return typeof value === "string" && /^#[\da-f]{6}$/i.test(value);
|
|
408
|
+
}
|
|
409
|
+
function normalizeAppearance(value) {
|
|
410
|
+
const input = value && typeof value === "object" ? value : {};
|
|
411
|
+
const window = input.window && typeof input.window === "object" ? input.window : {};
|
|
412
|
+
const appearance = {};
|
|
413
|
+
if (window.backgroundColor !== void 0) {
|
|
414
|
+
if (!isHexColor(window.backgroundColor)) throw new Error("app.config.ts appearance.window.backgroundColor must be a #rrggbb color");
|
|
415
|
+
appearance.window = { backgroundColor: window.backgroundColor };
|
|
416
|
+
}
|
|
417
|
+
if (input.userInterfaceStyle !== void 0) {
|
|
418
|
+
if (input.userInterfaceStyle !== "automatic" && input.userInterfaceStyle !== "light" && input.userInterfaceStyle !== "dark") throw new Error("app.config.ts appearance.userInterfaceStyle must be automatic, light, or dark");
|
|
419
|
+
appearance.userInterfaceStyle = input.userInterfaceStyle;
|
|
420
|
+
}
|
|
421
|
+
return appearance;
|
|
422
|
+
}
|
|
151
423
|
function loadAppConfig(projectRoot) {
|
|
152
424
|
const configPath = node_path.default.join(projectRoot, "app.config.ts");
|
|
153
425
|
const loader = `
|
|
@@ -174,11 +446,15 @@ function loadAppConfig(projectRoot) {
|
|
|
174
446
|
});
|
|
175
447
|
if (result.status !== 0) throw new Error(result.stderr.trim() || "Failed to load app.config.ts");
|
|
176
448
|
const value = JSON.parse(result.stdout);
|
|
449
|
+
const bundleIdentifier = typeof value.bundleIdentifier === "string" ? value.bundleIdentifier : void 0;
|
|
177
450
|
return {
|
|
178
451
|
name: assertStringField(value.name, "name"),
|
|
179
452
|
version: typeof value.version === "string" ? value.version : void 0,
|
|
180
|
-
|
|
181
|
-
|
|
453
|
+
buildNumber: typeof value.buildNumber === "string" ? value.buildNumber : void 0,
|
|
454
|
+
bundleIdentifier,
|
|
455
|
+
appGroups: normalizeAppGroups(value.appGroups, bundleIdentifier),
|
|
456
|
+
teamId: typeof value.teamId === "string" ? value.teamId : void 0,
|
|
457
|
+
appearance: normalizeAppearance(value.appearance)
|
|
182
458
|
};
|
|
183
459
|
}
|
|
184
460
|
function assertBleamConfigFiles(projectRoot) {
|
|
@@ -197,8 +473,11 @@ function readProjectConfig(options) {
|
|
|
197
473
|
return {
|
|
198
474
|
name: config.name,
|
|
199
475
|
version: config.version,
|
|
476
|
+
buildNumber: config.buildNumber ?? "1",
|
|
200
477
|
bundleIdentifier: config.bundleIdentifier,
|
|
478
|
+
appGroups: config.appGroups ?? [],
|
|
201
479
|
teamId: config.teamId,
|
|
480
|
+
appearance: config.appearance ?? normalizeAppearance(void 0),
|
|
202
481
|
runtimeVersion,
|
|
203
482
|
sdkVersion: runtimeVersion
|
|
204
483
|
};
|
|
@@ -211,20 +490,43 @@ function nameFromDirectory(projectRoot) {
|
|
|
211
490
|
if (!name) return "Bleam App";
|
|
212
491
|
return name.replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
213
492
|
}
|
|
214
|
-
function
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
(0, node_fs.
|
|
493
|
+
function singleQuotedString(value) {
|
|
494
|
+
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\r/g, "\\r").replace(/\n/g, "\\n")}'`;
|
|
495
|
+
}
|
|
496
|
+
function updateStarterAppName(projectRoot, name) {
|
|
497
|
+
const appPath = node_path.default.join(projectRoot, "app", "index.tsx");
|
|
498
|
+
const source = (0, node_fs.readFileSync)(appPath, "utf8");
|
|
499
|
+
const placeholder = `const appName = ${singleQuotedString(starterAppName)}`;
|
|
500
|
+
if (!source.includes(placeholder)) throw new Error(`Missing starter app name placeholder: ${appPath}`);
|
|
501
|
+
(0, node_fs.writeFileSync)(appPath, source.replace(placeholder, `const appName = ${singleQuotedString(name)}`));
|
|
502
|
+
}
|
|
503
|
+
function createProject(options) {
|
|
504
|
+
const template = options.template ?? "basic";
|
|
505
|
+
const templateRoot = node_path.default.join(packageRoot, "templates", template);
|
|
506
|
+
if (!(0, node_fs.existsSync)(templateRoot)) throw new Error(`Missing ${template} template: ${templateRoot}`);
|
|
507
|
+
if ((0, node_fs.existsSync)(options.projectRoot)) throw new Error(`Destination already exists: ${options.projectRoot}`);
|
|
220
508
|
const name = nameFromDirectory(options.projectRoot);
|
|
221
|
-
(0, node_fs.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
name
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
509
|
+
(0, node_fs.mkdirSync)(options.projectRoot, { recursive: true });
|
|
510
|
+
try {
|
|
511
|
+
(0, node_fs.cpSync)(templateRoot, options.projectRoot, { recursive: true });
|
|
512
|
+
updateStarterAppName(options.projectRoot, name);
|
|
513
|
+
(0, node_fs.writeFileSync)(node_path.default.join(options.projectRoot, "app.config.ts"), `import { appConfig } from 'bleam'\n\nexport default appConfig({\n name: ${singleQuotedString(name)},\n})\n`);
|
|
514
|
+
(0, node_fs.writeFileSync)(node_path.default.join(options.projectRoot, ".gitignore"), `.bleam\nbiome.json\n.DS_Store\n`);
|
|
515
|
+
createDevWorkspace(options.projectRoot, {
|
|
516
|
+
name,
|
|
517
|
+
buildNumber: "1",
|
|
518
|
+
appGroups: [],
|
|
519
|
+
appearance: normalizeAppearance(void 0),
|
|
520
|
+
runtimeVersion,
|
|
521
|
+
sdkVersion: runtimeVersion
|
|
522
|
+
});
|
|
523
|
+
} catch (error) {
|
|
524
|
+
(0, node_fs.rmSync)(options.projectRoot, {
|
|
525
|
+
recursive: true,
|
|
526
|
+
force: true
|
|
527
|
+
});
|
|
528
|
+
throw error;
|
|
529
|
+
}
|
|
228
530
|
console.log(`Created Bleam project at ${options.projectRoot}`);
|
|
229
531
|
}
|
|
230
532
|
function createDevWorkspace(projectRoot, config) {
|
|
@@ -238,14 +540,23 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
238
540
|
});
|
|
239
541
|
(0, node_fs.symlinkSync)(dependencyRoot, workspaceNodeModules);
|
|
240
542
|
ensureProjectTsconfig(projectRoot);
|
|
241
|
-
|
|
543
|
+
const expoConfig = {
|
|
242
544
|
name: config.name,
|
|
243
545
|
slug: slugFromName(config.name),
|
|
244
546
|
version: config.version ?? "0.0.0",
|
|
245
547
|
orientation: "default",
|
|
246
548
|
platforms: ["ios"],
|
|
247
|
-
newArchEnabled: true
|
|
248
|
-
|
|
549
|
+
newArchEnabled: true,
|
|
550
|
+
extra: { bleam: {
|
|
551
|
+
appearance: config.appearance,
|
|
552
|
+
buildNumber: config.buildNumber,
|
|
553
|
+
runtimeVersion: config.runtimeVersion,
|
|
554
|
+
sdkVersion: config.sdkVersion
|
|
555
|
+
} }
|
|
556
|
+
};
|
|
557
|
+
if ((0, node_fs.existsSync)(node_path.default.join(projectRoot, "icon.png"))) expoConfig.icon = "../../icon.png";
|
|
558
|
+
if ((0, node_fs.existsSync)(node_path.default.join(projectRoot, "splash.png"))) expoConfig.plugins = [["expo-splash-screen", { image: "../../splash.png" }]];
|
|
559
|
+
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "app.config.js"), `module.exports = ${JSON.stringify({ expo: expoConfig }, null, 2)}\n`);
|
|
249
560
|
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "index.js"), `import { registerApp } from 'bleam/app'\nimport App from ${JSON.stringify(node_path.default.join(projectRoot, "app"))}\n\nregisterApp(App)\n`);
|
|
250
561
|
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "metro.config.js"), `const { getDefaultConfig } = require(${JSON.stringify(node_path.default.join(packageRoot, "metro-config.cjs"))})\n\nmodule.exports = getDefaultConfig(__dirname)\n`);
|
|
251
562
|
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "package.json"), `${JSON.stringify({
|
|
@@ -255,7 +566,9 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
255
566
|
main: "index.js",
|
|
256
567
|
dependencies: {
|
|
257
568
|
"@types/react": packageJson.dependencies?.["@types/react"],
|
|
569
|
+
"@biomejs/biome": packageJson.dependencies?.["@biomejs/biome"],
|
|
258
570
|
expo: packageJson.dependencies?.expo,
|
|
571
|
+
"expo-splash-screen": packageJson.dependencies?.["expo-splash-screen"],
|
|
259
572
|
react: packageJson.dependencies?.react,
|
|
260
573
|
"react-native": packageJson.dependencies?.["react-native"],
|
|
261
574
|
typescript: packageJson.dependencies?.typescript
|
|
@@ -265,8 +578,8 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
265
578
|
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "tsconfig.json"), `${JSON.stringify({
|
|
266
579
|
extends: "bleam/tsconfig",
|
|
267
580
|
compilerOptions: { paths: {
|
|
268
|
-
bleam: ["./node_modules/bleam"],
|
|
269
|
-
"bleam/*": ["./node_modules/bleam/*"],
|
|
581
|
+
bleam: ["./node_modules/bleam/dist/index"],
|
|
582
|
+
"bleam/*": ["./node_modules/bleam/dist/*"],
|
|
270
583
|
expo: ["./node_modules/expo"],
|
|
271
584
|
"expo/*": ["./node_modules/expo/*"],
|
|
272
585
|
react: ["./node_modules/@types/react"],
|
|
@@ -279,6 +592,34 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
279
592
|
}, null, 2)}\n`);
|
|
280
593
|
return workspaceRoot;
|
|
281
594
|
}
|
|
595
|
+
function writeBiomeConfig(configPath) {
|
|
596
|
+
(0, node_fs.writeFileSync)(configPath, `${JSON.stringify({
|
|
597
|
+
$schema: "https://biomejs.dev/schemas/2.5.2/schema.json",
|
|
598
|
+
files: { includes: [
|
|
599
|
+
"app/**/*",
|
|
600
|
+
"app.config.ts",
|
|
601
|
+
"tsconfig.json"
|
|
602
|
+
] },
|
|
603
|
+
formatter: {
|
|
604
|
+
enabled: true,
|
|
605
|
+
indentStyle: "space",
|
|
606
|
+
indentWidth: 2,
|
|
607
|
+
lineWidth: 80
|
|
608
|
+
},
|
|
609
|
+
javascript: { formatter: {
|
|
610
|
+
quoteStyle: "single",
|
|
611
|
+
semicolons: "asNeeded",
|
|
612
|
+
trailingCommas: "all"
|
|
613
|
+
} },
|
|
614
|
+
linter: {
|
|
615
|
+
enabled: true,
|
|
616
|
+
rules: {
|
|
617
|
+
preset: "recommended",
|
|
618
|
+
suspicious: { noExplicitAny: "off" }
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}, null, 2)}\n`);
|
|
622
|
+
}
|
|
282
623
|
function writeProjectRuntimeConfig(projectRoot, config, origin) {
|
|
283
624
|
const projectConfigPath = node_path.default.join(projectRoot, ".bleam", "project.json");
|
|
284
625
|
(0, node_fs.mkdirSync)(node_path.default.dirname(projectConfigPath), { recursive: true });
|
|
@@ -287,28 +628,463 @@ function writeProjectRuntimeConfig(projectRoot, config, origin) {
|
|
|
287
628
|
version: config.version,
|
|
288
629
|
bundleIdentifier: config.bundleIdentifier,
|
|
289
630
|
teamId: config.teamId,
|
|
631
|
+
appearance: config.appearance,
|
|
290
632
|
devServer: origin,
|
|
291
633
|
runtimeVersion: config.runtimeVersion,
|
|
292
634
|
sdkVersion: config.sdkVersion
|
|
293
635
|
}, null, 2)}\n`);
|
|
294
636
|
return projectConfigPath;
|
|
295
637
|
}
|
|
638
|
+
function nativeRuntimeTemplateRoot() {
|
|
639
|
+
return node_path.default.resolve(packageRoot, "..", "..", "app", "bleam");
|
|
640
|
+
}
|
|
641
|
+
function safeArtifactName(name) {
|
|
642
|
+
return name.trim().replace(/[/:\\]/g, "-").replace(/\s+/g, " ") || "App";
|
|
643
|
+
}
|
|
644
|
+
function xcodeSettingValue(value) {
|
|
645
|
+
if (/^[A-Za-z0-9_.$-]+$/.test(value)) return value;
|
|
646
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
647
|
+
}
|
|
648
|
+
function plistString(value) {
|
|
649
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
650
|
+
}
|
|
651
|
+
function replacePlistString(plist, key, value) {
|
|
652
|
+
const pattern = /* @__PURE__ */ new RegExp(`(<key>${key}</key>\\s*<string>)([^<]*)(</string>)`);
|
|
653
|
+
if (!pattern.test(plist)) return plist;
|
|
654
|
+
return plist.replace(pattern, `$1${plistString(value)}$3`);
|
|
655
|
+
}
|
|
656
|
+
function plistStringArray(values) {
|
|
657
|
+
return values.map((value) => `\t\t<string>${plistString(value)}</string>`).join("\n");
|
|
658
|
+
}
|
|
659
|
+
function replaceOrInsertPlistString(plist, key, value) {
|
|
660
|
+
const replaced = replacePlistString(plist, key, value);
|
|
661
|
+
if (replaced !== plist) return replaced;
|
|
662
|
+
const closingDictionary = plist.lastIndexOf("</dict>");
|
|
663
|
+
if (closingDictionary < 0) return plist;
|
|
664
|
+
return `${plist.slice(0, closingDictionary)}\t<key>${key}</key>\n\t<string>${plistString(value)}</string>\n${plist.slice(closingDictionary)}`;
|
|
665
|
+
}
|
|
666
|
+
function replaceOrInsertPlistStringArray(plist, key, values) {
|
|
667
|
+
const pattern = /* @__PURE__ */ new RegExp(`(<key>${key}</key>\\s*<array>)([\\s\\S]*?)(</array>)`);
|
|
668
|
+
const replacement = `$1\n${plistStringArray(values)}\n\t$3`;
|
|
669
|
+
if (pattern.test(plist)) return plist.replace(pattern, replacement);
|
|
670
|
+
const closingDictionary = plist.lastIndexOf("</dict>");
|
|
671
|
+
if (closingDictionary < 0) return plist;
|
|
672
|
+
return `${plist.slice(0, closingDictionary)}\t<key>${key}</key>\n\t<array>\n${plistStringArray(values)}\n\t</array>\n${plist.slice(closingDictionary)}`;
|
|
673
|
+
}
|
|
674
|
+
function writeGeneratedAppJson(nativeRoot, config) {
|
|
675
|
+
(0, node_fs.writeFileSync)(node_path.default.join(nativeRoot, "app.json"), `${JSON.stringify({ expo: {
|
|
676
|
+
name: config.name,
|
|
677
|
+
slug: slugFromName(config.name),
|
|
678
|
+
version: config.version ?? "1.0.0",
|
|
679
|
+
platforms: ["ios"],
|
|
680
|
+
ios: {
|
|
681
|
+
appleTeamId: config.teamId,
|
|
682
|
+
buildNumber: config.buildNumber,
|
|
683
|
+
bundleIdentifier: config.bundleIdentifier
|
|
684
|
+
}
|
|
685
|
+
} }, null, 2)}\n`);
|
|
686
|
+
}
|
|
687
|
+
function patchNativeProject(nativeRoot, config) {
|
|
688
|
+
const projectPath = node_path.default.join(nativeRoot, "ios", "Bleam.xcodeproj", "project.pbxproj");
|
|
689
|
+
const infoPlistPath = node_path.default.join(nativeRoot, "ios", "Bleam", "Info.plist");
|
|
690
|
+
const generationInfoPlistPath = node_path.default.join(nativeRoot, "ios", "GenerationService", "Info.plist");
|
|
691
|
+
const platformInfoPlistPath = node_path.default.join(nativeRoot, "ios", "PlatformHelper", "Info.plist");
|
|
692
|
+
const appEntitlementsPath = node_path.default.join(nativeRoot, "ios", "Bleam", "bleam.entitlements");
|
|
693
|
+
const generationEntitlementsPath = node_path.default.join(nativeRoot, "ios", "GenerationService", "GenerationService.entitlements");
|
|
694
|
+
const productName = xcodeSettingValue(config.name);
|
|
695
|
+
const bundleIdentifier = xcodeSettingValue(config.bundleIdentifier ?? "");
|
|
696
|
+
const generationBundleIdentifier = xcodeSettingValue(`${config.bundleIdentifier}.GenerationService`);
|
|
697
|
+
const platformBundleIdentifier = xcodeSettingValue(`${config.bundleIdentifier}.PlatformHelper`);
|
|
698
|
+
const teamId = xcodeSettingValue(config.teamId ?? "");
|
|
699
|
+
const version = xcodeSettingValue(config.version ?? "1.0.0");
|
|
700
|
+
const buildNumber = xcodeSettingValue(config.buildNumber);
|
|
701
|
+
const primaryAppGroup = config.appGroups[0];
|
|
702
|
+
let project = (0, node_fs.readFileSync)(projectPath, "utf8");
|
|
703
|
+
project = project.replace(/PRODUCT_BUNDLE_IDENTIFIER = ([^;]+);/g, (_, current) => {
|
|
704
|
+
return `PRODUCT_BUNDLE_IDENTIFIER = ${current.endsWith(".GenerationService") ? generationBundleIdentifier : current.endsWith(".PlatformHelper") ? platformBundleIdentifier : bundleIdentifier};`;
|
|
705
|
+
}).replace(/DEVELOPMENT_TEAM = [^;]+;/g, () => {
|
|
706
|
+
return `DEVELOPMENT_TEAM = ${teamId};`;
|
|
707
|
+
}).replace(/MARKETING_VERSION = [^;]+;/g, () => {
|
|
708
|
+
return `MARKETING_VERSION = ${version};`;
|
|
709
|
+
}).replace(/CURRENT_PROJECT_VERSION = [^;]+;/g, () => {
|
|
710
|
+
return `CURRENT_PROJECT_VERSION = ${buildNumber};`;
|
|
711
|
+
}).replace(/PRODUCT_NAME = bleam;/g, () => {
|
|
712
|
+
return `PRODUCT_NAME = ${productName};`;
|
|
713
|
+
});
|
|
714
|
+
(0, node_fs.writeFileSync)(projectPath, project);
|
|
715
|
+
let infoPlist = (0, node_fs.readFileSync)(infoPlistPath, "utf8");
|
|
716
|
+
infoPlist = replacePlistString(infoPlist, "CFBundleDisplayName", config.name);
|
|
717
|
+
infoPlist = replacePlistString(infoPlist, "CFBundleShortVersionString", config.version ?? "1.0.0");
|
|
718
|
+
infoPlist = replaceOrInsertPlistString(infoPlist, "BleamRuntimeVersion", config.runtimeVersion);
|
|
719
|
+
infoPlist = replaceOrInsertPlistString(infoPlist, "BleamTeamIdentifier", config.teamId ?? "");
|
|
720
|
+
const updateServiceUrl = process.env.BLEAM_UPDATE_SERVICE_URL;
|
|
721
|
+
if (updateServiceUrl) infoPlist = replaceOrInsertPlistString(infoPlist, "BleamUpdateServiceURL", updateServiceUrl);
|
|
722
|
+
infoPlist = replacePlistString(infoPlist, "CFBundleVersion", config.buildNumber);
|
|
723
|
+
if (primaryAppGroup) infoPlist = replaceOrInsertPlistString(infoPlist, "AppGroupIdentifier", primaryAppGroup);
|
|
724
|
+
(0, node_fs.writeFileSync)(infoPlistPath, infoPlist);
|
|
725
|
+
if (primaryAppGroup) {
|
|
726
|
+
let generationInfoPlist = (0, node_fs.readFileSync)(generationInfoPlistPath, "utf8");
|
|
727
|
+
generationInfoPlist = replaceOrInsertPlistString(generationInfoPlist, "AppGroupIdentifier", primaryAppGroup);
|
|
728
|
+
(0, node_fs.writeFileSync)(generationInfoPlistPath, generationInfoPlist);
|
|
729
|
+
(0, node_fs.writeFileSync)(platformInfoPlistPath, replaceOrInsertPlistString((0, node_fs.readFileSync)(platformInfoPlistPath, "utf8"), "BleamPlatformVersion", config.runtimeVersion));
|
|
730
|
+
for (const entitlementsPath of [appEntitlementsPath, generationEntitlementsPath]) (0, node_fs.writeFileSync)(entitlementsPath, replaceOrInsertPlistStringArray((0, node_fs.readFileSync)(entitlementsPath, "utf8"), "com.apple.security.application-groups", config.appGroups));
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
function createBuildNativeWorkspace(options, config) {
|
|
734
|
+
const nativeRoot = node_path.default.join(options.projectRoot, ".bleam", "build", "native");
|
|
735
|
+
const templateRoot = nativeRuntimeTemplateRoot();
|
|
736
|
+
if (options.clean) (0, node_fs.rmSync)(nativeRoot, {
|
|
737
|
+
recursive: true,
|
|
738
|
+
force: true
|
|
739
|
+
});
|
|
740
|
+
(0, node_fs.mkdirSync)(node_path.default.dirname(nativeRoot), { recursive: true });
|
|
741
|
+
(0, node_fs.cpSync)(templateRoot, nativeRoot, {
|
|
742
|
+
recursive: true,
|
|
743
|
+
verbatimSymlinks: true,
|
|
744
|
+
filter(source) {
|
|
745
|
+
return !node_path.default.relative(templateRoot, source).split(node_path.default.sep).some((part) => {
|
|
746
|
+
return part === "build" || part === "dist" || part === "node_modules" || part === ".expo" || part === "Pods" || part === ".xcode.env.local" || part === ".DS_Store" || part.endsWith(".xcworkspace");
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
const nodeModules = node_path.default.join(nativeRoot, "node_modules");
|
|
751
|
+
(0, node_fs.rmSync)(nodeModules, {
|
|
752
|
+
recursive: true,
|
|
753
|
+
force: true
|
|
754
|
+
});
|
|
755
|
+
(0, node_fs.symlinkSync)(resolvedDependencyRoot(), nodeModules);
|
|
756
|
+
writeGeneratedAppJson(nativeRoot, config);
|
|
757
|
+
(0, node_fs.writeFileSync)(node_path.default.join(nativeRoot, "index.ts"), `import { registerApp } from 'bleam/app'\nimport App from ${JSON.stringify(node_path.default.join(options.projectRoot, "app"))}\n\nregisterApp(App)\n`);
|
|
758
|
+
(0, node_fs.writeFileSync)(node_path.default.join(nativeRoot, "metro.config.js"), `const { getDefaultConfig } = require(${JSON.stringify(node_path.default.join(packageRoot, "metro-config.cjs"))})\n\nmodule.exports = getDefaultConfig(__dirname)\n`);
|
|
759
|
+
(0, node_fs.writeFileSync)(node_path.default.join(nativeRoot, "ios", ".xcode.env"), `export NODE_BINARY=$(command -v node)\nexport BLEAM_PROJECT_ROOT=${singleQuotedString(options.projectRoot)}\nexport BLEAM_DEV_PLATFORM=macos\n`);
|
|
760
|
+
patchNativeProject(nativeRoot, config);
|
|
761
|
+
return nativeRoot;
|
|
762
|
+
}
|
|
763
|
+
function preflightBuild(options, config) {
|
|
764
|
+
if (process.platform !== "darwin") throw new Error(`bleam build requires macOS and Xcode. Current platform: ${process.platform}.\n${doctorHint(options.projectRoot)}`);
|
|
765
|
+
if (!config.bundleIdentifier) throw missingBuildFieldError("bundleIdentifier");
|
|
766
|
+
if (!config.teamId) throw missingBuildFieldError("teamId");
|
|
767
|
+
const templateRoot = nativeRuntimeTemplateRoot();
|
|
768
|
+
if (!(0, node_fs.existsSync)(templateRoot)) throw new Error(`Missing native runtime template: ${templateRoot}\n${doctorHint(options.projectRoot)}`);
|
|
769
|
+
if (!commandSucceeds("pod", ["--version"])) throw new Error(`CocoaPods is required for bleam build, but ${(0, yoctocolors.bold)("pod")} is unavailable.\nInstall CocoaPods, then run bleam build again.\n${doctorHint(options.projectRoot)}`);
|
|
770
|
+
if (!commandSucceeds("xcodebuild", ["-version"])) throw new Error(`Xcode command line tools are required for bleam build, but ${(0, yoctocolors.bold)("xcodebuild")} is unavailable.\nInstall Xcode or run ${(0, yoctocolors.bold)("xcode-select --install")}, then run bleam build again.\n${doctorHint(options.projectRoot)}`);
|
|
771
|
+
}
|
|
772
|
+
function runInheritedCommand(command, args, cwd) {
|
|
773
|
+
const text = commandText(command, args);
|
|
774
|
+
const result = (0, node_child_process.spawnSync)(command, args, {
|
|
775
|
+
cwd,
|
|
776
|
+
stdio: "inherit",
|
|
777
|
+
env: process.env
|
|
778
|
+
});
|
|
779
|
+
if (result.error) throw new Error(`${text} could not start in ${cwd}: ${result.error.message}\n${doctorHint()}`);
|
|
780
|
+
if (result.status !== 0) throw new Error(`${text} failed in ${cwd} with exit code ${result.status ?? "unknown"}.\nNative command output above may contain the underlying Xcode/CocoaPods error.\n${doctorHint()}`);
|
|
781
|
+
}
|
|
782
|
+
function installPods(nativeRoot) {
|
|
783
|
+
const iosRoot = node_path.default.join(nativeRoot, "ios");
|
|
784
|
+
const expectedStamp = podInstallInputStamp(iosRoot);
|
|
785
|
+
if (hasCurrentPodInstall(iosRoot, expectedStamp)) {
|
|
786
|
+
console.log("Using cached native dependencies");
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
console.log("Installing native dependencies...");
|
|
790
|
+
runInheritedCommand("pod", ["install"], iosRoot);
|
|
791
|
+
(0, node_fs.writeFileSync)(podInstallStampPath(iosRoot), `${expectedStamp}\n`);
|
|
792
|
+
}
|
|
793
|
+
function podInstallInputStamp(iosRoot) {
|
|
794
|
+
const inputHash = (0, node_crypto.createHash)("sha256");
|
|
795
|
+
for (const relative of [
|
|
796
|
+
"Podfile",
|
|
797
|
+
"Podfile.lock",
|
|
798
|
+
"../package.json"
|
|
799
|
+
]) {
|
|
800
|
+
const input = node_path.default.resolve(iosRoot, relative);
|
|
801
|
+
if ((0, node_fs.existsSync)(input)) inputHash.update((0, node_fs.readFileSync)(input));
|
|
802
|
+
}
|
|
803
|
+
return inputHash.digest("hex");
|
|
804
|
+
}
|
|
805
|
+
function podInstallStampPath(iosRoot) {
|
|
806
|
+
return node_path.default.join(iosRoot, ".bleam-pods-input");
|
|
807
|
+
}
|
|
808
|
+
function hasCurrentPodInstall(iosRoot, expectedStamp) {
|
|
809
|
+
const stampPath = podInstallStampPath(iosRoot);
|
|
810
|
+
return (0, node_fs.existsSync)(node_path.default.join(iosRoot, "Bleam.xcworkspace")) && (0, node_fs.existsSync)(node_path.default.join(iosRoot, "Pods", "Manifest.lock")) && (0, node_fs.existsSync)(stampPath) && (0, node_fs.readFileSync)(stampPath, "utf8").trim() === expectedStamp;
|
|
811
|
+
}
|
|
812
|
+
function nativeArchiveArgs(options) {
|
|
813
|
+
return [
|
|
814
|
+
"-allowProvisioningUpdates",
|
|
815
|
+
"-workspace",
|
|
816
|
+
node_path.default.join(options.nativeRoot, "ios", "Bleam.xcworkspace"),
|
|
817
|
+
"-scheme",
|
|
818
|
+
"Bleam",
|
|
819
|
+
"-configuration",
|
|
820
|
+
options.configuration,
|
|
821
|
+
"-destination",
|
|
822
|
+
"platform=macOS,arch=arm64,variant=Mac Catalyst",
|
|
823
|
+
"-archivePath",
|
|
824
|
+
options.archivePath,
|
|
825
|
+
"ARCHS=arm64",
|
|
826
|
+
"archive"
|
|
827
|
+
];
|
|
828
|
+
}
|
|
829
|
+
function archiveNativeApp(options) {
|
|
830
|
+
const platformOutput = node_path.default.join(options.outputRoot, "macos");
|
|
831
|
+
const archivePath = node_path.default.join(platformOutput, `${safeArtifactName(options.config.name)}.xcarchive`);
|
|
832
|
+
(0, node_fs.mkdirSync)(platformOutput, { recursive: true });
|
|
833
|
+
(0, node_fs.rmSync)(archivePath, {
|
|
834
|
+
recursive: true,
|
|
835
|
+
force: true
|
|
836
|
+
});
|
|
837
|
+
console.log(`Archiving ${options.config.name} for macOS...`);
|
|
838
|
+
runInheritedCommand("xcodebuild", nativeArchiveArgs({
|
|
839
|
+
nativeRoot: options.nativeRoot,
|
|
840
|
+
archivePath,
|
|
841
|
+
configuration: options.configuration
|
|
842
|
+
}), options.nativeRoot);
|
|
843
|
+
return archivePath;
|
|
844
|
+
}
|
|
845
|
+
function exportNativeArchive(options) {
|
|
846
|
+
const exportPath = node_path.default.join(options.outputRoot, "macos", "export");
|
|
847
|
+
(0, node_fs.rmSync)(exportPath, {
|
|
848
|
+
recursive: true,
|
|
849
|
+
force: true
|
|
850
|
+
});
|
|
851
|
+
(0, node_fs.mkdirSync)(exportPath, { recursive: true });
|
|
852
|
+
console.log("Exporting macOS archive...");
|
|
853
|
+
runInheritedCommand("xcodebuild", [
|
|
854
|
+
"-allowProvisioningUpdates",
|
|
855
|
+
"-exportArchive",
|
|
856
|
+
"-archivePath",
|
|
857
|
+
options.archivePath,
|
|
858
|
+
"-exportPath",
|
|
859
|
+
exportPath,
|
|
860
|
+
"-exportOptionsPlist",
|
|
861
|
+
options.exportOptionsPlist
|
|
862
|
+
], node_path.default.dirname(options.archivePath));
|
|
863
|
+
return exportPath;
|
|
864
|
+
}
|
|
865
|
+
async function buildNativeArchives(options) {
|
|
866
|
+
const config = readProjectConfig(options);
|
|
867
|
+
preflightBuild(options, config);
|
|
868
|
+
const nativeRoot = createBuildNativeWorkspace(options, config);
|
|
869
|
+
installPods(nativeRoot);
|
|
870
|
+
const archivePath = archiveNativeApp({
|
|
871
|
+
nativeRoot,
|
|
872
|
+
outputRoot: options.output,
|
|
873
|
+
configuration: options.configuration,
|
|
874
|
+
config
|
|
875
|
+
});
|
|
876
|
+
console.log(`Created ${archivePath}`);
|
|
877
|
+
if (options.exportOptionsPlist) {
|
|
878
|
+
const exportPath = exportNativeArchive({
|
|
879
|
+
archivePath,
|
|
880
|
+
outputRoot: options.output,
|
|
881
|
+
exportOptionsPlist: options.exportOptionsPlist
|
|
882
|
+
});
|
|
883
|
+
console.log(`Exported ${exportPath}`);
|
|
884
|
+
}
|
|
885
|
+
return archivePath;
|
|
886
|
+
}
|
|
887
|
+
async function installNativeApp(options) {
|
|
888
|
+
const destination = installArchivedApp(await buildNativeArchives(options));
|
|
889
|
+
console.log(`Installed ${destination}`);
|
|
890
|
+
}
|
|
891
|
+
function installArchivedApp(archivePath, applications = node_path.default.join(node_os.default.homedir(), "Applications")) {
|
|
892
|
+
const products = node_path.default.join(archivePath, "Products", "Applications");
|
|
893
|
+
const appName = (0, node_fs.readdirSync)(products).find((name) => name.endsWith(".app"));
|
|
894
|
+
if (!appName) throw new Error(`Archive does not contain a macOS app: ${archivePath}`);
|
|
895
|
+
const source = node_path.default.join(products, appName);
|
|
896
|
+
const destination = applications === node_path.default.join(node_os.default.homedir(), "Applications") ? installedAppPath(appName) : node_path.default.join(applications, appName);
|
|
897
|
+
(0, node_fs.mkdirSync)(applications, { recursive: true });
|
|
898
|
+
(0, node_fs.rmSync)(destination, {
|
|
899
|
+
recursive: true,
|
|
900
|
+
force: true
|
|
901
|
+
});
|
|
902
|
+
(0, node_child_process.execFileSync)("ditto", [source, destination], { stdio: "inherit" });
|
|
903
|
+
return destination;
|
|
904
|
+
}
|
|
905
|
+
function installedAppPath(appName) {
|
|
906
|
+
if (node_path.default.basename(appName) !== appName || !appName.endsWith(".app")) throw new Error(`Invalid macOS app name: ${appName}`);
|
|
907
|
+
return node_path.default.join(node_os.default.homedir(), "Applications", appName);
|
|
908
|
+
}
|
|
909
|
+
async function publishOta(options) {
|
|
910
|
+
const config = readProjectConfig(options);
|
|
911
|
+
if (!config.bundleIdentifier) throw missingBuildFieldError("bundleIdentifier");
|
|
912
|
+
if (!config.teamId) throw missingBuildFieldError("teamId");
|
|
913
|
+
const workspaceRoot = createBuildNativeWorkspace({
|
|
914
|
+
projectRoot: options.projectRoot,
|
|
915
|
+
output: node_path.default.join(options.projectRoot, "dist"),
|
|
916
|
+
configuration: "Release",
|
|
917
|
+
clean: false
|
|
918
|
+
}, config);
|
|
919
|
+
const outputRoot = node_path.default.join(options.projectRoot, ".bleam", "publish", "ota");
|
|
920
|
+
const bundleRoot = node_path.default.join(outputRoot, "bundle");
|
|
921
|
+
const bundlePath = node_path.default.join(bundleRoot, "bundle.js");
|
|
922
|
+
const archivePath = node_path.default.join(outputRoot, "ota.zip");
|
|
923
|
+
(0, node_fs.rmSync)(outputRoot, {
|
|
924
|
+
recursive: true,
|
|
925
|
+
force: true
|
|
926
|
+
});
|
|
927
|
+
(0, node_fs.mkdirSync)(bundleRoot, { recursive: true });
|
|
928
|
+
console.log(`Bundling OTA update for runtime ${runtimeVersion}...`);
|
|
929
|
+
runInheritedCommand(process.execPath, [
|
|
930
|
+
require$1.resolve("@expo/cli"),
|
|
931
|
+
"export:embed",
|
|
932
|
+
"--entry-file",
|
|
933
|
+
node_path.default.join(workspaceRoot, "index.ts"),
|
|
934
|
+
"--platform",
|
|
935
|
+
"ios",
|
|
936
|
+
"--dev",
|
|
937
|
+
"false",
|
|
938
|
+
"--bundle-output",
|
|
939
|
+
bundlePath,
|
|
940
|
+
"--assets-dest",
|
|
941
|
+
node_path.default.join(bundleRoot, "assets"),
|
|
942
|
+
"--minify",
|
|
943
|
+
"true"
|
|
944
|
+
], workspaceRoot);
|
|
945
|
+
runInheritedCommand("ditto", [
|
|
946
|
+
"-c",
|
|
947
|
+
"-k",
|
|
948
|
+
"--keepParent",
|
|
949
|
+
bundleRoot,
|
|
950
|
+
archivePath
|
|
951
|
+
], outputRoot);
|
|
952
|
+
const sizeBytes = (0, node_fs.readFileSync)(archivePath).byteLength;
|
|
953
|
+
const digest = sha256(archivePath);
|
|
954
|
+
const releaseId = `ota_${Date.now().toString(36)}_${digest.slice(0, 12)}`;
|
|
955
|
+
const release = {
|
|
956
|
+
schemaVersion: 1,
|
|
957
|
+
kind: "ota",
|
|
958
|
+
bundleIdentifier: config.bundleIdentifier,
|
|
959
|
+
teamIdentifier: config.teamId,
|
|
960
|
+
channel: "stable",
|
|
961
|
+
releaseId,
|
|
962
|
+
bundleVersion: `${config.version ?? "1.0.0"}+${config.buildNumber}`,
|
|
963
|
+
runtimeVersion,
|
|
964
|
+
artifact: {
|
|
965
|
+
format: "bleam-ota-zip-v1",
|
|
966
|
+
downloadId: releaseId,
|
|
967
|
+
sizeBytes,
|
|
968
|
+
sha256: digest
|
|
969
|
+
},
|
|
970
|
+
publishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
971
|
+
};
|
|
972
|
+
const response = await fetch(`${options.serviceUrl}/v1/local/releases/ota`, {
|
|
973
|
+
method: "POST",
|
|
974
|
+
headers: { "content-type": "application/json" },
|
|
975
|
+
body: JSON.stringify({
|
|
976
|
+
release,
|
|
977
|
+
artifactBase64: (0, node_fs.readFileSync)(archivePath).toString("base64")
|
|
978
|
+
})
|
|
979
|
+
});
|
|
980
|
+
if (!response.ok) throw new Error(`Local OTA publication failed: ${response.status} ${await response.text()}`);
|
|
981
|
+
console.log(`Published OTA update ${releaseId}`);
|
|
982
|
+
console.log(`${options.serviceUrl}/v1/apps/${encodeURIComponent(config.bundleIdentifier)}/ota/${runtimeVersion}`);
|
|
983
|
+
}
|
|
984
|
+
async function publishPlatform(options) {
|
|
985
|
+
const config = readProjectConfig(options);
|
|
986
|
+
if (!config.bundleIdentifier) throw missingBuildFieldError("bundleIdentifier");
|
|
987
|
+
if (!config.teamId) throw missingBuildFieldError("teamId");
|
|
988
|
+
const archivePath = await buildNativeArchives({
|
|
989
|
+
projectRoot: options.projectRoot,
|
|
990
|
+
output: node_path.default.join(options.projectRoot, "dist"),
|
|
991
|
+
configuration: "Release",
|
|
992
|
+
clean: false
|
|
993
|
+
});
|
|
994
|
+
const products = node_path.default.join(archivePath, "Products", "Applications");
|
|
995
|
+
const appName = (0, node_fs.readdirSync)(products).find((name) => name.endsWith(".app"));
|
|
996
|
+
if (!appName) throw new Error(`Archive does not contain a macOS app: ${archivePath}`);
|
|
997
|
+
const outputRoot = node_path.default.join(options.projectRoot, ".bleam", "publish", "platform");
|
|
998
|
+
const stagingRoot = node_path.default.join(outputRoot, "app");
|
|
999
|
+
const artifactPath = node_path.default.join(outputRoot, "platform.zip");
|
|
1000
|
+
(0, node_fs.rmSync)(outputRoot, {
|
|
1001
|
+
recursive: true,
|
|
1002
|
+
force: true
|
|
1003
|
+
});
|
|
1004
|
+
(0, node_fs.mkdirSync)(stagingRoot, { recursive: true });
|
|
1005
|
+
(0, node_child_process.execFileSync)("ditto", [node_path.default.join(products, appName), node_path.default.join(stagingRoot, appName)]);
|
|
1006
|
+
runInheritedCommand("zip", [
|
|
1007
|
+
"-q",
|
|
1008
|
+
"-r",
|
|
1009
|
+
"-y",
|
|
1010
|
+
artifactPath,
|
|
1011
|
+
"app"
|
|
1012
|
+
], outputRoot);
|
|
1013
|
+
const sizeBytes = (0, node_fs.readFileSync)(artifactPath).byteLength;
|
|
1014
|
+
const digest = sha256(artifactPath);
|
|
1015
|
+
const releaseId = `platform_${Date.now().toString(36)}_${digest.slice(0, 12)}`;
|
|
1016
|
+
const release = platformRelease(config, releaseId, sizeBytes, digest);
|
|
1017
|
+
const response = await fetch(`${options.serviceUrl}/v1/local/releases/platform`, {
|
|
1018
|
+
method: "POST",
|
|
1019
|
+
headers: { "content-type": "application/json" },
|
|
1020
|
+
body: JSON.stringify({
|
|
1021
|
+
release,
|
|
1022
|
+
artifactBase64: (0, node_fs.readFileSync)(artifactPath).toString("base64")
|
|
1023
|
+
})
|
|
1024
|
+
});
|
|
1025
|
+
if (!response.ok) throw new Error(`Local platform publication failed: ${response.status} ${await response.text()}`);
|
|
1026
|
+
console.log(`Published platform update ${releaseId}`);
|
|
1027
|
+
console.log(`${options.serviceUrl}/v1/apps/${encodeURIComponent(config.bundleIdentifier)}/platform/macos-arm64`);
|
|
1028
|
+
}
|
|
1029
|
+
function platformRelease(config, releaseId, sizeBytes, digest) {
|
|
1030
|
+
if (!config.bundleIdentifier) throw missingBuildFieldError("bundleIdentifier");
|
|
1031
|
+
if (!config.teamId) throw missingBuildFieldError("teamId");
|
|
1032
|
+
return {
|
|
1033
|
+
schemaVersion: 1,
|
|
1034
|
+
kind: "platform",
|
|
1035
|
+
bundleIdentifier: config.bundleIdentifier,
|
|
1036
|
+
teamIdentifier: config.teamId,
|
|
1037
|
+
channel: "stable",
|
|
1038
|
+
releaseId,
|
|
1039
|
+
appVersion: config.version ?? "1.0.0",
|
|
1040
|
+
buildNumber: config.buildNumber,
|
|
1041
|
+
bleamPlatformVersion: runtimeVersion,
|
|
1042
|
+
target: {
|
|
1043
|
+
os: "macos",
|
|
1044
|
+
architecture: "arm64",
|
|
1045
|
+
installLocation: "user-applications",
|
|
1046
|
+
minimumMacOSVersion: "14.0"
|
|
1047
|
+
},
|
|
1048
|
+
artifact: {
|
|
1049
|
+
format: "bleam-macos-app-zip-v1",
|
|
1050
|
+
downloadId: releaseId,
|
|
1051
|
+
sizeBytes,
|
|
1052
|
+
sha256: digest
|
|
1053
|
+
},
|
|
1054
|
+
publishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
296
1057
|
function runtimeCacheRoot() {
|
|
297
|
-
return node_path.default.join(node_os.default.homedir(), "Library", "Caches", "bleam", "runtimes", runtimeVersion,
|
|
1058
|
+
return node_path.default.join(node_os.default.homedir(), "Library", "Caches", "bleam", "runtimes", runtimeVersion, artifactPlatform());
|
|
298
1059
|
}
|
|
299
1060
|
function localDevelopmentRuntimeAppPath() {
|
|
300
|
-
|
|
1061
|
+
const productsRoot = node_path.default.resolve(packageRoot, "..", "..", "app", "bleam", "build", "Build", "Products", "Debug-maccatalyst");
|
|
1062
|
+
for (const appName of ["Bleam.app", "bleam.app"]) {
|
|
1063
|
+
const appPath = node_path.default.join(productsRoot, appName);
|
|
1064
|
+
if ((0, node_fs.existsSync)(appPath)) return appPath;
|
|
1065
|
+
}
|
|
1066
|
+
return node_path.default.join(productsRoot, "Bleam.app");
|
|
301
1067
|
}
|
|
302
1068
|
function runtimeReleaseBaseUrl() {
|
|
303
1069
|
return process.env.BLEAM_RUNTIME_RELEASE_BASE_URL ?? "https://github.com/bajedev/bleam-app/releases/download";
|
|
304
1070
|
}
|
|
305
1071
|
function runtimeArchiveName() {
|
|
306
|
-
return `bleam-runtime-v${runtimeVersion}-${
|
|
1072
|
+
return `bleam-runtime-v${runtimeVersion}-${artifactPlatform()}.zip`;
|
|
307
1073
|
}
|
|
308
1074
|
function runtimeArchiveUrl() {
|
|
309
1075
|
const tag = encodeURIComponent(`bleam@${runtimeVersion}`);
|
|
310
1076
|
return `${runtimeReleaseBaseUrl()}/${tag}/${runtimeArchiveName()}`;
|
|
311
1077
|
}
|
|
1078
|
+
function runtimeResolutionDetails() {
|
|
1079
|
+
return [
|
|
1080
|
+
`Runtime version: ${runtimeVersion}`,
|
|
1081
|
+
`Runtime platform: ${artifactPlatform()}`,
|
|
1082
|
+
`Runtime cache: ${runtimeCacheRoot()}`,
|
|
1083
|
+
`Release URL: ${runtimeArchiveUrl()}`,
|
|
1084
|
+
`Override with BLEAM_RUNTIME_APP=/path/to/Bleam.app for local testing.`,
|
|
1085
|
+
doctorHint()
|
|
1086
|
+
].join("\n");
|
|
1087
|
+
}
|
|
312
1088
|
function sha256(filePath) {
|
|
313
1089
|
return (0, node_crypto.createHash)("sha256").update((0, node_fs.readFileSync)(filePath)).digest("hex");
|
|
314
1090
|
}
|
|
@@ -323,19 +1099,26 @@ async function downloadExpectedSha256(url) {
|
|
|
323
1099
|
return (await response.text()).trim().split(/\s+/)[0];
|
|
324
1100
|
}
|
|
325
1101
|
async function downloadRuntimeArtifact() {
|
|
326
|
-
if (process.platform !== "darwin") throw new Error("Bleam runtime artifacts are currently only available
|
|
1102
|
+
if (process.platform !== "darwin") throw new Error("Bleam runtime artifacts are currently only available from macOS hosts.");
|
|
1103
|
+
const runtimePlatform = artifactPlatform();
|
|
327
1104
|
const cacheRoot = runtimeCacheRoot();
|
|
328
1105
|
const cachedAppPath = node_path.default.join(cacheRoot, "Bleam.app");
|
|
329
|
-
if ((0, node_fs.existsSync)(cachedAppPath))
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
1106
|
+
if ((0, node_fs.existsSync)(cachedAppPath)) {
|
|
1107
|
+
console.log(`Using cached Bleam runtime at ${prettyPath(cachedAppPath)}`);
|
|
1108
|
+
return {
|
|
1109
|
+
appPath: cachedAppPath,
|
|
1110
|
+
version: runtimeVersion,
|
|
1111
|
+
platform: runtimePlatform
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
334
1114
|
(0, node_fs.mkdirSync)(cacheRoot, { recursive: true });
|
|
335
1115
|
const archiveUrl = runtimeArchiveUrl();
|
|
336
1116
|
const archivePath = node_path.default.join(cacheRoot, runtimeArchiveName());
|
|
337
1117
|
const extractRoot = node_path.default.join(cacheRoot, "extract");
|
|
1118
|
+
console.log(`Downloading Bleam runtime ${runtimeVersion} for ${runtimePlatform}`);
|
|
1119
|
+
console.log(`Runtime archive: ${archiveUrl}`);
|
|
338
1120
|
await downloadFile(archiveUrl, archivePath);
|
|
1121
|
+
console.log("Verifying Bleam runtime archive");
|
|
339
1122
|
const expectedSha256 = await downloadExpectedSha256(archiveUrl);
|
|
340
1123
|
if (expectedSha256 && sha256(archivePath) !== expectedSha256) {
|
|
341
1124
|
(0, node_fs.rmSync)(archivePath, { force: true });
|
|
@@ -346,6 +1129,7 @@ async function downloadRuntimeArtifact() {
|
|
|
346
1129
|
force: true
|
|
347
1130
|
});
|
|
348
1131
|
(0, node_fs.mkdirSync)(extractRoot, { recursive: true });
|
|
1132
|
+
console.log("Extracting Bleam runtime archive");
|
|
349
1133
|
(0, node_child_process.execFileSync)("ditto", [
|
|
350
1134
|
"-x",
|
|
351
1135
|
"-k",
|
|
@@ -358,11 +1142,15 @@ async function downloadRuntimeArtifact() {
|
|
|
358
1142
|
recursive: true,
|
|
359
1143
|
force: true
|
|
360
1144
|
});
|
|
361
|
-
(0, node_fs.cpSync)(extractedAppPath, cachedAppPath, {
|
|
1145
|
+
(0, node_fs.cpSync)(extractedAppPath, cachedAppPath, {
|
|
1146
|
+
recursive: true,
|
|
1147
|
+
verbatimSymlinks: true
|
|
1148
|
+
});
|
|
362
1149
|
(0, node_fs.rmSync)(extractRoot, {
|
|
363
1150
|
recursive: true,
|
|
364
1151
|
force: true
|
|
365
1152
|
});
|
|
1153
|
+
console.log(`Cached Bleam runtime at ${prettyPath(cachedAppPath)}`);
|
|
366
1154
|
return {
|
|
367
1155
|
appPath: cachedAppPath,
|
|
368
1156
|
version: runtimeVersion,
|
|
@@ -370,10 +1158,13 @@ async function downloadRuntimeArtifact() {
|
|
|
370
1158
|
};
|
|
371
1159
|
}
|
|
372
1160
|
async function resolveRuntimeArtifact() {
|
|
1161
|
+
const runtimePlatform = artifactPlatform();
|
|
1162
|
+
console.log(`Resolving Bleam runtime ${runtimeVersion} for ${runtimePlatform}`);
|
|
373
1163
|
const overrideAppPath = process.env.BLEAM_RUNTIME_APP;
|
|
374
1164
|
if (overrideAppPath) {
|
|
375
1165
|
const appPath = node_path.default.resolve(overrideAppPath);
|
|
376
|
-
if (!(0, node_fs.existsSync)(appPath)) throw new Error(`BLEAM_RUNTIME_APP
|
|
1166
|
+
if (!(0, node_fs.existsSync)(appPath)) throw new Error(`BLEAM_RUNTIME_APP points to a missing app bundle: ${appPath}\nUnset BLEAM_RUNTIME_APP or point it to a valid Bleam.app.\n${doctorHint()}`);
|
|
1167
|
+
console.log(`Using BLEAM_RUNTIME_APP runtime at ${prettyPath(appPath)}`);
|
|
377
1168
|
return {
|
|
378
1169
|
appPath,
|
|
379
1170
|
version: runtimeVersion,
|
|
@@ -381,23 +1172,47 @@ async function resolveRuntimeArtifact() {
|
|
|
381
1172
|
};
|
|
382
1173
|
}
|
|
383
1174
|
const localAppPath = localDevelopmentRuntimeAppPath();
|
|
384
|
-
if ((0, node_fs.existsSync)(localAppPath))
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
1175
|
+
if ((0, node_fs.existsSync)(localAppPath)) {
|
|
1176
|
+
console.log(`Using local development runtime at ${prettyPath(localAppPath)}`);
|
|
1177
|
+
return {
|
|
1178
|
+
appPath: localAppPath,
|
|
1179
|
+
version: runtimeVersion,
|
|
1180
|
+
platform: runtimePlatform
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
try {
|
|
1184
|
+
return await downloadRuntimeArtifact();
|
|
1185
|
+
} catch (error) {
|
|
1186
|
+
throw new Error(`Failed to resolve the Bleam runtime.\n${runtimeResolutionDetails()}\n\nCause: ${error instanceof Error ? error.message : String(error)}`);
|
|
1187
|
+
}
|
|
390
1188
|
}
|
|
391
1189
|
function copyRuntimeClient(projectRoot, runtime) {
|
|
392
1190
|
const clientAppPath = node_path.default.join(projectRoot, ".bleam", "client", "Bleam.app");
|
|
1191
|
+
console.log(`Preparing Bleam app at ${prettyPath(clientAppPath)}`);
|
|
393
1192
|
(0, node_fs.rmSync)(clientAppPath, {
|
|
394
1193
|
recursive: true,
|
|
395
1194
|
force: true
|
|
396
1195
|
});
|
|
397
1196
|
(0, node_fs.mkdirSync)(node_path.default.dirname(clientAppPath), { recursive: true });
|
|
398
|
-
(0, node_fs.cpSync)(runtime.appPath, clientAppPath, {
|
|
1197
|
+
(0, node_fs.cpSync)(runtime.appPath, clientAppPath, {
|
|
1198
|
+
recursive: true,
|
|
1199
|
+
verbatimSymlinks: true
|
|
1200
|
+
});
|
|
399
1201
|
return clientAppPath;
|
|
400
1202
|
}
|
|
1203
|
+
function cleanDevArtifacts(projectRoot) {
|
|
1204
|
+
const bleamRoot = node_path.default.join(projectRoot, ".bleam");
|
|
1205
|
+
const targets = [
|
|
1206
|
+
"client",
|
|
1207
|
+
"dev",
|
|
1208
|
+
"project.json"
|
|
1209
|
+
].map((name) => node_path.default.join(bleamRoot, name));
|
|
1210
|
+
console.log("Cleaning Bleam dev artifacts");
|
|
1211
|
+
for (const target of targets) (0, node_fs.rmSync)(target, {
|
|
1212
|
+
recursive: true,
|
|
1213
|
+
force: true
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
401
1216
|
function isBleamManifest(value) {
|
|
402
1217
|
const manifest = value && typeof value === "object" ? value : {};
|
|
403
1218
|
return typeof manifest.name === "string" && typeof manifest.bundleUrl === "string" && manifest.platform === "macos" && manifest.dev === true;
|
|
@@ -405,24 +1220,113 @@ function isBleamManifest(value) {
|
|
|
405
1220
|
async function readDevManifest(origin, timeoutMs = 3e4) {
|
|
406
1221
|
const manifestUrl = `${origin}/bleam/manifest.json`;
|
|
407
1222
|
const startedAt = Date.now();
|
|
408
|
-
|
|
1223
|
+
const spinner = startSpinner("Waiting for Bleam dev server...");
|
|
409
1224
|
while (Date.now() - startedAt <= timeoutMs) {
|
|
410
1225
|
try {
|
|
411
1226
|
const response = await fetch(manifestUrl, { cache: "no-store" });
|
|
412
1227
|
const value = await response.json();
|
|
413
|
-
if (response.ok && isBleamManifest(value))
|
|
1228
|
+
if (response.ok && isBleamManifest(value)) {
|
|
1229
|
+
spinner?.success("Bleam dev server is ready");
|
|
1230
|
+
return value;
|
|
1231
|
+
}
|
|
414
1232
|
} catch {}
|
|
415
1233
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
416
1234
|
}
|
|
1235
|
+
spinner?.error("Bleam dev server did not become available");
|
|
417
1236
|
throw new Error(`Bleam manifest did not become available: ${manifestUrl}`);
|
|
418
1237
|
}
|
|
1238
|
+
function pushDoctorCheck(checks, status, label, detail) {
|
|
1239
|
+
checks.push({
|
|
1240
|
+
status,
|
|
1241
|
+
label,
|
|
1242
|
+
detail
|
|
1243
|
+
});
|
|
1244
|
+
}
|
|
1245
|
+
function printDoctorSection(title, checks) {
|
|
1246
|
+
if (checks.length === 0) return;
|
|
1247
|
+
console.log(`\n${heading(title)}`);
|
|
1248
|
+
for (const check of checks) {
|
|
1249
|
+
const detail = check.detail ? muted(`: ${check.detail}`) : "";
|
|
1250
|
+
console.log(` ${statusLabel(check.status)} ${check.label}${detail}`);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
function runDoctor(options) {
|
|
1254
|
+
const projectChecks = [];
|
|
1255
|
+
const runtimeChecks = [];
|
|
1256
|
+
const environmentChecks = [];
|
|
1257
|
+
const appConfigPath = node_path.default.join(options.projectRoot, "app.config.ts");
|
|
1258
|
+
const appEntryPath = node_path.default.join(options.projectRoot, "app", "index.tsx");
|
|
1259
|
+
if ((0, node_fs.existsSync)(appConfigPath)) pushDoctorCheck(projectChecks, "pass", "app.config.ts found");
|
|
1260
|
+
else pushDoctorCheck(projectChecks, "fail", "app.config.ts missing");
|
|
1261
|
+
if ((0, node_fs.existsSync)(appEntryPath)) pushDoctorCheck(projectChecks, "pass", "app/index.tsx found");
|
|
1262
|
+
else pushDoctorCheck(projectChecks, "fail", "app/index.tsx missing");
|
|
1263
|
+
try {
|
|
1264
|
+
const config = readProjectConfig(options);
|
|
1265
|
+
pushDoctorCheck(projectChecks, "pass", "config loaded");
|
|
1266
|
+
pushDoctorCheck(projectChecks, "pass", "name", config.name);
|
|
1267
|
+
if (config.bundleIdentifier) pushDoctorCheck(projectChecks, "pass", "bundleIdentifier", config.bundleIdentifier);
|
|
1268
|
+
else pushDoctorCheck(projectChecks, "warn", "bundleIdentifier not configured", "required for bleam build");
|
|
1269
|
+
if (config.teamId) pushDoctorCheck(projectChecks, "pass", "teamId", config.teamId);
|
|
1270
|
+
else pushDoctorCheck(projectChecks, "warn", "teamId not configured", "required for bleam build");
|
|
1271
|
+
} catch (error) {
|
|
1272
|
+
pushDoctorCheck(projectChecks, "fail", "config failed to load", error instanceof Error ? error.message : String(error));
|
|
1273
|
+
}
|
|
1274
|
+
const cacheRoot = runtimeCacheRoot();
|
|
1275
|
+
const cachedAppPath = node_path.default.join(cacheRoot, "Bleam.app");
|
|
1276
|
+
const localAppPath = localDevelopmentRuntimeAppPath();
|
|
1277
|
+
pushDoctorCheck(runtimeChecks, "pass", "version", runtimeVersion);
|
|
1278
|
+
pushDoctorCheck(runtimeChecks, "pass", "platform", artifactPlatform());
|
|
1279
|
+
pushDoctorCheck(runtimeChecks, "pass", "cache", prettyPath(cacheRoot));
|
|
1280
|
+
if ((0, node_fs.existsSync)(cachedAppPath)) pushDoctorCheck(runtimeChecks, "pass", "cached runtime found");
|
|
1281
|
+
else pushDoctorCheck(runtimeChecks, "warn", "runtime not cached yet", "bleam dev can download it on demand");
|
|
1282
|
+
if ((0, node_fs.existsSync)(localAppPath)) pushDoctorCheck(runtimeChecks, "pass", "local development runtime found", prettyPath(localAppPath));
|
|
1283
|
+
else pushDoctorCheck(runtimeChecks, "warn", "local development runtime not found", prettyPath(localAppPath));
|
|
1284
|
+
const overrideAppPath = process.env.BLEAM_RUNTIME_APP;
|
|
1285
|
+
if (overrideAppPath) {
|
|
1286
|
+
const appPath = node_path.default.resolve(overrideAppPath);
|
|
1287
|
+
pushDoctorCheck(runtimeChecks, (0, node_fs.existsSync)(appPath) ? "pass" : "fail", "BLEAM_RUNTIME_APP", prettyPath(appPath));
|
|
1288
|
+
}
|
|
1289
|
+
pushDoctorCheck(runtimeChecks, "pass", "release artifact URL", runtimeArchiveUrl());
|
|
1290
|
+
pushDoctorCheck(environmentChecks, process.platform === "darwin" ? "pass" : "fail", "macOS host", process.platform);
|
|
1291
|
+
pushDoctorCheck(environmentChecks, "pass", "node", prettyPath(process.execPath));
|
|
1292
|
+
const hasXcodebuild = commandSucceeds("xcodebuild", ["-version"]);
|
|
1293
|
+
pushDoctorCheck(environmentChecks, hasXcodebuild ? "pass" : "warn", "xcodebuild", hasXcodebuild ? "available" : "unavailable");
|
|
1294
|
+
const hasPod = commandSucceeds("pod", ["--version"]);
|
|
1295
|
+
pushDoctorCheck(environmentChecks, hasPod ? "pass" : "warn", "pod", hasPod ? "available" : "unavailable");
|
|
1296
|
+
const allChecks = [
|
|
1297
|
+
...projectChecks,
|
|
1298
|
+
...runtimeChecks,
|
|
1299
|
+
...environmentChecks
|
|
1300
|
+
];
|
|
1301
|
+
const counts = {
|
|
1302
|
+
pass: allChecks.filter((check) => check.status === "pass").length,
|
|
1303
|
+
warn: allChecks.filter((check) => check.status === "warn").length,
|
|
1304
|
+
fail: allChecks.filter((check) => check.status === "fail").length
|
|
1305
|
+
};
|
|
1306
|
+
console.log(heading("Bleam Doctor"));
|
|
1307
|
+
printDoctorSection("Project", projectChecks);
|
|
1308
|
+
printDoctorSection("Runtime", runtimeChecks);
|
|
1309
|
+
printDoctorSection("Environment", environmentChecks);
|
|
1310
|
+
console.log(`\n${heading("Summary")}`);
|
|
1311
|
+
console.log(` ${(0, yoctocolors.green)(`${counts.pass} passed`)}, ${(0, yoctocolors.yellow)(`${counts.warn} warnings`)}, ${counts.fail > 0 ? (0, yoctocolors.red)(`${counts.fail} failed`) : (0, yoctocolors.green)("0 failed")}`);
|
|
1312
|
+
if (counts.fail > 0) process.exit(1);
|
|
1313
|
+
}
|
|
419
1314
|
function formatDuration(ms) {
|
|
420
1315
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
421
1316
|
}
|
|
1317
|
+
async function bundleErrorPreview(response) {
|
|
1318
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
1319
|
+
if (!contentType.includes("json") && !contentType.includes("text")) return "";
|
|
1320
|
+
try {
|
|
1321
|
+
return (await response.text()).trim().slice(0, 1e3);
|
|
1322
|
+
} catch {
|
|
1323
|
+
return "";
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
422
1326
|
async function waitForDevBundle(bundleUrl, timeoutMs = 6e4) {
|
|
423
1327
|
const startedAt = Date.now();
|
|
424
1328
|
const requestTimeoutMs = 3e4;
|
|
425
|
-
|
|
1329
|
+
const spinner = startSpinner("Bundling app...");
|
|
426
1330
|
while (Date.now() - startedAt <= timeoutMs) {
|
|
427
1331
|
const requestStartedAt = Date.now();
|
|
428
1332
|
try {
|
|
@@ -430,19 +1334,32 @@ async function waitForDevBundle(bundleUrl, timeoutMs = 6e4) {
|
|
|
430
1334
|
cache: "no-store",
|
|
431
1335
|
signal: AbortSignal.timeout(requestTimeoutMs)
|
|
432
1336
|
});
|
|
433
|
-
await response.body?.cancel();
|
|
434
1337
|
if (response.ok) {
|
|
435
|
-
|
|
1338
|
+
await response.body?.cancel();
|
|
1339
|
+
spinner?.success(`Bundled app in ${formatDuration(Date.now() - startedAt)}`);
|
|
1340
|
+
if (!spinner) console.log(`Bundled app in ${formatDuration(Date.now() - startedAt)}`);
|
|
436
1341
|
return;
|
|
437
1342
|
}
|
|
438
|
-
|
|
1343
|
+
const preview = await bundleErrorPreview(response);
|
|
1344
|
+
const detail = preview ? `\n${preview}` : "";
|
|
1345
|
+
const message = `Bundle request returned ${response.status}, retrying...${detail}`;
|
|
1346
|
+
if (spinner) spinner.text = message;
|
|
1347
|
+
else console.log(message);
|
|
439
1348
|
} catch (error) {
|
|
440
|
-
if (error instanceof Error && error.name === "TimeoutError")
|
|
441
|
-
|
|
1349
|
+
if (error instanceof Error && error.name === "TimeoutError") {
|
|
1350
|
+
const message = `Bundle request timed out after ${formatDuration(Date.now() - requestStartedAt)}, retrying...`;
|
|
1351
|
+
if (spinner) spinner.text = message;
|
|
1352
|
+
else console.log(message);
|
|
1353
|
+
} else {
|
|
1354
|
+
const message = `Bundle request failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
1355
|
+
if (spinner) spinner.text = `${message}, retrying...`;
|
|
1356
|
+
else console.log(message);
|
|
1357
|
+
}
|
|
442
1358
|
}
|
|
443
1359
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
444
1360
|
}
|
|
445
|
-
|
|
1361
|
+
spinner?.error("Bundle did not complete");
|
|
1362
|
+
throw new Error(`Bleam bundle did not complete within ${formatDuration(timeoutMs)}.\nBundle URL: ${bundleUrl}\n${doctorHint()}`);
|
|
446
1363
|
}
|
|
447
1364
|
function openRuntimeClient(appPath, projectConfigPath, manifest) {
|
|
448
1365
|
const child = (0, node_child_process.spawn)("open", [
|
|
@@ -463,18 +1380,234 @@ function openRuntimeClient(appPath, projectConfigPath, manifest) {
|
|
|
463
1380
|
if (code && code !== 0) console.error(`Failed to open Bleam runtime at ${appPath}`);
|
|
464
1381
|
});
|
|
465
1382
|
}
|
|
1383
|
+
function quitRuntimeClient() {
|
|
1384
|
+
(0, node_child_process.spawnSync)("osascript", ["-e", "tell application id \"dev.bleam.app\" to quit"], { stdio: "ignore" });
|
|
1385
|
+
}
|
|
1386
|
+
async function launchRuntimeClient(appPath, projectConfigPath, manifest) {
|
|
1387
|
+
quitRuntimeClient();
|
|
1388
|
+
openRuntimeClient(appPath, projectConfigPath, manifest);
|
|
1389
|
+
}
|
|
1390
|
+
function focusRuntimeClient() {
|
|
1391
|
+
return (0, node_child_process.spawnSync)("osascript", ["-e", "tell application id \"dev.bleam.app\" to activate"], { stdio: "ignore" }).status === 0;
|
|
1392
|
+
}
|
|
1393
|
+
function sendJson(res, status, value) {
|
|
1394
|
+
res.writeHead(status, {
|
|
1395
|
+
"Cache-Control": "no-store",
|
|
1396
|
+
"Content-Type": "application/json; charset=utf-8"
|
|
1397
|
+
});
|
|
1398
|
+
res.end(JSON.stringify(value));
|
|
1399
|
+
}
|
|
1400
|
+
function readRequestBody(req, limit = 1e6) {
|
|
1401
|
+
return new Promise((resolve, reject) => {
|
|
1402
|
+
const chunks = [];
|
|
1403
|
+
let size = 0;
|
|
1404
|
+
req.on("data", (chunk) => {
|
|
1405
|
+
size += chunk.length;
|
|
1406
|
+
if (size > limit) {
|
|
1407
|
+
reject(/* @__PURE__ */ new Error("Request body too large"));
|
|
1408
|
+
req.destroy();
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1411
|
+
chunks.push(chunk);
|
|
1412
|
+
});
|
|
1413
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
1414
|
+
req.on("error", reject);
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
function isLogLevel(value) {
|
|
1418
|
+
return value === "debug" || value === "info" || value === "warn" || value === "error";
|
|
1419
|
+
}
|
|
1420
|
+
function isLogSource(value) {
|
|
1421
|
+
return value === "cli" || value === "metro" || value === "runtime" || value === "js" || value === "native" || value === "xpc";
|
|
1422
|
+
}
|
|
1423
|
+
function normalizeDevLogEvent(value) {
|
|
1424
|
+
const input = value && typeof value === "object" ? value : {};
|
|
1425
|
+
const message = typeof input.message === "string" ? input.message : input.message === void 0 ? "" : JSON.stringify(input.message);
|
|
1426
|
+
return {
|
|
1427
|
+
type: "log",
|
|
1428
|
+
id: typeof input.id === "string" && input.id ? input.id : (0, node_crypto.randomUUID)(),
|
|
1429
|
+
time: typeof input.time === "string" && input.time ? input.time : (/* @__PURE__ */ new Date()).toISOString(),
|
|
1430
|
+
source: isLogSource(input.source) ? input.source : "runtime",
|
|
1431
|
+
level: isLogLevel(input.level) ? input.level : "info",
|
|
1432
|
+
category: typeof input.category === "string" && input.category ? input.category : void 0,
|
|
1433
|
+
message,
|
|
1434
|
+
details: input.details,
|
|
1435
|
+
jobId: typeof input.jobId === "string" && input.jobId ? input.jobId : void 0
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
function formatDevLogEvent(event) {
|
|
1439
|
+
const category = event.category ? `:${event.category}` : "";
|
|
1440
|
+
const job = event.jobId ? ` ${event.jobId.slice(0, 8)}` : "";
|
|
1441
|
+
return `[${event.source}${category}:${event.level}${job}] ${event.message}`;
|
|
1442
|
+
}
|
|
1443
|
+
async function requestRuntimeReload(origin) {
|
|
1444
|
+
const response = await fetch(`${origin}/bleam/reload`, {
|
|
1445
|
+
method: "POST",
|
|
1446
|
+
cache: "no-store"
|
|
1447
|
+
});
|
|
1448
|
+
const value = await response.json();
|
|
1449
|
+
if (!response.ok) throw new Error(`Reload request failed: ${response.status}`);
|
|
1450
|
+
const reload = value;
|
|
1451
|
+
return typeof reload.clients === "number" ? reload.clients : 0;
|
|
1452
|
+
}
|
|
1453
|
+
function biomeBinPath() {
|
|
1454
|
+
const biomePackageJsonPath = require$1.resolve("@biomejs/biome/package.json");
|
|
1455
|
+
const biomePackageRoot = node_path.default.dirname(biomePackageJsonPath);
|
|
1456
|
+
const biomePackage = require$1("@biomejs/biome/package.json");
|
|
1457
|
+
const bin = typeof biomePackage.bin === "string" ? biomePackage.bin : biomePackage.bin?.biome;
|
|
1458
|
+
if (!bin) throw new Error("Could not resolve @biomejs/biome binary");
|
|
1459
|
+
return node_path.default.join(biomePackageRoot, bin);
|
|
1460
|
+
}
|
|
1461
|
+
function typescriptBinPath() {
|
|
1462
|
+
const typescriptPackageJsonPath = require$1.resolve("typescript/package.json");
|
|
1463
|
+
const typescriptPackageRoot = node_path.default.dirname(typescriptPackageJsonPath);
|
|
1464
|
+
const bin = require$1("typescript/package.json").bin?.tsc;
|
|
1465
|
+
if (!bin) throw new Error("Could not resolve TypeScript compiler binary");
|
|
1466
|
+
return node_path.default.join(typescriptPackageRoot, bin);
|
|
1467
|
+
}
|
|
1468
|
+
function ensureProjectToolWorkspace(options) {
|
|
1469
|
+
const config = readProjectConfig({ projectRoot: options.projectRoot });
|
|
1470
|
+
return createDevWorkspace(options.projectRoot, config);
|
|
1471
|
+
}
|
|
1472
|
+
function runBiomeCommand(command, options) {
|
|
1473
|
+
assertBleamConfigFiles(options.projectRoot);
|
|
1474
|
+
ensureProjectToolWorkspace(options);
|
|
1475
|
+
const configPath = node_path.default.join(options.projectRoot, "biome.json");
|
|
1476
|
+
const existingConfig = (0, node_fs.existsSync)(configPath) ? (0, node_fs.readFileSync)(configPath, "utf8") : void 0;
|
|
1477
|
+
const args = [
|
|
1478
|
+
command,
|
|
1479
|
+
"--config-path",
|
|
1480
|
+
"biome.json"
|
|
1481
|
+
];
|
|
1482
|
+
if (command === "check" && options.write) args.push("--write");
|
|
1483
|
+
if (command === "format" && !options.formatCheck) args.push("--write");
|
|
1484
|
+
args.push("app", "app.config.ts", "tsconfig.json");
|
|
1485
|
+
writeBiomeConfig(configPath);
|
|
1486
|
+
const result = (0, node_child_process.spawnSync)(biomeBinPath(), args, {
|
|
1487
|
+
cwd: options.projectRoot,
|
|
1488
|
+
stdio: "inherit"
|
|
1489
|
+
});
|
|
1490
|
+
if (existingConfig === void 0) (0, node_fs.rmSync)(configPath, { force: true });
|
|
1491
|
+
else (0, node_fs.writeFileSync)(configPath, existingConfig);
|
|
1492
|
+
if (result.error) throw result.error;
|
|
1493
|
+
process.exit(result.status ?? 1);
|
|
1494
|
+
}
|
|
1495
|
+
function runTypecheckCommand(options) {
|
|
1496
|
+
assertBleamConfigFiles(options.projectRoot);
|
|
1497
|
+
ensureProjectToolWorkspace(options);
|
|
1498
|
+
const result = (0, node_child_process.spawnSync)(typescriptBinPath(), [
|
|
1499
|
+
"--noEmit",
|
|
1500
|
+
"-p",
|
|
1501
|
+
node_path.default.join(options.projectRoot, "tsconfig.json")
|
|
1502
|
+
], {
|
|
1503
|
+
cwd: options.projectRoot,
|
|
1504
|
+
stdio: "inherit"
|
|
1505
|
+
});
|
|
1506
|
+
if (result.error) throw result.error;
|
|
1507
|
+
process.exit(result.status ?? 1);
|
|
1508
|
+
}
|
|
1509
|
+
function setupInteractiveControls(options) {
|
|
1510
|
+
if (!process.stdin.isTTY) return () => {};
|
|
1511
|
+
const wasRaw = process.stdin.isRaw;
|
|
1512
|
+
let closed = false;
|
|
1513
|
+
const cleanup = () => {
|
|
1514
|
+
if (closed) return;
|
|
1515
|
+
closed = true;
|
|
1516
|
+
process.stdin.off("data", onData);
|
|
1517
|
+
process.stdin.setRawMode(wasRaw);
|
|
1518
|
+
};
|
|
1519
|
+
const onData = (data) => {
|
|
1520
|
+
for (const byte of data) {
|
|
1521
|
+
if (byte === 3) {
|
|
1522
|
+
cleanup();
|
|
1523
|
+
options.stop();
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
const key = String.fromCharCode(byte).toLowerCase();
|
|
1527
|
+
if (key === "o") {
|
|
1528
|
+
(async () => {
|
|
1529
|
+
try {
|
|
1530
|
+
if (focusRuntimeClient()) {
|
|
1531
|
+
console.log("Focused Bleam app");
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
console.log(`Opening Bleam app at ${prettyPath(options.clientAppPath)}`);
|
|
1535
|
+
await launchRuntimeClient(options.clientAppPath, options.projectConfigPath, options.manifest);
|
|
1536
|
+
} catch (error) {
|
|
1537
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1538
|
+
}
|
|
1539
|
+
})();
|
|
1540
|
+
continue;
|
|
1541
|
+
}
|
|
1542
|
+
if (key === "r") {
|
|
1543
|
+
console.log("Requesting app reload");
|
|
1544
|
+
requestRuntimeReload(options.origin).then((clients) => {
|
|
1545
|
+
console.log(`Reloaded app (${clients} client${clients === 1 ? "" : "s"})`);
|
|
1546
|
+
}).catch((error) => {
|
|
1547
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
};
|
|
1552
|
+
process.stdin.setRawMode(true);
|
|
1553
|
+
process.stdin.resume();
|
|
1554
|
+
process.stdin.on("data", onData);
|
|
1555
|
+
console.log("Press o to open, r to reload, Ctrl+C to stop.");
|
|
1556
|
+
return cleanup;
|
|
1557
|
+
}
|
|
466
1558
|
async function startInternalMetroServer(options) {
|
|
1559
|
+
process.env.BLEAM_DEV_PLATFORM ??= "macos";
|
|
1560
|
+
const projectRoot = process.env.BLEAM_PROJECT_ROOT ?? options.workspaceRoot;
|
|
1561
|
+
const logPath = node_path.default.join(projectRoot, ".bleam", "dev", "logs", "dev.log");
|
|
1562
|
+
const recentLogs = [];
|
|
1563
|
+
const logClients = /* @__PURE__ */ new Set();
|
|
1564
|
+
const maxRecentLogs = 1e3;
|
|
467
1565
|
const metro = require$1("@expo/metro/metro");
|
|
468
1566
|
const { loadConfig } = require$1("@expo/metro/metro-config");
|
|
469
1567
|
const config = await loadConfig({
|
|
470
1568
|
config: node_path.default.join(options.workspaceRoot, "metro.config.js"),
|
|
471
1569
|
cwd: options.workspaceRoot,
|
|
472
|
-
port: options.port
|
|
1570
|
+
port: options.port,
|
|
1571
|
+
resetCache: options.resetCache
|
|
473
1572
|
});
|
|
474
1573
|
const { middleware, end, attachHmrServer } = await metro.createConnectMiddleware(config, {
|
|
475
1574
|
watch: true,
|
|
476
1575
|
waitForBundler: true
|
|
477
1576
|
});
|
|
1577
|
+
const messageClients = /* @__PURE__ */ new Set();
|
|
1578
|
+
const messageServer = new ws.WebSocketServer({ noServer: true });
|
|
1579
|
+
const logServer = new ws.WebSocketServer({ noServer: true });
|
|
1580
|
+
const recordLog = (event) => {
|
|
1581
|
+
recentLogs.push(event);
|
|
1582
|
+
if (recentLogs.length > maxRecentLogs) recentLogs.splice(0, recentLogs.length - maxRecentLogs);
|
|
1583
|
+
(0, node_fs.mkdirSync)(node_path.default.dirname(logPath), { recursive: true });
|
|
1584
|
+
(0, node_fs.appendFileSync)(logPath, `${JSON.stringify(event)}\n`, "utf8");
|
|
1585
|
+
const payload = JSON.stringify(event);
|
|
1586
|
+
for (const client of logClients) if (client.readyState === ws.WebSocket.OPEN) client.send(payload);
|
|
1587
|
+
console.log(formatDevLogEvent(event));
|
|
1588
|
+
};
|
|
1589
|
+
const broadcastReload = () => {
|
|
1590
|
+
const message = JSON.stringify({
|
|
1591
|
+
version: 2,
|
|
1592
|
+
method: "reload",
|
|
1593
|
+
params: {}
|
|
1594
|
+
});
|
|
1595
|
+
let clients = 0;
|
|
1596
|
+
for (const client of messageClients) if (client.readyState === ws.WebSocket.OPEN) {
|
|
1597
|
+
client.send(message);
|
|
1598
|
+
clients += 1;
|
|
1599
|
+
}
|
|
1600
|
+
return clients;
|
|
1601
|
+
};
|
|
1602
|
+
messageServer.on("connection", (client) => {
|
|
1603
|
+
messageClients.add(client);
|
|
1604
|
+
client.on("close", () => messageClients.delete(client));
|
|
1605
|
+
});
|
|
1606
|
+
logServer.on("connection", (client) => {
|
|
1607
|
+
logClients.add(client);
|
|
1608
|
+
for (const event of recentLogs) client.send(JSON.stringify(event));
|
|
1609
|
+
client.on("close", () => logClients.delete(client));
|
|
1610
|
+
});
|
|
478
1611
|
const server = node_http.default.createServer((req, res) => {
|
|
479
1612
|
if (req.url?.split("?")[0] === "/status") {
|
|
480
1613
|
res.writeHead(200, {
|
|
@@ -485,10 +1618,78 @@ async function startInternalMetroServer(options) {
|
|
|
485
1618
|
res.end("packager-status:running");
|
|
486
1619
|
return;
|
|
487
1620
|
}
|
|
488
|
-
|
|
1621
|
+
if (req.url?.split("?")[0] === "/bleam/reload") {
|
|
1622
|
+
if (req.method !== "POST") {
|
|
1623
|
+
res.writeHead(405, { Allow: "POST" });
|
|
1624
|
+
res.end();
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
sendJson(res, 200, {
|
|
1628
|
+
ok: true,
|
|
1629
|
+
clients: broadcastReload()
|
|
1630
|
+
});
|
|
1631
|
+
return;
|
|
1632
|
+
}
|
|
1633
|
+
if (req.url?.split("?")[0] === "/bleam/logs") {
|
|
1634
|
+
if (req.method === "GET") {
|
|
1635
|
+
sendJson(res, 200, { logs: recentLogs });
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
if (req.method !== "POST") {
|
|
1639
|
+
res.writeHead(405, { Allow: "GET, POST" });
|
|
1640
|
+
res.end();
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
readRequestBody(req).then((body) => {
|
|
1644
|
+
const parsed = body ? JSON.parse(body) : {};
|
|
1645
|
+
const events = Array.isArray(parsed) ? parsed : [parsed];
|
|
1646
|
+
for (const value of events) recordLog(normalizeDevLogEvent(value));
|
|
1647
|
+
sendJson(res, 200, { ok: true });
|
|
1648
|
+
}).catch((error) => {
|
|
1649
|
+
sendJson(res, 400, {
|
|
1650
|
+
ok: false,
|
|
1651
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1652
|
+
});
|
|
1653
|
+
});
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1656
|
+
middleware(req, res, (error) => {
|
|
1657
|
+
if (res.headersSent) return;
|
|
1658
|
+
if (error) {
|
|
1659
|
+
console.error(error.message);
|
|
1660
|
+
res.writeHead(500, {
|
|
1661
|
+
"Cache-Control": "no-store",
|
|
1662
|
+
"Content-Type": "text/plain; charset=utf-8"
|
|
1663
|
+
});
|
|
1664
|
+
res.end(error.message);
|
|
1665
|
+
return;
|
|
1666
|
+
}
|
|
1667
|
+
res.writeHead(404, {
|
|
1668
|
+
"Cache-Control": "no-store",
|
|
1669
|
+
"Content-Type": "text/plain; charset=utf-8"
|
|
1670
|
+
});
|
|
1671
|
+
res.end("Not found");
|
|
1672
|
+
});
|
|
489
1673
|
});
|
|
490
1674
|
server.timeout = 0;
|
|
491
1675
|
attachHmrServer(server);
|
|
1676
|
+
const metroUpgradeListeners = server.listeners("upgrade");
|
|
1677
|
+
server.removeAllListeners("upgrade");
|
|
1678
|
+
server.on("upgrade", (req, socket, head) => {
|
|
1679
|
+
if (req.url?.split("?")[0] === "/message") {
|
|
1680
|
+
messageServer.handleUpgrade(req, socket, head, (client) => {
|
|
1681
|
+
messageServer.emit("connection", client, req);
|
|
1682
|
+
});
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1685
|
+
if (req.url?.split("?")[0] === "/bleam/logs/stream") {
|
|
1686
|
+
logServer.handleUpgrade(req, socket, head, (client) => {
|
|
1687
|
+
logServer.emit("connection", client, req);
|
|
1688
|
+
});
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1691
|
+
for (const listener of metroUpgradeListeners) listener.call(server, req, socket, head);
|
|
1692
|
+
});
|
|
492
1693
|
await new Promise((resolve, reject) => {
|
|
493
1694
|
server.on("error", reject);
|
|
494
1695
|
server.listen(options.port, "localhost", () => resolve());
|
|
@@ -498,6 +1699,11 @@ async function startInternalMetroServer(options) {
|
|
|
498
1699
|
});
|
|
499
1700
|
console.log(`Bleam dev server running at http://localhost:${options.port}`);
|
|
500
1701
|
const close = () => {
|
|
1702
|
+
setTimeout(() => process.exit(0), 1e3).unref();
|
|
1703
|
+
messageServer.close();
|
|
1704
|
+
logServer.close();
|
|
1705
|
+
for (const client of messageClients) client.terminate();
|
|
1706
|
+
for (const client of logClients) client.terminate();
|
|
501
1707
|
server.close(() => {
|
|
502
1708
|
end();
|
|
503
1709
|
process.exit(0);
|
|
@@ -508,8 +1714,10 @@ async function startInternalMetroServer(options) {
|
|
|
508
1714
|
}
|
|
509
1715
|
async function startDevServer(options) {
|
|
510
1716
|
const config = readProjectConfig(options);
|
|
1717
|
+
if (options.clean) cleanDevArtifacts(options.projectRoot);
|
|
511
1718
|
const runtime = await resolveRuntimeArtifact();
|
|
512
1719
|
const clientAppPath = copyRuntimeClient(options.projectRoot, runtime);
|
|
1720
|
+
console.log("Preparing Bleam dev workspace");
|
|
513
1721
|
const workspaceRoot = createDevWorkspace(options.projectRoot, config);
|
|
514
1722
|
const origin = `http://localhost:${options.port}`;
|
|
515
1723
|
const projectConfigPath = writeProjectRuntimeConfig(options.projectRoot, config, origin);
|
|
@@ -519,7 +1727,8 @@ async function startDevServer(options) {
|
|
|
519
1727
|
"--workspace-root",
|
|
520
1728
|
workspaceRoot,
|
|
521
1729
|
"--port",
|
|
522
|
-
String(options.port)
|
|
1730
|
+
String(options.port),
|
|
1731
|
+
...options.clean ? ["--reset-cache"] : []
|
|
523
1732
|
], {
|
|
524
1733
|
stdio: "inherit",
|
|
525
1734
|
env: {
|
|
@@ -529,6 +1738,7 @@ async function startDevServer(options) {
|
|
|
529
1738
|
BLEAM_DEV_NAME: config.name,
|
|
530
1739
|
BLEAM_DEV_ORIGIN: origin,
|
|
531
1740
|
BLEAM_DEV_PORT: String(options.port),
|
|
1741
|
+
BLEAM_DEV_PLATFORM: "macos",
|
|
532
1742
|
BLEAM_DEV_RUNTIME_VERSION: config.runtimeVersion,
|
|
533
1743
|
BLEAM_DEV_SDK_VERSION: config.sdkVersion,
|
|
534
1744
|
NODE_PATH: [
|
|
@@ -541,20 +1751,57 @@ async function startDevServer(options) {
|
|
|
541
1751
|
].filter(Boolean).join(node_path.default.delimiter)
|
|
542
1752
|
}
|
|
543
1753
|
});
|
|
1754
|
+
let cleanupInteractiveControls = () => {};
|
|
1755
|
+
let didLaunchRuntimeClient = false;
|
|
1756
|
+
let didCleanupDevSession = false;
|
|
1757
|
+
let stopping = false;
|
|
1758
|
+
const cleanupDevSession = () => {
|
|
1759
|
+
if (didCleanupDevSession) return;
|
|
1760
|
+
didCleanupDevSession = true;
|
|
1761
|
+
cleanupInteractiveControls();
|
|
1762
|
+
if (didLaunchRuntimeClient) quitRuntimeClient();
|
|
1763
|
+
};
|
|
544
1764
|
const stop = (signal) => {
|
|
1765
|
+
if (stopping) return;
|
|
1766
|
+
stopping = true;
|
|
1767
|
+
cleanupDevSession();
|
|
545
1768
|
child.kill(signal);
|
|
1769
|
+
setTimeout(() => process.exit(0), 2e3).unref();
|
|
546
1770
|
};
|
|
547
1771
|
process.on("SIGINT", () => stop("SIGINT"));
|
|
548
1772
|
process.on("SIGTERM", () => stop("SIGTERM"));
|
|
549
|
-
child.on("
|
|
1773
|
+
child.on("error", (error) => {
|
|
1774
|
+
cleanupDevSession();
|
|
1775
|
+
console.error(`Bleam dev server process failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1776
|
+
console.error(doctorHint(options.projectRoot));
|
|
1777
|
+
process.exit(1);
|
|
1778
|
+
});
|
|
1779
|
+
child.on("exit", (code) => {
|
|
1780
|
+
cleanupDevSession();
|
|
1781
|
+
process.exit(code ?? 0);
|
|
1782
|
+
});
|
|
550
1783
|
try {
|
|
551
1784
|
const manifest = await readDevManifest(origin);
|
|
552
|
-
|
|
1785
|
+
cleanupInteractiveControls = setupInteractiveControls({
|
|
1786
|
+
origin,
|
|
1787
|
+
clientAppPath,
|
|
1788
|
+
projectConfigPath,
|
|
1789
|
+
manifest,
|
|
1790
|
+
stop: () => stop("SIGINT")
|
|
1791
|
+
});
|
|
1792
|
+
if (options.run && process.env.BLEAM_NO_OPEN !== "1") try {
|
|
553
1793
|
await waitForDevBundle(manifest.bundleUrl);
|
|
554
|
-
console.log(
|
|
555
|
-
|
|
1794
|
+
console.log(`Opening Bleam app at ${prettyPath(clientAppPath)}`);
|
|
1795
|
+
await launchRuntimeClient(clientAppPath, projectConfigPath, manifest);
|
|
1796
|
+
didLaunchRuntimeClient = true;
|
|
1797
|
+
} catch (error) {
|
|
1798
|
+
console.error(`Initial app launch failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1799
|
+
console.error(doctorHint(options.projectRoot));
|
|
1800
|
+
console.error("Check BLEAM_RUNTIME_APP if you are using a runtime override.");
|
|
1801
|
+
console.error("Bleam dev server is still running.");
|
|
556
1802
|
}
|
|
557
1803
|
} catch (error) {
|
|
1804
|
+
cleanupDevSession();
|
|
558
1805
|
child.kill("SIGTERM");
|
|
559
1806
|
throw error;
|
|
560
1807
|
}
|
|
@@ -567,10 +1814,12 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
567
1814
|
}
|
|
568
1815
|
if (command === "new") {
|
|
569
1816
|
const options = parseNewOptions(args);
|
|
570
|
-
|
|
571
|
-
|
|
1817
|
+
createProject(options);
|
|
1818
|
+
await startDevServer({
|
|
572
1819
|
projectRoot: options.projectRoot,
|
|
573
|
-
port: 8081
|
|
1820
|
+
port: 8081,
|
|
1821
|
+
run: true,
|
|
1822
|
+
clean: false
|
|
574
1823
|
});
|
|
575
1824
|
return;
|
|
576
1825
|
}
|
|
@@ -578,15 +1827,70 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
578
1827
|
await startDevServer(parseDevOptions(args));
|
|
579
1828
|
return;
|
|
580
1829
|
}
|
|
1830
|
+
if (command === "install") {
|
|
1831
|
+
await installNativeApp(parseBuildOptions(args));
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
if (command === "build") {
|
|
1835
|
+
await buildNativeArchives(parseBuildOptions(args));
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1838
|
+
if (command === "publish") {
|
|
1839
|
+
const [kind, ...publishArgs] = args;
|
|
1840
|
+
if (kind === "ota") {
|
|
1841
|
+
await publishOta(parsePublishOtaOptions(publishArgs));
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1844
|
+
if (kind === "platform") {
|
|
1845
|
+
await publishPlatform(parsePublishOtaOptions(publishArgs));
|
|
1846
|
+
return;
|
|
1847
|
+
}
|
|
1848
|
+
throw new Error("Usage: bleam publish <ota|platform> [dir] [--service-url <url>]");
|
|
1849
|
+
}
|
|
1850
|
+
if (command === "doctor") {
|
|
1851
|
+
runDoctor(parseDoctorOptions(args));
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
if (command === "typecheck") {
|
|
1855
|
+
runTypecheckCommand(parseProjectToolOptions(args));
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1858
|
+
if (command === "check") {
|
|
1859
|
+
runBiomeCommand("check", parseProjectToolOptions(args));
|
|
1860
|
+
return;
|
|
1861
|
+
}
|
|
1862
|
+
if (command === "format") {
|
|
1863
|
+
runBiomeCommand("format", parseProjectToolOptions(args));
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
if (command === "lint") {
|
|
1867
|
+
runBiomeCommand("lint", parseProjectToolOptions(args));
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
581
1870
|
if (command === "internal:metro") {
|
|
582
1871
|
await startInternalMetroServer(parseInternalMetroOptions(args));
|
|
583
1872
|
return;
|
|
584
1873
|
}
|
|
585
1874
|
throw new Error(`Unknown command: ${command}`);
|
|
586
1875
|
}
|
|
587
|
-
main().catch((error) => {
|
|
1876
|
+
if (process.env.VITEST !== "true") main().catch((error) => {
|
|
588
1877
|
console.error(error instanceof Error ? error.message : String(error));
|
|
589
1878
|
process.exit(1);
|
|
590
1879
|
});
|
|
1880
|
+
const __test = {
|
|
1881
|
+
createProject,
|
|
1882
|
+
createBuildNativeWorkspace,
|
|
1883
|
+
hasCurrentPodInstall,
|
|
1884
|
+
installedAppPath,
|
|
1885
|
+
installArchivedApp,
|
|
1886
|
+
nativeArchiveArgs,
|
|
1887
|
+
parseBuildOptions,
|
|
1888
|
+
parseNewOptions,
|
|
1889
|
+
parsePublishOtaOptions,
|
|
1890
|
+
platformRelease,
|
|
1891
|
+
podInstallInputStamp,
|
|
1892
|
+
replaceOrInsertPlistString
|
|
1893
|
+
};
|
|
591
1894
|
|
|
592
|
-
//#endregion
|
|
1895
|
+
//#endregion
|
|
1896
|
+
exports.__test = __test;
|