bleam 0.0.5 → 0.0.6
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 +187 -0
- package/dist/ai.d.cts +52 -0
- package/dist/ai.d.ts +52 -0
- package/dist/ai.js +182 -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.d.cts +1 -2
- package/dist/app.d.ts +1 -2
- package/dist/app.js +1 -2
- package/dist/bundler.d.cts +1 -2
- package/dist/bundler.d.ts +1 -2
- package/dist/chrome.cjs +265 -0
- package/dist/chrome.d.cts +19 -0
- package/dist/chrome.d.ts +19 -0
- package/dist/chrome.js +262 -0
- package/dist/cli.cjs +768 -31
- package/dist/cli.js +767 -34
- package/dist/config-Bb6SULnR.cjs +46 -0
- package/dist/config-CfWa3q-k.js +28 -0
- package/dist/config-ClDGHNb3.d.ts +39 -0
- package/dist/config-D3gPaVMb.d.cts +39 -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 +8 -1
- package/dist/crypto.d.ts +8 -1
- package/dist/crypto.js +2 -2
- package/dist/dev-protocol.d.cts +3 -3
- package/dist/dev-protocol.d.ts +3 -3
- package/dist/dev-protocol.js +1 -2
- package/dist/fs.cjs +12 -2
- package/dist/fs.d.cts +7 -1
- package/dist/fs.d.ts +7 -1
- package/dist/fs.js +10 -1
- 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-macos-D6p2SmUj.js +20 -0
- package/dist/native-macos-DLwo_ii9.cjs +31 -0
- package/dist/native-runtime-C85Nuc4F.js +10 -0
- package/dist/native-runtime-CbPzrs8j.d.cts +33 -0
- package/dist/{native-runtime-CdeT0JyQ.cjs → native-runtime-CsXnXkQn.cjs} +1 -14
- package/dist/native-runtime-DxHSrsTX.d.ts +33 -0
- package/dist/native.cjs +35 -32
- package/dist/native.d.cts +4 -34
- package/dist/native.d.ts +3 -33
- package/dist/native.js +36 -34
- package/dist/runtime.d.cts +1 -2
- package/dist/runtime.d.ts +1 -2
- package/dist/schema-BOuUHcqo.d.cts +58 -0
- package/dist/schema-DVmoD9JL.js +90 -0
- package/dist/schema-bxeeCyLn.cjs +102 -0
- package/dist/schema-ipsECAso.d.ts +58 -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.cjs +765 -0
- package/dist/state.d.cts +129 -0
- package/dist/state.d.ts +129 -0
- package/dist/state.js +747 -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.cjs +113 -0
- package/dist/ui.d.cts +30 -0
- package/dist/ui.d.ts +30 -0
- package/dist/ui.js +110 -0
- package/metro-config.cjs +18 -13
- package/package.json +47 -13
- package/templates/basic/app/index.tsx +130 -12
- package/templates/basic/app.config.ts +4 -2
- 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/native-runtime-BoqybBBf.js +0 -18
- package/dist/native-runtime-BoqybBBf.js.map +0 -1
- package/dist/native.d.cts.map +0 -1
- package/dist/native.d.ts.map +0 -1
- 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,98 @@ 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
|
-
|
|
31
|
+
function artifactPlatform() {
|
|
32
|
+
return `macos-${process.arch}`;
|
|
33
|
+
}
|
|
34
|
+
function prettyPath(value) {
|
|
35
|
+
const home = node_os.default.homedir();
|
|
36
|
+
return value === home || value.startsWith(`${home}${node_path.default.sep}`) ? `~${value.slice(home.length)}` : value;
|
|
37
|
+
}
|
|
38
|
+
function commandSucceeds(command, args) {
|
|
39
|
+
const result = (0, node_child_process.spawnSync)(command, args, { stdio: "ignore" });
|
|
40
|
+
return !result.error && result.status === 0;
|
|
41
|
+
}
|
|
42
|
+
function commandText(command, args) {
|
|
43
|
+
return [command, ...args].join(" ");
|
|
44
|
+
}
|
|
45
|
+
function doctorHint(projectRoot) {
|
|
46
|
+
return projectRoot ? `Run ${(0, yoctocolors.bold)(`bleam doctor ${projectRoot}`)} for diagnostics.` : `Run ${(0, yoctocolors.bold)("bleam doctor")} for diagnostics.`;
|
|
47
|
+
}
|
|
48
|
+
function appConfigBuildExample() {
|
|
49
|
+
return [
|
|
50
|
+
"Example:",
|
|
51
|
+
"import { appConfig } from 'bleam'",
|
|
52
|
+
"",
|
|
53
|
+
"export default appConfig({",
|
|
54
|
+
" name: 'My App',",
|
|
55
|
+
" bundleIdentifier: 'com.example.myapp',",
|
|
56
|
+
" teamId: 'ABCDE12345',",
|
|
57
|
+
"})"
|
|
58
|
+
].join("\n");
|
|
59
|
+
}
|
|
60
|
+
function missingBuildFieldError(field) {
|
|
61
|
+
return /* @__PURE__ */ new Error(`app.config.ts must define ${field} for bleam build.\n\n${appConfigBuildExample()}`);
|
|
62
|
+
}
|
|
63
|
+
function heading(text) {
|
|
64
|
+
return (0, yoctocolors.bold)(text);
|
|
65
|
+
}
|
|
66
|
+
function muted(text) {
|
|
67
|
+
return (0, yoctocolors.dim)(text);
|
|
68
|
+
}
|
|
69
|
+
function statusLabel(status) {
|
|
70
|
+
if (status === "pass") return (0, yoctocolors.green)("[ok]");
|
|
71
|
+
if (status === "warn") return (0, yoctocolors.yellow)("[warn]");
|
|
72
|
+
return (0, yoctocolors.red)("[fail]");
|
|
73
|
+
}
|
|
74
|
+
function startSpinner(text) {
|
|
75
|
+
if (!process.stderr.isTTY) {
|
|
76
|
+
console.log(text);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
return (0, yocto_spinner.default)({
|
|
80
|
+
text,
|
|
81
|
+
handleSignals: false
|
|
82
|
+
}).start();
|
|
83
|
+
}
|
|
26
84
|
function printUsage() {
|
|
27
85
|
console.log(`Usage: bleam <command>
|
|
28
86
|
|
|
29
87
|
Commands:
|
|
30
88
|
new [dir] [--run] Create a new Bleam project
|
|
31
|
-
dev [dir] [--port <port>]
|
|
89
|
+
dev [dir] [--port <port>] [--run]
|
|
90
|
+
Start a Bleam dev server
|
|
91
|
+
build [dir] [--output <dir>]
|
|
92
|
+
Build App Store-ready native archives
|
|
93
|
+
doctor [dir] Check the local Bleam environment
|
|
94
|
+
check [dir] [--write] Format, lint, and organize imports
|
|
95
|
+
format [dir] [--check] Format project files
|
|
96
|
+
lint [dir] Lint project files`);
|
|
32
97
|
}
|
|
33
98
|
function invocationRoot() {
|
|
34
|
-
|
|
99
|
+
const pwd = process.env.PWD;
|
|
100
|
+
return pwd && node_path.default.isAbsolute(pwd) ? pwd : process.cwd();
|
|
101
|
+
}
|
|
102
|
+
function canonicalPath(value) {
|
|
103
|
+
const resolved = node_path.default.resolve(value);
|
|
104
|
+
return (0, node_fs.existsSync)(resolved) ? node_fs.realpathSync.native(resolved) : resolved;
|
|
35
105
|
}
|
|
36
106
|
function parseDevOptions(argv) {
|
|
37
107
|
const root = invocationRoot();
|
|
38
108
|
let projectRoot = root;
|
|
39
109
|
let port = 8081;
|
|
110
|
+
let run = false;
|
|
40
111
|
let hasProjectRootArg = false;
|
|
41
112
|
for (let index = 0; index < argv.length; index += 1) {
|
|
42
113
|
const arg = argv[index];
|
|
@@ -49,6 +120,10 @@ function parseDevOptions(argv) {
|
|
|
49
120
|
port = Number(arg.slice(7));
|
|
50
121
|
continue;
|
|
51
122
|
}
|
|
123
|
+
if (arg === "--run") {
|
|
124
|
+
run = true;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
52
127
|
if (arg === "--help" || arg === "-h") {
|
|
53
128
|
printUsage();
|
|
54
129
|
process.exit(0);
|
|
@@ -60,8 +135,9 @@ function parseDevOptions(argv) {
|
|
|
60
135
|
if (!Number.isInteger(port) || port <= 0) throw new Error(`Invalid port: ${port}`);
|
|
61
136
|
if (!hasProjectRootArg && !isBleamProjectRoot(projectRoot)) projectRoot = discoverBleamProjectRoot(projectRoot) ?? projectRoot;
|
|
62
137
|
return {
|
|
63
|
-
projectRoot:
|
|
64
|
-
port
|
|
138
|
+
projectRoot: canonicalPath(projectRoot),
|
|
139
|
+
port,
|
|
140
|
+
run
|
|
65
141
|
};
|
|
66
142
|
}
|
|
67
143
|
function parseNewOptions(argv) {
|
|
@@ -81,10 +157,108 @@ function parseNewOptions(argv) {
|
|
|
81
157
|
projectRoot = node_path.default.resolve(root, arg);
|
|
82
158
|
}
|
|
83
159
|
return {
|
|
84
|
-
projectRoot,
|
|
160
|
+
projectRoot: canonicalPath(projectRoot),
|
|
85
161
|
run
|
|
86
162
|
};
|
|
87
163
|
}
|
|
164
|
+
function parseBuildOptions(argv) {
|
|
165
|
+
const root = invocationRoot();
|
|
166
|
+
let projectRoot = root;
|
|
167
|
+
let hasProjectRootArg = false;
|
|
168
|
+
let output;
|
|
169
|
+
let configuration = "Release";
|
|
170
|
+
let exportOptionsPlist;
|
|
171
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
172
|
+
const arg = argv[index];
|
|
173
|
+
if (arg === "--output" || arg === "-o") {
|
|
174
|
+
output = argv[++index];
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (arg.startsWith("--output=")) {
|
|
178
|
+
output = arg.slice(9);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (arg === "--configuration") {
|
|
182
|
+
const value = argv[++index];
|
|
183
|
+
if (!value) throw new Error("Missing --configuration value");
|
|
184
|
+
configuration = value;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (arg.startsWith("--configuration=")) {
|
|
188
|
+
configuration = arg.slice(16);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (arg === "--export-options-plist") {
|
|
192
|
+
exportOptionsPlist = argv[++index];
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (arg.startsWith("--export-options-plist=")) {
|
|
196
|
+
exportOptionsPlist = arg.slice(23);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (arg === "--help" || arg === "-h") {
|
|
200
|
+
printUsage();
|
|
201
|
+
process.exit(0);
|
|
202
|
+
}
|
|
203
|
+
if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
|
|
204
|
+
projectRoot = node_path.default.resolve(root, arg);
|
|
205
|
+
hasProjectRootArg = true;
|
|
206
|
+
}
|
|
207
|
+
if (!hasProjectRootArg && !isBleamProjectRoot(projectRoot)) projectRoot = discoverBleamProjectRoot(projectRoot) ?? projectRoot;
|
|
208
|
+
const resolvedProjectRoot = canonicalPath(projectRoot);
|
|
209
|
+
return {
|
|
210
|
+
projectRoot: resolvedProjectRoot,
|
|
211
|
+
output: node_path.default.resolve(resolvedProjectRoot, output ?? "dist"),
|
|
212
|
+
configuration,
|
|
213
|
+
exportOptionsPlist: exportOptionsPlist ? node_path.default.resolve(root, exportOptionsPlist) : void 0
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
function parseProjectToolOptions(argv) {
|
|
217
|
+
const root = invocationRoot();
|
|
218
|
+
let projectRoot = root;
|
|
219
|
+
let hasProjectRootArg = false;
|
|
220
|
+
let write = false;
|
|
221
|
+
let formatCheck = false;
|
|
222
|
+
for (const arg of argv) {
|
|
223
|
+
if (arg === "--write") {
|
|
224
|
+
write = true;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (arg === "--check") {
|
|
228
|
+
formatCheck = true;
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (arg === "--help" || arg === "-h") {
|
|
232
|
+
printUsage();
|
|
233
|
+
process.exit(0);
|
|
234
|
+
}
|
|
235
|
+
if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
|
|
236
|
+
projectRoot = node_path.default.resolve(root, arg);
|
|
237
|
+
hasProjectRootArg = true;
|
|
238
|
+
}
|
|
239
|
+
if (!hasProjectRootArg && !isBleamProjectRoot(projectRoot)) projectRoot = discoverBleamProjectRoot(projectRoot) ?? projectRoot;
|
|
240
|
+
return {
|
|
241
|
+
projectRoot: canonicalPath(projectRoot),
|
|
242
|
+
write,
|
|
243
|
+
formatCheck
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function parseDoctorOptions(argv) {
|
|
247
|
+
const root = invocationRoot();
|
|
248
|
+
let projectRoot = root;
|
|
249
|
+
let hasProjectRootArg = false;
|
|
250
|
+
for (const arg of argv) {
|
|
251
|
+
if (arg === "--help" || arg === "-h") {
|
|
252
|
+
printUsage();
|
|
253
|
+
process.exit(0);
|
|
254
|
+
}
|
|
255
|
+
if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
|
|
256
|
+
projectRoot = node_path.default.resolve(root, arg);
|
|
257
|
+
hasProjectRootArg = true;
|
|
258
|
+
}
|
|
259
|
+
if (!hasProjectRootArg && !isBleamProjectRoot(projectRoot)) projectRoot = discoverBleamProjectRoot(projectRoot) ?? projectRoot;
|
|
260
|
+
return { projectRoot: canonicalPath(projectRoot) };
|
|
261
|
+
}
|
|
88
262
|
function parseInternalMetroOptions(argv) {
|
|
89
263
|
let workspaceRoot;
|
|
90
264
|
let port = 8081;
|
|
@@ -148,6 +322,23 @@ function assertStringField(value, field) {
|
|
|
148
322
|
if (typeof value !== "string" || value.trim() === "") throw new Error(`app.config.ts must define ${field}`);
|
|
149
323
|
return value;
|
|
150
324
|
}
|
|
325
|
+
function isHexColor(value) {
|
|
326
|
+
return typeof value === "string" && /^#[\da-f]{6}$/i.test(value);
|
|
327
|
+
}
|
|
328
|
+
function normalizeAppearance(value) {
|
|
329
|
+
const input = value && typeof value === "object" ? value : {};
|
|
330
|
+
const window = input.window && typeof input.window === "object" ? input.window : {};
|
|
331
|
+
const appearance = {};
|
|
332
|
+
if (window.backgroundColor !== void 0) {
|
|
333
|
+
if (!isHexColor(window.backgroundColor)) throw new Error("app.config.ts appearance.window.backgroundColor must be a #rrggbb color");
|
|
334
|
+
appearance.window = { backgroundColor: window.backgroundColor };
|
|
335
|
+
}
|
|
336
|
+
if (input.userInterfaceStyle !== void 0) {
|
|
337
|
+
if (input.userInterfaceStyle !== "automatic" && input.userInterfaceStyle !== "light" && input.userInterfaceStyle !== "dark") throw new Error("app.config.ts appearance.userInterfaceStyle must be automatic, light, or dark");
|
|
338
|
+
appearance.userInterfaceStyle = input.userInterfaceStyle;
|
|
339
|
+
}
|
|
340
|
+
return appearance;
|
|
341
|
+
}
|
|
151
342
|
function loadAppConfig(projectRoot) {
|
|
152
343
|
const configPath = node_path.default.join(projectRoot, "app.config.ts");
|
|
153
344
|
const loader = `
|
|
@@ -177,8 +368,10 @@ function loadAppConfig(projectRoot) {
|
|
|
177
368
|
return {
|
|
178
369
|
name: assertStringField(value.name, "name"),
|
|
179
370
|
version: typeof value.version === "string" ? value.version : void 0,
|
|
371
|
+
buildNumber: typeof value.buildNumber === "string" ? value.buildNumber : void 0,
|
|
180
372
|
bundleIdentifier: typeof value.bundleIdentifier === "string" ? value.bundleIdentifier : void 0,
|
|
181
|
-
teamId: typeof value.teamId === "string" ? value.teamId : void 0
|
|
373
|
+
teamId: typeof value.teamId === "string" ? value.teamId : void 0,
|
|
374
|
+
appearance: normalizeAppearance(value.appearance)
|
|
182
375
|
};
|
|
183
376
|
}
|
|
184
377
|
function assertBleamConfigFiles(projectRoot) {
|
|
@@ -197,8 +390,10 @@ function readProjectConfig(options) {
|
|
|
197
390
|
return {
|
|
198
391
|
name: config.name,
|
|
199
392
|
version: config.version,
|
|
393
|
+
buildNumber: config.buildNumber ?? "1",
|
|
200
394
|
bundleIdentifier: config.bundleIdentifier,
|
|
201
395
|
teamId: config.teamId,
|
|
396
|
+
appearance: config.appearance ?? normalizeAppearance(void 0),
|
|
202
397
|
runtimeVersion,
|
|
203
398
|
sdkVersion: runtimeVersion
|
|
204
399
|
};
|
|
@@ -211,6 +406,9 @@ function nameFromDirectory(projectRoot) {
|
|
|
211
406
|
if (!name) return "Bleam App";
|
|
212
407
|
return name.replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
213
408
|
}
|
|
409
|
+
function singleQuotedString(value) {
|
|
410
|
+
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\r/g, "\\r").replace(/\n/g, "\\n")}'`;
|
|
411
|
+
}
|
|
214
412
|
function createNewProject(options) {
|
|
215
413
|
const templateRoot = node_path.default.join(packageRoot, "templates", "basic");
|
|
216
414
|
if (!(0, node_fs.existsSync)(templateRoot)) throw new Error(`Missing basic template: ${templateRoot}`);
|
|
@@ -218,10 +416,12 @@ function createNewProject(options) {
|
|
|
218
416
|
(0, node_fs.mkdirSync)(options.projectRoot, { recursive: true });
|
|
219
417
|
(0, node_fs.cpSync)(templateRoot, options.projectRoot, { recursive: true });
|
|
220
418
|
const name = nameFromDirectory(options.projectRoot);
|
|
221
|
-
(0, node_fs.writeFileSync)(node_path.default.join(options.projectRoot, "app.config.ts"), `
|
|
222
|
-
(0, node_fs.writeFileSync)(node_path.default.join(options.projectRoot, ".gitignore"), `.bleam\n`);
|
|
419
|
+
(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`);
|
|
420
|
+
(0, node_fs.writeFileSync)(node_path.default.join(options.projectRoot, ".gitignore"), `.bleam\nbiome.json\n.DS_Store\n`);
|
|
223
421
|
createDevWorkspace(options.projectRoot, {
|
|
224
422
|
name,
|
|
423
|
+
buildNumber: "1",
|
|
424
|
+
appearance: normalizeAppearance(void 0),
|
|
225
425
|
runtimeVersion,
|
|
226
426
|
sdkVersion: runtimeVersion
|
|
227
427
|
});
|
|
@@ -244,7 +444,13 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
244
444
|
version: config.version ?? "0.0.0",
|
|
245
445
|
orientation: "default",
|
|
246
446
|
platforms: ["ios"],
|
|
247
|
-
newArchEnabled: true
|
|
447
|
+
newArchEnabled: true,
|
|
448
|
+
extra: { bleam: {
|
|
449
|
+
appearance: config.appearance,
|
|
450
|
+
buildNumber: config.buildNumber,
|
|
451
|
+
runtimeVersion: config.runtimeVersion,
|
|
452
|
+
sdkVersion: config.sdkVersion
|
|
453
|
+
} }
|
|
248
454
|
} }, null, 2)}\n`);
|
|
249
455
|
(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
456
|
(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`);
|
|
@@ -255,6 +461,7 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
255
461
|
main: "index.js",
|
|
256
462
|
dependencies: {
|
|
257
463
|
"@types/react": packageJson.dependencies?.["@types/react"],
|
|
464
|
+
"@biomejs/biome": packageJson.dependencies?.["@biomejs/biome"],
|
|
258
465
|
expo: packageJson.dependencies?.expo,
|
|
259
466
|
react: packageJson.dependencies?.react,
|
|
260
467
|
"react-native": packageJson.dependencies?.["react-native"],
|
|
@@ -265,8 +472,8 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
265
472
|
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "tsconfig.json"), `${JSON.stringify({
|
|
266
473
|
extends: "bleam/tsconfig",
|
|
267
474
|
compilerOptions: { paths: {
|
|
268
|
-
bleam: ["./node_modules/bleam"],
|
|
269
|
-
"bleam/*": ["./node_modules/bleam/*"],
|
|
475
|
+
bleam: ["./node_modules/bleam/dist/index"],
|
|
476
|
+
"bleam/*": ["./node_modules/bleam/dist/*"],
|
|
270
477
|
expo: ["./node_modules/expo"],
|
|
271
478
|
"expo/*": ["./node_modules/expo/*"],
|
|
272
479
|
react: ["./node_modules/@types/react"],
|
|
@@ -279,6 +486,34 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
279
486
|
}, null, 2)}\n`);
|
|
280
487
|
return workspaceRoot;
|
|
281
488
|
}
|
|
489
|
+
function writeBiomeConfig(configPath) {
|
|
490
|
+
(0, node_fs.writeFileSync)(configPath, `${JSON.stringify({
|
|
491
|
+
$schema: "https://biomejs.dev/schemas/2.5.2/schema.json",
|
|
492
|
+
files: { includes: [
|
|
493
|
+
"app/**/*",
|
|
494
|
+
"app.config.ts",
|
|
495
|
+
"tsconfig.json"
|
|
496
|
+
] },
|
|
497
|
+
formatter: {
|
|
498
|
+
enabled: true,
|
|
499
|
+
indentStyle: "space",
|
|
500
|
+
indentWidth: 2,
|
|
501
|
+
lineWidth: 80
|
|
502
|
+
},
|
|
503
|
+
javascript: { formatter: {
|
|
504
|
+
quoteStyle: "single",
|
|
505
|
+
semicolons: "asNeeded",
|
|
506
|
+
trailingCommas: "all"
|
|
507
|
+
} },
|
|
508
|
+
linter: {
|
|
509
|
+
enabled: true,
|
|
510
|
+
rules: {
|
|
511
|
+
preset: "recommended",
|
|
512
|
+
suspicious: { noExplicitAny: "off" }
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}, null, 2)}\n`);
|
|
516
|
+
}
|
|
282
517
|
function writeProjectRuntimeConfig(projectRoot, config, origin) {
|
|
283
518
|
const projectConfigPath = node_path.default.join(projectRoot, ".bleam", "project.json");
|
|
284
519
|
(0, node_fs.mkdirSync)(node_path.default.dirname(projectConfigPath), { recursive: true });
|
|
@@ -287,28 +522,220 @@ function writeProjectRuntimeConfig(projectRoot, config, origin) {
|
|
|
287
522
|
version: config.version,
|
|
288
523
|
bundleIdentifier: config.bundleIdentifier,
|
|
289
524
|
teamId: config.teamId,
|
|
525
|
+
appearance: config.appearance,
|
|
290
526
|
devServer: origin,
|
|
291
527
|
runtimeVersion: config.runtimeVersion,
|
|
292
528
|
sdkVersion: config.sdkVersion
|
|
293
529
|
}, null, 2)}\n`);
|
|
294
530
|
return projectConfigPath;
|
|
295
531
|
}
|
|
532
|
+
function nativeRuntimeTemplateRoot() {
|
|
533
|
+
return node_path.default.resolve(packageRoot, "..", "..", "app", "bleam");
|
|
534
|
+
}
|
|
535
|
+
function safeArtifactName(name) {
|
|
536
|
+
return name.trim().replace(/[/:\\]/g, "-").replace(/\s+/g, " ") || "App";
|
|
537
|
+
}
|
|
538
|
+
function xcodeSettingValue(value) {
|
|
539
|
+
if (/^[A-Za-z0-9_.$-]+$/.test(value)) return value;
|
|
540
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
541
|
+
}
|
|
542
|
+
function plistString(value) {
|
|
543
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
544
|
+
}
|
|
545
|
+
function replacePlistString(plist, key, value) {
|
|
546
|
+
const pattern = /* @__PURE__ */ new RegExp(`(<key>${key}</key>\\s*<string>)([^<]*)(</string>)`);
|
|
547
|
+
if (!pattern.test(plist)) return plist;
|
|
548
|
+
return plist.replace(pattern, `$1${plistString(value)}$3`);
|
|
549
|
+
}
|
|
550
|
+
function writeGeneratedAppJson(nativeRoot, config) {
|
|
551
|
+
(0, node_fs.writeFileSync)(node_path.default.join(nativeRoot, "app.json"), `${JSON.stringify({ expo: {
|
|
552
|
+
name: config.name,
|
|
553
|
+
slug: slugFromName(config.name),
|
|
554
|
+
version: config.version ?? "1.0.0",
|
|
555
|
+
platforms: ["ios"],
|
|
556
|
+
ios: {
|
|
557
|
+
appleTeamId: config.teamId,
|
|
558
|
+
buildNumber: config.buildNumber,
|
|
559
|
+
bundleIdentifier: config.bundleIdentifier
|
|
560
|
+
}
|
|
561
|
+
} }, null, 2)}\n`);
|
|
562
|
+
}
|
|
563
|
+
function patchNativeProject(nativeRoot, config) {
|
|
564
|
+
const projectPath = node_path.default.join(nativeRoot, "ios", "Bleam.xcodeproj", "project.pbxproj");
|
|
565
|
+
const infoPlistPath = node_path.default.join(nativeRoot, "ios", "Bleam", "Info.plist");
|
|
566
|
+
const productName = xcodeSettingValue(config.name);
|
|
567
|
+
const bundleIdentifier = xcodeSettingValue(config.bundleIdentifier ?? "");
|
|
568
|
+
const teamId = xcodeSettingValue(config.teamId ?? "");
|
|
569
|
+
const version = xcodeSettingValue(config.version ?? "1.0.0");
|
|
570
|
+
const buildNumber = xcodeSettingValue(config.buildNumber);
|
|
571
|
+
let project = (0, node_fs.readFileSync)(projectPath, "utf8");
|
|
572
|
+
project = project.replace(/PRODUCT_BUNDLE_IDENTIFIER = [^;]+;/g, () => {
|
|
573
|
+
return `PRODUCT_BUNDLE_IDENTIFIER = ${bundleIdentifier};`;
|
|
574
|
+
}).replace(/DEVELOPMENT_TEAM = [^;]+;/g, () => {
|
|
575
|
+
return `DEVELOPMENT_TEAM = ${teamId};`;
|
|
576
|
+
}).replace(/MARKETING_VERSION = [^;]+;/g, () => {
|
|
577
|
+
return `MARKETING_VERSION = ${version};`;
|
|
578
|
+
}).replace(/CURRENT_PROJECT_VERSION = [^;]+;/g, () => {
|
|
579
|
+
return `CURRENT_PROJECT_VERSION = ${buildNumber};`;
|
|
580
|
+
}).replace(/PRODUCT_NAME = [^;]+;/g, () => {
|
|
581
|
+
return `PRODUCT_NAME = ${productName};`;
|
|
582
|
+
});
|
|
583
|
+
(0, node_fs.writeFileSync)(projectPath, project);
|
|
584
|
+
let infoPlist = (0, node_fs.readFileSync)(infoPlistPath, "utf8");
|
|
585
|
+
infoPlist = replacePlistString(infoPlist, "CFBundleDisplayName", config.name);
|
|
586
|
+
infoPlist = replacePlistString(infoPlist, "CFBundleShortVersionString", config.version ?? "1.0.0");
|
|
587
|
+
infoPlist = replacePlistString(infoPlist, "CFBundleVersion", config.buildNumber);
|
|
588
|
+
(0, node_fs.writeFileSync)(infoPlistPath, infoPlist);
|
|
589
|
+
}
|
|
590
|
+
function createBuildNativeWorkspace(options, config) {
|
|
591
|
+
const nativeRoot = node_path.default.join(options.projectRoot, ".bleam", "build", "native");
|
|
592
|
+
const templateRoot = nativeRuntimeTemplateRoot();
|
|
593
|
+
(0, node_fs.rmSync)(nativeRoot, {
|
|
594
|
+
recursive: true,
|
|
595
|
+
force: true
|
|
596
|
+
});
|
|
597
|
+
(0, node_fs.mkdirSync)(node_path.default.dirname(nativeRoot), { recursive: true });
|
|
598
|
+
(0, node_fs.cpSync)(templateRoot, nativeRoot, {
|
|
599
|
+
recursive: true,
|
|
600
|
+
filter(source) {
|
|
601
|
+
return !node_path.default.relative(templateRoot, source).split(node_path.default.sep).some((part) => {
|
|
602
|
+
return part === "build" || part === "dist" || part === "node_modules" || part === ".expo" || part === "Pods" || part === ".xcode.env.local" || part === ".DS_Store" || part.endsWith(".xcworkspace");
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
const nodeModules = node_path.default.join(nativeRoot, "node_modules");
|
|
607
|
+
(0, node_fs.rmSync)(nodeModules, {
|
|
608
|
+
recursive: true,
|
|
609
|
+
force: true
|
|
610
|
+
});
|
|
611
|
+
(0, node_fs.symlinkSync)(resolvedDependencyRoot(), nodeModules);
|
|
612
|
+
writeGeneratedAppJson(nativeRoot, config);
|
|
613
|
+
(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`);
|
|
614
|
+
(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`);
|
|
615
|
+
(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`);
|
|
616
|
+
patchNativeProject(nativeRoot, config);
|
|
617
|
+
return nativeRoot;
|
|
618
|
+
}
|
|
619
|
+
function preflightBuild(options, config) {
|
|
620
|
+
if (process.platform !== "darwin") throw new Error(`bleam build requires macOS and Xcode. Current platform: ${process.platform}.\n${doctorHint(options.projectRoot)}`);
|
|
621
|
+
if (!config.bundleIdentifier) throw missingBuildFieldError("bundleIdentifier");
|
|
622
|
+
if (!config.teamId) throw missingBuildFieldError("teamId");
|
|
623
|
+
const templateRoot = nativeRuntimeTemplateRoot();
|
|
624
|
+
if (!(0, node_fs.existsSync)(templateRoot)) throw new Error(`Missing native runtime template: ${templateRoot}\n${doctorHint(options.projectRoot)}`);
|
|
625
|
+
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)}`);
|
|
626
|
+
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)}`);
|
|
627
|
+
}
|
|
628
|
+
function runInheritedCommand(command, args, cwd) {
|
|
629
|
+
const text = commandText(command, args);
|
|
630
|
+
const result = (0, node_child_process.spawnSync)(command, args, {
|
|
631
|
+
cwd,
|
|
632
|
+
stdio: "inherit",
|
|
633
|
+
env: process.env
|
|
634
|
+
});
|
|
635
|
+
if (result.error) throw new Error(`${text} could not start in ${cwd}: ${result.error.message}\n${doctorHint()}`);
|
|
636
|
+
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()}`);
|
|
637
|
+
}
|
|
638
|
+
function installPods(nativeRoot) {
|
|
639
|
+
console.log("Installing native dependencies...");
|
|
640
|
+
runInheritedCommand("pod", ["install"], node_path.default.join(nativeRoot, "ios"));
|
|
641
|
+
}
|
|
642
|
+
function archiveNativeApp(options) {
|
|
643
|
+
const platformOutput = node_path.default.join(options.outputRoot, "macos");
|
|
644
|
+
const archivePath = node_path.default.join(platformOutput, `${safeArtifactName(options.config.name)}.xcarchive`);
|
|
645
|
+
(0, node_fs.mkdirSync)(platformOutput, { recursive: true });
|
|
646
|
+
(0, node_fs.rmSync)(archivePath, {
|
|
647
|
+
recursive: true,
|
|
648
|
+
force: true
|
|
649
|
+
});
|
|
650
|
+
console.log(`Archiving ${options.config.name} for macOS...`);
|
|
651
|
+
runInheritedCommand("xcodebuild", [
|
|
652
|
+
"-allowProvisioningUpdates",
|
|
653
|
+
"-workspace",
|
|
654
|
+
node_path.default.join(options.nativeRoot, "ios", "Bleam.xcworkspace"),
|
|
655
|
+
"-scheme",
|
|
656
|
+
"bleam",
|
|
657
|
+
"-configuration",
|
|
658
|
+
options.configuration,
|
|
659
|
+
"-destination",
|
|
660
|
+
"platform=macOS,arch=arm64,variant=Mac Catalyst",
|
|
661
|
+
"-archivePath",
|
|
662
|
+
archivePath,
|
|
663
|
+
"archive"
|
|
664
|
+
], options.nativeRoot);
|
|
665
|
+
return archivePath;
|
|
666
|
+
}
|
|
667
|
+
function exportNativeArchive(options) {
|
|
668
|
+
const exportPath = node_path.default.join(options.outputRoot, "macos", "export");
|
|
669
|
+
(0, node_fs.rmSync)(exportPath, {
|
|
670
|
+
recursive: true,
|
|
671
|
+
force: true
|
|
672
|
+
});
|
|
673
|
+
(0, node_fs.mkdirSync)(exportPath, { recursive: true });
|
|
674
|
+
console.log("Exporting macOS archive...");
|
|
675
|
+
runInheritedCommand("xcodebuild", [
|
|
676
|
+
"-allowProvisioningUpdates",
|
|
677
|
+
"-exportArchive",
|
|
678
|
+
"-archivePath",
|
|
679
|
+
options.archivePath,
|
|
680
|
+
"-exportPath",
|
|
681
|
+
exportPath,
|
|
682
|
+
"-exportOptionsPlist",
|
|
683
|
+
options.exportOptionsPlist
|
|
684
|
+
], node_path.default.dirname(options.archivePath));
|
|
685
|
+
return exportPath;
|
|
686
|
+
}
|
|
687
|
+
async function buildNativeArchives(options) {
|
|
688
|
+
const config = readProjectConfig(options);
|
|
689
|
+
preflightBuild(options, config);
|
|
690
|
+
const nativeRoot = createBuildNativeWorkspace(options, config);
|
|
691
|
+
installPods(nativeRoot);
|
|
692
|
+
const archivePath = archiveNativeApp({
|
|
693
|
+
nativeRoot,
|
|
694
|
+
outputRoot: options.output,
|
|
695
|
+
configuration: options.configuration,
|
|
696
|
+
config
|
|
697
|
+
});
|
|
698
|
+
console.log(`Created ${archivePath}`);
|
|
699
|
+
if (options.exportOptionsPlist) {
|
|
700
|
+
const exportPath = exportNativeArchive({
|
|
701
|
+
archivePath,
|
|
702
|
+
outputRoot: options.output,
|
|
703
|
+
exportOptionsPlist: options.exportOptionsPlist
|
|
704
|
+
});
|
|
705
|
+
console.log(`Exported ${exportPath}`);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
296
708
|
function runtimeCacheRoot() {
|
|
297
|
-
return node_path.default.join(node_os.default.homedir(), "Library", "Caches", "bleam", "runtimes", runtimeVersion,
|
|
709
|
+
return node_path.default.join(node_os.default.homedir(), "Library", "Caches", "bleam", "runtimes", runtimeVersion, artifactPlatform());
|
|
298
710
|
}
|
|
299
711
|
function localDevelopmentRuntimeAppPath() {
|
|
300
|
-
|
|
712
|
+
const productsRoot = node_path.default.resolve(packageRoot, "..", "..", "app", "bleam", "build", "Build", "Products", "Debug-maccatalyst");
|
|
713
|
+
for (const appName of ["Bleam.app", "bleam.app"]) {
|
|
714
|
+
const appPath = node_path.default.join(productsRoot, appName);
|
|
715
|
+
if ((0, node_fs.existsSync)(appPath)) return appPath;
|
|
716
|
+
}
|
|
717
|
+
return node_path.default.join(productsRoot, "Bleam.app");
|
|
301
718
|
}
|
|
302
719
|
function runtimeReleaseBaseUrl() {
|
|
303
720
|
return process.env.BLEAM_RUNTIME_RELEASE_BASE_URL ?? "https://github.com/bajedev/bleam-app/releases/download";
|
|
304
721
|
}
|
|
305
722
|
function runtimeArchiveName() {
|
|
306
|
-
return `bleam-runtime-v${runtimeVersion}-${
|
|
723
|
+
return `bleam-runtime-v${runtimeVersion}-${artifactPlatform()}.zip`;
|
|
307
724
|
}
|
|
308
725
|
function runtimeArchiveUrl() {
|
|
309
726
|
const tag = encodeURIComponent(`bleam@${runtimeVersion}`);
|
|
310
727
|
return `${runtimeReleaseBaseUrl()}/${tag}/${runtimeArchiveName()}`;
|
|
311
728
|
}
|
|
729
|
+
function runtimeResolutionDetails() {
|
|
730
|
+
return [
|
|
731
|
+
`Runtime version: ${runtimeVersion}`,
|
|
732
|
+
`Runtime platform: ${artifactPlatform()}`,
|
|
733
|
+
`Runtime cache: ${runtimeCacheRoot()}`,
|
|
734
|
+
`Release URL: ${runtimeArchiveUrl()}`,
|
|
735
|
+
`Override with BLEAM_RUNTIME_APP=/path/to/Bleam.app for local testing.`,
|
|
736
|
+
doctorHint()
|
|
737
|
+
].join("\n");
|
|
738
|
+
}
|
|
312
739
|
function sha256(filePath) {
|
|
313
740
|
return (0, node_crypto.createHash)("sha256").update((0, node_fs.readFileSync)(filePath)).digest("hex");
|
|
314
741
|
}
|
|
@@ -323,7 +750,8 @@ async function downloadExpectedSha256(url) {
|
|
|
323
750
|
return (await response.text()).trim().split(/\s+/)[0];
|
|
324
751
|
}
|
|
325
752
|
async function downloadRuntimeArtifact() {
|
|
326
|
-
if (process.platform !== "darwin") throw new Error("Bleam runtime artifacts are currently only available
|
|
753
|
+
if (process.platform !== "darwin") throw new Error("Bleam runtime artifacts are currently only available from macOS hosts.");
|
|
754
|
+
const runtimePlatform = artifactPlatform();
|
|
327
755
|
const cacheRoot = runtimeCacheRoot();
|
|
328
756
|
const cachedAppPath = node_path.default.join(cacheRoot, "Bleam.app");
|
|
329
757
|
if ((0, node_fs.existsSync)(cachedAppPath)) return {
|
|
@@ -370,10 +798,11 @@ async function downloadRuntimeArtifact() {
|
|
|
370
798
|
};
|
|
371
799
|
}
|
|
372
800
|
async function resolveRuntimeArtifact() {
|
|
801
|
+
const runtimePlatform = artifactPlatform();
|
|
373
802
|
const overrideAppPath = process.env.BLEAM_RUNTIME_APP;
|
|
374
803
|
if (overrideAppPath) {
|
|
375
804
|
const appPath = node_path.default.resolve(overrideAppPath);
|
|
376
|
-
if (!(0, node_fs.existsSync)(appPath)) throw new Error(`BLEAM_RUNTIME_APP
|
|
805
|
+
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()}`);
|
|
377
806
|
return {
|
|
378
807
|
appPath,
|
|
379
808
|
version: runtimeVersion,
|
|
@@ -386,7 +815,11 @@ async function resolveRuntimeArtifact() {
|
|
|
386
815
|
version: runtimeVersion,
|
|
387
816
|
platform: runtimePlatform
|
|
388
817
|
};
|
|
389
|
-
|
|
818
|
+
try {
|
|
819
|
+
return await downloadRuntimeArtifact();
|
|
820
|
+
} catch (error) {
|
|
821
|
+
throw new Error(`Failed to resolve the Bleam runtime.\n${runtimeResolutionDetails()}\n\nCause: ${error instanceof Error ? error.message : String(error)}`);
|
|
822
|
+
}
|
|
390
823
|
}
|
|
391
824
|
function copyRuntimeClient(projectRoot, runtime) {
|
|
392
825
|
const clientAppPath = node_path.default.join(projectRoot, ".bleam", "client", "Bleam.app");
|
|
@@ -405,24 +838,104 @@ function isBleamManifest(value) {
|
|
|
405
838
|
async function readDevManifest(origin, timeoutMs = 3e4) {
|
|
406
839
|
const manifestUrl = `${origin}/bleam/manifest.json`;
|
|
407
840
|
const startedAt = Date.now();
|
|
408
|
-
|
|
841
|
+
const spinner = startSpinner("Waiting for Bleam dev server...");
|
|
409
842
|
while (Date.now() - startedAt <= timeoutMs) {
|
|
410
843
|
try {
|
|
411
844
|
const response = await fetch(manifestUrl, { cache: "no-store" });
|
|
412
845
|
const value = await response.json();
|
|
413
|
-
if (response.ok && isBleamManifest(value))
|
|
846
|
+
if (response.ok && isBleamManifest(value)) {
|
|
847
|
+
spinner?.success("Bleam dev server is ready");
|
|
848
|
+
return value;
|
|
849
|
+
}
|
|
414
850
|
} catch {}
|
|
415
851
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
416
852
|
}
|
|
853
|
+
spinner?.error("Bleam dev server did not become available");
|
|
417
854
|
throw new Error(`Bleam manifest did not become available: ${manifestUrl}`);
|
|
418
855
|
}
|
|
856
|
+
function pushDoctorCheck(checks, status, label, detail) {
|
|
857
|
+
checks.push({
|
|
858
|
+
status,
|
|
859
|
+
label,
|
|
860
|
+
detail
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
function printDoctorSection(title, checks) {
|
|
864
|
+
if (checks.length === 0) return;
|
|
865
|
+
console.log(`\n${heading(title)}`);
|
|
866
|
+
for (const check of checks) {
|
|
867
|
+
const detail = check.detail ? muted(`: ${check.detail}`) : "";
|
|
868
|
+
console.log(` ${statusLabel(check.status)} ${check.label}${detail}`);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
function runDoctor(options) {
|
|
872
|
+
const projectChecks = [];
|
|
873
|
+
const runtimeChecks = [];
|
|
874
|
+
const environmentChecks = [];
|
|
875
|
+
const appConfigPath = node_path.default.join(options.projectRoot, "app.config.ts");
|
|
876
|
+
const appEntryPath = node_path.default.join(options.projectRoot, "app", "index.tsx");
|
|
877
|
+
if ((0, node_fs.existsSync)(appConfigPath)) pushDoctorCheck(projectChecks, "pass", "app.config.ts found");
|
|
878
|
+
else pushDoctorCheck(projectChecks, "fail", "app.config.ts missing");
|
|
879
|
+
if ((0, node_fs.existsSync)(appEntryPath)) pushDoctorCheck(projectChecks, "pass", "app/index.tsx found");
|
|
880
|
+
else pushDoctorCheck(projectChecks, "fail", "app/index.tsx missing");
|
|
881
|
+
try {
|
|
882
|
+
const config = readProjectConfig(options);
|
|
883
|
+
pushDoctorCheck(projectChecks, "pass", "config loaded");
|
|
884
|
+
pushDoctorCheck(projectChecks, "pass", "name", config.name);
|
|
885
|
+
if (config.bundleIdentifier) pushDoctorCheck(projectChecks, "pass", "bundleIdentifier", config.bundleIdentifier);
|
|
886
|
+
else pushDoctorCheck(projectChecks, "warn", "bundleIdentifier not configured", "required for bleam build");
|
|
887
|
+
if (config.teamId) pushDoctorCheck(projectChecks, "pass", "teamId", config.teamId);
|
|
888
|
+
else pushDoctorCheck(projectChecks, "warn", "teamId not configured", "required for bleam build");
|
|
889
|
+
} catch (error) {
|
|
890
|
+
pushDoctorCheck(projectChecks, "fail", "config failed to load", error instanceof Error ? error.message : String(error));
|
|
891
|
+
}
|
|
892
|
+
const cacheRoot = runtimeCacheRoot();
|
|
893
|
+
const cachedAppPath = node_path.default.join(cacheRoot, "Bleam.app");
|
|
894
|
+
const localAppPath = localDevelopmentRuntimeAppPath();
|
|
895
|
+
pushDoctorCheck(runtimeChecks, "pass", "version", runtimeVersion);
|
|
896
|
+
pushDoctorCheck(runtimeChecks, "pass", "platform", artifactPlatform());
|
|
897
|
+
pushDoctorCheck(runtimeChecks, "pass", "cache", prettyPath(cacheRoot));
|
|
898
|
+
if ((0, node_fs.existsSync)(cachedAppPath)) pushDoctorCheck(runtimeChecks, "pass", "cached runtime found");
|
|
899
|
+
else pushDoctorCheck(runtimeChecks, "warn", "runtime not cached yet", "bleam dev can download it on demand");
|
|
900
|
+
if ((0, node_fs.existsSync)(localAppPath)) pushDoctorCheck(runtimeChecks, "pass", "local development runtime found", prettyPath(localAppPath));
|
|
901
|
+
else pushDoctorCheck(runtimeChecks, "warn", "local development runtime not found", prettyPath(localAppPath));
|
|
902
|
+
const overrideAppPath = process.env.BLEAM_RUNTIME_APP;
|
|
903
|
+
if (overrideAppPath) {
|
|
904
|
+
const appPath = node_path.default.resolve(overrideAppPath);
|
|
905
|
+
pushDoctorCheck(runtimeChecks, (0, node_fs.existsSync)(appPath) ? "pass" : "fail", "BLEAM_RUNTIME_APP", prettyPath(appPath));
|
|
906
|
+
}
|
|
907
|
+
pushDoctorCheck(runtimeChecks, "pass", "release artifact URL", runtimeArchiveUrl());
|
|
908
|
+
pushDoctorCheck(environmentChecks, process.platform === "darwin" ? "pass" : "fail", "macOS host", process.platform);
|
|
909
|
+
pushDoctorCheck(environmentChecks, "pass", "node", prettyPath(process.execPath));
|
|
910
|
+
const hasXcodebuild = commandSucceeds("xcodebuild", ["-version"]);
|
|
911
|
+
pushDoctorCheck(environmentChecks, hasXcodebuild ? "pass" : "warn", "xcodebuild", hasXcodebuild ? "available" : "unavailable");
|
|
912
|
+
const hasPod = commandSucceeds("pod", ["--version"]);
|
|
913
|
+
pushDoctorCheck(environmentChecks, hasPod ? "pass" : "warn", "pod", hasPod ? "available" : "unavailable");
|
|
914
|
+
const allChecks = [
|
|
915
|
+
...projectChecks,
|
|
916
|
+
...runtimeChecks,
|
|
917
|
+
...environmentChecks
|
|
918
|
+
];
|
|
919
|
+
const counts = {
|
|
920
|
+
pass: allChecks.filter((check) => check.status === "pass").length,
|
|
921
|
+
warn: allChecks.filter((check) => check.status === "warn").length,
|
|
922
|
+
fail: allChecks.filter((check) => check.status === "fail").length
|
|
923
|
+
};
|
|
924
|
+
console.log(heading("Bleam Doctor"));
|
|
925
|
+
printDoctorSection("Project", projectChecks);
|
|
926
|
+
printDoctorSection("Runtime", runtimeChecks);
|
|
927
|
+
printDoctorSection("Environment", environmentChecks);
|
|
928
|
+
console.log(`\n${heading("Summary")}`);
|
|
929
|
+
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")}`);
|
|
930
|
+
if (counts.fail > 0) process.exit(1);
|
|
931
|
+
}
|
|
419
932
|
function formatDuration(ms) {
|
|
420
933
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
421
934
|
}
|
|
422
935
|
async function waitForDevBundle(bundleUrl, timeoutMs = 6e4) {
|
|
423
936
|
const startedAt = Date.now();
|
|
424
937
|
const requestTimeoutMs = 3e4;
|
|
425
|
-
|
|
938
|
+
const spinner = startSpinner("Bundling app...");
|
|
426
939
|
while (Date.now() - startedAt <= timeoutMs) {
|
|
427
940
|
const requestStartedAt = Date.now();
|
|
428
941
|
try {
|
|
@@ -432,17 +945,27 @@ async function waitForDevBundle(bundleUrl, timeoutMs = 6e4) {
|
|
|
432
945
|
});
|
|
433
946
|
await response.body?.cancel();
|
|
434
947
|
if (response.ok) {
|
|
435
|
-
|
|
948
|
+
spinner?.success(`Bundled app in ${formatDuration(Date.now() - startedAt)}`);
|
|
949
|
+
if (!spinner) console.log(`Bundled app in ${formatDuration(Date.now() - startedAt)}`);
|
|
436
950
|
return;
|
|
437
951
|
}
|
|
438
|
-
|
|
952
|
+
if (spinner) spinner.text = `Bundle request returned ${response.status}, retrying...`;
|
|
953
|
+
else console.log(`Bundle request returned ${response.status}, retrying...`);
|
|
439
954
|
} catch (error) {
|
|
440
|
-
if (error instanceof Error && error.name === "TimeoutError")
|
|
441
|
-
|
|
955
|
+
if (error instanceof Error && error.name === "TimeoutError") {
|
|
956
|
+
const message = `Bundle request timed out after ${formatDuration(Date.now() - requestStartedAt)}, retrying...`;
|
|
957
|
+
if (spinner) spinner.text = message;
|
|
958
|
+
else console.log(message);
|
|
959
|
+
} else {
|
|
960
|
+
const message = `Bundle request failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
961
|
+
if (spinner) spinner.text = `${message}, retrying...`;
|
|
962
|
+
else console.log(message);
|
|
963
|
+
}
|
|
442
964
|
}
|
|
443
965
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
444
966
|
}
|
|
445
|
-
|
|
967
|
+
spinner?.error("Bundle did not complete");
|
|
968
|
+
throw new Error(`Bleam bundle did not complete within ${formatDuration(timeoutMs)}.\nBundle URL: ${bundleUrl}\n${doctorHint()}`);
|
|
446
969
|
}
|
|
447
970
|
function openRuntimeClient(appPath, projectConfigPath, manifest) {
|
|
448
971
|
const child = (0, node_child_process.spawn)("open", [
|
|
@@ -463,7 +986,110 @@ function openRuntimeClient(appPath, projectConfigPath, manifest) {
|
|
|
463
986
|
if (code && code !== 0) console.error(`Failed to open Bleam runtime at ${appPath}`);
|
|
464
987
|
});
|
|
465
988
|
}
|
|
989
|
+
async function launchRuntimeClient(appPath, projectConfigPath, manifest) {
|
|
990
|
+
openRuntimeClient(appPath, projectConfigPath, manifest);
|
|
991
|
+
}
|
|
992
|
+
function focusRuntimeClient() {
|
|
993
|
+
return (0, node_child_process.spawnSync)("osascript", ["-e", "tell application id \"dev.bleam.app\" to activate"], { stdio: "ignore" }).status === 0;
|
|
994
|
+
}
|
|
995
|
+
function sendJson(res, status, value) {
|
|
996
|
+
res.writeHead(status, {
|
|
997
|
+
"Cache-Control": "no-store",
|
|
998
|
+
"Content-Type": "application/json; charset=utf-8"
|
|
999
|
+
});
|
|
1000
|
+
res.end(JSON.stringify(value));
|
|
1001
|
+
}
|
|
1002
|
+
async function requestRuntimeReload(origin) {
|
|
1003
|
+
const response = await fetch(`${origin}/bleam/reload`, {
|
|
1004
|
+
method: "POST",
|
|
1005
|
+
cache: "no-store"
|
|
1006
|
+
});
|
|
1007
|
+
const value = await response.json();
|
|
1008
|
+
if (!response.ok) throw new Error(`Reload request failed: ${response.status}`);
|
|
1009
|
+
const reload = value;
|
|
1010
|
+
return typeof reload.clients === "number" ? reload.clients : 0;
|
|
1011
|
+
}
|
|
1012
|
+
function biomeBinPath() {
|
|
1013
|
+
const biomePackageJsonPath = require$1.resolve("@biomejs/biome/package.json");
|
|
1014
|
+
const biomePackageRoot = node_path.default.dirname(biomePackageJsonPath);
|
|
1015
|
+
const biomePackage = require$1("@biomejs/biome/package.json");
|
|
1016
|
+
const bin = typeof biomePackage.bin === "string" ? biomePackage.bin : biomePackage.bin?.biome;
|
|
1017
|
+
if (!bin) throw new Error("Could not resolve @biomejs/biome binary");
|
|
1018
|
+
return node_path.default.join(biomePackageRoot, bin);
|
|
1019
|
+
}
|
|
1020
|
+
function ensureProjectToolWorkspace(options) {
|
|
1021
|
+
const config = readProjectConfig({ projectRoot: options.projectRoot });
|
|
1022
|
+
return createDevWorkspace(options.projectRoot, config);
|
|
1023
|
+
}
|
|
1024
|
+
function runBiomeCommand(command, options) {
|
|
1025
|
+
assertBleamConfigFiles(options.projectRoot);
|
|
1026
|
+
ensureProjectToolWorkspace(options);
|
|
1027
|
+
const configPath = node_path.default.join(options.projectRoot, "biome.json");
|
|
1028
|
+
const existingConfig = (0, node_fs.existsSync)(configPath) ? (0, node_fs.readFileSync)(configPath, "utf8") : void 0;
|
|
1029
|
+
const args = [
|
|
1030
|
+
command,
|
|
1031
|
+
"--config-path",
|
|
1032
|
+
"biome.json"
|
|
1033
|
+
];
|
|
1034
|
+
if (command === "check" && options.write) args.push("--write");
|
|
1035
|
+
if (command === "format" && !options.formatCheck) args.push("--write");
|
|
1036
|
+
args.push("app", "app.config.ts", "tsconfig.json");
|
|
1037
|
+
writeBiomeConfig(configPath);
|
|
1038
|
+
const result = (0, node_child_process.spawnSync)(biomeBinPath(), args, {
|
|
1039
|
+
cwd: options.projectRoot,
|
|
1040
|
+
stdio: "inherit"
|
|
1041
|
+
});
|
|
1042
|
+
if (existingConfig === void 0) (0, node_fs.rmSync)(configPath, { force: true });
|
|
1043
|
+
else (0, node_fs.writeFileSync)(configPath, existingConfig);
|
|
1044
|
+
if (result.error) throw result.error;
|
|
1045
|
+
process.exit(result.status ?? 1);
|
|
1046
|
+
}
|
|
1047
|
+
function setupInteractiveControls(options) {
|
|
1048
|
+
if (!process.stdin.isTTY) return () => {};
|
|
1049
|
+
const wasRaw = process.stdin.isRaw;
|
|
1050
|
+
let closed = false;
|
|
1051
|
+
const cleanup = () => {
|
|
1052
|
+
if (closed) return;
|
|
1053
|
+
closed = true;
|
|
1054
|
+
process.stdin.off("data", onData);
|
|
1055
|
+
process.stdin.setRawMode(wasRaw);
|
|
1056
|
+
};
|
|
1057
|
+
const onData = (data) => {
|
|
1058
|
+
for (const byte of data) {
|
|
1059
|
+
if (byte === 3) {
|
|
1060
|
+
cleanup();
|
|
1061
|
+
options.stop();
|
|
1062
|
+
return;
|
|
1063
|
+
}
|
|
1064
|
+
const key = String.fromCharCode(byte).toLowerCase();
|
|
1065
|
+
if (key === "o") {
|
|
1066
|
+
(async () => {
|
|
1067
|
+
try {
|
|
1068
|
+
if (!focusRuntimeClient()) {
|
|
1069
|
+
console.log("Opening Bleam app...");
|
|
1070
|
+
await launchRuntimeClient(options.clientAppPath, options.projectConfigPath, options.manifest);
|
|
1071
|
+
}
|
|
1072
|
+
} catch (error) {
|
|
1073
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1074
|
+
}
|
|
1075
|
+
})();
|
|
1076
|
+
continue;
|
|
1077
|
+
}
|
|
1078
|
+
if (key === "r") requestRuntimeReload(options.origin).then((clients) => {
|
|
1079
|
+
console.log(`Reloaded app (${clients} client${clients === 1 ? "" : "s"})`);
|
|
1080
|
+
}).catch((error) => {
|
|
1081
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
process.stdin.setRawMode(true);
|
|
1086
|
+
process.stdin.resume();
|
|
1087
|
+
process.stdin.on("data", onData);
|
|
1088
|
+
console.log("Press o to open, r to reload, Ctrl+C to stop.");
|
|
1089
|
+
return cleanup;
|
|
1090
|
+
}
|
|
466
1091
|
async function startInternalMetroServer(options) {
|
|
1092
|
+
process.env.BLEAM_DEV_PLATFORM ??= "macos";
|
|
467
1093
|
const metro = require$1("@expo/metro/metro");
|
|
468
1094
|
const { loadConfig } = require$1("@expo/metro/metro-config");
|
|
469
1095
|
const config = await loadConfig({
|
|
@@ -475,6 +1101,25 @@ async function startInternalMetroServer(options) {
|
|
|
475
1101
|
watch: true,
|
|
476
1102
|
waitForBundler: true
|
|
477
1103
|
});
|
|
1104
|
+
const messageClients = /* @__PURE__ */ new Set();
|
|
1105
|
+
const messageServer = new ws.WebSocketServer({ noServer: true });
|
|
1106
|
+
const broadcastReload = () => {
|
|
1107
|
+
const message = JSON.stringify({
|
|
1108
|
+
version: 2,
|
|
1109
|
+
method: "reload",
|
|
1110
|
+
params: {}
|
|
1111
|
+
});
|
|
1112
|
+
let clients = 0;
|
|
1113
|
+
for (const client of messageClients) if (client.readyState === ws.WebSocket.OPEN) {
|
|
1114
|
+
client.send(message);
|
|
1115
|
+
clients += 1;
|
|
1116
|
+
}
|
|
1117
|
+
return clients;
|
|
1118
|
+
};
|
|
1119
|
+
messageServer.on("connection", (client) => {
|
|
1120
|
+
messageClients.add(client);
|
|
1121
|
+
client.on("close", () => messageClients.delete(client));
|
|
1122
|
+
});
|
|
478
1123
|
const server = node_http.default.createServer((req, res) => {
|
|
479
1124
|
if (req.url?.split("?")[0] === "/status") {
|
|
480
1125
|
res.writeHead(200, {
|
|
@@ -485,10 +1130,49 @@ async function startInternalMetroServer(options) {
|
|
|
485
1130
|
res.end("packager-status:running");
|
|
486
1131
|
return;
|
|
487
1132
|
}
|
|
488
|
-
|
|
1133
|
+
if (req.url?.split("?")[0] === "/bleam/reload") {
|
|
1134
|
+
if (req.method !== "POST") {
|
|
1135
|
+
res.writeHead(405, { Allow: "POST" });
|
|
1136
|
+
res.end();
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
sendJson(res, 200, {
|
|
1140
|
+
ok: true,
|
|
1141
|
+
clients: broadcastReload()
|
|
1142
|
+
});
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
middleware(req, res, (error) => {
|
|
1146
|
+
if (res.headersSent) return;
|
|
1147
|
+
if (error) {
|
|
1148
|
+
console.error(error.message);
|
|
1149
|
+
res.writeHead(500, {
|
|
1150
|
+
"Cache-Control": "no-store",
|
|
1151
|
+
"Content-Type": "text/plain; charset=utf-8"
|
|
1152
|
+
});
|
|
1153
|
+
res.end(error.message);
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
res.writeHead(404, {
|
|
1157
|
+
"Cache-Control": "no-store",
|
|
1158
|
+
"Content-Type": "text/plain; charset=utf-8"
|
|
1159
|
+
});
|
|
1160
|
+
res.end("Not found");
|
|
1161
|
+
});
|
|
489
1162
|
});
|
|
490
1163
|
server.timeout = 0;
|
|
491
1164
|
attachHmrServer(server);
|
|
1165
|
+
const metroUpgradeListeners = server.listeners("upgrade");
|
|
1166
|
+
server.removeAllListeners("upgrade");
|
|
1167
|
+
server.on("upgrade", (req, socket, head) => {
|
|
1168
|
+
if (req.url?.split("?")[0] === "/message") {
|
|
1169
|
+
messageServer.handleUpgrade(req, socket, head, (client) => {
|
|
1170
|
+
messageServer.emit("connection", client, req);
|
|
1171
|
+
});
|
|
1172
|
+
return;
|
|
1173
|
+
}
|
|
1174
|
+
for (const listener of metroUpgradeListeners) listener.call(server, req, socket, head);
|
|
1175
|
+
});
|
|
492
1176
|
await new Promise((resolve, reject) => {
|
|
493
1177
|
server.on("error", reject);
|
|
494
1178
|
server.listen(options.port, "localhost", () => resolve());
|
|
@@ -498,6 +1182,9 @@ async function startInternalMetroServer(options) {
|
|
|
498
1182
|
});
|
|
499
1183
|
console.log(`Bleam dev server running at http://localhost:${options.port}`);
|
|
500
1184
|
const close = () => {
|
|
1185
|
+
setTimeout(() => process.exit(0), 1e3).unref();
|
|
1186
|
+
messageServer.close();
|
|
1187
|
+
for (const client of messageClients) client.terminate();
|
|
501
1188
|
server.close(() => {
|
|
502
1189
|
end();
|
|
503
1190
|
process.exit(0);
|
|
@@ -529,6 +1216,7 @@ async function startDevServer(options) {
|
|
|
529
1216
|
BLEAM_DEV_NAME: config.name,
|
|
530
1217
|
BLEAM_DEV_ORIGIN: origin,
|
|
531
1218
|
BLEAM_DEV_PORT: String(options.port),
|
|
1219
|
+
BLEAM_DEV_PLATFORM: "macos",
|
|
532
1220
|
BLEAM_DEV_RUNTIME_VERSION: config.runtimeVersion,
|
|
533
1221
|
BLEAM_DEV_SDK_VERSION: config.sdkVersion,
|
|
534
1222
|
NODE_PATH: [
|
|
@@ -541,20 +1229,48 @@ async function startDevServer(options) {
|
|
|
541
1229
|
].filter(Boolean).join(node_path.default.delimiter)
|
|
542
1230
|
}
|
|
543
1231
|
});
|
|
1232
|
+
let cleanupInteractiveControls = () => {};
|
|
1233
|
+
let stopping = false;
|
|
544
1234
|
const stop = (signal) => {
|
|
1235
|
+
if (stopping) return;
|
|
1236
|
+
stopping = true;
|
|
1237
|
+
cleanupInteractiveControls();
|
|
545
1238
|
child.kill(signal);
|
|
1239
|
+
setTimeout(() => process.exit(0), 2e3).unref();
|
|
546
1240
|
};
|
|
547
1241
|
process.on("SIGINT", () => stop("SIGINT"));
|
|
548
1242
|
process.on("SIGTERM", () => stop("SIGTERM"));
|
|
549
|
-
child.on("
|
|
1243
|
+
child.on("error", (error) => {
|
|
1244
|
+
cleanupInteractiveControls();
|
|
1245
|
+
console.error(`Bleam dev server process failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1246
|
+
console.error(doctorHint(options.projectRoot));
|
|
1247
|
+
process.exit(1);
|
|
1248
|
+
});
|
|
1249
|
+
child.on("exit", (code) => {
|
|
1250
|
+
cleanupInteractiveControls();
|
|
1251
|
+
process.exit(code ?? 0);
|
|
1252
|
+
});
|
|
550
1253
|
try {
|
|
551
1254
|
const manifest = await readDevManifest(origin);
|
|
552
|
-
|
|
1255
|
+
cleanupInteractiveControls = setupInteractiveControls({
|
|
1256
|
+
origin,
|
|
1257
|
+
clientAppPath,
|
|
1258
|
+
projectConfigPath,
|
|
1259
|
+
manifest,
|
|
1260
|
+
stop: () => stop("SIGINT")
|
|
1261
|
+
});
|
|
1262
|
+
if (options.run && process.env.BLEAM_NO_OPEN !== "1") try {
|
|
553
1263
|
await waitForDevBundle(manifest.bundleUrl);
|
|
554
1264
|
console.log("Opening Bleam app...");
|
|
555
|
-
|
|
1265
|
+
await launchRuntimeClient(clientAppPath, projectConfigPath, manifest);
|
|
1266
|
+
} catch (error) {
|
|
1267
|
+
console.error(`Initial app launch failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1268
|
+
console.error(doctorHint(options.projectRoot));
|
|
1269
|
+
console.error("Check BLEAM_RUNTIME_APP if you are using a runtime override.");
|
|
1270
|
+
console.error("Bleam dev server is still running.");
|
|
556
1271
|
}
|
|
557
1272
|
} catch (error) {
|
|
1273
|
+
cleanupInteractiveControls();
|
|
558
1274
|
child.kill("SIGTERM");
|
|
559
1275
|
throw error;
|
|
560
1276
|
}
|
|
@@ -570,7 +1286,8 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
570
1286
|
createNewProject(options);
|
|
571
1287
|
if (options.run) await startDevServer({
|
|
572
1288
|
projectRoot: options.projectRoot,
|
|
573
|
-
port: 8081
|
|
1289
|
+
port: 8081,
|
|
1290
|
+
run: true
|
|
574
1291
|
});
|
|
575
1292
|
return;
|
|
576
1293
|
}
|
|
@@ -578,6 +1295,26 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
578
1295
|
await startDevServer(parseDevOptions(args));
|
|
579
1296
|
return;
|
|
580
1297
|
}
|
|
1298
|
+
if (command === "build") {
|
|
1299
|
+
await buildNativeArchives(parseBuildOptions(args));
|
|
1300
|
+
return;
|
|
1301
|
+
}
|
|
1302
|
+
if (command === "doctor") {
|
|
1303
|
+
runDoctor(parseDoctorOptions(args));
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
if (command === "check") {
|
|
1307
|
+
runBiomeCommand("check", parseProjectToolOptions(args));
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
if (command === "format") {
|
|
1311
|
+
runBiomeCommand("format", parseProjectToolOptions(args));
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1314
|
+
if (command === "lint") {
|
|
1315
|
+
runBiomeCommand("lint", parseProjectToolOptions(args));
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
581
1318
|
if (command === "internal:metro") {
|
|
582
1319
|
await startInternalMetroServer(parseInternalMetroOptions(args));
|
|
583
1320
|
return;
|