bleam 0.0.4 → 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 +918 -68
- package/dist/cli.js +917 -71
- 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 +48 -13
- package/templates/basic/app/index.tsx +136 -0
- 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/templates/basic/app.tsx +0 -18
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,12 +157,139 @@ 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
|
+
}
|
|
262
|
+
function parseInternalMetroOptions(argv) {
|
|
263
|
+
let workspaceRoot;
|
|
264
|
+
let port = 8081;
|
|
265
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
266
|
+
const arg = argv[index];
|
|
267
|
+
if (arg === "--workspace-root") {
|
|
268
|
+
workspaceRoot = node_path.default.resolve(invocationRoot(), argv[++index] ?? "");
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
if (arg === "--port") {
|
|
272
|
+
port = Number(argv[++index]);
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (arg.startsWith("--port=")) {
|
|
276
|
+
port = Number(arg.slice(7));
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
throw new Error(`Unknown internal option: ${arg}`);
|
|
280
|
+
}
|
|
281
|
+
if (!workspaceRoot) throw new Error("Missing --workspace-root");
|
|
282
|
+
if (!Number.isInteger(port) || port <= 0) throw new Error(`Invalid port: ${port}`);
|
|
283
|
+
return {
|
|
284
|
+
workspaceRoot,
|
|
285
|
+
port
|
|
286
|
+
};
|
|
287
|
+
}
|
|
88
288
|
function isBleamProjectRoot(projectRoot) {
|
|
89
|
-
return (0, node_fs.existsSync)(node_path.default.join(projectRoot, "app.config.ts")) && (0, node_fs.existsSync)(node_path.default.join(projectRoot, "app.tsx"));
|
|
289
|
+
return (0, node_fs.existsSync)(node_path.default.join(projectRoot, "app.config.ts")) && (0, node_fs.existsSync)(node_path.default.join(projectRoot, "app", "index.tsx"));
|
|
290
|
+
}
|
|
291
|
+
function resolvedDependencyRoot() {
|
|
292
|
+
return node_path.default.dirname(node_path.default.dirname(require$1.resolve("react-native/package.json")));
|
|
90
293
|
}
|
|
91
294
|
function discoverBleamProjectRoot(searchRoot) {
|
|
92
295
|
const ignoredNames = new Set([
|
|
@@ -119,6 +322,23 @@ function assertStringField(value, field) {
|
|
|
119
322
|
if (typeof value !== "string" || value.trim() === "") throw new Error(`app.config.ts must define ${field}`);
|
|
120
323
|
return value;
|
|
121
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
|
+
}
|
|
122
342
|
function loadAppConfig(projectRoot) {
|
|
123
343
|
const configPath = node_path.default.join(projectRoot, "app.config.ts");
|
|
124
344
|
const loader = `
|
|
@@ -138,7 +358,7 @@ function loadAppConfig(projectRoot) {
|
|
|
138
358
|
...process.env,
|
|
139
359
|
NODE_PATH: [
|
|
140
360
|
node_path.default.join(projectRoot, "node_modules"),
|
|
141
|
-
|
|
361
|
+
resolvedDependencyRoot(),
|
|
142
362
|
process.env.NODE_PATH
|
|
143
363
|
].filter(Boolean).join(node_path.default.delimiter)
|
|
144
364
|
}
|
|
@@ -148,14 +368,21 @@ function loadAppConfig(projectRoot) {
|
|
|
148
368
|
return {
|
|
149
369
|
name: assertStringField(value.name, "name"),
|
|
150
370
|
version: typeof value.version === "string" ? value.version : void 0,
|
|
371
|
+
buildNumber: typeof value.buildNumber === "string" ? value.buildNumber : void 0,
|
|
151
372
|
bundleIdentifier: typeof value.bundleIdentifier === "string" ? value.bundleIdentifier : void 0,
|
|
152
|
-
teamId: typeof value.teamId === "string" ? value.teamId : void 0
|
|
373
|
+
teamId: typeof value.teamId === "string" ? value.teamId : void 0,
|
|
374
|
+
appearance: normalizeAppearance(value.appearance)
|
|
153
375
|
};
|
|
154
376
|
}
|
|
155
377
|
function assertBleamConfigFiles(projectRoot) {
|
|
156
378
|
if ((0, node_fs.existsSync)(node_path.default.join(projectRoot, "app.json"))) throw new Error("Bleam projects use app.config.ts; app.json is not supported.");
|
|
157
379
|
if (!(0, node_fs.existsSync)(node_path.default.join(projectRoot, "app.config.ts"))) throw new Error("Missing app.config.ts. Bleam projects must define app.config.ts.");
|
|
158
|
-
if (!(0, node_fs.existsSync)(node_path.default.join(projectRoot, "app.tsx"))) throw new Error("Missing app.tsx. Bleam projects must define app.tsx.");
|
|
380
|
+
if (!(0, node_fs.existsSync)(node_path.default.join(projectRoot, "app", "index.tsx"))) throw new Error("Missing app/index.tsx. Bleam projects must define app/index.tsx.");
|
|
381
|
+
}
|
|
382
|
+
function ensureProjectTsconfig(projectRoot) {
|
|
383
|
+
const tsconfigPath = node_path.default.join(projectRoot, "tsconfig.json");
|
|
384
|
+
if ((0, node_fs.existsSync)(tsconfigPath)) return;
|
|
385
|
+
(0, node_fs.writeFileSync)(tsconfigPath, `${JSON.stringify({ extends: "./.bleam/dev/tsconfig.json" }, null, 2)}\n`);
|
|
159
386
|
}
|
|
160
387
|
function readProjectConfig(options) {
|
|
161
388
|
assertBleamConfigFiles(options.projectRoot);
|
|
@@ -163,8 +390,10 @@ function readProjectConfig(options) {
|
|
|
163
390
|
return {
|
|
164
391
|
name: config.name,
|
|
165
392
|
version: config.version,
|
|
393
|
+
buildNumber: config.buildNumber ?? "1",
|
|
166
394
|
bundleIdentifier: config.bundleIdentifier,
|
|
167
395
|
teamId: config.teamId,
|
|
396
|
+
appearance: config.appearance ?? normalizeAppearance(void 0),
|
|
168
397
|
runtimeVersion,
|
|
169
398
|
sdkVersion: runtimeVersion
|
|
170
399
|
};
|
|
@@ -177,27 +406,51 @@ function nameFromDirectory(projectRoot) {
|
|
|
177
406
|
if (!name) return "Bleam App";
|
|
178
407
|
return name.replace(/\b\w/g, (letter) => letter.toUpperCase());
|
|
179
408
|
}
|
|
409
|
+
function singleQuotedString(value) {
|
|
410
|
+
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\r/g, "\\r").replace(/\n/g, "\\n")}'`;
|
|
411
|
+
}
|
|
180
412
|
function createNewProject(options) {
|
|
181
413
|
const templateRoot = node_path.default.join(packageRoot, "templates", "basic");
|
|
182
414
|
if (!(0, node_fs.existsSync)(templateRoot)) throw new Error(`Missing basic template: ${templateRoot}`);
|
|
183
415
|
if ((0, node_fs.existsSync)(options.projectRoot) && (0, node_fs.readdirSync)(options.projectRoot).length > 0) throw new Error(`Directory is not empty: ${options.projectRoot}`);
|
|
184
416
|
(0, node_fs.mkdirSync)(options.projectRoot, { recursive: true });
|
|
185
417
|
(0, node_fs.cpSync)(templateRoot, options.projectRoot, { recursive: true });
|
|
186
|
-
|
|
418
|
+
const name = nameFromDirectory(options.projectRoot);
|
|
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`);
|
|
421
|
+
createDevWorkspace(options.projectRoot, {
|
|
422
|
+
name,
|
|
423
|
+
buildNumber: "1",
|
|
424
|
+
appearance: normalizeAppearance(void 0),
|
|
425
|
+
runtimeVersion,
|
|
426
|
+
sdkVersion: runtimeVersion
|
|
427
|
+
});
|
|
187
428
|
console.log(`Created Bleam project at ${options.projectRoot}`);
|
|
188
429
|
}
|
|
189
430
|
function createDevWorkspace(projectRoot, config) {
|
|
190
431
|
const workspaceRoot = node_path.default.join(projectRoot, ".bleam", "dev");
|
|
191
432
|
(0, node_fs.mkdirSync)(workspaceRoot, { recursive: true });
|
|
192
433
|
const workspaceNodeModules = node_path.default.join(workspaceRoot, "node_modules");
|
|
193
|
-
|
|
434
|
+
const dependencyRoot = resolvedDependencyRoot();
|
|
435
|
+
(0, node_fs.rmSync)(workspaceNodeModules, {
|
|
436
|
+
recursive: true,
|
|
437
|
+
force: true
|
|
438
|
+
});
|
|
439
|
+
(0, node_fs.symlinkSync)(dependencyRoot, workspaceNodeModules);
|
|
440
|
+
ensureProjectTsconfig(projectRoot);
|
|
194
441
|
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "app.config.js"), `module.exports = ${JSON.stringify({ expo: {
|
|
195
442
|
name: config.name,
|
|
196
443
|
slug: slugFromName(config.name),
|
|
197
444
|
version: config.version ?? "0.0.0",
|
|
198
445
|
orientation: "default",
|
|
199
446
|
platforms: ["ios"],
|
|
200
|
-
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
|
+
} }
|
|
201
454
|
} }, null, 2)}\n`);
|
|
202
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`);
|
|
203
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`);
|
|
@@ -208,6 +461,7 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
208
461
|
main: "index.js",
|
|
209
462
|
dependencies: {
|
|
210
463
|
"@types/react": packageJson.dependencies?.["@types/react"],
|
|
464
|
+
"@biomejs/biome": packageJson.dependencies?.["@biomejs/biome"],
|
|
211
465
|
expo: packageJson.dependencies?.expo,
|
|
212
466
|
react: packageJson.dependencies?.react,
|
|
213
467
|
"react-native": packageJson.dependencies?.["react-native"],
|
|
@@ -217,10 +471,49 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
217
471
|
}, null, 2)}\n`);
|
|
218
472
|
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "tsconfig.json"), `${JSON.stringify({
|
|
219
473
|
extends: "bleam/tsconfig",
|
|
220
|
-
|
|
474
|
+
compilerOptions: { paths: {
|
|
475
|
+
bleam: ["./node_modules/bleam/dist/index"],
|
|
476
|
+
"bleam/*": ["./node_modules/bleam/dist/*"],
|
|
477
|
+
expo: ["./node_modules/expo"],
|
|
478
|
+
"expo/*": ["./node_modules/expo/*"],
|
|
479
|
+
react: ["./node_modules/@types/react"],
|
|
480
|
+
"react/jsx-runtime": ["./node_modules/@types/react/jsx-runtime"],
|
|
481
|
+
"react/jsx-dev-runtime": ["./node_modules/@types/react/jsx-dev-runtime"],
|
|
482
|
+
"react-native": ["./node_modules/react-native"],
|
|
483
|
+
"react-native/*": ["./node_modules/react-native/*"]
|
|
484
|
+
} },
|
|
485
|
+
include: [node_path.default.relative(workspaceRoot, node_path.default.join(projectRoot, "app")), node_path.default.relative(workspaceRoot, node_path.default.join(projectRoot, "app.config.ts"))]
|
|
221
486
|
}, null, 2)}\n`);
|
|
222
487
|
return workspaceRoot;
|
|
223
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
|
+
}
|
|
224
517
|
function writeProjectRuntimeConfig(projectRoot, config, origin) {
|
|
225
518
|
const projectConfigPath = node_path.default.join(projectRoot, ".bleam", "project.json");
|
|
226
519
|
(0, node_fs.mkdirSync)(node_path.default.dirname(projectConfigPath), { recursive: true });
|
|
@@ -229,28 +522,220 @@ function writeProjectRuntimeConfig(projectRoot, config, origin) {
|
|
|
229
522
|
version: config.version,
|
|
230
523
|
bundleIdentifier: config.bundleIdentifier,
|
|
231
524
|
teamId: config.teamId,
|
|
525
|
+
appearance: config.appearance,
|
|
232
526
|
devServer: origin,
|
|
233
527
|
runtimeVersion: config.runtimeVersion,
|
|
234
528
|
sdkVersion: config.sdkVersion
|
|
235
529
|
}, null, 2)}\n`);
|
|
236
530
|
return projectConfigPath;
|
|
237
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
|
+
}
|
|
238
708
|
function runtimeCacheRoot() {
|
|
239
|
-
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());
|
|
240
710
|
}
|
|
241
711
|
function localDevelopmentRuntimeAppPath() {
|
|
242
|
-
|
|
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");
|
|
243
718
|
}
|
|
244
719
|
function runtimeReleaseBaseUrl() {
|
|
245
720
|
return process.env.BLEAM_RUNTIME_RELEASE_BASE_URL ?? "https://github.com/bajedev/bleam-app/releases/download";
|
|
246
721
|
}
|
|
247
722
|
function runtimeArchiveName() {
|
|
248
|
-
return `bleam-runtime-v${runtimeVersion}-${
|
|
723
|
+
return `bleam-runtime-v${runtimeVersion}-${artifactPlatform()}.zip`;
|
|
249
724
|
}
|
|
250
725
|
function runtimeArchiveUrl() {
|
|
251
726
|
const tag = encodeURIComponent(`bleam@${runtimeVersion}`);
|
|
252
727
|
return `${runtimeReleaseBaseUrl()}/${tag}/${runtimeArchiveName()}`;
|
|
253
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
|
+
}
|
|
254
739
|
function sha256(filePath) {
|
|
255
740
|
return (0, node_crypto.createHash)("sha256").update((0, node_fs.readFileSync)(filePath)).digest("hex");
|
|
256
741
|
}
|
|
@@ -265,7 +750,8 @@ async function downloadExpectedSha256(url) {
|
|
|
265
750
|
return (await response.text()).trim().split(/\s+/)[0];
|
|
266
751
|
}
|
|
267
752
|
async function downloadRuntimeArtifact() {
|
|
268
|
-
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();
|
|
269
755
|
const cacheRoot = runtimeCacheRoot();
|
|
270
756
|
const cachedAppPath = node_path.default.join(cacheRoot, "Bleam.app");
|
|
271
757
|
if ((0, node_fs.existsSync)(cachedAppPath)) return {
|
|
@@ -312,10 +798,11 @@ async function downloadRuntimeArtifact() {
|
|
|
312
798
|
};
|
|
313
799
|
}
|
|
314
800
|
async function resolveRuntimeArtifact() {
|
|
801
|
+
const runtimePlatform = artifactPlatform();
|
|
315
802
|
const overrideAppPath = process.env.BLEAM_RUNTIME_APP;
|
|
316
803
|
if (overrideAppPath) {
|
|
317
804
|
const appPath = node_path.default.resolve(overrideAppPath);
|
|
318
|
-
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()}`);
|
|
319
806
|
return {
|
|
320
807
|
appPath,
|
|
321
808
|
version: runtimeVersion,
|
|
@@ -328,7 +815,11 @@ async function resolveRuntimeArtifact() {
|
|
|
328
815
|
version: runtimeVersion,
|
|
329
816
|
platform: runtimePlatform
|
|
330
817
|
};
|
|
331
|
-
|
|
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
|
+
}
|
|
332
823
|
}
|
|
333
824
|
function copyRuntimeClient(projectRoot, runtime) {
|
|
334
825
|
const clientAppPath = node_path.default.join(projectRoot, ".bleam", "client", "Bleam.app");
|
|
@@ -340,39 +831,6 @@ function copyRuntimeClient(projectRoot, runtime) {
|
|
|
340
831
|
(0, node_fs.cpSync)(runtime.appPath, clientAppPath, { recursive: true });
|
|
341
832
|
return clientAppPath;
|
|
342
833
|
}
|
|
343
|
-
function waitForDevServer(port, timeoutMs = 12e4) {
|
|
344
|
-
return new Promise((resolve, reject) => {
|
|
345
|
-
const startedAt = Date.now();
|
|
346
|
-
const poll = () => {
|
|
347
|
-
const req = node_http.default.get(`http://localhost:${port}/status`, (res) => {
|
|
348
|
-
let data = "";
|
|
349
|
-
res.on("data", (chunk) => {
|
|
350
|
-
data += chunk.toString();
|
|
351
|
-
});
|
|
352
|
-
res.on("end", () => {
|
|
353
|
-
if (data.includes("packager-status:running")) {
|
|
354
|
-
resolve();
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
retry();
|
|
358
|
-
});
|
|
359
|
-
});
|
|
360
|
-
req.on("error", retry);
|
|
361
|
-
req.setTimeout(2e3, () => {
|
|
362
|
-
req.destroy();
|
|
363
|
-
retry();
|
|
364
|
-
});
|
|
365
|
-
};
|
|
366
|
-
const retry = () => {
|
|
367
|
-
if (Date.now() - startedAt > timeoutMs) {
|
|
368
|
-
reject(/* @__PURE__ */ new Error(`Bleam dev server did not start within ${timeoutMs / 1e3}s`));
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
setTimeout(poll, 500);
|
|
372
|
-
};
|
|
373
|
-
poll();
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
834
|
function isBleamManifest(value) {
|
|
377
835
|
const manifest = value && typeof value === "object" ? value : {};
|
|
378
836
|
return typeof manifest.name === "string" && typeof manifest.bundleUrl === "string" && manifest.platform === "macos" && manifest.dev === true;
|
|
@@ -380,18 +838,138 @@ function isBleamManifest(value) {
|
|
|
380
838
|
async function readDevManifest(origin, timeoutMs = 3e4) {
|
|
381
839
|
const manifestUrl = `${origin}/bleam/manifest.json`;
|
|
382
840
|
const startedAt = Date.now();
|
|
841
|
+
const spinner = startSpinner("Waiting for Bleam dev server...");
|
|
383
842
|
while (Date.now() - startedAt <= timeoutMs) {
|
|
384
843
|
try {
|
|
385
844
|
const response = await fetch(manifestUrl, { cache: "no-store" });
|
|
386
845
|
const value = await response.json();
|
|
387
|
-
if (response.ok && isBleamManifest(value))
|
|
846
|
+
if (response.ok && isBleamManifest(value)) {
|
|
847
|
+
spinner?.success("Bleam dev server is ready");
|
|
848
|
+
return value;
|
|
849
|
+
}
|
|
388
850
|
} catch {}
|
|
389
851
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
390
852
|
}
|
|
853
|
+
spinner?.error("Bleam dev server did not become available");
|
|
391
854
|
throw new Error(`Bleam manifest did not become available: ${manifestUrl}`);
|
|
392
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
|
+
}
|
|
932
|
+
function formatDuration(ms) {
|
|
933
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
934
|
+
}
|
|
935
|
+
async function waitForDevBundle(bundleUrl, timeoutMs = 6e4) {
|
|
936
|
+
const startedAt = Date.now();
|
|
937
|
+
const requestTimeoutMs = 3e4;
|
|
938
|
+
const spinner = startSpinner("Bundling app...");
|
|
939
|
+
while (Date.now() - startedAt <= timeoutMs) {
|
|
940
|
+
const requestStartedAt = Date.now();
|
|
941
|
+
try {
|
|
942
|
+
const response = await fetch(bundleUrl, {
|
|
943
|
+
cache: "no-store",
|
|
944
|
+
signal: AbortSignal.timeout(requestTimeoutMs)
|
|
945
|
+
});
|
|
946
|
+
await response.body?.cancel();
|
|
947
|
+
if (response.ok) {
|
|
948
|
+
spinner?.success(`Bundled app in ${formatDuration(Date.now() - startedAt)}`);
|
|
949
|
+
if (!spinner) console.log(`Bundled app in ${formatDuration(Date.now() - startedAt)}`);
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
952
|
+
if (spinner) spinner.text = `Bundle request returned ${response.status}, retrying...`;
|
|
953
|
+
else console.log(`Bundle request returned ${response.status}, retrying...`);
|
|
954
|
+
} catch (error) {
|
|
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
|
+
}
|
|
964
|
+
}
|
|
965
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
966
|
+
}
|
|
967
|
+
spinner?.error("Bundle did not complete");
|
|
968
|
+
throw new Error(`Bleam bundle did not complete within ${formatDuration(timeoutMs)}.\nBundle URL: ${bundleUrl}\n${doctorHint()}`);
|
|
969
|
+
}
|
|
393
970
|
function openRuntimeClient(appPath, projectConfigPath, manifest) {
|
|
394
|
-
(0, node_child_process.spawn)("open", [
|
|
971
|
+
const child = (0, node_child_process.spawn)("open", [
|
|
972
|
+
"-n",
|
|
395
973
|
appPath,
|
|
396
974
|
"--args",
|
|
397
975
|
"--bleam-project-config",
|
|
@@ -400,10 +978,220 @@ function openRuntimeClient(appPath, projectConfigPath, manifest) {
|
|
|
400
978
|
manifest.bundleUrl,
|
|
401
979
|
"--bleam-title",
|
|
402
980
|
manifest.name
|
|
403
|
-
], {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
})
|
|
981
|
+
], { stdio: "ignore" });
|
|
982
|
+
child.on("error", (error) => {
|
|
983
|
+
console.error(`Failed to open Bleam runtime at ${appPath}: ${error.message}`);
|
|
984
|
+
});
|
|
985
|
+
child.on("exit", (code) => {
|
|
986
|
+
if (code && code !== 0) console.error(`Failed to open Bleam runtime at ${appPath}`);
|
|
987
|
+
});
|
|
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
|
+
}
|
|
1091
|
+
async function startInternalMetroServer(options) {
|
|
1092
|
+
process.env.BLEAM_DEV_PLATFORM ??= "macos";
|
|
1093
|
+
const metro = require$1("@expo/metro/metro");
|
|
1094
|
+
const { loadConfig } = require$1("@expo/metro/metro-config");
|
|
1095
|
+
const config = await loadConfig({
|
|
1096
|
+
config: node_path.default.join(options.workspaceRoot, "metro.config.js"),
|
|
1097
|
+
cwd: options.workspaceRoot,
|
|
1098
|
+
port: options.port
|
|
1099
|
+
});
|
|
1100
|
+
const { middleware, end, attachHmrServer } = await metro.createConnectMiddleware(config, {
|
|
1101
|
+
watch: true,
|
|
1102
|
+
waitForBundler: true
|
|
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
|
+
});
|
|
1123
|
+
const server = node_http.default.createServer((req, res) => {
|
|
1124
|
+
if (req.url?.split("?")[0] === "/status") {
|
|
1125
|
+
res.writeHead(200, {
|
|
1126
|
+
"Cache-Control": "no-store",
|
|
1127
|
+
"Content-Type": "text/plain; charset=utf-8",
|
|
1128
|
+
"X-React-Native-Project-Root": encodeURI(config.projectRoot)
|
|
1129
|
+
});
|
|
1130
|
+
res.end("packager-status:running");
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
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
|
+
});
|
|
1162
|
+
});
|
|
1163
|
+
server.timeout = 0;
|
|
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
|
+
});
|
|
1176
|
+
await new Promise((resolve, reject) => {
|
|
1177
|
+
server.on("error", reject);
|
|
1178
|
+
server.listen(options.port, "localhost", () => resolve());
|
|
1179
|
+
});
|
|
1180
|
+
server.on("error", (error) => {
|
|
1181
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1182
|
+
});
|
|
1183
|
+
console.log(`Bleam dev server running at http://localhost:${options.port}`);
|
|
1184
|
+
const close = () => {
|
|
1185
|
+
setTimeout(() => process.exit(0), 1e3).unref();
|
|
1186
|
+
messageServer.close();
|
|
1187
|
+
for (const client of messageClients) client.terminate();
|
|
1188
|
+
server.close(() => {
|
|
1189
|
+
end();
|
|
1190
|
+
process.exit(0);
|
|
1191
|
+
});
|
|
1192
|
+
};
|
|
1193
|
+
process.on("SIGINT", close);
|
|
1194
|
+
process.on("SIGTERM", close);
|
|
407
1195
|
}
|
|
408
1196
|
async function startDevServer(options) {
|
|
409
1197
|
const config = readProjectConfig(options);
|
|
@@ -413,10 +1201,10 @@ async function startDevServer(options) {
|
|
|
413
1201
|
const origin = `http://localhost:${options.port}`;
|
|
414
1202
|
const projectConfigPath = writeProjectRuntimeConfig(options.projectRoot, config, origin);
|
|
415
1203
|
const child = (0, node_child_process.spawn)(process.execPath, [
|
|
416
|
-
|
|
417
|
-
"
|
|
1204
|
+
(0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href),
|
|
1205
|
+
"internal:metro",
|
|
1206
|
+
"--workspace-root",
|
|
418
1207
|
workspaceRoot,
|
|
419
|
-
"--localhost",
|
|
420
1208
|
"--port",
|
|
421
1209
|
String(options.port)
|
|
422
1210
|
], {
|
|
@@ -428,11 +1216,12 @@ async function startDevServer(options) {
|
|
|
428
1216
|
BLEAM_DEV_NAME: config.name,
|
|
429
1217
|
BLEAM_DEV_ORIGIN: origin,
|
|
430
1218
|
BLEAM_DEV_PORT: String(options.port),
|
|
1219
|
+
BLEAM_DEV_PLATFORM: "macos",
|
|
431
1220
|
BLEAM_DEV_RUNTIME_VERSION: config.runtimeVersion,
|
|
432
1221
|
BLEAM_DEV_SDK_VERSION: config.sdkVersion,
|
|
433
1222
|
NODE_PATH: [
|
|
434
1223
|
node_path.default.join(options.projectRoot, "node_modules"),
|
|
435
|
-
|
|
1224
|
+
resolvedDependencyRoot(),
|
|
436
1225
|
node_path.default.dirname(node_path.default.dirname(require$1.resolve("expo/package.json"))),
|
|
437
1226
|
node_path.default.dirname(node_path.default.dirname(require$1.resolve("react/package.json"))),
|
|
438
1227
|
node_path.default.dirname(node_path.default.dirname(require$1.resolve("react-native/package.json"))),
|
|
@@ -440,15 +1229,51 @@ async function startDevServer(options) {
|
|
|
440
1229
|
].filter(Boolean).join(node_path.default.delimiter)
|
|
441
1230
|
}
|
|
442
1231
|
});
|
|
1232
|
+
let cleanupInteractiveControls = () => {};
|
|
1233
|
+
let stopping = false;
|
|
443
1234
|
const stop = (signal) => {
|
|
1235
|
+
if (stopping) return;
|
|
1236
|
+
stopping = true;
|
|
1237
|
+
cleanupInteractiveControls();
|
|
444
1238
|
child.kill(signal);
|
|
1239
|
+
setTimeout(() => process.exit(0), 2e3).unref();
|
|
445
1240
|
};
|
|
446
1241
|
process.on("SIGINT", () => stop("SIGINT"));
|
|
447
1242
|
process.on("SIGTERM", () => stop("SIGTERM"));
|
|
448
|
-
child.on("
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
+
});
|
|
1253
|
+
try {
|
|
1254
|
+
const manifest = await readDevManifest(origin);
|
|
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 {
|
|
1263
|
+
await waitForDevBundle(manifest.bundleUrl);
|
|
1264
|
+
console.log("Opening Bleam app...");
|
|
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.");
|
|
1271
|
+
}
|
|
1272
|
+
} catch (error) {
|
|
1273
|
+
cleanupInteractiveControls();
|
|
1274
|
+
child.kill("SIGTERM");
|
|
1275
|
+
throw error;
|
|
1276
|
+
}
|
|
452
1277
|
}
|
|
453
1278
|
async function main(argv = process.argv.slice(2)) {
|
|
454
1279
|
const [command, ...args] = argv;
|
|
@@ -461,7 +1286,8 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
461
1286
|
createNewProject(options);
|
|
462
1287
|
if (options.run) await startDevServer({
|
|
463
1288
|
projectRoot: options.projectRoot,
|
|
464
|
-
port: 8081
|
|
1289
|
+
port: 8081,
|
|
1290
|
+
run: true
|
|
465
1291
|
});
|
|
466
1292
|
return;
|
|
467
1293
|
}
|
|
@@ -469,6 +1295,30 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
469
1295
|
await startDevServer(parseDevOptions(args));
|
|
470
1296
|
return;
|
|
471
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
|
+
}
|
|
1318
|
+
if (command === "internal:metro") {
|
|
1319
|
+
await startInternalMetroServer(parseInternalMetroOptions(args));
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
472
1322
|
throw new Error(`Unknown command: ${command}`);
|
|
473
1323
|
}
|
|
474
1324
|
main().catch((error) => {
|