bleam 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai.cjs +3984 -25
- package/dist/ai.d.cts +503 -20
- package/dist/ai.d.ts +503 -20
- package/dist/ai.js +3946 -26
- package/dist/animated.cjs +1 -1
- package/dist/animated.js +1 -1
- package/dist/app.cjs +92 -0
- package/dist/app.js +92 -0
- package/dist/cli.cjs +653 -86
- package/dist/cli.d.cts +89 -1
- package/dist/cli.d.ts +89 -1
- package/dist/cli.js +654 -88
- package/dist/{config-ClDGHNb3.d.ts → config-Cms0rvqg.d.ts} +1 -0
- package/dist/{config-D3gPaVMb.d.cts → config-CufOVJV3.d.cts} +1 -0
- package/dist/config.d.cts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/crypto.d.cts +0 -2
- package/dist/crypto.d.ts +1 -1
- package/dist/dev-protocol.d.cts +14 -1
- package/dist/dev-protocol.d.ts +14 -1
- package/dist/files-Bo7h9fik.cjs +468 -0
- package/dist/files-Ds1wT8C2.js +445 -0
- package/dist/files-DwA7pzr3.d.cts +99 -0
- package/dist/files-VrkQlKIT.d.ts +99 -0
- package/dist/files.cjs +7 -0
- package/dist/files.d.cts +2 -0
- package/dist/files.d.ts +2 -0
- package/dist/files.js +4 -0
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/native-sqlite-xcGdamRD.js +64 -0
- package/dist/native-sqlite-yQLD5s9i.cjs +66 -0
- package/dist/platform.cjs +27 -0
- package/dist/platform.d.cts +39 -0
- package/dist/platform.d.ts +39 -0
- package/dist/platform.js +21 -0
- package/dist/runtime.d.cts +1 -6
- package/dist/runtime.d.ts +1 -6
- package/dist/{schema-ipsECAso.d.ts → schema-DOOjfXvs.d.ts} +1 -1
- package/dist/{schema-BOuUHcqo.d.cts → schema-ENSMX_1t.d.cts} +1 -1
- package/dist/schema.cjs +1 -1
- package/dist/schema.d.cts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +1 -1
- package/dist/state-Bx0VlTlO.cjs +852 -0
- package/dist/state-CAwe-Vw1.js +767 -0
- package/dist/state.cjs +17 -763
- package/dist/state.d.cts +107 -77
- package/dist/state.d.ts +107 -77
- package/dist/state.js +4 -745
- package/dist/ui-1WepaMS4.d.cts +92 -0
- package/dist/ui-234Plg7Z.d.cts +92 -0
- package/dist/ui-BJmXhz9Q.d.ts +92 -0
- package/dist/ui-Dd7SXdbg.d.cts +92 -0
- package/dist/ui-Ds88eETu.d.ts +92 -0
- package/dist/ui-TaqnB5SP.d.ts +92 -0
- package/dist/ui-WQvnXL0W.d.ts +92 -0
- package/dist/ui.cjs +286 -35
- package/dist/ui.d.cts +2 -30
- package/dist/ui.d.ts +2 -30
- package/dist/ui.js +283 -36
- package/dist/window.cjs +596 -0
- package/dist/window.d.cts +63 -0
- package/dist/window.d.ts +63 -0
- package/dist/window.js +589 -0
- package/package.json +16 -14
- package/templates/basic/app/index.tsx +8 -5
- package/templates/foundation-models/app/index.tsx +32 -0
- package/templates/foundation-models/app.config.ts +5 -0
- package/templates/image-generation/app/index.tsx +39 -0
- package/templates/image-generation/app.config.ts +5 -0
- package/templates/state/app/index.tsx +30 -0
- package/templates/state/app.config.ts +5 -0
- package/dist/chrome.cjs +0 -265
- package/dist/chrome.d.cts +0 -19
- package/dist/chrome.d.ts +0 -19
- package/dist/chrome.js +0 -262
- package/dist/fs.cjs +0 -13
- package/dist/fs.d.cts +0 -8
- package/dist/fs.d.ts +0 -8
- package/dist/fs.js +0 -12
- package/dist/native-macos-D6p2SmUj.js +0 -20
- package/dist/native-macos-DLwo_ii9.cjs +0 -31
- package/dist/native-runtime-CbPzrs8j.d.cts +0 -33
- package/dist/native-runtime-DxHSrsTX.d.ts +0 -33
- package/dist/native.cjs +0 -135
- package/dist/native.d.cts +0 -34
- package/dist/native.d.ts +0 -34
- package/dist/native.js +0 -135
- /package/dist/{schema-DVmoD9JL.js → schema-Bo5Jvqus.js} +0 -0
- /package/dist/{schema-bxeeCyLn.cjs → schema-rQ13mrpD.cjs} +0 -0
package/dist/cli.cjs
CHANGED
|
@@ -28,6 +28,7 @@ const require$1 = (0, node_module.createRequire)(require("url").pathToFileURL(__
|
|
|
28
28
|
const packageRoot = node_path.default.dirname((0, node_url.fileURLToPath)(new URL("../package.json", require("url").pathToFileURL(__filename).href)));
|
|
29
29
|
const packageJson = require$1("../package.json");
|
|
30
30
|
const runtimeVersion = packageJson.version;
|
|
31
|
+
const starterAppName = "Bleam Basic";
|
|
31
32
|
function artifactPlatform() {
|
|
32
33
|
return `macos-${process.arch}`;
|
|
33
34
|
}
|
|
@@ -85,16 +86,52 @@ function printUsage() {
|
|
|
85
86
|
console.log(`Usage: bleam <command>
|
|
86
87
|
|
|
87
88
|
Commands:
|
|
88
|
-
new
|
|
89
|
-
|
|
89
|
+
new <dir> [--template <name>]
|
|
90
|
+
Create and run a Bleam project
|
|
91
|
+
dev [dir] [--port <port>] [--no-run] [--clean]
|
|
90
92
|
Start a Bleam dev server
|
|
91
|
-
build [dir] [--output <dir>]
|
|
92
|
-
|
|
93
|
+
build [dir] [--output <dir>] [--clean]
|
|
94
|
+
Export standalone native archives
|
|
95
|
+
install [dir] [--output <dir>] [--clean]
|
|
96
|
+
Build and install a standalone macOS app
|
|
97
|
+
publish ota [dir] [--service-url <url>]
|
|
98
|
+
Publish an OTA update to the local update service
|
|
99
|
+
publish platform [dir] [--service-url <url>]
|
|
100
|
+
Build and publish a platform update locally
|
|
93
101
|
doctor [dir] Check the local Bleam environment
|
|
102
|
+
typecheck [dir] Typecheck project files
|
|
94
103
|
check [dir] [--write] Format, lint, and organize imports
|
|
95
104
|
format [dir] [--check] Format project files
|
|
96
105
|
lint [dir] Lint project files`);
|
|
97
106
|
}
|
|
107
|
+
function parsePublishOtaOptions(argv) {
|
|
108
|
+
const root = invocationRoot();
|
|
109
|
+
let projectRoot = root;
|
|
110
|
+
let hasProjectRootArg = false;
|
|
111
|
+
let serviceUrl = process.env.BLEAM_UPDATE_SERVICE_URL ?? "http://127.0.0.1:8787";
|
|
112
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
113
|
+
const arg = argv[index];
|
|
114
|
+
if (arg === "--service-url") {
|
|
115
|
+
serviceUrl = argv[++index] ?? "";
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (arg.startsWith("--service-url=")) {
|
|
119
|
+
serviceUrl = arg.slice(14);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
|
|
123
|
+
if (hasProjectRootArg) throw new Error("Only one project directory may be specified");
|
|
124
|
+
projectRoot = node_path.default.resolve(root, arg);
|
|
125
|
+
hasProjectRootArg = true;
|
|
126
|
+
}
|
|
127
|
+
const url = new URL(serviceUrl);
|
|
128
|
+
if (url.protocol !== "http:" || !["127.0.0.1", "localhost"].includes(url.hostname)) throw new Error("Local publishing requires an http://localhost service URL");
|
|
129
|
+
if (!hasProjectRootArg && !isBleamProjectRoot(projectRoot)) projectRoot = discoverBleamProjectRoot(projectRoot) ?? projectRoot;
|
|
130
|
+
return {
|
|
131
|
+
projectRoot: canonicalPath(projectRoot),
|
|
132
|
+
serviceUrl: url.origin
|
|
133
|
+
};
|
|
134
|
+
}
|
|
98
135
|
function invocationRoot() {
|
|
99
136
|
const pwd = process.env.PWD;
|
|
100
137
|
return pwd && node_path.default.isAbsolute(pwd) ? pwd : process.cwd();
|
|
@@ -107,7 +144,8 @@ function parseDevOptions(argv) {
|
|
|
107
144
|
const root = invocationRoot();
|
|
108
145
|
let projectRoot = root;
|
|
109
146
|
let port = 8081;
|
|
110
|
-
let run =
|
|
147
|
+
let run = true;
|
|
148
|
+
let clean = false;
|
|
111
149
|
let hasProjectRootArg = false;
|
|
112
150
|
for (let index = 0; index < argv.length; index += 1) {
|
|
113
151
|
const arg = argv[index];
|
|
@@ -124,6 +162,14 @@ function parseDevOptions(argv) {
|
|
|
124
162
|
run = true;
|
|
125
163
|
continue;
|
|
126
164
|
}
|
|
165
|
+
if (arg === "--no-run") {
|
|
166
|
+
run = false;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (arg === "--clean" || arg === "-c") {
|
|
170
|
+
clean = true;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
127
173
|
if (arg === "--help" || arg === "-h") {
|
|
128
174
|
printUsage();
|
|
129
175
|
process.exit(0);
|
|
@@ -137,36 +183,55 @@ function parseDevOptions(argv) {
|
|
|
137
183
|
return {
|
|
138
184
|
projectRoot: canonicalPath(projectRoot),
|
|
139
185
|
port,
|
|
140
|
-
run
|
|
186
|
+
run,
|
|
187
|
+
clean
|
|
141
188
|
};
|
|
142
189
|
}
|
|
143
190
|
function parseNewOptions(argv) {
|
|
144
191
|
const root = invocationRoot();
|
|
145
|
-
let projectRoot
|
|
146
|
-
let
|
|
147
|
-
for (
|
|
148
|
-
|
|
149
|
-
run = true;
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
192
|
+
let projectRoot;
|
|
193
|
+
let template = "basic";
|
|
194
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
195
|
+
const arg = argv[index];
|
|
152
196
|
if (arg === "--help" || arg === "-h") {
|
|
153
197
|
printUsage();
|
|
154
198
|
process.exit(0);
|
|
155
199
|
}
|
|
200
|
+
if (arg === "--template") {
|
|
201
|
+
template = projectTemplate(argv[++index] ?? "");
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (arg.startsWith("--template=")) {
|
|
205
|
+
template = projectTemplate(arg.slice(11));
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
156
208
|
if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
|
|
209
|
+
if (projectRoot) throw new Error("Only one project directory may be specified");
|
|
157
210
|
projectRoot = node_path.default.resolve(root, arg);
|
|
158
211
|
}
|
|
212
|
+
if (!projectRoot) throw new Error("Usage: bleam new <dir>");
|
|
159
213
|
return {
|
|
160
214
|
projectRoot: canonicalPath(projectRoot),
|
|
161
|
-
|
|
215
|
+
template
|
|
162
216
|
};
|
|
163
217
|
}
|
|
218
|
+
const projectTemplates = [
|
|
219
|
+
"basic",
|
|
220
|
+
"state",
|
|
221
|
+
"foundation-models",
|
|
222
|
+
"image-generation"
|
|
223
|
+
];
|
|
224
|
+
function projectTemplate(value) {
|
|
225
|
+
if (projectTemplates.includes(value)) return value;
|
|
226
|
+
throw new Error(`Unknown template: ${value}. Expected ${projectTemplates.join(", ")}`);
|
|
227
|
+
}
|
|
164
228
|
function parseBuildOptions(argv) {
|
|
165
229
|
const root = invocationRoot();
|
|
166
230
|
let projectRoot = root;
|
|
167
231
|
let hasProjectRootArg = false;
|
|
168
232
|
let output;
|
|
169
233
|
let configuration = "Release";
|
|
234
|
+
let clean = false;
|
|
170
235
|
let exportOptionsPlist;
|
|
171
236
|
for (let index = 0; index < argv.length; index += 1) {
|
|
172
237
|
const arg = argv[index];
|
|
@@ -188,6 +253,10 @@ function parseBuildOptions(argv) {
|
|
|
188
253
|
configuration = arg.slice(16);
|
|
189
254
|
continue;
|
|
190
255
|
}
|
|
256
|
+
if (arg === "--clean") {
|
|
257
|
+
clean = true;
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
191
260
|
if (arg === "--export-options-plist") {
|
|
192
261
|
exportOptionsPlist = argv[++index];
|
|
193
262
|
continue;
|
|
@@ -210,6 +279,7 @@ function parseBuildOptions(argv) {
|
|
|
210
279
|
projectRoot: resolvedProjectRoot,
|
|
211
280
|
output: node_path.default.resolve(resolvedProjectRoot, output ?? "dist"),
|
|
212
281
|
configuration,
|
|
282
|
+
clean,
|
|
213
283
|
exportOptionsPlist: exportOptionsPlist ? node_path.default.resolve(root, exportOptionsPlist) : void 0
|
|
214
284
|
};
|
|
215
285
|
}
|
|
@@ -262,6 +332,7 @@ function parseDoctorOptions(argv) {
|
|
|
262
332
|
function parseInternalMetroOptions(argv) {
|
|
263
333
|
let workspaceRoot;
|
|
264
334
|
let port = 8081;
|
|
335
|
+
let resetCache = false;
|
|
265
336
|
for (let index = 0; index < argv.length; index += 1) {
|
|
266
337
|
const arg = argv[index];
|
|
267
338
|
if (arg === "--workspace-root") {
|
|
@@ -276,13 +347,18 @@ function parseInternalMetroOptions(argv) {
|
|
|
276
347
|
port = Number(arg.slice(7));
|
|
277
348
|
continue;
|
|
278
349
|
}
|
|
350
|
+
if (arg === "--reset-cache") {
|
|
351
|
+
resetCache = true;
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
279
354
|
throw new Error(`Unknown internal option: ${arg}`);
|
|
280
355
|
}
|
|
281
356
|
if (!workspaceRoot) throw new Error("Missing --workspace-root");
|
|
282
357
|
if (!Number.isInteger(port) || port <= 0) throw new Error(`Invalid port: ${port}`);
|
|
283
358
|
return {
|
|
284
359
|
workspaceRoot,
|
|
285
|
-
port
|
|
360
|
+
port,
|
|
361
|
+
resetCache
|
|
286
362
|
};
|
|
287
363
|
}
|
|
288
364
|
function isBleamProjectRoot(projectRoot) {
|
|
@@ -322,6 +398,11 @@ function assertStringField(value, field) {
|
|
|
322
398
|
if (typeof value !== "string" || value.trim() === "") throw new Error(`app.config.ts must define ${field}`);
|
|
323
399
|
return value;
|
|
324
400
|
}
|
|
401
|
+
function normalizeAppGroups(value, bundleIdentifier) {
|
|
402
|
+
const configured = Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
403
|
+
if (configured.length > 0) return configured;
|
|
404
|
+
return bundleIdentifier ? [`group.${bundleIdentifier}`] : [];
|
|
405
|
+
}
|
|
325
406
|
function isHexColor(value) {
|
|
326
407
|
return typeof value === "string" && /^#[\da-f]{6}$/i.test(value);
|
|
327
408
|
}
|
|
@@ -365,11 +446,13 @@ function loadAppConfig(projectRoot) {
|
|
|
365
446
|
});
|
|
366
447
|
if (result.status !== 0) throw new Error(result.stderr.trim() || "Failed to load app.config.ts");
|
|
367
448
|
const value = JSON.parse(result.stdout);
|
|
449
|
+
const bundleIdentifier = typeof value.bundleIdentifier === "string" ? value.bundleIdentifier : void 0;
|
|
368
450
|
return {
|
|
369
451
|
name: assertStringField(value.name, "name"),
|
|
370
452
|
version: typeof value.version === "string" ? value.version : void 0,
|
|
371
453
|
buildNumber: typeof value.buildNumber === "string" ? value.buildNumber : void 0,
|
|
372
|
-
bundleIdentifier
|
|
454
|
+
bundleIdentifier,
|
|
455
|
+
appGroups: normalizeAppGroups(value.appGroups, bundleIdentifier),
|
|
373
456
|
teamId: typeof value.teamId === "string" ? value.teamId : void 0,
|
|
374
457
|
appearance: normalizeAppearance(value.appearance)
|
|
375
458
|
};
|
|
@@ -392,6 +475,7 @@ function readProjectConfig(options) {
|
|
|
392
475
|
version: config.version,
|
|
393
476
|
buildNumber: config.buildNumber ?? "1",
|
|
394
477
|
bundleIdentifier: config.bundleIdentifier,
|
|
478
|
+
appGroups: config.appGroups ?? [],
|
|
395
479
|
teamId: config.teamId,
|
|
396
480
|
appearance: config.appearance ?? normalizeAppearance(void 0),
|
|
397
481
|
runtimeVersion,
|
|
@@ -409,22 +493,40 @@ function nameFromDirectory(projectRoot) {
|
|
|
409
493
|
function singleQuotedString(value) {
|
|
410
494
|
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\r/g, "\\r").replace(/\n/g, "\\n")}'`;
|
|
411
495
|
}
|
|
412
|
-
function
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
(
|
|
417
|
-
(0, node_fs.
|
|
496
|
+
function updateStarterAppName(projectRoot, name) {
|
|
497
|
+
const appPath = node_path.default.join(projectRoot, "app", "index.tsx");
|
|
498
|
+
const source = (0, node_fs.readFileSync)(appPath, "utf8");
|
|
499
|
+
const placeholder = `const appName = ${singleQuotedString(starterAppName)}`;
|
|
500
|
+
if (!source.includes(placeholder)) throw new Error(`Missing starter app name placeholder: ${appPath}`);
|
|
501
|
+
(0, node_fs.writeFileSync)(appPath, source.replace(placeholder, `const appName = ${singleQuotedString(name)}`));
|
|
502
|
+
}
|
|
503
|
+
function createProject(options) {
|
|
504
|
+
const template = options.template ?? "basic";
|
|
505
|
+
const templateRoot = node_path.default.join(packageRoot, "templates", template);
|
|
506
|
+
if (!(0, node_fs.existsSync)(templateRoot)) throw new Error(`Missing ${template} template: ${templateRoot}`);
|
|
507
|
+
if ((0, node_fs.existsSync)(options.projectRoot)) throw new Error(`Destination already exists: ${options.projectRoot}`);
|
|
418
508
|
const name = nameFromDirectory(options.projectRoot);
|
|
419
|
-
(0, node_fs.
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
name
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
509
|
+
(0, node_fs.mkdirSync)(options.projectRoot, { recursive: true });
|
|
510
|
+
try {
|
|
511
|
+
(0, node_fs.cpSync)(templateRoot, options.projectRoot, { recursive: true });
|
|
512
|
+
updateStarterAppName(options.projectRoot, name);
|
|
513
|
+
(0, node_fs.writeFileSync)(node_path.default.join(options.projectRoot, "app.config.ts"), `import { appConfig } from 'bleam'\n\nexport default appConfig({\n name: ${singleQuotedString(name)},\n})\n`);
|
|
514
|
+
(0, node_fs.writeFileSync)(node_path.default.join(options.projectRoot, ".gitignore"), `.bleam\nbiome.json\n.DS_Store\n`);
|
|
515
|
+
createDevWorkspace(options.projectRoot, {
|
|
516
|
+
name,
|
|
517
|
+
buildNumber: "1",
|
|
518
|
+
appGroups: [],
|
|
519
|
+
appearance: normalizeAppearance(void 0),
|
|
520
|
+
runtimeVersion,
|
|
521
|
+
sdkVersion: runtimeVersion
|
|
522
|
+
});
|
|
523
|
+
} catch (error) {
|
|
524
|
+
(0, node_fs.rmSync)(options.projectRoot, {
|
|
525
|
+
recursive: true,
|
|
526
|
+
force: true
|
|
527
|
+
});
|
|
528
|
+
throw error;
|
|
529
|
+
}
|
|
428
530
|
console.log(`Created Bleam project at ${options.projectRoot}`);
|
|
429
531
|
}
|
|
430
532
|
function createDevWorkspace(projectRoot, config) {
|
|
@@ -438,7 +540,7 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
438
540
|
});
|
|
439
541
|
(0, node_fs.symlinkSync)(dependencyRoot, workspaceNodeModules);
|
|
440
542
|
ensureProjectTsconfig(projectRoot);
|
|
441
|
-
|
|
543
|
+
const expoConfig = {
|
|
442
544
|
name: config.name,
|
|
443
545
|
slug: slugFromName(config.name),
|
|
444
546
|
version: config.version ?? "0.0.0",
|
|
@@ -451,7 +553,10 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
451
553
|
runtimeVersion: config.runtimeVersion,
|
|
452
554
|
sdkVersion: config.sdkVersion
|
|
453
555
|
} }
|
|
454
|
-
}
|
|
556
|
+
};
|
|
557
|
+
if ((0, node_fs.existsSync)(node_path.default.join(projectRoot, "icon.png"))) expoConfig.icon = "../../icon.png";
|
|
558
|
+
if ((0, node_fs.existsSync)(node_path.default.join(projectRoot, "splash.png"))) expoConfig.plugins = [["expo-splash-screen", { image: "../../splash.png" }]];
|
|
559
|
+
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "app.config.js"), `module.exports = ${JSON.stringify({ expo: expoConfig }, null, 2)}\n`);
|
|
455
560
|
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "index.js"), `import { registerApp } from 'bleam/app'\nimport App from ${JSON.stringify(node_path.default.join(projectRoot, "app"))}\n\nregisterApp(App)\n`);
|
|
456
561
|
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "metro.config.js"), `const { getDefaultConfig } = require(${JSON.stringify(node_path.default.join(packageRoot, "metro-config.cjs"))})\n\nmodule.exports = getDefaultConfig(__dirname)\n`);
|
|
457
562
|
(0, node_fs.writeFileSync)(node_path.default.join(workspaceRoot, "package.json"), `${JSON.stringify({
|
|
@@ -463,6 +568,7 @@ function createDevWorkspace(projectRoot, config) {
|
|
|
463
568
|
"@types/react": packageJson.dependencies?.["@types/react"],
|
|
464
569
|
"@biomejs/biome": packageJson.dependencies?.["@biomejs/biome"],
|
|
465
570
|
expo: packageJson.dependencies?.expo,
|
|
571
|
+
"expo-splash-screen": packageJson.dependencies?.["expo-splash-screen"],
|
|
466
572
|
react: packageJson.dependencies?.react,
|
|
467
573
|
"react-native": packageJson.dependencies?.["react-native"],
|
|
468
574
|
typescript: packageJson.dependencies?.typescript
|
|
@@ -547,6 +653,24 @@ function replacePlistString(plist, key, value) {
|
|
|
547
653
|
if (!pattern.test(plist)) return plist;
|
|
548
654
|
return plist.replace(pattern, `$1${plistString(value)}$3`);
|
|
549
655
|
}
|
|
656
|
+
function plistStringArray(values) {
|
|
657
|
+
return values.map((value) => `\t\t<string>${plistString(value)}</string>`).join("\n");
|
|
658
|
+
}
|
|
659
|
+
function replaceOrInsertPlistString(plist, key, value) {
|
|
660
|
+
const replaced = replacePlistString(plist, key, value);
|
|
661
|
+
if (replaced !== plist) return replaced;
|
|
662
|
+
const closingDictionary = plist.lastIndexOf("</dict>");
|
|
663
|
+
if (closingDictionary < 0) return plist;
|
|
664
|
+
return `${plist.slice(0, closingDictionary)}\t<key>${key}</key>\n\t<string>${plistString(value)}</string>\n${plist.slice(closingDictionary)}`;
|
|
665
|
+
}
|
|
666
|
+
function replaceOrInsertPlistStringArray(plist, key, values) {
|
|
667
|
+
const pattern = /* @__PURE__ */ new RegExp(`(<key>${key}</key>\\s*<array>)([\\s\\S]*?)(</array>)`);
|
|
668
|
+
const replacement = `$1\n${plistStringArray(values)}\n\t$3`;
|
|
669
|
+
if (pattern.test(plist)) return plist.replace(pattern, replacement);
|
|
670
|
+
const closingDictionary = plist.lastIndexOf("</dict>");
|
|
671
|
+
if (closingDictionary < 0) return plist;
|
|
672
|
+
return `${plist.slice(0, closingDictionary)}\t<key>${key}</key>\n\t<array>\n${plistStringArray(values)}\n\t</array>\n${plist.slice(closingDictionary)}`;
|
|
673
|
+
}
|
|
550
674
|
function writeGeneratedAppJson(nativeRoot, config) {
|
|
551
675
|
(0, node_fs.writeFileSync)(node_path.default.join(nativeRoot, "app.json"), `${JSON.stringify({ expo: {
|
|
552
676
|
name: config.name,
|
|
@@ -563,40 +687,60 @@ function writeGeneratedAppJson(nativeRoot, config) {
|
|
|
563
687
|
function patchNativeProject(nativeRoot, config) {
|
|
564
688
|
const projectPath = node_path.default.join(nativeRoot, "ios", "Bleam.xcodeproj", "project.pbxproj");
|
|
565
689
|
const infoPlistPath = node_path.default.join(nativeRoot, "ios", "Bleam", "Info.plist");
|
|
690
|
+
const generationInfoPlistPath = node_path.default.join(nativeRoot, "ios", "GenerationService", "Info.plist");
|
|
691
|
+
const platformInfoPlistPath = node_path.default.join(nativeRoot, "ios", "PlatformHelper", "Info.plist");
|
|
692
|
+
const appEntitlementsPath = node_path.default.join(nativeRoot, "ios", "Bleam", "bleam.entitlements");
|
|
693
|
+
const generationEntitlementsPath = node_path.default.join(nativeRoot, "ios", "GenerationService", "GenerationService.entitlements");
|
|
566
694
|
const productName = xcodeSettingValue(config.name);
|
|
567
695
|
const bundleIdentifier = xcodeSettingValue(config.bundleIdentifier ?? "");
|
|
696
|
+
const generationBundleIdentifier = xcodeSettingValue(`${config.bundleIdentifier}.GenerationService`);
|
|
697
|
+
const platformBundleIdentifier = xcodeSettingValue(`${config.bundleIdentifier}.PlatformHelper`);
|
|
568
698
|
const teamId = xcodeSettingValue(config.teamId ?? "");
|
|
569
699
|
const version = xcodeSettingValue(config.version ?? "1.0.0");
|
|
570
700
|
const buildNumber = xcodeSettingValue(config.buildNumber);
|
|
701
|
+
const primaryAppGroup = config.appGroups[0];
|
|
571
702
|
let project = (0, node_fs.readFileSync)(projectPath, "utf8");
|
|
572
|
-
project = project.replace(/PRODUCT_BUNDLE_IDENTIFIER = [^;]
|
|
573
|
-
return `PRODUCT_BUNDLE_IDENTIFIER = ${bundleIdentifier};`;
|
|
703
|
+
project = project.replace(/PRODUCT_BUNDLE_IDENTIFIER = ([^;]+);/g, (_, current) => {
|
|
704
|
+
return `PRODUCT_BUNDLE_IDENTIFIER = ${current.endsWith(".GenerationService") ? generationBundleIdentifier : current.endsWith(".PlatformHelper") ? platformBundleIdentifier : bundleIdentifier};`;
|
|
574
705
|
}).replace(/DEVELOPMENT_TEAM = [^;]+;/g, () => {
|
|
575
706
|
return `DEVELOPMENT_TEAM = ${teamId};`;
|
|
576
707
|
}).replace(/MARKETING_VERSION = [^;]+;/g, () => {
|
|
577
708
|
return `MARKETING_VERSION = ${version};`;
|
|
578
709
|
}).replace(/CURRENT_PROJECT_VERSION = [^;]+;/g, () => {
|
|
579
710
|
return `CURRENT_PROJECT_VERSION = ${buildNumber};`;
|
|
580
|
-
}).replace(/PRODUCT_NAME =
|
|
711
|
+
}).replace(/PRODUCT_NAME = bleam;/g, () => {
|
|
581
712
|
return `PRODUCT_NAME = ${productName};`;
|
|
582
713
|
});
|
|
583
714
|
(0, node_fs.writeFileSync)(projectPath, project);
|
|
584
715
|
let infoPlist = (0, node_fs.readFileSync)(infoPlistPath, "utf8");
|
|
585
716
|
infoPlist = replacePlistString(infoPlist, "CFBundleDisplayName", config.name);
|
|
586
717
|
infoPlist = replacePlistString(infoPlist, "CFBundleShortVersionString", config.version ?? "1.0.0");
|
|
718
|
+
infoPlist = replaceOrInsertPlistString(infoPlist, "BleamRuntimeVersion", config.runtimeVersion);
|
|
719
|
+
infoPlist = replaceOrInsertPlistString(infoPlist, "BleamTeamIdentifier", config.teamId ?? "");
|
|
720
|
+
const updateServiceUrl = process.env.BLEAM_UPDATE_SERVICE_URL;
|
|
721
|
+
if (updateServiceUrl) infoPlist = replaceOrInsertPlistString(infoPlist, "BleamUpdateServiceURL", updateServiceUrl);
|
|
587
722
|
infoPlist = replacePlistString(infoPlist, "CFBundleVersion", config.buildNumber);
|
|
723
|
+
if (primaryAppGroup) infoPlist = replaceOrInsertPlistString(infoPlist, "AppGroupIdentifier", primaryAppGroup);
|
|
588
724
|
(0, node_fs.writeFileSync)(infoPlistPath, infoPlist);
|
|
725
|
+
if (primaryAppGroup) {
|
|
726
|
+
let generationInfoPlist = (0, node_fs.readFileSync)(generationInfoPlistPath, "utf8");
|
|
727
|
+
generationInfoPlist = replaceOrInsertPlistString(generationInfoPlist, "AppGroupIdentifier", primaryAppGroup);
|
|
728
|
+
(0, node_fs.writeFileSync)(generationInfoPlistPath, generationInfoPlist);
|
|
729
|
+
(0, node_fs.writeFileSync)(platformInfoPlistPath, replaceOrInsertPlistString((0, node_fs.readFileSync)(platformInfoPlistPath, "utf8"), "BleamPlatformVersion", config.runtimeVersion));
|
|
730
|
+
for (const entitlementsPath of [appEntitlementsPath, generationEntitlementsPath]) (0, node_fs.writeFileSync)(entitlementsPath, replaceOrInsertPlistStringArray((0, node_fs.readFileSync)(entitlementsPath, "utf8"), "com.apple.security.application-groups", config.appGroups));
|
|
731
|
+
}
|
|
589
732
|
}
|
|
590
733
|
function createBuildNativeWorkspace(options, config) {
|
|
591
734
|
const nativeRoot = node_path.default.join(options.projectRoot, ".bleam", "build", "native");
|
|
592
735
|
const templateRoot = nativeRuntimeTemplateRoot();
|
|
593
|
-
(0, node_fs.rmSync)(nativeRoot, {
|
|
736
|
+
if (options.clean) (0, node_fs.rmSync)(nativeRoot, {
|
|
594
737
|
recursive: true,
|
|
595
738
|
force: true
|
|
596
739
|
});
|
|
597
740
|
(0, node_fs.mkdirSync)(node_path.default.dirname(nativeRoot), { recursive: true });
|
|
598
741
|
(0, node_fs.cpSync)(templateRoot, nativeRoot, {
|
|
599
742
|
recursive: true,
|
|
743
|
+
verbatimSymlinks: true,
|
|
600
744
|
filter(source) {
|
|
601
745
|
return !node_path.default.relative(templateRoot, source).split(node_path.default.sep).some((part) => {
|
|
602
746
|
return part === "build" || part === "dist" || part === "node_modules" || part === ".expo" || part === "Pods" || part === ".xcode.env.local" || part === ".DS_Store" || part.endsWith(".xcworkspace");
|
|
@@ -636,32 +780,66 @@ function runInheritedCommand(command, args, cwd) {
|
|
|
636
780
|
if (result.status !== 0) throw new Error(`${text} failed in ${cwd} with exit code ${result.status ?? "unknown"}.\nNative command output above may contain the underlying Xcode/CocoaPods error.\n${doctorHint()}`);
|
|
637
781
|
}
|
|
638
782
|
function installPods(nativeRoot) {
|
|
783
|
+
const iosRoot = node_path.default.join(nativeRoot, "ios");
|
|
784
|
+
const expectedStamp = podInstallInputStamp(iosRoot);
|
|
785
|
+
if (hasCurrentPodInstall(iosRoot, expectedStamp)) {
|
|
786
|
+
console.log("Using cached native dependencies");
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
639
789
|
console.log("Installing native dependencies...");
|
|
640
|
-
runInheritedCommand("pod", ["install"],
|
|
790
|
+
runInheritedCommand("pod", ["install"], iosRoot);
|
|
791
|
+
(0, node_fs.writeFileSync)(podInstallStampPath(iosRoot), `${expectedStamp}\n`);
|
|
792
|
+
}
|
|
793
|
+
function podInstallInputStamp(iosRoot) {
|
|
794
|
+
const inputHash = (0, node_crypto.createHash)("sha256");
|
|
795
|
+
for (const relative of [
|
|
796
|
+
"Podfile",
|
|
797
|
+
"Podfile.lock",
|
|
798
|
+
"../package.json"
|
|
799
|
+
]) {
|
|
800
|
+
const input = node_path.default.resolve(iosRoot, relative);
|
|
801
|
+
if ((0, node_fs.existsSync)(input)) inputHash.update((0, node_fs.readFileSync)(input));
|
|
802
|
+
}
|
|
803
|
+
return inputHash.digest("hex");
|
|
641
804
|
}
|
|
642
|
-
function
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
(
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
runInheritedCommand("xcodebuild", [
|
|
805
|
+
function podInstallStampPath(iosRoot) {
|
|
806
|
+
return node_path.default.join(iosRoot, ".bleam-pods-input");
|
|
807
|
+
}
|
|
808
|
+
function hasCurrentPodInstall(iosRoot, expectedStamp) {
|
|
809
|
+
const stampPath = podInstallStampPath(iosRoot);
|
|
810
|
+
return (0, node_fs.existsSync)(node_path.default.join(iosRoot, "Bleam.xcworkspace")) && (0, node_fs.existsSync)(node_path.default.join(iosRoot, "Pods", "Manifest.lock")) && (0, node_fs.existsSync)(stampPath) && (0, node_fs.readFileSync)(stampPath, "utf8").trim() === expectedStamp;
|
|
811
|
+
}
|
|
812
|
+
function nativeArchiveArgs(options) {
|
|
813
|
+
return [
|
|
652
814
|
"-allowProvisioningUpdates",
|
|
653
815
|
"-workspace",
|
|
654
816
|
node_path.default.join(options.nativeRoot, "ios", "Bleam.xcworkspace"),
|
|
655
817
|
"-scheme",
|
|
656
|
-
"
|
|
818
|
+
"Bleam",
|
|
657
819
|
"-configuration",
|
|
658
820
|
options.configuration,
|
|
659
821
|
"-destination",
|
|
660
822
|
"platform=macOS,arch=arm64,variant=Mac Catalyst",
|
|
661
823
|
"-archivePath",
|
|
662
|
-
archivePath,
|
|
824
|
+
options.archivePath,
|
|
825
|
+
"ARCHS=arm64",
|
|
663
826
|
"archive"
|
|
664
|
-
]
|
|
827
|
+
];
|
|
828
|
+
}
|
|
829
|
+
function archiveNativeApp(options) {
|
|
830
|
+
const platformOutput = node_path.default.join(options.outputRoot, "macos");
|
|
831
|
+
const archivePath = node_path.default.join(platformOutput, `${safeArtifactName(options.config.name)}.xcarchive`);
|
|
832
|
+
(0, node_fs.mkdirSync)(platformOutput, { recursive: true });
|
|
833
|
+
(0, node_fs.rmSync)(archivePath, {
|
|
834
|
+
recursive: true,
|
|
835
|
+
force: true
|
|
836
|
+
});
|
|
837
|
+
console.log(`Archiving ${options.config.name} for macOS...`);
|
|
838
|
+
runInheritedCommand("xcodebuild", nativeArchiveArgs({
|
|
839
|
+
nativeRoot: options.nativeRoot,
|
|
840
|
+
archivePath,
|
|
841
|
+
configuration: options.configuration
|
|
842
|
+
}), options.nativeRoot);
|
|
665
843
|
return archivePath;
|
|
666
844
|
}
|
|
667
845
|
function exportNativeArchive(options) {
|
|
@@ -704,6 +882,177 @@ async function buildNativeArchives(options) {
|
|
|
704
882
|
});
|
|
705
883
|
console.log(`Exported ${exportPath}`);
|
|
706
884
|
}
|
|
885
|
+
return archivePath;
|
|
886
|
+
}
|
|
887
|
+
async function installNativeApp(options) {
|
|
888
|
+
const destination = installArchivedApp(await buildNativeArchives(options));
|
|
889
|
+
console.log(`Installed ${destination}`);
|
|
890
|
+
}
|
|
891
|
+
function installArchivedApp(archivePath, applications = node_path.default.join(node_os.default.homedir(), "Applications")) {
|
|
892
|
+
const products = node_path.default.join(archivePath, "Products", "Applications");
|
|
893
|
+
const appName = (0, node_fs.readdirSync)(products).find((name) => name.endsWith(".app"));
|
|
894
|
+
if (!appName) throw new Error(`Archive does not contain a macOS app: ${archivePath}`);
|
|
895
|
+
const source = node_path.default.join(products, appName);
|
|
896
|
+
const destination = applications === node_path.default.join(node_os.default.homedir(), "Applications") ? installedAppPath(appName) : node_path.default.join(applications, appName);
|
|
897
|
+
(0, node_fs.mkdirSync)(applications, { recursive: true });
|
|
898
|
+
(0, node_fs.rmSync)(destination, {
|
|
899
|
+
recursive: true,
|
|
900
|
+
force: true
|
|
901
|
+
});
|
|
902
|
+
(0, node_child_process.execFileSync)("ditto", [source, destination], { stdio: "inherit" });
|
|
903
|
+
return destination;
|
|
904
|
+
}
|
|
905
|
+
function installedAppPath(appName) {
|
|
906
|
+
if (node_path.default.basename(appName) !== appName || !appName.endsWith(".app")) throw new Error(`Invalid macOS app name: ${appName}`);
|
|
907
|
+
return node_path.default.join(node_os.default.homedir(), "Applications", appName);
|
|
908
|
+
}
|
|
909
|
+
async function publishOta(options) {
|
|
910
|
+
const config = readProjectConfig(options);
|
|
911
|
+
if (!config.bundleIdentifier) throw missingBuildFieldError("bundleIdentifier");
|
|
912
|
+
if (!config.teamId) throw missingBuildFieldError("teamId");
|
|
913
|
+
const workspaceRoot = createBuildNativeWorkspace({
|
|
914
|
+
projectRoot: options.projectRoot,
|
|
915
|
+
output: node_path.default.join(options.projectRoot, "dist"),
|
|
916
|
+
configuration: "Release",
|
|
917
|
+
clean: false
|
|
918
|
+
}, config);
|
|
919
|
+
const outputRoot = node_path.default.join(options.projectRoot, ".bleam", "publish", "ota");
|
|
920
|
+
const bundleRoot = node_path.default.join(outputRoot, "bundle");
|
|
921
|
+
const bundlePath = node_path.default.join(bundleRoot, "bundle.js");
|
|
922
|
+
const archivePath = node_path.default.join(outputRoot, "ota.zip");
|
|
923
|
+
(0, node_fs.rmSync)(outputRoot, {
|
|
924
|
+
recursive: true,
|
|
925
|
+
force: true
|
|
926
|
+
});
|
|
927
|
+
(0, node_fs.mkdirSync)(bundleRoot, { recursive: true });
|
|
928
|
+
console.log(`Bundling OTA update for runtime ${runtimeVersion}...`);
|
|
929
|
+
runInheritedCommand(process.execPath, [
|
|
930
|
+
require$1.resolve("@expo/cli"),
|
|
931
|
+
"export:embed",
|
|
932
|
+
"--entry-file",
|
|
933
|
+
node_path.default.join(workspaceRoot, "index.ts"),
|
|
934
|
+
"--platform",
|
|
935
|
+
"ios",
|
|
936
|
+
"--dev",
|
|
937
|
+
"false",
|
|
938
|
+
"--bundle-output",
|
|
939
|
+
bundlePath,
|
|
940
|
+
"--assets-dest",
|
|
941
|
+
node_path.default.join(bundleRoot, "assets"),
|
|
942
|
+
"--minify",
|
|
943
|
+
"true"
|
|
944
|
+
], workspaceRoot);
|
|
945
|
+
runInheritedCommand("ditto", [
|
|
946
|
+
"-c",
|
|
947
|
+
"-k",
|
|
948
|
+
"--keepParent",
|
|
949
|
+
bundleRoot,
|
|
950
|
+
archivePath
|
|
951
|
+
], outputRoot);
|
|
952
|
+
const sizeBytes = (0, node_fs.readFileSync)(archivePath).byteLength;
|
|
953
|
+
const digest = sha256(archivePath);
|
|
954
|
+
const releaseId = `ota_${Date.now().toString(36)}_${digest.slice(0, 12)}`;
|
|
955
|
+
const release = {
|
|
956
|
+
schemaVersion: 1,
|
|
957
|
+
kind: "ota",
|
|
958
|
+
bundleIdentifier: config.bundleIdentifier,
|
|
959
|
+
teamIdentifier: config.teamId,
|
|
960
|
+
channel: "stable",
|
|
961
|
+
releaseId,
|
|
962
|
+
bundleVersion: `${config.version ?? "1.0.0"}+${config.buildNumber}`,
|
|
963
|
+
runtimeVersion,
|
|
964
|
+
artifact: {
|
|
965
|
+
format: "bleam-ota-zip-v1",
|
|
966
|
+
downloadId: releaseId,
|
|
967
|
+
sizeBytes,
|
|
968
|
+
sha256: digest
|
|
969
|
+
},
|
|
970
|
+
publishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
971
|
+
};
|
|
972
|
+
const response = await fetch(`${options.serviceUrl}/v1/local/releases/ota`, {
|
|
973
|
+
method: "POST",
|
|
974
|
+
headers: { "content-type": "application/json" },
|
|
975
|
+
body: JSON.stringify({
|
|
976
|
+
release,
|
|
977
|
+
artifactBase64: (0, node_fs.readFileSync)(archivePath).toString("base64")
|
|
978
|
+
})
|
|
979
|
+
});
|
|
980
|
+
if (!response.ok) throw new Error(`Local OTA publication failed: ${response.status} ${await response.text()}`);
|
|
981
|
+
console.log(`Published OTA update ${releaseId}`);
|
|
982
|
+
console.log(`${options.serviceUrl}/v1/apps/${encodeURIComponent(config.bundleIdentifier)}/ota/${runtimeVersion}`);
|
|
983
|
+
}
|
|
984
|
+
async function publishPlatform(options) {
|
|
985
|
+
const config = readProjectConfig(options);
|
|
986
|
+
if (!config.bundleIdentifier) throw missingBuildFieldError("bundleIdentifier");
|
|
987
|
+
if (!config.teamId) throw missingBuildFieldError("teamId");
|
|
988
|
+
const archivePath = await buildNativeArchives({
|
|
989
|
+
projectRoot: options.projectRoot,
|
|
990
|
+
output: node_path.default.join(options.projectRoot, "dist"),
|
|
991
|
+
configuration: "Release",
|
|
992
|
+
clean: false
|
|
993
|
+
});
|
|
994
|
+
const products = node_path.default.join(archivePath, "Products", "Applications");
|
|
995
|
+
const appName = (0, node_fs.readdirSync)(products).find((name) => name.endsWith(".app"));
|
|
996
|
+
if (!appName) throw new Error(`Archive does not contain a macOS app: ${archivePath}`);
|
|
997
|
+
const outputRoot = node_path.default.join(options.projectRoot, ".bleam", "publish", "platform");
|
|
998
|
+
const stagingRoot = node_path.default.join(outputRoot, "app");
|
|
999
|
+
const artifactPath = node_path.default.join(outputRoot, "platform.zip");
|
|
1000
|
+
(0, node_fs.rmSync)(outputRoot, {
|
|
1001
|
+
recursive: true,
|
|
1002
|
+
force: true
|
|
1003
|
+
});
|
|
1004
|
+
(0, node_fs.mkdirSync)(stagingRoot, { recursive: true });
|
|
1005
|
+
(0, node_child_process.execFileSync)("ditto", [node_path.default.join(products, appName), node_path.default.join(stagingRoot, appName)]);
|
|
1006
|
+
runInheritedCommand("zip", [
|
|
1007
|
+
"-q",
|
|
1008
|
+
"-r",
|
|
1009
|
+
"-y",
|
|
1010
|
+
artifactPath,
|
|
1011
|
+
"app"
|
|
1012
|
+
], outputRoot);
|
|
1013
|
+
const sizeBytes = (0, node_fs.readFileSync)(artifactPath).byteLength;
|
|
1014
|
+
const digest = sha256(artifactPath);
|
|
1015
|
+
const releaseId = `platform_${Date.now().toString(36)}_${digest.slice(0, 12)}`;
|
|
1016
|
+
const release = platformRelease(config, releaseId, sizeBytes, digest);
|
|
1017
|
+
const response = await fetch(`${options.serviceUrl}/v1/local/releases/platform`, {
|
|
1018
|
+
method: "POST",
|
|
1019
|
+
headers: { "content-type": "application/json" },
|
|
1020
|
+
body: JSON.stringify({
|
|
1021
|
+
release,
|
|
1022
|
+
artifactBase64: (0, node_fs.readFileSync)(artifactPath).toString("base64")
|
|
1023
|
+
})
|
|
1024
|
+
});
|
|
1025
|
+
if (!response.ok) throw new Error(`Local platform publication failed: ${response.status} ${await response.text()}`);
|
|
1026
|
+
console.log(`Published platform update ${releaseId}`);
|
|
1027
|
+
console.log(`${options.serviceUrl}/v1/apps/${encodeURIComponent(config.bundleIdentifier)}/platform/macos-arm64`);
|
|
1028
|
+
}
|
|
1029
|
+
function platformRelease(config, releaseId, sizeBytes, digest) {
|
|
1030
|
+
if (!config.bundleIdentifier) throw missingBuildFieldError("bundleIdentifier");
|
|
1031
|
+
if (!config.teamId) throw missingBuildFieldError("teamId");
|
|
1032
|
+
return {
|
|
1033
|
+
schemaVersion: 1,
|
|
1034
|
+
kind: "platform",
|
|
1035
|
+
bundleIdentifier: config.bundleIdentifier,
|
|
1036
|
+
teamIdentifier: config.teamId,
|
|
1037
|
+
channel: "stable",
|
|
1038
|
+
releaseId,
|
|
1039
|
+
appVersion: config.version ?? "1.0.0",
|
|
1040
|
+
buildNumber: config.buildNumber,
|
|
1041
|
+
bleamPlatformVersion: runtimeVersion,
|
|
1042
|
+
target: {
|
|
1043
|
+
os: "macos",
|
|
1044
|
+
architecture: "arm64",
|
|
1045
|
+
installLocation: "user-applications",
|
|
1046
|
+
minimumMacOSVersion: "14.0"
|
|
1047
|
+
},
|
|
1048
|
+
artifact: {
|
|
1049
|
+
format: "bleam-macos-app-zip-v1",
|
|
1050
|
+
downloadId: releaseId,
|
|
1051
|
+
sizeBytes,
|
|
1052
|
+
sha256: digest
|
|
1053
|
+
},
|
|
1054
|
+
publishedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1055
|
+
};
|
|
707
1056
|
}
|
|
708
1057
|
function runtimeCacheRoot() {
|
|
709
1058
|
return node_path.default.join(node_os.default.homedir(), "Library", "Caches", "bleam", "runtimes", runtimeVersion, artifactPlatform());
|
|
@@ -754,16 +1103,22 @@ async function downloadRuntimeArtifact() {
|
|
|
754
1103
|
const runtimePlatform = artifactPlatform();
|
|
755
1104
|
const cacheRoot = runtimeCacheRoot();
|
|
756
1105
|
const cachedAppPath = node_path.default.join(cacheRoot, "Bleam.app");
|
|
757
|
-
if ((0, node_fs.existsSync)(cachedAppPath))
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
1106
|
+
if ((0, node_fs.existsSync)(cachedAppPath)) {
|
|
1107
|
+
console.log(`Using cached Bleam runtime at ${prettyPath(cachedAppPath)}`);
|
|
1108
|
+
return {
|
|
1109
|
+
appPath: cachedAppPath,
|
|
1110
|
+
version: runtimeVersion,
|
|
1111
|
+
platform: runtimePlatform
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
762
1114
|
(0, node_fs.mkdirSync)(cacheRoot, { recursive: true });
|
|
763
1115
|
const archiveUrl = runtimeArchiveUrl();
|
|
764
1116
|
const archivePath = node_path.default.join(cacheRoot, runtimeArchiveName());
|
|
765
1117
|
const extractRoot = node_path.default.join(cacheRoot, "extract");
|
|
1118
|
+
console.log(`Downloading Bleam runtime ${runtimeVersion} for ${runtimePlatform}`);
|
|
1119
|
+
console.log(`Runtime archive: ${archiveUrl}`);
|
|
766
1120
|
await downloadFile(archiveUrl, archivePath);
|
|
1121
|
+
console.log("Verifying Bleam runtime archive");
|
|
767
1122
|
const expectedSha256 = await downloadExpectedSha256(archiveUrl);
|
|
768
1123
|
if (expectedSha256 && sha256(archivePath) !== expectedSha256) {
|
|
769
1124
|
(0, node_fs.rmSync)(archivePath, { force: true });
|
|
@@ -774,6 +1129,7 @@ async function downloadRuntimeArtifact() {
|
|
|
774
1129
|
force: true
|
|
775
1130
|
});
|
|
776
1131
|
(0, node_fs.mkdirSync)(extractRoot, { recursive: true });
|
|
1132
|
+
console.log("Extracting Bleam runtime archive");
|
|
777
1133
|
(0, node_child_process.execFileSync)("ditto", [
|
|
778
1134
|
"-x",
|
|
779
1135
|
"-k",
|
|
@@ -786,11 +1142,15 @@ async function downloadRuntimeArtifact() {
|
|
|
786
1142
|
recursive: true,
|
|
787
1143
|
force: true
|
|
788
1144
|
});
|
|
789
|
-
(0, node_fs.cpSync)(extractedAppPath, cachedAppPath, {
|
|
1145
|
+
(0, node_fs.cpSync)(extractedAppPath, cachedAppPath, {
|
|
1146
|
+
recursive: true,
|
|
1147
|
+
verbatimSymlinks: true
|
|
1148
|
+
});
|
|
790
1149
|
(0, node_fs.rmSync)(extractRoot, {
|
|
791
1150
|
recursive: true,
|
|
792
1151
|
force: true
|
|
793
1152
|
});
|
|
1153
|
+
console.log(`Cached Bleam runtime at ${prettyPath(cachedAppPath)}`);
|
|
794
1154
|
return {
|
|
795
1155
|
appPath: cachedAppPath,
|
|
796
1156
|
version: runtimeVersion,
|
|
@@ -799,10 +1159,12 @@ async function downloadRuntimeArtifact() {
|
|
|
799
1159
|
}
|
|
800
1160
|
async function resolveRuntimeArtifact() {
|
|
801
1161
|
const runtimePlatform = artifactPlatform();
|
|
1162
|
+
console.log(`Resolving Bleam runtime ${runtimeVersion} for ${runtimePlatform}`);
|
|
802
1163
|
const overrideAppPath = process.env.BLEAM_RUNTIME_APP;
|
|
803
1164
|
if (overrideAppPath) {
|
|
804
1165
|
const appPath = node_path.default.resolve(overrideAppPath);
|
|
805
1166
|
if (!(0, node_fs.existsSync)(appPath)) throw new Error(`BLEAM_RUNTIME_APP points to a missing app bundle: ${appPath}\nUnset BLEAM_RUNTIME_APP or point it to a valid Bleam.app.\n${doctorHint()}`);
|
|
1167
|
+
console.log(`Using BLEAM_RUNTIME_APP runtime at ${prettyPath(appPath)}`);
|
|
806
1168
|
return {
|
|
807
1169
|
appPath,
|
|
808
1170
|
version: runtimeVersion,
|
|
@@ -810,11 +1172,14 @@ async function resolveRuntimeArtifact() {
|
|
|
810
1172
|
};
|
|
811
1173
|
}
|
|
812
1174
|
const localAppPath = localDevelopmentRuntimeAppPath();
|
|
813
|
-
if ((0, node_fs.existsSync)(localAppPath))
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
1175
|
+
if ((0, node_fs.existsSync)(localAppPath)) {
|
|
1176
|
+
console.log(`Using local development runtime at ${prettyPath(localAppPath)}`);
|
|
1177
|
+
return {
|
|
1178
|
+
appPath: localAppPath,
|
|
1179
|
+
version: runtimeVersion,
|
|
1180
|
+
platform: runtimePlatform
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
818
1183
|
try {
|
|
819
1184
|
return await downloadRuntimeArtifact();
|
|
820
1185
|
} catch (error) {
|
|
@@ -823,14 +1188,31 @@ async function resolveRuntimeArtifact() {
|
|
|
823
1188
|
}
|
|
824
1189
|
function copyRuntimeClient(projectRoot, runtime) {
|
|
825
1190
|
const clientAppPath = node_path.default.join(projectRoot, ".bleam", "client", "Bleam.app");
|
|
1191
|
+
console.log(`Preparing Bleam app at ${prettyPath(clientAppPath)}`);
|
|
826
1192
|
(0, node_fs.rmSync)(clientAppPath, {
|
|
827
1193
|
recursive: true,
|
|
828
1194
|
force: true
|
|
829
1195
|
});
|
|
830
1196
|
(0, node_fs.mkdirSync)(node_path.default.dirname(clientAppPath), { recursive: true });
|
|
831
|
-
(0, node_fs.cpSync)(runtime.appPath, clientAppPath, {
|
|
1197
|
+
(0, node_fs.cpSync)(runtime.appPath, clientAppPath, {
|
|
1198
|
+
recursive: true,
|
|
1199
|
+
verbatimSymlinks: true
|
|
1200
|
+
});
|
|
832
1201
|
return clientAppPath;
|
|
833
1202
|
}
|
|
1203
|
+
function cleanDevArtifacts(projectRoot) {
|
|
1204
|
+
const bleamRoot = node_path.default.join(projectRoot, ".bleam");
|
|
1205
|
+
const targets = [
|
|
1206
|
+
"client",
|
|
1207
|
+
"dev",
|
|
1208
|
+
"project.json"
|
|
1209
|
+
].map((name) => node_path.default.join(bleamRoot, name));
|
|
1210
|
+
console.log("Cleaning Bleam dev artifacts");
|
|
1211
|
+
for (const target of targets) (0, node_fs.rmSync)(target, {
|
|
1212
|
+
recursive: true,
|
|
1213
|
+
force: true
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
834
1216
|
function isBleamManifest(value) {
|
|
835
1217
|
const manifest = value && typeof value === "object" ? value : {};
|
|
836
1218
|
return typeof manifest.name === "string" && typeof manifest.bundleUrl === "string" && manifest.platform === "macos" && manifest.dev === true;
|
|
@@ -932,6 +1314,15 @@ function runDoctor(options) {
|
|
|
932
1314
|
function formatDuration(ms) {
|
|
933
1315
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
934
1316
|
}
|
|
1317
|
+
async function bundleErrorPreview(response) {
|
|
1318
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
1319
|
+
if (!contentType.includes("json") && !contentType.includes("text")) return "";
|
|
1320
|
+
try {
|
|
1321
|
+
return (await response.text()).trim().slice(0, 1e3);
|
|
1322
|
+
} catch {
|
|
1323
|
+
return "";
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
935
1326
|
async function waitForDevBundle(bundleUrl, timeoutMs = 6e4) {
|
|
936
1327
|
const startedAt = Date.now();
|
|
937
1328
|
const requestTimeoutMs = 3e4;
|
|
@@ -943,14 +1334,17 @@ async function waitForDevBundle(bundleUrl, timeoutMs = 6e4) {
|
|
|
943
1334
|
cache: "no-store",
|
|
944
1335
|
signal: AbortSignal.timeout(requestTimeoutMs)
|
|
945
1336
|
});
|
|
946
|
-
await response.body?.cancel();
|
|
947
1337
|
if (response.ok) {
|
|
1338
|
+
await response.body?.cancel();
|
|
948
1339
|
spinner?.success(`Bundled app in ${formatDuration(Date.now() - startedAt)}`);
|
|
949
1340
|
if (!spinner) console.log(`Bundled app in ${formatDuration(Date.now() - startedAt)}`);
|
|
950
1341
|
return;
|
|
951
1342
|
}
|
|
952
|
-
|
|
953
|
-
|
|
1343
|
+
const preview = await bundleErrorPreview(response);
|
|
1344
|
+
const detail = preview ? `\n${preview}` : "";
|
|
1345
|
+
const message = `Bundle request returned ${response.status}, retrying...${detail}`;
|
|
1346
|
+
if (spinner) spinner.text = message;
|
|
1347
|
+
else console.log(message);
|
|
954
1348
|
} catch (error) {
|
|
955
1349
|
if (error instanceof Error && error.name === "TimeoutError") {
|
|
956
1350
|
const message = `Bundle request timed out after ${formatDuration(Date.now() - requestStartedAt)}, retrying...`;
|
|
@@ -986,7 +1380,11 @@ function openRuntimeClient(appPath, projectConfigPath, manifest) {
|
|
|
986
1380
|
if (code && code !== 0) console.error(`Failed to open Bleam runtime at ${appPath}`);
|
|
987
1381
|
});
|
|
988
1382
|
}
|
|
1383
|
+
function quitRuntimeClient() {
|
|
1384
|
+
(0, node_child_process.spawnSync)("osascript", ["-e", "tell application id \"dev.bleam.app\" to quit"], { stdio: "ignore" });
|
|
1385
|
+
}
|
|
989
1386
|
async function launchRuntimeClient(appPath, projectConfigPath, manifest) {
|
|
1387
|
+
quitRuntimeClient();
|
|
990
1388
|
openRuntimeClient(appPath, projectConfigPath, manifest);
|
|
991
1389
|
}
|
|
992
1390
|
function focusRuntimeClient() {
|
|
@@ -999,6 +1397,49 @@ function sendJson(res, status, value) {
|
|
|
999
1397
|
});
|
|
1000
1398
|
res.end(JSON.stringify(value));
|
|
1001
1399
|
}
|
|
1400
|
+
function readRequestBody(req, limit = 1e6) {
|
|
1401
|
+
return new Promise((resolve, reject) => {
|
|
1402
|
+
const chunks = [];
|
|
1403
|
+
let size = 0;
|
|
1404
|
+
req.on("data", (chunk) => {
|
|
1405
|
+
size += chunk.length;
|
|
1406
|
+
if (size > limit) {
|
|
1407
|
+
reject(/* @__PURE__ */ new Error("Request body too large"));
|
|
1408
|
+
req.destroy();
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1411
|
+
chunks.push(chunk);
|
|
1412
|
+
});
|
|
1413
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
1414
|
+
req.on("error", reject);
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
function isLogLevel(value) {
|
|
1418
|
+
return value === "debug" || value === "info" || value === "warn" || value === "error";
|
|
1419
|
+
}
|
|
1420
|
+
function isLogSource(value) {
|
|
1421
|
+
return value === "cli" || value === "metro" || value === "runtime" || value === "js" || value === "native" || value === "xpc";
|
|
1422
|
+
}
|
|
1423
|
+
function normalizeDevLogEvent(value) {
|
|
1424
|
+
const input = value && typeof value === "object" ? value : {};
|
|
1425
|
+
const message = typeof input.message === "string" ? input.message : input.message === void 0 ? "" : JSON.stringify(input.message);
|
|
1426
|
+
return {
|
|
1427
|
+
type: "log",
|
|
1428
|
+
id: typeof input.id === "string" && input.id ? input.id : (0, node_crypto.randomUUID)(),
|
|
1429
|
+
time: typeof input.time === "string" && input.time ? input.time : (/* @__PURE__ */ new Date()).toISOString(),
|
|
1430
|
+
source: isLogSource(input.source) ? input.source : "runtime",
|
|
1431
|
+
level: isLogLevel(input.level) ? input.level : "info",
|
|
1432
|
+
category: typeof input.category === "string" && input.category ? input.category : void 0,
|
|
1433
|
+
message,
|
|
1434
|
+
details: input.details,
|
|
1435
|
+
jobId: typeof input.jobId === "string" && input.jobId ? input.jobId : void 0
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
function formatDevLogEvent(event) {
|
|
1439
|
+
const category = event.category ? `:${event.category}` : "";
|
|
1440
|
+
const job = event.jobId ? ` ${event.jobId.slice(0, 8)}` : "";
|
|
1441
|
+
return `[${event.source}${category}:${event.level}${job}] ${event.message}`;
|
|
1442
|
+
}
|
|
1002
1443
|
async function requestRuntimeReload(origin) {
|
|
1003
1444
|
const response = await fetch(`${origin}/bleam/reload`, {
|
|
1004
1445
|
method: "POST",
|
|
@@ -1017,6 +1458,13 @@ function biomeBinPath() {
|
|
|
1017
1458
|
if (!bin) throw new Error("Could not resolve @biomejs/biome binary");
|
|
1018
1459
|
return node_path.default.join(biomePackageRoot, bin);
|
|
1019
1460
|
}
|
|
1461
|
+
function typescriptBinPath() {
|
|
1462
|
+
const typescriptPackageJsonPath = require$1.resolve("typescript/package.json");
|
|
1463
|
+
const typescriptPackageRoot = node_path.default.dirname(typescriptPackageJsonPath);
|
|
1464
|
+
const bin = require$1("typescript/package.json").bin?.tsc;
|
|
1465
|
+
if (!bin) throw new Error("Could not resolve TypeScript compiler binary");
|
|
1466
|
+
return node_path.default.join(typescriptPackageRoot, bin);
|
|
1467
|
+
}
|
|
1020
1468
|
function ensureProjectToolWorkspace(options) {
|
|
1021
1469
|
const config = readProjectConfig({ projectRoot: options.projectRoot });
|
|
1022
1470
|
return createDevWorkspace(options.projectRoot, config);
|
|
@@ -1044,6 +1492,20 @@ function runBiomeCommand(command, options) {
|
|
|
1044
1492
|
if (result.error) throw result.error;
|
|
1045
1493
|
process.exit(result.status ?? 1);
|
|
1046
1494
|
}
|
|
1495
|
+
function runTypecheckCommand(options) {
|
|
1496
|
+
assertBleamConfigFiles(options.projectRoot);
|
|
1497
|
+
ensureProjectToolWorkspace(options);
|
|
1498
|
+
const result = (0, node_child_process.spawnSync)(typescriptBinPath(), [
|
|
1499
|
+
"--noEmit",
|
|
1500
|
+
"-p",
|
|
1501
|
+
node_path.default.join(options.projectRoot, "tsconfig.json")
|
|
1502
|
+
], {
|
|
1503
|
+
cwd: options.projectRoot,
|
|
1504
|
+
stdio: "inherit"
|
|
1505
|
+
});
|
|
1506
|
+
if (result.error) throw result.error;
|
|
1507
|
+
process.exit(result.status ?? 1);
|
|
1508
|
+
}
|
|
1047
1509
|
function setupInteractiveControls(options) {
|
|
1048
1510
|
if (!process.stdin.isTTY) return () => {};
|
|
1049
1511
|
const wasRaw = process.stdin.isRaw;
|
|
@@ -1065,21 +1527,26 @@ function setupInteractiveControls(options) {
|
|
|
1065
1527
|
if (key === "o") {
|
|
1066
1528
|
(async () => {
|
|
1067
1529
|
try {
|
|
1068
|
-
if (
|
|
1069
|
-
console.log("
|
|
1070
|
-
|
|
1530
|
+
if (focusRuntimeClient()) {
|
|
1531
|
+
console.log("Focused Bleam app");
|
|
1532
|
+
return;
|
|
1071
1533
|
}
|
|
1534
|
+
console.log(`Opening Bleam app at ${prettyPath(options.clientAppPath)}`);
|
|
1535
|
+
await launchRuntimeClient(options.clientAppPath, options.projectConfigPath, options.manifest);
|
|
1072
1536
|
} catch (error) {
|
|
1073
1537
|
console.error(error instanceof Error ? error.message : String(error));
|
|
1074
1538
|
}
|
|
1075
1539
|
})();
|
|
1076
1540
|
continue;
|
|
1077
1541
|
}
|
|
1078
|
-
if (key === "r")
|
|
1079
|
-
console.log(
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1542
|
+
if (key === "r") {
|
|
1543
|
+
console.log("Requesting app reload");
|
|
1544
|
+
requestRuntimeReload(options.origin).then((clients) => {
|
|
1545
|
+
console.log(`Reloaded app (${clients} client${clients === 1 ? "" : "s"})`);
|
|
1546
|
+
}).catch((error) => {
|
|
1547
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1083
1550
|
}
|
|
1084
1551
|
};
|
|
1085
1552
|
process.stdin.setRawMode(true);
|
|
@@ -1090,12 +1557,18 @@ function setupInteractiveControls(options) {
|
|
|
1090
1557
|
}
|
|
1091
1558
|
async function startInternalMetroServer(options) {
|
|
1092
1559
|
process.env.BLEAM_DEV_PLATFORM ??= "macos";
|
|
1560
|
+
const projectRoot = process.env.BLEAM_PROJECT_ROOT ?? options.workspaceRoot;
|
|
1561
|
+
const logPath = node_path.default.join(projectRoot, ".bleam", "dev", "logs", "dev.log");
|
|
1562
|
+
const recentLogs = [];
|
|
1563
|
+
const logClients = /* @__PURE__ */ new Set();
|
|
1564
|
+
const maxRecentLogs = 1e3;
|
|
1093
1565
|
const metro = require$1("@expo/metro/metro");
|
|
1094
1566
|
const { loadConfig } = require$1("@expo/metro/metro-config");
|
|
1095
1567
|
const config = await loadConfig({
|
|
1096
1568
|
config: node_path.default.join(options.workspaceRoot, "metro.config.js"),
|
|
1097
1569
|
cwd: options.workspaceRoot,
|
|
1098
|
-
port: options.port
|
|
1570
|
+
port: options.port,
|
|
1571
|
+
resetCache: options.resetCache
|
|
1099
1572
|
});
|
|
1100
1573
|
const { middleware, end, attachHmrServer } = await metro.createConnectMiddleware(config, {
|
|
1101
1574
|
watch: true,
|
|
@@ -1103,6 +1576,16 @@ async function startInternalMetroServer(options) {
|
|
|
1103
1576
|
});
|
|
1104
1577
|
const messageClients = /* @__PURE__ */ new Set();
|
|
1105
1578
|
const messageServer = new ws.WebSocketServer({ noServer: true });
|
|
1579
|
+
const logServer = new ws.WebSocketServer({ noServer: true });
|
|
1580
|
+
const recordLog = (event) => {
|
|
1581
|
+
recentLogs.push(event);
|
|
1582
|
+
if (recentLogs.length > maxRecentLogs) recentLogs.splice(0, recentLogs.length - maxRecentLogs);
|
|
1583
|
+
(0, node_fs.mkdirSync)(node_path.default.dirname(logPath), { recursive: true });
|
|
1584
|
+
(0, node_fs.appendFileSync)(logPath, `${JSON.stringify(event)}\n`, "utf8");
|
|
1585
|
+
const payload = JSON.stringify(event);
|
|
1586
|
+
for (const client of logClients) if (client.readyState === ws.WebSocket.OPEN) client.send(payload);
|
|
1587
|
+
console.log(formatDevLogEvent(event));
|
|
1588
|
+
};
|
|
1106
1589
|
const broadcastReload = () => {
|
|
1107
1590
|
const message = JSON.stringify({
|
|
1108
1591
|
version: 2,
|
|
@@ -1120,6 +1603,11 @@ async function startInternalMetroServer(options) {
|
|
|
1120
1603
|
messageClients.add(client);
|
|
1121
1604
|
client.on("close", () => messageClients.delete(client));
|
|
1122
1605
|
});
|
|
1606
|
+
logServer.on("connection", (client) => {
|
|
1607
|
+
logClients.add(client);
|
|
1608
|
+
for (const event of recentLogs) client.send(JSON.stringify(event));
|
|
1609
|
+
client.on("close", () => logClients.delete(client));
|
|
1610
|
+
});
|
|
1123
1611
|
const server = node_http.default.createServer((req, res) => {
|
|
1124
1612
|
if (req.url?.split("?")[0] === "/status") {
|
|
1125
1613
|
res.writeHead(200, {
|
|
@@ -1142,6 +1630,29 @@ async function startInternalMetroServer(options) {
|
|
|
1142
1630
|
});
|
|
1143
1631
|
return;
|
|
1144
1632
|
}
|
|
1633
|
+
if (req.url?.split("?")[0] === "/bleam/logs") {
|
|
1634
|
+
if (req.method === "GET") {
|
|
1635
|
+
sendJson(res, 200, { logs: recentLogs });
|
|
1636
|
+
return;
|
|
1637
|
+
}
|
|
1638
|
+
if (req.method !== "POST") {
|
|
1639
|
+
res.writeHead(405, { Allow: "GET, POST" });
|
|
1640
|
+
res.end();
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
readRequestBody(req).then((body) => {
|
|
1644
|
+
const parsed = body ? JSON.parse(body) : {};
|
|
1645
|
+
const events = Array.isArray(parsed) ? parsed : [parsed];
|
|
1646
|
+
for (const value of events) recordLog(normalizeDevLogEvent(value));
|
|
1647
|
+
sendJson(res, 200, { ok: true });
|
|
1648
|
+
}).catch((error) => {
|
|
1649
|
+
sendJson(res, 400, {
|
|
1650
|
+
ok: false,
|
|
1651
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1652
|
+
});
|
|
1653
|
+
});
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1145
1656
|
middleware(req, res, (error) => {
|
|
1146
1657
|
if (res.headersSent) return;
|
|
1147
1658
|
if (error) {
|
|
@@ -1171,6 +1682,12 @@ async function startInternalMetroServer(options) {
|
|
|
1171
1682
|
});
|
|
1172
1683
|
return;
|
|
1173
1684
|
}
|
|
1685
|
+
if (req.url?.split("?")[0] === "/bleam/logs/stream") {
|
|
1686
|
+
logServer.handleUpgrade(req, socket, head, (client) => {
|
|
1687
|
+
logServer.emit("connection", client, req);
|
|
1688
|
+
});
|
|
1689
|
+
return;
|
|
1690
|
+
}
|
|
1174
1691
|
for (const listener of metroUpgradeListeners) listener.call(server, req, socket, head);
|
|
1175
1692
|
});
|
|
1176
1693
|
await new Promise((resolve, reject) => {
|
|
@@ -1184,7 +1701,9 @@ async function startInternalMetroServer(options) {
|
|
|
1184
1701
|
const close = () => {
|
|
1185
1702
|
setTimeout(() => process.exit(0), 1e3).unref();
|
|
1186
1703
|
messageServer.close();
|
|
1704
|
+
logServer.close();
|
|
1187
1705
|
for (const client of messageClients) client.terminate();
|
|
1706
|
+
for (const client of logClients) client.terminate();
|
|
1188
1707
|
server.close(() => {
|
|
1189
1708
|
end();
|
|
1190
1709
|
process.exit(0);
|
|
@@ -1195,8 +1714,10 @@ async function startInternalMetroServer(options) {
|
|
|
1195
1714
|
}
|
|
1196
1715
|
async function startDevServer(options) {
|
|
1197
1716
|
const config = readProjectConfig(options);
|
|
1717
|
+
if (options.clean) cleanDevArtifacts(options.projectRoot);
|
|
1198
1718
|
const runtime = await resolveRuntimeArtifact();
|
|
1199
1719
|
const clientAppPath = copyRuntimeClient(options.projectRoot, runtime);
|
|
1720
|
+
console.log("Preparing Bleam dev workspace");
|
|
1200
1721
|
const workspaceRoot = createDevWorkspace(options.projectRoot, config);
|
|
1201
1722
|
const origin = `http://localhost:${options.port}`;
|
|
1202
1723
|
const projectConfigPath = writeProjectRuntimeConfig(options.projectRoot, config, origin);
|
|
@@ -1206,7 +1727,8 @@ async function startDevServer(options) {
|
|
|
1206
1727
|
"--workspace-root",
|
|
1207
1728
|
workspaceRoot,
|
|
1208
1729
|
"--port",
|
|
1209
|
-
String(options.port)
|
|
1730
|
+
String(options.port),
|
|
1731
|
+
...options.clean ? ["--reset-cache"] : []
|
|
1210
1732
|
], {
|
|
1211
1733
|
stdio: "inherit",
|
|
1212
1734
|
env: {
|
|
@@ -1230,24 +1752,32 @@ async function startDevServer(options) {
|
|
|
1230
1752
|
}
|
|
1231
1753
|
});
|
|
1232
1754
|
let cleanupInteractiveControls = () => {};
|
|
1755
|
+
let didLaunchRuntimeClient = false;
|
|
1756
|
+
let didCleanupDevSession = false;
|
|
1233
1757
|
let stopping = false;
|
|
1758
|
+
const cleanupDevSession = () => {
|
|
1759
|
+
if (didCleanupDevSession) return;
|
|
1760
|
+
didCleanupDevSession = true;
|
|
1761
|
+
cleanupInteractiveControls();
|
|
1762
|
+
if (didLaunchRuntimeClient) quitRuntimeClient();
|
|
1763
|
+
};
|
|
1234
1764
|
const stop = (signal) => {
|
|
1235
1765
|
if (stopping) return;
|
|
1236
1766
|
stopping = true;
|
|
1237
|
-
|
|
1767
|
+
cleanupDevSession();
|
|
1238
1768
|
child.kill(signal);
|
|
1239
1769
|
setTimeout(() => process.exit(0), 2e3).unref();
|
|
1240
1770
|
};
|
|
1241
1771
|
process.on("SIGINT", () => stop("SIGINT"));
|
|
1242
1772
|
process.on("SIGTERM", () => stop("SIGTERM"));
|
|
1243
1773
|
child.on("error", (error) => {
|
|
1244
|
-
|
|
1774
|
+
cleanupDevSession();
|
|
1245
1775
|
console.error(`Bleam dev server process failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1246
1776
|
console.error(doctorHint(options.projectRoot));
|
|
1247
1777
|
process.exit(1);
|
|
1248
1778
|
});
|
|
1249
1779
|
child.on("exit", (code) => {
|
|
1250
|
-
|
|
1780
|
+
cleanupDevSession();
|
|
1251
1781
|
process.exit(code ?? 0);
|
|
1252
1782
|
});
|
|
1253
1783
|
try {
|
|
@@ -1261,8 +1791,9 @@ async function startDevServer(options) {
|
|
|
1261
1791
|
});
|
|
1262
1792
|
if (options.run && process.env.BLEAM_NO_OPEN !== "1") try {
|
|
1263
1793
|
await waitForDevBundle(manifest.bundleUrl);
|
|
1264
|
-
console.log(
|
|
1794
|
+
console.log(`Opening Bleam app at ${prettyPath(clientAppPath)}`);
|
|
1265
1795
|
await launchRuntimeClient(clientAppPath, projectConfigPath, manifest);
|
|
1796
|
+
didLaunchRuntimeClient = true;
|
|
1266
1797
|
} catch (error) {
|
|
1267
1798
|
console.error(`Initial app launch failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1268
1799
|
console.error(doctorHint(options.projectRoot));
|
|
@@ -1270,7 +1801,7 @@ async function startDevServer(options) {
|
|
|
1270
1801
|
console.error("Bleam dev server is still running.");
|
|
1271
1802
|
}
|
|
1272
1803
|
} catch (error) {
|
|
1273
|
-
|
|
1804
|
+
cleanupDevSession();
|
|
1274
1805
|
child.kill("SIGTERM");
|
|
1275
1806
|
throw error;
|
|
1276
1807
|
}
|
|
@@ -1283,11 +1814,12 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1283
1814
|
}
|
|
1284
1815
|
if (command === "new") {
|
|
1285
1816
|
const options = parseNewOptions(args);
|
|
1286
|
-
|
|
1287
|
-
|
|
1817
|
+
createProject(options);
|
|
1818
|
+
await startDevServer({
|
|
1288
1819
|
projectRoot: options.projectRoot,
|
|
1289
1820
|
port: 8081,
|
|
1290
|
-
run: true
|
|
1821
|
+
run: true,
|
|
1822
|
+
clean: false
|
|
1291
1823
|
});
|
|
1292
1824
|
return;
|
|
1293
1825
|
}
|
|
@@ -1295,14 +1827,34 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1295
1827
|
await startDevServer(parseDevOptions(args));
|
|
1296
1828
|
return;
|
|
1297
1829
|
}
|
|
1830
|
+
if (command === "install") {
|
|
1831
|
+
await installNativeApp(parseBuildOptions(args));
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1298
1834
|
if (command === "build") {
|
|
1299
1835
|
await buildNativeArchives(parseBuildOptions(args));
|
|
1300
1836
|
return;
|
|
1301
1837
|
}
|
|
1838
|
+
if (command === "publish") {
|
|
1839
|
+
const [kind, ...publishArgs] = args;
|
|
1840
|
+
if (kind === "ota") {
|
|
1841
|
+
await publishOta(parsePublishOtaOptions(publishArgs));
|
|
1842
|
+
return;
|
|
1843
|
+
}
|
|
1844
|
+
if (kind === "platform") {
|
|
1845
|
+
await publishPlatform(parsePublishOtaOptions(publishArgs));
|
|
1846
|
+
return;
|
|
1847
|
+
}
|
|
1848
|
+
throw new Error("Usage: bleam publish <ota|platform> [dir] [--service-url <url>]");
|
|
1849
|
+
}
|
|
1302
1850
|
if (command === "doctor") {
|
|
1303
1851
|
runDoctor(parseDoctorOptions(args));
|
|
1304
1852
|
return;
|
|
1305
1853
|
}
|
|
1854
|
+
if (command === "typecheck") {
|
|
1855
|
+
runTypecheckCommand(parseProjectToolOptions(args));
|
|
1856
|
+
return;
|
|
1857
|
+
}
|
|
1306
1858
|
if (command === "check") {
|
|
1307
1859
|
runBiomeCommand("check", parseProjectToolOptions(args));
|
|
1308
1860
|
return;
|
|
@@ -1321,9 +1873,24 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1321
1873
|
}
|
|
1322
1874
|
throw new Error(`Unknown command: ${command}`);
|
|
1323
1875
|
}
|
|
1324
|
-
main().catch((error) => {
|
|
1876
|
+
if (process.env.VITEST !== "true") main().catch((error) => {
|
|
1325
1877
|
console.error(error instanceof Error ? error.message : String(error));
|
|
1326
1878
|
process.exit(1);
|
|
1327
1879
|
});
|
|
1880
|
+
const __test = {
|
|
1881
|
+
createProject,
|
|
1882
|
+
createBuildNativeWorkspace,
|
|
1883
|
+
hasCurrentPodInstall,
|
|
1884
|
+
installedAppPath,
|
|
1885
|
+
installArchivedApp,
|
|
1886
|
+
nativeArchiveArgs,
|
|
1887
|
+
parseBuildOptions,
|
|
1888
|
+
parseNewOptions,
|
|
1889
|
+
parsePublishOtaOptions,
|
|
1890
|
+
platformRelease,
|
|
1891
|
+
podInstallInputStamp,
|
|
1892
|
+
replaceOrInsertPlistString
|
|
1893
|
+
};
|
|
1328
1894
|
|
|
1329
|
-
//#endregion
|
|
1895
|
+
//#endregion
|
|
1896
|
+
exports.__test = __test;
|