bleam 0.0.9 → 0.0.10
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/cli.cjs +246 -18
- package/dist/cli.d.cts +30 -2
- package/dist/cli.d.ts +30 -2
- package/dist/cli.js +247 -19
- package/dist/platform.d.cts +2 -0
- package/dist/platform.d.ts +2 -0
- package/dist/{ui-1WepaMS4.d.cts → ui-Dd7SXdbg.d.cts} +7 -7
- package/dist/ui.d.cts +1 -1
- package/dist/window.d.cts +1 -1
- package/package.json +2 -1
- package/templates/native/ios/Bleam/AppDelegate.swift +129 -20
- package/templates/native/ios/Bleam.xcodeproj/project.pbxproj +19 -18
- package/templates/native/ios/PlatformHelper/main.swift +457 -66
- package/templates/native/modules/bleam-runtime/ios/PlatformModule.swift +21 -5
- package/templates/updates/README.md +272 -0
- package/templates/updates/src/index.ts +385 -0
- package/templates/updates/src/schema.ts +385 -0
- package/templates/updates/tsconfig.json +12 -0
- package/templates/updates/wrangler.jsonc +19 -0
- package/templates/native/ios/PlatformHelper/Info.plist +0 -29
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
4
4
|
import { createHash, randomUUID } from "node:crypto";
|
|
5
|
-
import { appendFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { appendFileSync, closeSync, cpSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
|
|
6
6
|
import http from "node:http";
|
|
7
7
|
import os from "node:os";
|
|
8
8
|
import path from "node:path";
|
|
@@ -12,6 +12,7 @@ import yoctoSpinner from "yocto-spinner";
|
|
|
12
12
|
import { bold, dim, green, red, yellow } from "yoctocolors";
|
|
13
13
|
|
|
14
14
|
//#region src/cli.ts
|
|
15
|
+
const localUpdateServiceUrl = "http://127.0.0.1:8787";
|
|
15
16
|
const require = createRequire(import.meta.url);
|
|
16
17
|
const packageRoot = path.dirname(fileURLToPath(new URL("../package.json", import.meta.url)));
|
|
17
18
|
const packageJson = require("../package.json");
|
|
@@ -84,7 +85,7 @@ Commands:
|
|
|
84
85
|
Build and install a standalone macOS app
|
|
85
86
|
publish ota [dir] [--service-url <url>]
|
|
86
87
|
Publish an OTA update to the local update service
|
|
87
|
-
publish platform [dir] [--service-url <url>]
|
|
88
|
+
publish platform [dir] [--service-url <url>] [--redeploy]
|
|
88
89
|
Build and publish a platform update locally
|
|
89
90
|
doctor [dir] Check the local Bleam environment
|
|
90
91
|
typecheck [dir] Typecheck project files
|
|
@@ -96,7 +97,7 @@ function parsePublishOtaOptions(argv) {
|
|
|
96
97
|
const root = invocationRoot();
|
|
97
98
|
let projectRoot = root;
|
|
98
99
|
let hasProjectRootArg = false;
|
|
99
|
-
let serviceUrl = process.env.BLEAM_UPDATE_SERVICE_URL ??
|
|
100
|
+
let serviceUrl = process.env.BLEAM_UPDATE_SERVICE_URL ?? localUpdateServiceUrl;
|
|
100
101
|
for (let index = 0; index < argv.length; index += 1) {
|
|
101
102
|
const arg = argv[index];
|
|
102
103
|
if (arg === "--service-url") {
|
|
@@ -120,6 +121,13 @@ function parsePublishOtaOptions(argv) {
|
|
|
120
121
|
serviceUrl: url.origin
|
|
121
122
|
};
|
|
122
123
|
}
|
|
124
|
+
function parsePublishPlatformOptions(argv) {
|
|
125
|
+
const redeploy = argv.includes("--redeploy");
|
|
126
|
+
return {
|
|
127
|
+
...parsePublishOtaOptions(argv.filter((argument) => argument !== "--redeploy")),
|
|
128
|
+
redeploy
|
|
129
|
+
};
|
|
130
|
+
}
|
|
123
131
|
function invocationRoot() {
|
|
124
132
|
const pwd = process.env.PWD;
|
|
125
133
|
return pwd && path.isAbsolute(pwd) ? pwd : process.cwd();
|
|
@@ -467,7 +475,8 @@ function readProjectConfig(options) {
|
|
|
467
475
|
teamId: config.teamId,
|
|
468
476
|
appearance: config.appearance ?? normalizeAppearance(void 0),
|
|
469
477
|
runtimeVersion,
|
|
470
|
-
sdkVersion: runtimeVersion
|
|
478
|
+
sdkVersion: runtimeVersion,
|
|
479
|
+
iconPath: existsSync(path.join(options.projectRoot, "icon.png")) ? path.join(options.projectRoot, "icon.png") : void 0
|
|
471
480
|
};
|
|
472
481
|
}
|
|
473
482
|
function slugFromName(name) {
|
|
@@ -627,6 +636,18 @@ function nativeRuntimeTemplateRoot(root = packageRoot) {
|
|
|
627
636
|
const bundledTemplate = path.join(root, "templates", "native");
|
|
628
637
|
return existsSync(bundledTemplate) ? bundledTemplate : path.resolve(root, "..", "..", "app", "bleam");
|
|
629
638
|
}
|
|
639
|
+
function localUpdateServiceRoot(root = packageRoot) {
|
|
640
|
+
const bundledService = path.join(root, "templates", "updates");
|
|
641
|
+
return existsSync(bundledService) ? bundledService : path.resolve(root, "..", "..", "services", "updates");
|
|
642
|
+
}
|
|
643
|
+
function localUpdateServicePaths(home = os.homedir()) {
|
|
644
|
+
const root = path.join(home, "Library", "Caches", "bleam", "updates");
|
|
645
|
+
return {
|
|
646
|
+
root,
|
|
647
|
+
state: path.join(root, "state"),
|
|
648
|
+
log: path.join(root, "worker.log")
|
|
649
|
+
};
|
|
650
|
+
}
|
|
630
651
|
function safeArtifactName(name) {
|
|
631
652
|
return name.trim().replace(/[/:\\]/g, "-").replace(/\s+/g, " ") || "App";
|
|
632
653
|
}
|
|
@@ -661,11 +682,13 @@ function replaceOrInsertPlistStringArray(plist, key, values) {
|
|
|
661
682
|
return `${plist.slice(0, closingDictionary)}\t<key>${key}</key>\n\t<array>\n${plistStringArray(values)}\n\t</array>\n${plist.slice(closingDictionary)}`;
|
|
662
683
|
}
|
|
663
684
|
function writeGeneratedAppJson(nativeRoot, config) {
|
|
685
|
+
const icon = config.iconPath ? "./icon.png" : void 0;
|
|
664
686
|
writeFileSync(path.join(nativeRoot, "app.json"), `${JSON.stringify({ expo: {
|
|
665
687
|
name: config.name,
|
|
666
688
|
slug: slugFromName(config.name),
|
|
667
689
|
version: config.version ?? "1.0.0",
|
|
668
690
|
platforms: ["ios"],
|
|
691
|
+
icon,
|
|
669
692
|
ios: {
|
|
670
693
|
appleTeamId: config.teamId,
|
|
671
694
|
buildNumber: config.buildNumber,
|
|
@@ -673,24 +696,65 @@ function writeGeneratedAppJson(nativeRoot, config) {
|
|
|
673
696
|
}
|
|
674
697
|
} }, null, 2)}\n`);
|
|
675
698
|
}
|
|
699
|
+
function prepareNativeIcon(nativeRoot, iconPath) {
|
|
700
|
+
const generatedIcon = path.join(nativeRoot, "icon.png");
|
|
701
|
+
const appIconRoot = path.join(nativeRoot, "ios", "Bleam", "Images.xcassets", "AppIcon.appiconset");
|
|
702
|
+
rmSync(generatedIcon, { force: true });
|
|
703
|
+
rmSync(path.join(appIconRoot, "AppIcon.png"), { force: true });
|
|
704
|
+
if (!iconPath) return;
|
|
705
|
+
cpSync(iconPath, generatedIcon);
|
|
706
|
+
cpSync(iconPath, path.join(appIconRoot, "AppIcon.png"));
|
|
707
|
+
writeFileSync(path.join(appIconRoot, "Contents.json"), `${JSON.stringify({
|
|
708
|
+
images: [{
|
|
709
|
+
filename: "AppIcon.png",
|
|
710
|
+
idiom: "universal",
|
|
711
|
+
platform: "ios",
|
|
712
|
+
size: "1024x1024"
|
|
713
|
+
}],
|
|
714
|
+
info: {
|
|
715
|
+
version: 1,
|
|
716
|
+
author: "bleam"
|
|
717
|
+
}
|
|
718
|
+
}, null, 2)}\n`);
|
|
719
|
+
}
|
|
720
|
+
function platformInputFingerprint(config) {
|
|
721
|
+
const iconSha256 = config.iconPath ? sha256(config.iconPath) : null;
|
|
722
|
+
return createHash("sha256").update(JSON.stringify({
|
|
723
|
+
schemaVersion: 1,
|
|
724
|
+
bleamPlatformVersion: config.runtimeVersion,
|
|
725
|
+
name: config.name,
|
|
726
|
+
appVersion: config.version ?? "1.0.0",
|
|
727
|
+
buildNumber: config.buildNumber,
|
|
728
|
+
bundleIdentifier: config.bundleIdentifier,
|
|
729
|
+
teamIdentifier: config.teamId,
|
|
730
|
+
appGroups: config.appGroups,
|
|
731
|
+
appearance: config.appearance,
|
|
732
|
+
iconSha256,
|
|
733
|
+
updateServiceUrl: process.env.BLEAM_UPDATE_SERVICE_URL ?? localUpdateServiceUrl,
|
|
734
|
+
target: {
|
|
735
|
+
os: "macos",
|
|
736
|
+
architecture: "arm64",
|
|
737
|
+
minimumMacOSVersion: "14.0"
|
|
738
|
+
}
|
|
739
|
+
})).digest("hex");
|
|
740
|
+
}
|
|
676
741
|
function patchNativeProject(nativeRoot, config) {
|
|
677
742
|
const projectPath = path.join(nativeRoot, "ios", "Bleam.xcodeproj", "project.pbxproj");
|
|
678
743
|
const infoPlistPath = path.join(nativeRoot, "ios", "Bleam", "Info.plist");
|
|
679
744
|
const generationInfoPlistPath = path.join(nativeRoot, "ios", "GenerationService", "Info.plist");
|
|
680
|
-
const platformInfoPlistPath = path.join(nativeRoot, "ios", "PlatformHelper", "Info.plist");
|
|
681
745
|
const appEntitlementsPath = path.join(nativeRoot, "ios", "Bleam", "bleam.entitlements");
|
|
682
746
|
const generationEntitlementsPath = path.join(nativeRoot, "ios", "GenerationService", "GenerationService.entitlements");
|
|
683
747
|
const productName = xcodeSettingValue(config.name);
|
|
684
748
|
const bundleIdentifier = xcodeSettingValue(config.bundleIdentifier ?? "");
|
|
685
749
|
const generationBundleIdentifier = xcodeSettingValue(`${config.bundleIdentifier}.GenerationService`);
|
|
686
|
-
const platformBundleIdentifier = xcodeSettingValue(`${config.bundleIdentifier}.PlatformHelper`);
|
|
687
750
|
const teamId = xcodeSettingValue(config.teamId ?? "");
|
|
688
751
|
const version = xcodeSettingValue(config.version ?? "1.0.0");
|
|
689
752
|
const buildNumber = xcodeSettingValue(config.buildNumber);
|
|
690
753
|
const primaryAppGroup = config.appGroups[0];
|
|
754
|
+
const fingerprint = platformInputFingerprint(config);
|
|
691
755
|
let project = readFileSync(projectPath, "utf8");
|
|
692
756
|
project = project.replace(/PRODUCT_BUNDLE_IDENTIFIER = ([^;]+);/g, (_, current) => {
|
|
693
|
-
return `PRODUCT_BUNDLE_IDENTIFIER = ${current.endsWith(".GenerationService") ? generationBundleIdentifier :
|
|
757
|
+
return `PRODUCT_BUNDLE_IDENTIFIER = ${current.endsWith(".GenerationService") ? generationBundleIdentifier : bundleIdentifier};`;
|
|
694
758
|
}).replace(/DEVELOPMENT_TEAM = [^;]+;/g, () => {
|
|
695
759
|
return `DEVELOPMENT_TEAM = ${teamId};`;
|
|
696
760
|
}).replace(/MARKETING_VERSION = [^;]+;/g, () => {
|
|
@@ -705,9 +769,10 @@ function patchNativeProject(nativeRoot, config) {
|
|
|
705
769
|
infoPlist = replacePlistString(infoPlist, "CFBundleDisplayName", config.name);
|
|
706
770
|
infoPlist = replacePlistString(infoPlist, "CFBundleShortVersionString", config.version ?? "1.0.0");
|
|
707
771
|
infoPlist = replaceOrInsertPlistString(infoPlist, "BleamRuntimeVersion", config.runtimeVersion);
|
|
772
|
+
infoPlist = replaceOrInsertPlistString(infoPlist, "BleamPlatformFingerprint", fingerprint);
|
|
708
773
|
infoPlist = replaceOrInsertPlistString(infoPlist, "BleamTeamIdentifier", config.teamId ?? "");
|
|
709
|
-
const updateServiceUrl = process.env.BLEAM_UPDATE_SERVICE_URL;
|
|
710
|
-
|
|
774
|
+
const updateServiceUrl = process.env.BLEAM_UPDATE_SERVICE_URL ?? localUpdateServiceUrl;
|
|
775
|
+
infoPlist = replaceOrInsertPlistString(infoPlist, "BleamUpdateServiceURL", updateServiceUrl);
|
|
711
776
|
infoPlist = replacePlistString(infoPlist, "CFBundleVersion", config.buildNumber);
|
|
712
777
|
if (primaryAppGroup) infoPlist = replaceOrInsertPlistString(infoPlist, "AppGroupIdentifier", primaryAppGroup);
|
|
713
778
|
writeFileSync(infoPlistPath, infoPlist);
|
|
@@ -715,7 +780,6 @@ function patchNativeProject(nativeRoot, config) {
|
|
|
715
780
|
let generationInfoPlist = readFileSync(generationInfoPlistPath, "utf8");
|
|
716
781
|
generationInfoPlist = replaceOrInsertPlistString(generationInfoPlist, "AppGroupIdentifier", primaryAppGroup);
|
|
717
782
|
writeFileSync(generationInfoPlistPath, generationInfoPlist);
|
|
718
|
-
writeFileSync(platformInfoPlistPath, replaceOrInsertPlistString(readFileSync(platformInfoPlistPath, "utf8"), "BleamPlatformVersion", config.runtimeVersion));
|
|
719
783
|
for (const entitlementsPath of [appEntitlementsPath, generationEntitlementsPath]) writeFileSync(entitlementsPath, replaceOrInsertPlistStringArray(readFileSync(entitlementsPath, "utf8"), "com.apple.security.application-groups", config.appGroups));
|
|
720
784
|
}
|
|
721
785
|
}
|
|
@@ -748,6 +812,7 @@ function createBuildNativeWorkspace(options, config) {
|
|
|
748
812
|
writeFileSync(path.join(nativeRoot, "index.ts"), `import { registerApp } from 'bleam/app'\nimport App from ${JSON.stringify(path.join(options.projectRoot, "app"))}\n\nregisterApp(App)\n`);
|
|
749
813
|
writeFileSync(path.join(nativeRoot, "metro.config.js"), `const { getDefaultConfig } = require(${JSON.stringify(path.join(packageRoot, "metro-config.cjs"))})\n\nmodule.exports = getDefaultConfig(__dirname)\n`);
|
|
750
814
|
writeFileSync(path.join(nativeRoot, "ios", ".xcode.env"), `export NODE_BINARY=$(command -v node)\nexport BLEAM_PROJECT_ROOT=${singleQuotedString(options.projectRoot)}\nexport BLEAM_DEV_PLATFORM=macos\n`);
|
|
815
|
+
prepareNativeIcon(nativeRoot, config.iconPath);
|
|
751
816
|
patchNativeProject(nativeRoot, config);
|
|
752
817
|
return nativeRoot;
|
|
753
818
|
}
|
|
@@ -772,14 +837,13 @@ function runInheritedCommand(command, args, cwd) {
|
|
|
772
837
|
}
|
|
773
838
|
function installPods(nativeRoot) {
|
|
774
839
|
const iosRoot = path.join(nativeRoot, "ios");
|
|
775
|
-
|
|
776
|
-
if (hasCurrentPodInstall(iosRoot, expectedStamp)) {
|
|
840
|
+
if (hasCurrentPodInstall(iosRoot, podInstallInputStamp(iosRoot))) {
|
|
777
841
|
console.log("Using cached native dependencies");
|
|
778
842
|
return;
|
|
779
843
|
}
|
|
780
844
|
console.log("Installing native dependencies...");
|
|
781
845
|
runInheritedCommand("pod", ["install"], iosRoot);
|
|
782
|
-
writeFileSync(podInstallStampPath(iosRoot), `${
|
|
846
|
+
writeFileSync(podInstallStampPath(iosRoot), `${podInstallInputStamp(iosRoot)}\n`);
|
|
783
847
|
}
|
|
784
848
|
function ensureNativeFrameworks(nativeRoot) {
|
|
785
849
|
const frameworksRoot = path.join(nativeRoot, "ios", "Vendor", "MLXSwift", "0.31.6-macos");
|
|
@@ -812,7 +876,9 @@ function podInstallStampPath(iosRoot) {
|
|
|
812
876
|
}
|
|
813
877
|
function hasCurrentPodInstall(iosRoot, expectedStamp) {
|
|
814
878
|
const stampPath = podInstallStampPath(iosRoot);
|
|
815
|
-
|
|
879
|
+
const lockPath = path.join(iosRoot, "Podfile.lock");
|
|
880
|
+
const manifestPath = path.join(iosRoot, "Pods", "Manifest.lock");
|
|
881
|
+
return existsSync(path.join(iosRoot, "Bleam.xcworkspace")) && existsSync(lockPath) && existsSync(manifestPath) && readFileSync(lockPath, "utf8") === readFileSync(manifestPath, "utf8") && existsSync(stampPath) && readFileSync(stampPath, "utf8").trim() === expectedStamp;
|
|
816
882
|
}
|
|
817
883
|
function nativeArchiveArgs(options) {
|
|
818
884
|
return [
|
|
@@ -987,10 +1053,76 @@ async function publishOta(options) {
|
|
|
987
1053
|
console.log(`Published OTA update ${releaseId}`);
|
|
988
1054
|
console.log(`${options.serviceUrl}/v1/apps/${encodeURIComponent(config.bundleIdentifier)}/ota/${runtimeVersion}`);
|
|
989
1055
|
}
|
|
1056
|
+
function compareVersions(left, right) {
|
|
1057
|
+
const parse = (value) => {
|
|
1058
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([^+]+))?(?:\+.*)?$/.exec(value);
|
|
1059
|
+
if (!match) throw new Error(`Invalid Bleam platform version: ${value}`);
|
|
1060
|
+
return {
|
|
1061
|
+
core: match.slice(1, 4).map(Number),
|
|
1062
|
+
prerelease: match[4]?.split(".")
|
|
1063
|
+
};
|
|
1064
|
+
};
|
|
1065
|
+
const a = parse(left);
|
|
1066
|
+
const b = parse(right);
|
|
1067
|
+
for (let index = 0; index < a.core.length; index += 1) if (a.core[index] !== b.core[index]) return (a.core[index] ?? 0) < (b.core[index] ?? 0) ? -1 : 1;
|
|
1068
|
+
if (!a.prerelease && !b.prerelease) return 0;
|
|
1069
|
+
if (!a.prerelease) return 1;
|
|
1070
|
+
if (!b.prerelease) return -1;
|
|
1071
|
+
const length = Math.max(a.prerelease.length, b.prerelease.length);
|
|
1072
|
+
for (let index = 0; index < length; index += 1) {
|
|
1073
|
+
const aPart = a.prerelease[index];
|
|
1074
|
+
const bPart = b.prerelease[index];
|
|
1075
|
+
if (aPart === void 0) return -1;
|
|
1076
|
+
if (bPart === void 0) return 1;
|
|
1077
|
+
if (aPart === bPart) continue;
|
|
1078
|
+
const aNumber = /^\d+$/.test(aPart) ? Number(aPart) : void 0;
|
|
1079
|
+
const bNumber = /^\d+$/.test(bPart) ? Number(bPart) : void 0;
|
|
1080
|
+
if (aNumber !== void 0 && bNumber !== void 0) return aNumber < bNumber ? -1 : 1;
|
|
1081
|
+
if (aNumber !== void 0) return -1;
|
|
1082
|
+
if (bNumber !== void 0) return 1;
|
|
1083
|
+
return aPart < bPart ? -1 : 1;
|
|
1084
|
+
}
|
|
1085
|
+
return 0;
|
|
1086
|
+
}
|
|
1087
|
+
function platformPublicationReason(active, target, redeploy) {
|
|
1088
|
+
if (active && compareVersions(target.bleamPlatformVersion, active.bleamPlatformVersion) < 0) throw new Error(`Cannot publish older Bleam platform ${target.bleamPlatformVersion} over ${active.bleamPlatformVersion}. Rollback requires a separate release operation.`);
|
|
1089
|
+
const unchanged = active?.platformFingerprint === target.platformFingerprint;
|
|
1090
|
+
if (unchanged && !redeploy) throw new Error("Platform inputs are unchanged. Developer code and ordinary assets must be published with bleam publish ota. Use --redeploy only to intentionally republish identical platform inputs.");
|
|
1091
|
+
if (!unchanged && redeploy) throw new Error("--redeploy requires an existing release with the same platform fingerprint; publish normally because platform inputs changed.");
|
|
1092
|
+
if (unchanged) return "redeploy";
|
|
1093
|
+
if (!active) return "first-release";
|
|
1094
|
+
if (!active.platformFingerprint) return "legacy-migration";
|
|
1095
|
+
if (active.bleamPlatformVersion !== target.bleamPlatformVersion) return "runtime-upgrade";
|
|
1096
|
+
return "signed-input-change";
|
|
1097
|
+
}
|
|
1098
|
+
async function activePlatformRelease(serviceUrl, config) {
|
|
1099
|
+
const response = await fetch(`${serviceUrl}/v1/apps/${encodeURIComponent(config.bundleIdentifier ?? "")}/platform/macos-arm64`, { cache: "no-store" });
|
|
1100
|
+
if (response.status === 404) return void 0;
|
|
1101
|
+
if (!response.ok) throw new Error(`Could not resolve the active platform release: ${response.status} ${await response.text()}`);
|
|
1102
|
+
const release = await response.json();
|
|
1103
|
+
if (release.kind !== "platform" || release.bundleIdentifier !== config.bundleIdentifier || release.teamIdentifier !== config.teamId || typeof release.bleamPlatformVersion !== "string" || release.platformFingerprint !== void 0 && (typeof release.platformFingerprint !== "string" || !/^[a-f0-9]{64}$/.test(release.platformFingerprint))) throw new Error("The active platform release is invalid for this app");
|
|
1104
|
+
return {
|
|
1105
|
+
bleamPlatformVersion: release.bleamPlatformVersion,
|
|
1106
|
+
platformFingerprint: release.platformFingerprint
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
990
1109
|
async function publishPlatform(options) {
|
|
991
1110
|
const config = readProjectConfig(options);
|
|
992
1111
|
if (!config.bundleIdentifier) throw missingBuildFieldError("bundleIdentifier");
|
|
993
1112
|
if (!config.teamId) throw missingBuildFieldError("teamId");
|
|
1113
|
+
const fingerprint = platformInputFingerprint(config);
|
|
1114
|
+
const active = await activePlatformRelease(options.serviceUrl, config);
|
|
1115
|
+
console.log(`Bleam platform: ${active?.bleamPlatformVersion ?? "none"} -> ${config.runtimeVersion}`);
|
|
1116
|
+
console.log(`Platform fingerprint: ${active?.platformFingerprint ?? "none"} -> ${fingerprint}`);
|
|
1117
|
+
const reason = platformPublicationReason(active, {
|
|
1118
|
+
bleamPlatformVersion: config.runtimeVersion,
|
|
1119
|
+
platformFingerprint: fingerprint
|
|
1120
|
+
}, options.redeploy);
|
|
1121
|
+
if (reason === "redeploy") console.log("Redeploying unchanged platform inputs by explicit request");
|
|
1122
|
+
else if (reason === "first-release") console.log("Publishing the first platform release for this app");
|
|
1123
|
+
else if (reason === "legacy-migration") console.log("Migrating the active legacy release to platform fingerprints");
|
|
1124
|
+
else if (reason === "runtime-upgrade") console.log("Publishing a Bleam platform runtime upgrade");
|
|
1125
|
+
else console.log("Publishing changed signed app metadata or resources");
|
|
994
1126
|
const archivePath = await buildNativeArchives({
|
|
995
1127
|
projectRoot: options.projectRoot,
|
|
996
1128
|
output: path.join(options.projectRoot, "dist"),
|
|
@@ -1019,7 +1151,7 @@ async function publishPlatform(options) {
|
|
|
1019
1151
|
const sizeBytes = readFileSync(artifactPath).byteLength;
|
|
1020
1152
|
const digest = sha256(artifactPath);
|
|
1021
1153
|
const releaseId = `platform_${Date.now().toString(36)}_${digest.slice(0, 12)}`;
|
|
1022
|
-
const release = platformRelease(config, releaseId, sizeBytes, digest);
|
|
1154
|
+
const release = platformRelease(config, releaseId, sizeBytes, digest, options.redeploy);
|
|
1023
1155
|
const response = await fetch(`${options.serviceUrl}/v1/local/releases/platform`, {
|
|
1024
1156
|
method: "POST",
|
|
1025
1157
|
headers: { "content-type": "application/json" },
|
|
@@ -1032,7 +1164,7 @@ async function publishPlatform(options) {
|
|
|
1032
1164
|
console.log(`Published platform update ${releaseId}`);
|
|
1033
1165
|
console.log(`${options.serviceUrl}/v1/apps/${encodeURIComponent(config.bundleIdentifier)}/platform/macos-arm64`);
|
|
1034
1166
|
}
|
|
1035
|
-
function platformRelease(config, releaseId, sizeBytes, digest) {
|
|
1167
|
+
function platformRelease(config, releaseId, sizeBytes, digest, redeploy = false) {
|
|
1036
1168
|
if (!config.bundleIdentifier) throw missingBuildFieldError("bundleIdentifier");
|
|
1037
1169
|
if (!config.teamId) throw missingBuildFieldError("teamId");
|
|
1038
1170
|
return {
|
|
@@ -1044,7 +1176,9 @@ function platformRelease(config, releaseId, sizeBytes, digest) {
|
|
|
1044
1176
|
releaseId,
|
|
1045
1177
|
appVersion: config.version ?? "1.0.0",
|
|
1046
1178
|
buildNumber: config.buildNumber,
|
|
1047
|
-
bleamPlatformVersion: runtimeVersion,
|
|
1179
|
+
bleamPlatformVersion: config.runtimeVersion,
|
|
1180
|
+
platformFingerprint: platformInputFingerprint(config),
|
|
1181
|
+
redeploy,
|
|
1048
1182
|
target: {
|
|
1049
1183
|
os: "macos",
|
|
1050
1184
|
architecture: "arm64",
|
|
@@ -1393,6 +1527,92 @@ async function launchRuntimeClient(appPath, projectConfigPath, manifest) {
|
|
|
1393
1527
|
quitRuntimeClient();
|
|
1394
1528
|
openRuntimeClient(appPath, projectConfigPath, manifest);
|
|
1395
1529
|
}
|
|
1530
|
+
async function updateServiceHealthy(serviceUrl) {
|
|
1531
|
+
try {
|
|
1532
|
+
const response = await fetch(`${serviceUrl}/v1/health`, {
|
|
1533
|
+
cache: "no-store",
|
|
1534
|
+
signal: AbortSignal.timeout(1e3)
|
|
1535
|
+
});
|
|
1536
|
+
if (!response.ok) return false;
|
|
1537
|
+
return (await response.json()).healthy === true;
|
|
1538
|
+
} catch {
|
|
1539
|
+
return false;
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
function updateServiceLogTail(logPath) {
|
|
1543
|
+
if (!existsSync(logPath)) return "";
|
|
1544
|
+
return readFileSync(logPath, "utf8").slice(-4e3).trim();
|
|
1545
|
+
}
|
|
1546
|
+
async function waitForUpdateService(child, serviceUrl, logPath, timeoutMs = 3e4) {
|
|
1547
|
+
const startedAt = Date.now();
|
|
1548
|
+
let startupError;
|
|
1549
|
+
child.once("error", (error) => {
|
|
1550
|
+
startupError = error;
|
|
1551
|
+
});
|
|
1552
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
1553
|
+
if (startupError || child.exitCode !== null) break;
|
|
1554
|
+
if (await updateServiceHealthy(serviceUrl)) return;
|
|
1555
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
1556
|
+
}
|
|
1557
|
+
const log = updateServiceLogTail(logPath);
|
|
1558
|
+
const detail = log ? `\n\n${log}` : "";
|
|
1559
|
+
throw new Error(`Local update Worker failed to start.\nLog: ${logPath}${detail}`, startupError ? { cause: startupError } : void 0);
|
|
1560
|
+
}
|
|
1561
|
+
async function startLocalUpdateService() {
|
|
1562
|
+
const configuredUrl = process.env.BLEAM_UPDATE_SERVICE_URL ?? localUpdateServiceUrl;
|
|
1563
|
+
const serviceUrl = new URL(configuredUrl).origin;
|
|
1564
|
+
if (await updateServiceHealthy(serviceUrl)) {
|
|
1565
|
+
console.log(`Using local update Worker at ${serviceUrl}`);
|
|
1566
|
+
return {
|
|
1567
|
+
child: void 0,
|
|
1568
|
+
serviceUrl
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
if (serviceUrl !== localUpdateServiceUrl) throw new Error(`BLEAM_UPDATE_SERVICE_URL is not healthy: ${serviceUrl}/v1/health`);
|
|
1572
|
+
const serviceRoot = localUpdateServiceRoot();
|
|
1573
|
+
const configPath = path.join(serviceRoot, "wrangler.jsonc");
|
|
1574
|
+
if (!existsSync(configPath)) throw new Error(`Missing local update Worker: ${serviceRoot}`);
|
|
1575
|
+
const wrangler = path.join(resolvedDependencyRoot(), ".bin", "wrangler");
|
|
1576
|
+
if (!existsSync(wrangler)) throw new Error("Missing Wrangler dependency for the local update Worker");
|
|
1577
|
+
const paths = localUpdateServicePaths();
|
|
1578
|
+
mkdirSync(paths.state, { recursive: true });
|
|
1579
|
+
const log = openSync(paths.log, "a");
|
|
1580
|
+
const child = spawn(wrangler, [
|
|
1581
|
+
"dev",
|
|
1582
|
+
"--config",
|
|
1583
|
+
configPath,
|
|
1584
|
+
"--local",
|
|
1585
|
+
"--persist-to",
|
|
1586
|
+
paths.state,
|
|
1587
|
+
"--ip",
|
|
1588
|
+
"127.0.0.1",
|
|
1589
|
+
"--port",
|
|
1590
|
+
"8787"
|
|
1591
|
+
], {
|
|
1592
|
+
cwd: serviceRoot,
|
|
1593
|
+
stdio: [
|
|
1594
|
+
"ignore",
|
|
1595
|
+
log,
|
|
1596
|
+
log
|
|
1597
|
+
],
|
|
1598
|
+
env: {
|
|
1599
|
+
...process.env,
|
|
1600
|
+
NO_COLOR: "1"
|
|
1601
|
+
}
|
|
1602
|
+
});
|
|
1603
|
+
closeSync(log);
|
|
1604
|
+
try {
|
|
1605
|
+
await waitForUpdateService(child, serviceUrl, paths.log);
|
|
1606
|
+
} catch (error) {
|
|
1607
|
+
child.kill("SIGTERM");
|
|
1608
|
+
throw error;
|
|
1609
|
+
}
|
|
1610
|
+
console.log(`Local update Worker running at ${serviceUrl}`);
|
|
1611
|
+
return {
|
|
1612
|
+
child,
|
|
1613
|
+
serviceUrl
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1396
1616
|
function focusRuntimeClient() {
|
|
1397
1617
|
return spawnSync("osascript", ["-e", "tell application id \"dev.bleam.app\" to activate"], { stdio: "ignore" }).status === 0;
|
|
1398
1618
|
}
|
|
@@ -1727,6 +1947,7 @@ async function startDevServer(options) {
|
|
|
1727
1947
|
const workspaceRoot = createDevWorkspace(options.projectRoot, config);
|
|
1728
1948
|
const origin = `http://localhost:${options.port}`;
|
|
1729
1949
|
const projectConfigPath = writeProjectRuntimeConfig(options.projectRoot, config, origin);
|
|
1950
|
+
const updateService = await startLocalUpdateService();
|
|
1730
1951
|
const child = spawn(process.execPath, [
|
|
1731
1952
|
fileURLToPath(import.meta.url),
|
|
1732
1953
|
"internal:metro",
|
|
@@ -1747,6 +1968,7 @@ async function startDevServer(options) {
|
|
|
1747
1968
|
BLEAM_DEV_PLATFORM: "macos",
|
|
1748
1969
|
BLEAM_DEV_RUNTIME_VERSION: config.runtimeVersion,
|
|
1749
1970
|
BLEAM_DEV_SDK_VERSION: config.sdkVersion,
|
|
1971
|
+
BLEAM_UPDATE_SERVICE_URL: updateService.serviceUrl,
|
|
1750
1972
|
NODE_PATH: [
|
|
1751
1973
|
path.join(options.projectRoot, "node_modules"),
|
|
1752
1974
|
resolvedDependencyRoot(),
|
|
@@ -1766,6 +1988,7 @@ async function startDevServer(options) {
|
|
|
1766
1988
|
didCleanupDevSession = true;
|
|
1767
1989
|
cleanupInteractiveControls();
|
|
1768
1990
|
if (didLaunchRuntimeClient) quitRuntimeClient();
|
|
1991
|
+
if (updateService.child?.exitCode === null) updateService.child.kill("SIGTERM");
|
|
1769
1992
|
};
|
|
1770
1993
|
const stop = (signal) => {
|
|
1771
1994
|
if (stopping) return;
|
|
@@ -1848,10 +2071,10 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
1848
2071
|
return;
|
|
1849
2072
|
}
|
|
1850
2073
|
if (kind === "platform") {
|
|
1851
|
-
await publishPlatform(
|
|
2074
|
+
await publishPlatform(parsePublishPlatformOptions(publishArgs));
|
|
1852
2075
|
return;
|
|
1853
2076
|
}
|
|
1854
|
-
throw new Error("Usage: bleam publish <ota|platform> [dir] [--service-url <url>]");
|
|
2077
|
+
throw new Error("Usage: bleam publish <ota|platform> [dir] [--service-url <url>] [--redeploy]");
|
|
1855
2078
|
}
|
|
1856
2079
|
if (command === "doctor") {
|
|
1857
2080
|
runDoctor(parseDoctorOptions(args));
|
|
@@ -1889,11 +2112,16 @@ const __test = {
|
|
|
1889
2112
|
hasCurrentPodInstall,
|
|
1890
2113
|
installedAppPath,
|
|
1891
2114
|
installArchivedApp,
|
|
2115
|
+
localUpdateServicePaths,
|
|
2116
|
+
localUpdateServiceRoot,
|
|
1892
2117
|
nativeRuntimeTemplateRoot,
|
|
1893
2118
|
nativeArchiveArgs,
|
|
1894
2119
|
parseBuildOptions,
|
|
1895
2120
|
parseNewOptions,
|
|
1896
2121
|
parsePublishOtaOptions,
|
|
2122
|
+
parsePublishPlatformOptions,
|
|
2123
|
+
platformInputFingerprint,
|
|
2124
|
+
platformPublicationReason,
|
|
1897
2125
|
platformRelease,
|
|
1898
2126
|
podInstallInputStamp,
|
|
1899
2127
|
replaceOrInsertPlistString
|
package/dist/platform.d.cts
CHANGED
package/dist/platform.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import { ColorValue, StyleProp, TextStyle, ViewStyle } from "react-native";
|
|
3
|
-
import * as
|
|
3
|
+
import * as _nativescript_react_native31 from "@nativescript/react-native";
|
|
4
4
|
|
|
5
5
|
//#region src/ui/shared.d.ts
|
|
6
6
|
type NativeStyle = ViewStyle & TextStyle;
|
|
@@ -18,7 +18,7 @@ type ButtonProps = {
|
|
|
18
18
|
onPress?: () => void;
|
|
19
19
|
style?: StyleProp<NativeStyle>;
|
|
20
20
|
};
|
|
21
|
-
declare const Button:
|
|
21
|
+
declare const Button: _nativescript_react_native31.UIKitViewComponent<ButtonProps, UIButton>;
|
|
22
22
|
//#endregion
|
|
23
23
|
//#region src/ui/label.d.ts
|
|
24
24
|
type LabelTone = 'primary' | 'secondary' | 'tertiary';
|
|
@@ -29,7 +29,7 @@ type LabelProps = {
|
|
|
29
29
|
numberOfLines?: number;
|
|
30
30
|
style?: StyleProp<NativeStyle>;
|
|
31
31
|
};
|
|
32
|
-
declare const Label:
|
|
32
|
+
declare const Label: _nativescript_react_native31.UIKitViewComponent<LabelProps, UILabel>;
|
|
33
33
|
//#endregion
|
|
34
34
|
//#region src/ui/symbol.d.ts
|
|
35
35
|
type SymbolName = string;
|
|
@@ -43,7 +43,7 @@ type SymbolProps = {
|
|
|
43
43
|
color?: ColorValue;
|
|
44
44
|
style?: StyleProp<NativeStyle>;
|
|
45
45
|
};
|
|
46
|
-
declare const Symbol:
|
|
46
|
+
declare const Symbol: _nativescript_react_native31.UIKitViewComponent<SymbolProps, UIImageView>;
|
|
47
47
|
//#endregion
|
|
48
48
|
//#region src/ui/glass-shared.d.ts
|
|
49
49
|
type GlassStyle = 'regular' | 'clear' | 'none';
|
|
@@ -73,10 +73,10 @@ type GlassContainerProps = {
|
|
|
73
73
|
};
|
|
74
74
|
//#endregion
|
|
75
75
|
//#region src/ui/glass-view.d.ts
|
|
76
|
-
declare const GlassView:
|
|
76
|
+
declare const GlassView: _nativescript_react_native31.UIKitViewComponent<GlassViewProps, _nativescript_react_native31.UIKitContainerResult<UIVisualEffectView, UIView>>;
|
|
77
77
|
//#endregion
|
|
78
78
|
//#region src/ui/glass-container.d.ts
|
|
79
|
-
declare const GlassContainer:
|
|
79
|
+
declare const GlassContainer: _nativescript_react_native31.UIKitViewComponent<GlassContainerProps, _nativescript_react_native31.UIKitContainerResult<UIVisualEffectView, UIView>>;
|
|
80
80
|
//#endregion
|
|
81
81
|
//#region src/ui/blur-view.d.ts
|
|
82
82
|
type BlurIntensity = 'ultraThin' | 'thin' | 'regular' | 'thick' | 'chrome';
|
|
@@ -87,6 +87,6 @@ type BlurViewProps = {
|
|
|
87
87
|
intensity?: BlurIntensity;
|
|
88
88
|
colorScheme?: BlurColorScheme;
|
|
89
89
|
};
|
|
90
|
-
declare const BlurView:
|
|
90
|
+
declare const BlurView: _nativescript_react_native31.UIKitViewComponent<BlurViewProps, _nativescript_react_native31.UIKitContainerResult<UIVisualEffectView, UIView>>;
|
|
91
91
|
//#endregion
|
|
92
92
|
export { ButtonVariant as C, ButtonSize as S, Label as _, GlassContainer as a, Button as b, GlassEffectStyleConfig as c, GlassVisualStyle as d, Symbol as f, SymbolWeight as g, SymbolScale as h, BlurViewProps as i, GlassStyle as l, SymbolProps as m, BlurIntensity as n, GlassView as o, SymbolName as p, BlurView as r, GlassContainerProps as s, BlurColorScheme as t, GlassViewProps as u, LabelProps as v, ButtonProps as x, LabelTone as y };
|
package/dist/ui.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as ButtonVariant, S as ButtonSize, _ as Label, a as GlassContainer, b as Button, c as GlassEffectStyleConfig, d as GlassVisualStyle, f as Symbol, g as SymbolWeight, h as SymbolScale, i as BlurViewProps, l as GlassStyle, m as SymbolProps, n as BlurIntensity, o as GlassView, p as SymbolName, r as BlurView, s as GlassContainerProps, t as BlurColorScheme, u as GlassViewProps, v as LabelProps, x as ButtonProps, y as LabelTone } from "./ui-
|
|
1
|
+
import { C as ButtonVariant, S as ButtonSize, _ as Label, a as GlassContainer, b as Button, c as GlassEffectStyleConfig, d as GlassVisualStyle, f as Symbol, g as SymbolWeight, h as SymbolScale, i as BlurViewProps, l as GlassStyle, m as SymbolProps, n as BlurIntensity, o as GlassView, p as SymbolName, r as BlurView, s as GlassContainerProps, t as BlurColorScheme, u as GlassViewProps, v as LabelProps, x as ButtonProps, y as LabelTone } from "./ui-Dd7SXdbg.cjs";
|
|
2
2
|
export { BlurColorScheme, BlurIntensity, BlurView, BlurViewProps, Button, ButtonProps, ButtonSize, ButtonVariant, GlassContainer, GlassContainerProps, GlassEffectStyleConfig, GlassStyle, GlassView, GlassViewProps, GlassVisualStyle, Label, LabelProps, LabelTone, Symbol, SymbolName, SymbolProps, SymbolScale, SymbolWeight };
|
package/dist/window.d.cts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bleam",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.10",
|
|
4
4
|
"packageManager": "yarn@1.22.22",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"react-native": "0.86.0",
|
|
40
40
|
"tsx": "^4.21.0",
|
|
41
41
|
"typescript": "~6.0.3",
|
|
42
|
+
"wrangler": "4.110.0",
|
|
42
43
|
"ws": "^8.21.0",
|
|
43
44
|
"yocto-spinner": "^1.2.1",
|
|
44
45
|
"yoctocolors": "^2.1.2"
|