@comergehq/studio 0.1.13 → 0.1.15
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/index.d.mts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +211 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +211 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/data/apps/bundles/remote.ts +17 -0
- package/src/data/apps/bundles/repository.ts +14 -0
- package/src/data/apps/bundles/types.ts +15 -0
- package/src/studio/hooks/useBundleManager.ts +273 -22
package/dist/index.d.mts
CHANGED
|
@@ -6,11 +6,17 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
|
|
6
6
|
type EmbeddedBaseBundle = {
|
|
7
7
|
module: number;
|
|
8
8
|
meta?: BaseBundleMeta | null;
|
|
9
|
+
assetsModule?: number;
|
|
10
|
+
assetsMeta?: EmbeddedAssetsMeta | null;
|
|
9
11
|
};
|
|
10
12
|
type EmbeddedBaseBundles = {
|
|
11
13
|
ios?: EmbeddedBaseBundle;
|
|
12
14
|
android?: EmbeddedBaseBundle;
|
|
13
15
|
};
|
|
16
|
+
type EmbeddedAssetsMeta = {
|
|
17
|
+
checksumSha256: string | null;
|
|
18
|
+
size: number | null;
|
|
19
|
+
};
|
|
14
20
|
type BaseBundleMeta = {
|
|
15
21
|
fingerprint: string;
|
|
16
22
|
bundleId: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -6,11 +6,17 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
|
|
6
6
|
type EmbeddedBaseBundle = {
|
|
7
7
|
module: number;
|
|
8
8
|
meta?: BaseBundleMeta | null;
|
|
9
|
+
assetsModule?: number;
|
|
10
|
+
assetsMeta?: EmbeddedAssetsMeta | null;
|
|
9
11
|
};
|
|
10
12
|
type EmbeddedBaseBundles = {
|
|
11
13
|
ios?: EmbeddedBaseBundle;
|
|
12
14
|
android?: EmbeddedBaseBundle;
|
|
13
15
|
};
|
|
16
|
+
type EmbeddedAssetsMeta = {
|
|
17
|
+
checksumSha256: string | null;
|
|
18
|
+
size: number | null;
|
|
19
|
+
};
|
|
14
20
|
type BaseBundleMeta = {
|
|
15
21
|
fingerprint: string;
|
|
16
22
|
bundleId: string;
|
package/dist/index.js
CHANGED
|
@@ -914,6 +914,7 @@ function useThreadMessages(threadId) {
|
|
|
914
914
|
var React5 = __toESM(require("react"));
|
|
915
915
|
var FileSystem = __toESM(require("expo-file-system/legacy"));
|
|
916
916
|
var import_expo_asset = require("expo-asset");
|
|
917
|
+
var import_react_native_zip_archive = require("react-native-zip-archive");
|
|
917
918
|
|
|
918
919
|
// src/data/apps/bundles/remote.ts
|
|
919
920
|
var BundlesRemoteDataSourceImpl = class extends BaseRemote {
|
|
@@ -937,6 +938,13 @@ var BundlesRemoteDataSourceImpl = class extends BaseRemote {
|
|
|
937
938
|
);
|
|
938
939
|
return data;
|
|
939
940
|
}
|
|
941
|
+
async getSignedAssetsDownloadUrl(appId, bundleId, options) {
|
|
942
|
+
const { data } = await api.get(
|
|
943
|
+
`/v1/apps/${encodeURIComponent(appId)}/bundles/${encodeURIComponent(bundleId)}/assets/download`,
|
|
944
|
+
{ params: { redirect: (options == null ? void 0 : options.redirect) ?? false, kind: options == null ? void 0 : options.kind } }
|
|
945
|
+
);
|
|
946
|
+
return data;
|
|
947
|
+
}
|
|
940
948
|
};
|
|
941
949
|
var bundlesRemoteDataSource = new BundlesRemoteDataSourceImpl();
|
|
942
950
|
|
|
@@ -958,6 +966,10 @@ var BundlesRepositoryImpl = class extends BaseRepository {
|
|
|
958
966
|
const res = await this.remote.getSignedDownloadUrl(appId, bundleId, options);
|
|
959
967
|
return this.unwrapOrThrow(res);
|
|
960
968
|
}
|
|
969
|
+
async getSignedAssetsDownloadUrl(appId, bundleId, options) {
|
|
970
|
+
const res = await this.remote.getSignedAssetsDownloadUrl(appId, bundleId, options);
|
|
971
|
+
return this.unwrapOrThrow(res);
|
|
972
|
+
}
|
|
961
973
|
};
|
|
962
974
|
var bundlesRepository = new BundlesRepositoryImpl(bundlesRemoteDataSource);
|
|
963
975
|
|
|
@@ -1009,20 +1021,40 @@ async function ensureDir(path) {
|
|
|
1009
1021
|
if (info.exists) return;
|
|
1010
1022
|
await FileSystem.makeDirectoryAsync(path, { intermediates: true });
|
|
1011
1023
|
}
|
|
1024
|
+
async function ensureBundleDir(key) {
|
|
1025
|
+
await ensureDir(bundlesCacheDir());
|
|
1026
|
+
await ensureDir(bundleDir(key));
|
|
1027
|
+
}
|
|
1012
1028
|
function baseBundleKey(appId, platform) {
|
|
1013
1029
|
return `base:${appId}:${platform}`;
|
|
1014
1030
|
}
|
|
1015
1031
|
function testBundleKey(appId, commitId, platform, bundleId) {
|
|
1016
1032
|
return `test:${appId}:${commitId ?? "head"}:${platform}:${bundleId}`;
|
|
1017
1033
|
}
|
|
1018
|
-
function
|
|
1034
|
+
function legacyBundleFileUri(key) {
|
|
1019
1035
|
const dir = bundlesCacheDir();
|
|
1020
1036
|
return `${dir}${safeName(key)}.jsbundle`;
|
|
1021
1037
|
}
|
|
1022
|
-
function
|
|
1038
|
+
function legacyBundleMetaFileUri(key) {
|
|
1023
1039
|
const dir = bundlesCacheDir();
|
|
1024
1040
|
return `${dir}${safeName(key)}.meta.json`;
|
|
1025
1041
|
}
|
|
1042
|
+
function bundleDir(key) {
|
|
1043
|
+
const dir = bundlesCacheDir();
|
|
1044
|
+
return `${dir}${safeName(key)}/`;
|
|
1045
|
+
}
|
|
1046
|
+
function toBundleFileUri(key, platform) {
|
|
1047
|
+
return `${bundleDir(key)}index.${platform}.jsbundle`;
|
|
1048
|
+
}
|
|
1049
|
+
function toBundleMetaFileUri(key) {
|
|
1050
|
+
return `${bundleDir(key)}bundle.meta.json`;
|
|
1051
|
+
}
|
|
1052
|
+
function toAssetsMetaFileUri(key) {
|
|
1053
|
+
return `${bundleDir(key)}assets.meta.json`;
|
|
1054
|
+
}
|
|
1055
|
+
function toAssetsDir(key) {
|
|
1056
|
+
return `${bundleDir(key)}assets/`;
|
|
1057
|
+
}
|
|
1026
1058
|
async function readJsonFile(fileUri) {
|
|
1027
1059
|
try {
|
|
1028
1060
|
const info = await FileSystem.getInfoAsync(fileUri);
|
|
@@ -1049,6 +1081,14 @@ async function getExistingNonEmptyFileUri(fileUri) {
|
|
|
1049
1081
|
return null;
|
|
1050
1082
|
}
|
|
1051
1083
|
}
|
|
1084
|
+
async function getExistingBundleFileUri(key, platform) {
|
|
1085
|
+
const nextPath = toBundleFileUri(key, platform);
|
|
1086
|
+
const next = await getExistingNonEmptyFileUri(nextPath);
|
|
1087
|
+
if (next) return next;
|
|
1088
|
+
const legacyPath = legacyBundleFileUri(key);
|
|
1089
|
+
const legacy = await getExistingNonEmptyFileUri(legacyPath);
|
|
1090
|
+
return legacy;
|
|
1091
|
+
}
|
|
1052
1092
|
async function downloadIfMissing(url, fileUri) {
|
|
1053
1093
|
const existing = await getExistingNonEmptyFileUri(fileUri);
|
|
1054
1094
|
if (existing) return existing;
|
|
@@ -1075,9 +1115,12 @@ async function deleteFileIfExists(fileUri) {
|
|
|
1075
1115
|
async function hydrateBaseFromEmbeddedAsset(appId, platform, embedded) {
|
|
1076
1116
|
if (!(embedded == null ? void 0 : embedded.module)) return null;
|
|
1077
1117
|
const key = baseBundleKey(appId, platform);
|
|
1078
|
-
const
|
|
1079
|
-
|
|
1080
|
-
|
|
1118
|
+
const existing = await getExistingBundleFileUri(key, platform);
|
|
1119
|
+
if (existing) {
|
|
1120
|
+
return { bundlePath: existing, meta: embedded.meta ?? null };
|
|
1121
|
+
}
|
|
1122
|
+
await ensureBundleDir(key);
|
|
1123
|
+
const targetUri = toBundleFileUri(key, platform);
|
|
1081
1124
|
const asset = import_expo_asset.Asset.fromModule(embedded.module);
|
|
1082
1125
|
await asset.downloadAsync();
|
|
1083
1126
|
const sourceUri = asset.localUri ?? asset.uri;
|
|
@@ -1090,8 +1133,50 @@ async function hydrateBaseFromEmbeddedAsset(appId, platform, embedded) {
|
|
|
1090
1133
|
if (!finalUri) return null;
|
|
1091
1134
|
return { bundlePath: finalUri, meta: embedded.meta ?? null };
|
|
1092
1135
|
}
|
|
1093
|
-
async function
|
|
1094
|
-
|
|
1136
|
+
async function hydrateAssetsFromEmbeddedAsset(appId, platform, key, embedded) {
|
|
1137
|
+
var _a;
|
|
1138
|
+
const moduleId = embedded == null ? void 0 : embedded.assetsModule;
|
|
1139
|
+
if (!moduleId) return false;
|
|
1140
|
+
const assetsMeta = (embedded == null ? void 0 : embedded.assetsMeta) ?? null;
|
|
1141
|
+
const assetsDir = toAssetsDir(key);
|
|
1142
|
+
const metaUri = toAssetsMetaFileUri(key);
|
|
1143
|
+
const existingMeta = await readJsonFile(metaUri);
|
|
1144
|
+
const assetsDirInfo = await FileSystem.getInfoAsync(assetsDir);
|
|
1145
|
+
const assetsDirExists = assetsDirInfo.exists && assetsDirInfo.isDirectory;
|
|
1146
|
+
const checksumMatches = Boolean(existingMeta == null ? void 0 : existingMeta.checksumSha256) && Boolean(assetsMeta == null ? void 0 : assetsMeta.checksumSha256) && (existingMeta == null ? void 0 : existingMeta.checksumSha256) === (assetsMeta == null ? void 0 : assetsMeta.checksumSha256);
|
|
1147
|
+
const embeddedMetaMatches = (_a = existingMeta == null ? void 0 : existingMeta.storageKey) == null ? void 0 : _a.startsWith("embedded:");
|
|
1148
|
+
if (assetsDirExists && checksumMatches && embeddedMetaMatches) {
|
|
1149
|
+
return true;
|
|
1150
|
+
}
|
|
1151
|
+
await ensureBundleDir(key);
|
|
1152
|
+
await ensureDir(assetsDir);
|
|
1153
|
+
const asset = import_expo_asset.Asset.fromModule(moduleId);
|
|
1154
|
+
await asset.downloadAsync();
|
|
1155
|
+
const sourceUri = asset.localUri ?? asset.uri;
|
|
1156
|
+
if (!sourceUri) return false;
|
|
1157
|
+
const info = await FileSystem.getInfoAsync(sourceUri);
|
|
1158
|
+
if (!info.exists) return false;
|
|
1159
|
+
const zipUri = `${bundleDir(key)}assets.zip`;
|
|
1160
|
+
await deleteFileIfExists(zipUri);
|
|
1161
|
+
await FileSystem.copyAsync({ from: sourceUri, to: zipUri });
|
|
1162
|
+
try {
|
|
1163
|
+
await FileSystem.deleteAsync(assetsDir, { idempotent: true }).catch(() => {
|
|
1164
|
+
});
|
|
1165
|
+
} catch {
|
|
1166
|
+
}
|
|
1167
|
+
await ensureDir(assetsDir);
|
|
1168
|
+
await unzipArchive(zipUri, assetsDir);
|
|
1169
|
+
await writeJsonFile(metaUri, {
|
|
1170
|
+
checksumSha256: (assetsMeta == null ? void 0 : assetsMeta.checksumSha256) ?? null,
|
|
1171
|
+
storageKey: `embedded:${(assetsMeta == null ? void 0 : assetsMeta.checksumSha256) ?? "unknown"}`,
|
|
1172
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1173
|
+
});
|
|
1174
|
+
return true;
|
|
1175
|
+
}
|
|
1176
|
+
async function safeReplaceFileFromUrl(url, targetUri, tmpKey, platform) {
|
|
1177
|
+
const tmpKeySafe = `tmp:${tmpKey}:${Date.now()}`;
|
|
1178
|
+
const tmpUri = toBundleFileUri(tmpKeySafe, platform);
|
|
1179
|
+
await ensureDir(bundleDir(tmpKeySafe));
|
|
1095
1180
|
try {
|
|
1096
1181
|
await withRetry(
|
|
1097
1182
|
async () => {
|
|
@@ -1111,6 +1196,82 @@ async function safeReplaceFileFromUrl(url, targetUri, tmpKey) {
|
|
|
1111
1196
|
await deleteFileIfExists(tmpUri);
|
|
1112
1197
|
}
|
|
1113
1198
|
}
|
|
1199
|
+
async function safeReplaceFileFromUrlToPath(url, targetUri, tmpKey) {
|
|
1200
|
+
const tmpDir = `${bundlesCacheDir()}tmp/`;
|
|
1201
|
+
await ensureDir(tmpDir);
|
|
1202
|
+
const tmpUri = `${tmpDir}${safeName(tmpKey)}.tmp`;
|
|
1203
|
+
try {
|
|
1204
|
+
await withRetry(
|
|
1205
|
+
async () => {
|
|
1206
|
+
await deleteFileIfExists(tmpUri);
|
|
1207
|
+
await FileSystem.downloadAsync(url, tmpUri);
|
|
1208
|
+
const tmpOk = await getExistingNonEmptyFileUri(tmpUri);
|
|
1209
|
+
if (!tmpOk) throw new Error("Downloaded file is empty.");
|
|
1210
|
+
},
|
|
1211
|
+
{ attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
|
|
1212
|
+
);
|
|
1213
|
+
await deleteFileIfExists(targetUri);
|
|
1214
|
+
await FileSystem.moveAsync({ from: tmpUri, to: targetUri });
|
|
1215
|
+
const finalOk = await getExistingNonEmptyFileUri(targetUri);
|
|
1216
|
+
if (!finalOk) throw new Error("File replacement failed.");
|
|
1217
|
+
return targetUri;
|
|
1218
|
+
} finally {
|
|
1219
|
+
await deleteFileIfExists(tmpUri);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
function getMetroAssets(bundle) {
|
|
1223
|
+
const assets = bundle.assets ?? [];
|
|
1224
|
+
return assets.find((asset) => asset.kind === "metro-assets") ?? null;
|
|
1225
|
+
}
|
|
1226
|
+
async function ensureAssetsForBundle(appId, bundle, key, platform) {
|
|
1227
|
+
var _a;
|
|
1228
|
+
const asset = getMetroAssets(bundle);
|
|
1229
|
+
if (!(asset == null ? void 0 : asset.storageKey)) return;
|
|
1230
|
+
await ensureBundleDir(key);
|
|
1231
|
+
const assetsDir = toAssetsDir(key);
|
|
1232
|
+
await ensureDir(assetsDir);
|
|
1233
|
+
const metaUri = toAssetsMetaFileUri(key);
|
|
1234
|
+
const existingMeta = await readJsonFile(metaUri);
|
|
1235
|
+
const assetsDirInfo = await FileSystem.getInfoAsync(assetsDir);
|
|
1236
|
+
const assetsDirExists = assetsDirInfo.exists && assetsDirInfo.isDirectory;
|
|
1237
|
+
if ((existingMeta == null ? void 0 : existingMeta.checksumSha256) && asset.checksumSha256 && existingMeta.checksumSha256 === asset.checksumSha256 && (existingMeta.storageKey === asset.storageKey || ((_a = existingMeta.storageKey) == null ? void 0 : _a.startsWith("embedded:"))) && assetsDirExists) {
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
const signed = await withRetry(
|
|
1241
|
+
async () => {
|
|
1242
|
+
return await bundlesRepository.getSignedAssetsDownloadUrl(appId, bundle.id, {
|
|
1243
|
+
redirect: false,
|
|
1244
|
+
kind: asset.kind
|
|
1245
|
+
});
|
|
1246
|
+
},
|
|
1247
|
+
{ attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
|
|
1248
|
+
);
|
|
1249
|
+
const zipUri = `${bundleDir(key)}assets.zip`;
|
|
1250
|
+
await safeReplaceFileFromUrlToPath(signed.url, zipUri, `${appId}:${bundle.id}:${platform}:${asset.kind}`);
|
|
1251
|
+
try {
|
|
1252
|
+
await FileSystem.deleteAsync(assetsDir, { idempotent: true }).catch(() => {
|
|
1253
|
+
});
|
|
1254
|
+
} catch {
|
|
1255
|
+
}
|
|
1256
|
+
await ensureDir(assetsDir);
|
|
1257
|
+
await unzipArchive(zipUri, assetsDir);
|
|
1258
|
+
await writeJsonFile(metaUri, {
|
|
1259
|
+
checksumSha256: asset.checksumSha256 ?? null,
|
|
1260
|
+
storageKey: asset.storageKey,
|
|
1261
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
async function unzipArchive(sourceUri, destDir) {
|
|
1265
|
+
try {
|
|
1266
|
+
await (0, import_react_native_zip_archive.unzip)(sourceUri, destDir);
|
|
1267
|
+
} catch (e) {
|
|
1268
|
+
throw new Error(
|
|
1269
|
+
`Failed to extract assets archive. Ensure 'react-native-zip-archive' is installed in the host app. ${String(
|
|
1270
|
+
(e == null ? void 0 : e.message) ?? e
|
|
1271
|
+
)}`
|
|
1272
|
+
);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1114
1275
|
async function pollBundle(appId, bundleId, opts) {
|
|
1115
1276
|
const start = Date.now();
|
|
1116
1277
|
while (true) {
|
|
@@ -1146,18 +1307,33 @@ async function resolveBundlePath(src, platform, mode) {
|
|
|
1146
1307
|
if (finalBundle.status === "failed") {
|
|
1147
1308
|
throw new Error("Bundle build failed.");
|
|
1148
1309
|
}
|
|
1310
|
+
let bundleWithAssets = finalBundle;
|
|
1311
|
+
if (finalBundle.status === "succeeded" && (!finalBundle.assets || finalBundle.assets.length === 0)) {
|
|
1312
|
+
try {
|
|
1313
|
+
bundleWithAssets = await bundlesRepository.getById(appId, finalBundle.id);
|
|
1314
|
+
} catch {
|
|
1315
|
+
bundleWithAssets = finalBundle;
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1149
1318
|
const signed = await withRetry(
|
|
1150
1319
|
async () => {
|
|
1151
1320
|
return await bundlesRepository.getSignedDownloadUrl(appId, finalBundle.id, { redirect: false });
|
|
1152
1321
|
},
|
|
1153
1322
|
{ attempts: 3, baseDelayMs: 500, maxDelayMs: 4e3 }
|
|
1154
1323
|
);
|
|
1324
|
+
const key = mode === "base" ? baseBundleKey(appId, platform) : testBundleKey(appId, commitId, platform, finalBundle.id);
|
|
1325
|
+
await ensureBundleDir(key);
|
|
1155
1326
|
const bundlePath = mode === "base" ? await safeReplaceFileFromUrl(
|
|
1156
1327
|
signed.url,
|
|
1157
|
-
toBundleFileUri(
|
|
1158
|
-
`${appId}:${commitId ?? "head"}:${platform}:${finalBundle.id}
|
|
1159
|
-
|
|
1160
|
-
|
|
1328
|
+
toBundleFileUri(key, platform),
|
|
1329
|
+
`${appId}:${commitId ?? "head"}:${platform}:${finalBundle.id}`,
|
|
1330
|
+
platform
|
|
1331
|
+
) : await downloadIfMissing(signed.url, toBundleFileUri(key, platform));
|
|
1332
|
+
try {
|
|
1333
|
+
await ensureAssetsForBundle(appId, bundleWithAssets, key, platform);
|
|
1334
|
+
} catch {
|
|
1335
|
+
}
|
|
1336
|
+
return { bundlePath, label: "Ready", bundle: bundleWithAssets };
|
|
1161
1337
|
}
|
|
1162
1338
|
function useBundleManager({
|
|
1163
1339
|
base,
|
|
@@ -1198,13 +1374,12 @@ function useBundleManager({
|
|
|
1198
1374
|
const hasCompletedFirstNetworkBaseLoadRef = React5.useRef(false);
|
|
1199
1375
|
const hydrateBaseFromDisk = React5.useCallback(
|
|
1200
1376
|
async (appId, reason) => {
|
|
1201
|
-
var _a;
|
|
1377
|
+
var _a, _b, _c;
|
|
1202
1378
|
try {
|
|
1203
1379
|
const dir = bundlesCacheDir();
|
|
1204
1380
|
await ensureDir(dir);
|
|
1205
1381
|
const key = baseBundleKey(appId, platform);
|
|
1206
|
-
|
|
1207
|
-
let existing = await getExistingNonEmptyFileUri(uri);
|
|
1382
|
+
let existing = await getExistingBundleFileUri(key, platform);
|
|
1208
1383
|
let embeddedMeta = null;
|
|
1209
1384
|
if (!existing) {
|
|
1210
1385
|
const embedded = (_a = embeddedBaseBundlesRef.current) == null ? void 0 : _a[platform];
|
|
@@ -1213,14 +1388,25 @@ function useBundleManager({
|
|
|
1213
1388
|
existing = hydrated.bundlePath;
|
|
1214
1389
|
embeddedMeta = hydrated.meta ?? null;
|
|
1215
1390
|
if (embeddedMeta) {
|
|
1391
|
+
await ensureBundleDir(key);
|
|
1216
1392
|
await writeJsonFile(toBundleMetaFileUri(key), embeddedMeta);
|
|
1393
|
+
await writeJsonFile(legacyBundleMetaFileUri(key), embeddedMeta);
|
|
1217
1394
|
}
|
|
1218
1395
|
}
|
|
1219
1396
|
}
|
|
1220
1397
|
if (existing) {
|
|
1221
1398
|
lastBaseBundlePathRef.current = existing;
|
|
1222
1399
|
setBundlePath(existing);
|
|
1223
|
-
const meta = embeddedMeta ?? await readJsonFile(toBundleMetaFileUri(key));
|
|
1400
|
+
const meta = embeddedMeta ?? await readJsonFile(toBundleMetaFileUri(key)) ?? await readJsonFile(legacyBundleMetaFileUri(key));
|
|
1401
|
+
const embedded = (_b = embeddedBaseBundlesRef.current) == null ? void 0 : _b[platform];
|
|
1402
|
+
const embeddedFingerprint = ((_c = embedded == null ? void 0 : embedded.meta) == null ? void 0 : _c.fingerprint) ?? null;
|
|
1403
|
+
const actualFingerprint = (meta == null ? void 0 : meta.fingerprint) ?? (embeddedMeta == null ? void 0 : embeddedMeta.fingerprint) ?? null;
|
|
1404
|
+
if ((embedded == null ? void 0 : embedded.assetsModule) && embeddedFingerprint && actualFingerprint === embeddedFingerprint) {
|
|
1405
|
+
try {
|
|
1406
|
+
await hydrateAssetsFromEmbeddedAsset(appId, platform, key, embedded);
|
|
1407
|
+
} catch {
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1224
1410
|
if (meta == null ? void 0 : meta.fingerprint) {
|
|
1225
1411
|
lastBaseFingerprintRef.current = meta.fingerprint;
|
|
1226
1412
|
}
|
|
@@ -1285,7 +1471,16 @@ function useBundleManager({
|
|
|
1285
1471
|
lastBaseFingerprintRef.current = fingerprint;
|
|
1286
1472
|
hasCompletedFirstNetworkBaseLoadRef.current = true;
|
|
1287
1473
|
initialHydratedBaseFromDiskRef.current = false;
|
|
1288
|
-
|
|
1474
|
+
const metaKey = baseBundleKey(src.appId, platform);
|
|
1475
|
+
await ensureBundleDir(metaKey);
|
|
1476
|
+
void writeJsonFile(toBundleMetaFileUri(metaKey), {
|
|
1477
|
+
fingerprint,
|
|
1478
|
+
bundleId: bundle.id,
|
|
1479
|
+
checksumSha256: bundle.checksumSha256 ?? null,
|
|
1480
|
+
size: bundle.size ?? null,
|
|
1481
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1482
|
+
});
|
|
1483
|
+
void writeJsonFile(legacyBundleMetaFileUri(metaKey), {
|
|
1289
1484
|
fingerprint,
|
|
1290
1485
|
bundleId: bundle.id,
|
|
1291
1486
|
checksumSha256: bundle.checksumSha256 ?? null,
|