@absolutejs/absolute 0.20.0-beta.101 → 0.20.0-beta.103

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/CHANGELOG.md CHANGED
@@ -6,6 +6,13 @@ This file is generated by `absolute-changelog` from the entries in
6
6
  `changelog/`. Edit an entry, not this file — and add new ones under
7
7
  `changelog/unreleased/`.
8
8
 
9
+ ## 0.20.0-beta.103 — 2026-09-16
10
+
11
+ ### Added
12
+
13
+ - **Expo Android releases now have installed offline AAB acceptance**
14
+ `absolute mobile test android --release` revalidates one immutable AAB, approval-installs checksum-pinned Bundletool, starts the managed emulator, installs the derived APK set, and proves embedded content across two offline process launches. Expo production web files travel through Metro as one deterministic opaque archive and are reconstructed from a verified offset table, avoiding per-file registry failures. Sanitized reports and telemetry record only artifact identity, sizes, timings, provider, and outcome.
15
+
9
16
  ## 0.20.0-beta.101 — 2026-09-16
10
17
 
11
18
  ### Fixed
package/changelog.json CHANGED
@@ -2,6 +2,17 @@
2
2
  "contract": 1,
3
3
  "name": "@absolutejs/absolute",
4
4
  "releases": [
5
+ {
6
+ "changes": [
7
+ {
8
+ "detail": "`absolute mobile test android --release` revalidates one immutable AAB, approval-installs checksum-pinned Bundletool, starts the managed emulator, installs the derived APK set, and proves embedded content across two offline process launches. Expo production web files travel through Metro as one deterministic opaque archive and are reconstructed from a verified offset table, avoiding per-file registry failures. Sanitized reports and telemetry record only artifact identity, sizes, timings, provider, and outcome.",
9
+ "kind": "added",
10
+ "summary": "Expo Android releases now have installed offline AAB acceptance"
11
+ }
12
+ ],
13
+ "date": "2026-09-16",
14
+ "version": "0.20.0-beta.103"
15
+ },
5
16
  {
6
17
  "changes": [
7
18
  {
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-iD9yXe/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-nDO3E1/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-iD9yXe/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-nDO3E1/src/core/streamingSlotRegistrar.ts
5
5
  var STREAMING_SLOT_REGISTRAR_KEY = Symbol.for("absolutejs.streamingSlotRegistrar");
6
6
  var STREAMING_SLOT_WARNING_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotWarningController");
7
7
  var STREAMING_SLOT_COLLECTION_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotCollectionController");
@@ -48,7 +48,7 @@ var warnMissingStreamingSlotCollector = (primitiveName) => {
48
48
  getWarningController()?.maybeWarn(primitiveName);
49
49
  };
50
50
 
51
- // .angular-partial-tmp-iD9yXe/src/core/streamingSlotRegistry.ts
51
+ // .angular-partial-tmp-nDO3E1/src/core/streamingSlotRegistry.ts
52
52
  var STREAMING_SLOT_STORAGE_KEY = Symbol.for("absolutejs.streamingSlotAsyncLocalStorage");
53
53
  var isObjectRecord2 = (value) => Boolean(value) && typeof value === "object";
54
54
  var isAsyncLocalStorage = (value) => isObjectRecord2(value) && ("getStore" in value) && typeof value.getStore === "function" && ("run" in value) && typeof value.run === "function";
@@ -15,7 +15,7 @@ import {
15
15
  createIslandRegistryDefinitionPlugin,
16
16
  finalizeAbsoluteMobileCompatibilityBuild,
17
17
  resolveServerBundleExternals
18
- } from "./index-0bcf7pdw.js";
18
+ } from "./index-6ff78meg.js";
19
19
  import {
20
20
  loadIslandRegistryBuildInfo
21
21
  } from "./index-bzs19w3r.js";
@@ -36,7 +36,7 @@ import"./index-w5vswatm.js";
36
36
  import {
37
37
  normalizeAbsoluteMobileConfig
38
38
  } from "./index-rd2hbttb.js";
39
- import"./index-qd6mqgsc.js";
39
+ import"./index-d5fr1xp3.js";
40
40
  import {
41
41
  ABSOLUTE_NATIVE_AUTH_CLIENTS_ENV,
42
42
  installAbsoluteMobileAuthEnvironment
@@ -1286,8 +1286,8 @@ var loadAbsoluteMobileDevModules = async () => {
1286
1286
  expoNativeWatcher
1287
1287
  ] = await Promise.all([
1288
1288
  import("./config-vy04mqce.js"),
1289
- import("./expoProject-ceey4cfg.js"),
1290
- import("./expoDevController-mxd3h52y.js"),
1289
+ import("./expoProject-780thyfd.js"),
1290
+ import("./expoDevController-zz516pdd.js"),
1291
1291
  import("./nativeAuth-zx4tsb1f.js"),
1292
1292
  import("./androidEmulatorController-nybhzc6c.js"),
1293
1293
  import("./emulatorDoctor-y2nqmaha.js"),
@@ -7,7 +7,7 @@ import {
7
7
  parseBootedAbsoluteExpoIosSimulators,
8
8
  planAbsoluteExpoDevSession,
9
9
  startAbsoluteExpoDevSession
10
- } from "./index-kr23b0fp.js";
10
+ } from "./index-28nxv57v.js";
11
11
  import"./index-j66p8hn5.js";
12
12
  import"./index-knt92dm8.js";
13
13
  import"./index-t84wxk1p.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  syncAbsoluteExpoWebAssets,
4
4
  writeAbsoluteExpoProject
5
- } from "./index-qd6mqgsc.js";
5
+ } from "./index-d5fr1xp3.js";
6
6
  import"./index-ar4gz15x.js";
7
7
  import"./index-mywsk201.js";
8
8
  export {
@@ -218,6 +218,8 @@ var encodedWindowsExpoAndroidCommand = (project, androidRoot, appId, args, captu
218
218
  "$env:GRADLE_OPTS = (($env:GRADLE_OPTS + ' -Dorg.gradle.daemon=false').Trim())",
219
219
  "$autolinkingCache = Join-Path $mappedProject 'android\\build\\generated\\autolinking'",
220
220
  "if ([IO.Directory]::Exists($autolinkingCache)) { [IO.Directory]::Delete($autolinkingCache, $true) }",
221
+ "$reactGeneratedResources = Join-Path $mappedProject 'android\\app\\build\\generated\\res\\react'",
222
+ "if ([IO.Directory]::Exists($reactGeneratedResources)) { [IO.Directory]::Delete($reactGeneratedResources, $true) }",
221
223
  ...mode === "development" ? [
222
224
  "$expo = Join-Path $mappedProject 'node_modules\\.bin\\expo.exe'",
223
225
  "& $expo @expoArguments",
@@ -10,7 +10,7 @@ import {
10
10
  resolveAbsoluteMobileUpdateRuntime,
11
11
  syncAbsoluteExpoWebAssets,
12
12
  writeAbsoluteExpoProject
13
- } from "./index-qd6mqgsc.js";
13
+ } from "./index-d5fr1xp3.js";
14
14
 
15
15
  // src/build/islandRegistryTransform.ts
16
16
  import { basename } from "path";
@@ -13,7 +13,6 @@ import {
13
13
  // src/mobile/expoProject.ts
14
14
  import {
15
15
  access,
16
- cp,
17
16
  mkdir,
18
17
  mkdtemp,
19
18
  readdir,
@@ -1533,6 +1532,15 @@ class AbsoluteActivityResultRecoveryModule : Module() {
1533
1532
  Log.d("AbsoluteJS", "Expo application runtime ready for Android activity results")
1534
1533
  }
1535
1534
 
1535
+ Function("markEmbeddedWebReady") {
1536
+ Log.i("AbsoluteJS", "Expo embedded web content ready")
1537
+ }
1538
+
1539
+ Function("markEmbeddedWebPhase") { phase: String ->
1540
+ val allowed = setOf("assets-start", "assets-ready", "assets-root-failed", "assets-directory-failed", "assets-destination-failed", "assets-module-failed", "assets-source-failed", "assets-download-failed", "assets-copy-failed", "assets-read-failed", "assets-write-failed", "assets-finalize-failed", "assets-unexpected-failed", "devices-start", "devices-ready", "devices-failed")
1541
+ if (allowed.contains(phase)) Log.i("AbsoluteJS", "Expo embedded web phase: " + phase)
1542
+ }
1543
+
1536
1544
  Function("takePendingCancellation") {
1537
1545
  AbsoluteActivityResultRecoveryState.takePendingCancellation()
1538
1546
  }
@@ -1543,6 +1551,8 @@ var runtime = `${HEADER2}import { requireNativeModule } from 'expo-modules-core'
1543
1551
 
1544
1552
  type AbsoluteActivityResultRecoveryNative = {
1545
1553
  markApplicationRuntimeReady(): void;
1554
+ markEmbeddedWebPhase(phase: AbsoluteEmbeddedWebPhase): void;
1555
+ markEmbeddedWebReady(): void;
1546
1556
  takePendingCancellation(): boolean;
1547
1557
  };
1548
1558
 
@@ -1553,6 +1563,30 @@ const native = requireNativeModule<AbsoluteActivityResultRecoveryNative>(
1553
1563
  export const markAbsoluteApplicationRuntimeReady = () =>
1554
1564
  native.markApplicationRuntimeReady();
1555
1565
 
1566
+ export const markAbsoluteEmbeddedWebReady = () =>
1567
+ native.markEmbeddedWebReady();
1568
+
1569
+ export type AbsoluteEmbeddedWebPhase =
1570
+ | 'assets-start'
1571
+ | 'assets-ready'
1572
+ | 'assets-root-failed'
1573
+ | 'assets-directory-failed'
1574
+ | 'assets-destination-failed'
1575
+ | 'assets-module-failed'
1576
+ | 'assets-source-failed'
1577
+ | 'assets-download-failed'
1578
+ | 'assets-copy-failed'
1579
+ | 'assets-read-failed'
1580
+ | 'assets-write-failed'
1581
+ | 'assets-finalize-failed'
1582
+ | 'assets-unexpected-failed'
1583
+ | 'devices-start'
1584
+ | 'devices-ready'
1585
+ | 'devices-failed';
1586
+
1587
+ export const markAbsoluteEmbeddedWebPhase = (phase: AbsoluteEmbeddedWebPhase) =>
1588
+ native.markEmbeddedWebPhase(phase);
1589
+
1556
1590
  export const takeAbsoluteActivityResultCancellation = () =>
1557
1591
  native.takePendingCancellation();
1558
1592
  `;
@@ -2364,10 +2398,11 @@ var webHostSource = (config, auth, sync) => {
2364
2398
  return `${EXPO_GENERATED_HEADER}import * as Linking from 'expo-linking';
2365
2399
  import { router, usePathname } from 'expo-router';
2366
2400
  import { useEffect, useMemo, useRef, useState } from 'react';
2367
- import { ActivityIndicator, BackHandler, Platform, StyleSheet, View } from 'react-native';
2401
+ import { ActivityIndicator, BackHandler, Platform, Pressable, StyleSheet, Text, View } from 'react-native';
2368
2402
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
2369
2403
  import { WebView, type WebViewMessageEvent } from 'react-native-webview';
2370
2404
  import { materializeAbsoluteWebBundle } from './webAssets';
2405
+ import { markAbsoluteEmbeddedWebPhase, markAbsoluteEmbeddedWebReady } from './AbsoluteActivityResultRecovery';
2371
2406
  import { createExpoDevicesBridgeHost } from '@absolutejs/devices-expo/bridge';
2372
2407
  import { absoluteExpoDevices, beforeAbsoluteExpoDeviceSignOut } from './AbsoluteDevices';
2373
2408
  ${auth ? "import { absoluteExpoAuth, getAbsoluteExpoAuthPrincipal, startAbsoluteExpoAuth } from './AbsoluteAuth';" : ""}
@@ -2531,7 +2566,10 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
2531
2566
  const canGoBack = useRef(false);
2532
2567
  const [runtimeReady, setRuntimeReady] = useState(!AUTH_ENABLED && !SYNC_ENABLED);
2533
2568
  const [devicesReady, setDevicesReady] = useState(false);
2569
+ const [startupError, setStartupError] = useState<'assets' | 'devices'>();
2570
+ const [startupRevision, setStartupRevision] = useState(0);
2534
2571
  const activeWebPath = useRef(pathname);
2572
+ const embeddedReadyReported = useRef(false);
2535
2573
  const webSource = useMemo(() => indexUri ? { uri: indexUri } : undefined, [indexUri]);
2536
2574
 
2537
2575
  useEffect(() => {
@@ -2565,8 +2603,18 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
2565
2603
  setIndexUri(target.href);
2566
2604
  return;
2567
2605
  }
2568
- void materializeAbsoluteWebBundle().then(uri => setIndexUri(uri + '?absolutePath=' + encodeURIComponent(pathname)));
2569
- }, [pathname]);
2606
+ markAbsoluteEmbeddedWebPhase('assets-start');
2607
+ void materializeAbsoluteWebBundle().then(uri => {
2608
+ markAbsoluteEmbeddedWebPhase('assets-ready');
2609
+ setIndexUri(uri + '?absolutePath=' + encodeURIComponent(pathname));
2610
+ }).catch(error => {
2611
+ const phase = error instanceof Error && (error.message === 'assets-root-failed' || error.message === 'assets-directory-failed' || error.message === 'assets-destination-failed' || error.message === 'assets-module-failed' || error.message === 'assets-source-failed' || error.message === 'assets-download-failed' || error.message === 'assets-copy-failed' || error.message === 'assets-read-failed' || error.message === 'assets-write-failed' || error.message === 'assets-finalize-failed')
2612
+ ? error.message
2613
+ : 'assets-unexpected-failed';
2614
+ markAbsoluteEmbeddedWebPhase(phase);
2615
+ setStartupError('assets');
2616
+ });
2617
+ }, [pathname, startupRevision]);
2570
2618
  useEffect(() => {
2571
2619
  webView.current?.injectJavaScript(hostMetricsScript(safeAreaInsets));
2572
2620
  }, [safeAreaInsets.bottom, safeAreaInsets.left, safeAreaInsets.right, safeAreaInsets.top]);
@@ -2586,13 +2634,19 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
2586
2634
  };
2587
2635
  useEffect(() => {
2588
2636
  let active = true;
2637
+ markAbsoluteEmbeddedWebPhase('devices-start');
2589
2638
  void createExpoDevicesBridgeHost(absoluteExpoDevices, (event, payload) => {
2590
2639
  if (!active) return;
2591
2640
  respond({ event, format: BRIDGE_FORMAT, kind: 'event', path: activeWebPath.current, payload });
2592
2641
  }).then(host => {
2593
2642
  if (!active) return void Promise.resolve(host.close()).catch(() => undefined);
2594
2643
  devicesBridge.current = host;
2644
+ markAbsoluteEmbeddedWebPhase('devices-ready');
2595
2645
  setDevicesReady(true);
2646
+ }).catch(() => {
2647
+ if (!active) return;
2648
+ markAbsoluteEmbeddedWebPhase('devices-failed');
2649
+ setStartupError('devices');
2596
2650
  });
2597
2651
  return () => {
2598
2652
  active = false;
@@ -2600,7 +2654,7 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
2600
2654
  devicesBridge.current = undefined;
2601
2655
  if (host) void Promise.resolve(host.close()).catch(() => undefined);
2602
2656
  };
2603
- }, []);
2657
+ }, [startupRevision]);
2604
2658
  const hasOrigin = (source: string, origin: string) => {
2605
2659
  try { return new URL(source).origin === origin; } catch { return false; }
2606
2660
  };
@@ -2613,6 +2667,10 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
2613
2667
  if (message.kind === 'event' && (message.event === 'navigation' || message.event === 'ready')) {
2614
2668
  const target = new URL(message.path, PRODUCTION_ORIGIN);
2615
2669
  if (target.origin !== PRODUCTION_ORIGIN) return;
2670
+ if (message.event === 'ready' && !DEV_ORIGIN && !embeddedReadyReported.current) {
2671
+ embeddedReadyReported.current = true;
2672
+ markAbsoluteEmbeddedWebReady();
2673
+ }
2616
2674
  if (isNativeRoute(target.pathname)) router.push(message.path as never);
2617
2675
  else activeWebPath.current = message.path;
2618
2676
  return;
@@ -2652,6 +2710,15 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
2652
2710
  }
2653
2711
  };
2654
2712
 
2713
+ if (startupError) return <View style={styles.loading}>
2714
+ <Text accessibilityRole="alert" style={styles.error}>Embedded content could not start.</Text>
2715
+ <Pressable accessibilityRole="button" onPress={() => {
2716
+ setStartupError(undefined);
2717
+ setIndexUri(undefined);
2718
+ setDevicesReady(false);
2719
+ setStartupRevision(value => value + 1);
2720
+ }} style={styles.retry}><Text>Try again</Text></Pressable>
2721
+ </View>;
2655
2722
  if (!webSource || !runtimeReady || !devicesReady) return <View style={styles.loading}><ActivityIndicator /></View>;
2656
2723
  return <WebView
2657
2724
  allowFileAccess
@@ -2677,7 +2744,7 @@ export function AbsoluteWebHost({ path }: AbsoluteWebHostProps = {}) {
2677
2744
  />;
2678
2745
  }
2679
2746
 
2680
- const styles = StyleSheet.create({ loading: { alignItems: 'center', flex: 1, justifyContent: 'center' }, web: { flex: 1 } });
2747
+ const styles = StyleSheet.create({ error: { marginBottom: 12 }, loading: { alignItems: 'center', flex: 1, justifyContent: 'center' }, retry: { borderWidth: 1, paddingHorizontal: 16, paddingVertical: 12 }, web: { flex: 1 } });
2681
2748
  `;
2682
2749
  };
2683
2750
  var webRouteSource = `${EXPO_GENERATED_HEADER}import { AbsoluteWebHost } from '../src/generated/AbsoluteWebHost';
@@ -3125,35 +3192,72 @@ var installStagedDirectory = async (staging, destination) => {
3125
3192
  throw error;
3126
3193
  }
3127
3194
  };
3128
- var assetModuleSource = (assets, bundleId, manifest) => `${EXPO_GENERATED_HEADER}import { Asset } from 'expo-asset';
3195
+ var assetModuleSource = (assets, archiveAsset, bundleId, manifest) => `${EXPO_GENERATED_HEADER}import { Asset } from 'expo-asset';
3129
3196
  import { Directory, File, Paths } from 'expo-file-system';
3197
+ import { copyAsync as copyLegacyAsync } from 'expo-file-system/legacy';
3130
3198
 
3131
3199
  ${nativeDataManifestTypeSource}
3132
3200
  declare const require: (path: string) => number;
3133
3201
  const BUNDLE_ID = ${JSON.stringify(bundleId)};
3134
3202
  export const ABSOLUTE_MOBILE_MANIFEST: AbsoluteMobileManifest = ${JSON.stringify(manifest)};
3203
+ const ARCHIVE_MODULE = require(${JSON.stringify(archiveAsset)});
3135
3204
  const ASSETS = [
3136
- ${assets.map(({ asset, path }) => ` { module: require(${JSON.stringify(asset)}), path: ${JSON.stringify(path)} }`).join(`,
3205
+ ${assets.map((entry) => ` ${JSON.stringify(entry)}`).join(`,
3137
3206
  `)}
3138
3207
  ] as const;
3139
3208
 
3140
3209
  export const materializeAbsoluteWebBundle = async () => {
3141
- const root = new Directory(Paths.document, 'absolutejs-web', BUNDLE_ID);
3142
- root.create({ idempotent: true, intermediates: true });
3210
+ let root: Directory;
3211
+ try {
3212
+ root = new Directory(Paths.document, 'absolutejs-web', BUNDLE_ID);
3213
+ root.create({ idempotent: true, intermediates: true });
3214
+ } catch { throw new Error('assets-root-failed'); }
3215
+ let archive: File;
3216
+ try { archive = new File(root, '.absolutejs-bundle.absasset'); }
3217
+ catch { throw new Error('assets-destination-failed'); }
3218
+ if (!archive.exists) {
3219
+ let asset: Asset;
3220
+ try { asset = Asset.fromModule(ARCHIVE_MODULE); }
3221
+ catch { throw new Error('assets-module-failed'); }
3222
+ try { if (!asset.localUri) asset = await asset.downloadAsync(); }
3223
+ catch { throw new Error('assets-download-failed'); }
3224
+ if (!asset.localUri) throw new Error('assets-download-failed');
3225
+ let source: File;
3226
+ try { source = new File(asset.localUri); }
3227
+ catch { throw new Error('assets-source-failed'); }
3228
+ try { await source.copy(archive); }
3229
+ catch {
3230
+ try { await copyLegacyAsync({ from: asset.localUri, to: archive.uri }); }
3231
+ catch { throw new Error('assets-copy-failed'); }
3232
+ }
3233
+ }
3234
+ let contents: Uint8Array;
3235
+ try { contents = await archive.bytes(); }
3236
+ catch { throw new Error('assets-read-failed'); }
3143
3237
  for (const entry of ASSETS) {
3144
3238
  const parts = entry.path.split('/');
3145
3239
  const name = parts.pop();
3146
- if (!name) throw new Error('AbsoluteJS embedded asset path is invalid.');
3147
- const directory = new Directory(root, ...parts);
3148
- directory.create({ idempotent: true, intermediates: true });
3149
- const destination = new File(directory, name);
3150
- if (destination.exists) continue;
3151
- const asset = await Asset.fromModule(entry.module).downloadAsync();
3152
- if (!asset.localUri) throw new Error('Expo did not materialize an embedded AbsoluteJS asset.');
3153
- new File(asset.localUri).copy(destination);
3240
+ if (!name) throw new Error('assets-directory-failed');
3241
+ let directory: Directory;
3242
+ try {
3243
+ directory = new Directory(root, ...parts);
3244
+ directory.create({ idempotent: true, intermediates: true });
3245
+ }
3246
+ catch { throw new Error('assets-directory-failed'); }
3247
+ let destination: File;
3248
+ try {
3249
+ destination = new File(directory, name);
3250
+ if (destination.exists && destination.size === entry.length) continue;
3251
+ if (destination.exists) destination.delete();
3252
+ } catch { throw new Error('assets-destination-failed'); }
3253
+ try { destination.write(contents.slice(entry.offset, entry.offset + entry.length)); }
3254
+ catch { throw new Error('assets-write-failed'); }
3154
3255
  }
3256
+ try { archive.delete(); }
3257
+ catch { throw new Error('assets-finalize-failed'); }
3155
3258
 
3156
- return new File(root, 'index.html').uri;
3259
+ try { return new File(root, 'index.html').uri; }
3260
+ catch { throw new Error('assets-finalize-failed'); }
3157
3261
  };
3158
3262
  `;
3159
3263
  var syncAbsoluteExpoWebAssets = async (config) => {
@@ -3181,22 +3285,28 @@ var syncAbsoluteExpoWebAssets = async (config) => {
3181
3285
  await mkdir(dirname2(destination), { recursive: true });
3182
3286
  const staging = await mkdtemp(join5(dirname2(destination), `.${basename(destination)}.stage-`));
3183
3287
  let assets;
3288
+ let archiveAsset;
3184
3289
  try {
3185
- assets = await Promise.all(files.map(async (source, index) => {
3186
- const name = `${String(index).padStart(6, "0")}${EXPO_ASSET_EXTENSION}`;
3187
- await cp(source, join5(staging, name));
3188
- return {
3189
- asset: portableRelative(join5(config.nativeProjectDirectory, "src", "generated"), join5(destination, name)),
3190
- path: relative2(config.bundleDirectory, source).replaceAll("\\", "/")
3290
+ let offset = 0;
3291
+ assets = filesWithContents.map(({ contents, file }) => {
3292
+ const entry = {
3293
+ length: contents.byteLength,
3294
+ offset,
3295
+ path: relative2(config.bundleDirectory, file).replaceAll("\\", "/")
3191
3296
  };
3192
- }));
3297
+ offset += contents.byteLength;
3298
+ return entry;
3299
+ });
3300
+ const name = `bundle${EXPO_ASSET_EXTENSION}`;
3301
+ await writeFile(join5(staging, name), Buffer.concat(filesWithContents.map(({ contents }) => contents)));
3302
+ archiveAsset = portableRelative(join5(config.nativeProjectDirectory, "src", "generated"), join5(destination, name));
3193
3303
  await installStagedDirectory(staging, destination);
3194
3304
  } catch (error) {
3195
3305
  await rm(staging, { force: true, recursive: true });
3196
3306
  throw error;
3197
3307
  }
3198
3308
  const generated = join5(config.nativeProjectDirectory, "src", "generated", "webAssets.ts");
3199
- await writeManagedFile(generated, assetModuleSource(assets, bundleId, nativeDataManifest), true);
3309
+ await writeManagedFile(generated, assetModuleSource(assets, archiveAsset, bundleId, nativeDataManifest), true);
3200
3310
  return { appBuild, assets: assets.length, bundleId, path: destination };
3201
3311
  };
3202
3312
 
@@ -6,7 +6,7 @@ import {
6
6
  createIslandRegistryDefinitionPlugin,
7
7
  finalizeAbsoluteMobileCompatibilityBuild,
8
8
  resolveServerBundleExternals
9
- } from "./index-0bcf7pdw.js";
9
+ } from "./index-6ff78meg.js";
10
10
  import {
11
11
  loadIslandRegistryBuildInfo
12
12
  } from "./index-bzs19w3r.js";
package/dist/cli/index.js CHANGED
@@ -58,7 +58,7 @@ if (command === "dev") {
58
58
  }
59
59
  const positionalArgs = stripNamedArgs("--config", "--android-device", "--ios-device").filter((arg) => arg !== "--no-mobile" && arg !== "--eager");
60
60
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
61
- const { dev } = await import("./dev-tn9yfehm.js");
61
+ const { dev } = await import("./dev-m4r4zs2k.js");
62
62
  await dev(serverEntry, configPath, {
63
63
  androidDevice,
64
64
  eager: args.includes("--eager"),
@@ -71,7 +71,7 @@ if (command === "dev") {
71
71
  const configPath = parseNamedArg("--config");
72
72
  const positionalArgs = stripNamedArgs("--outdir", "--config").filter((arg) => arg !== "--prebuilt");
73
73
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
74
- const { start } = await import("./start-10dfrjvd.js");
74
+ const { start } = await import("./start-nmyy64tr.js");
75
75
  await start(serverEntry, outdir, configPath, {
76
76
  prebuilt: args.includes("--prebuilt")
77
77
  });
@@ -81,7 +81,7 @@ if (command === "dev") {
81
81
  const configPath = parseNamedArg("--config");
82
82
  const positionalArgs = stripNamedArgs("--outdir", "--config");
83
83
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
84
- const { start } = await import("./start-10dfrjvd.js");
84
+ const { start } = await import("./start-nmyy64tr.js");
85
85
  await start(serverEntry, outdir, configPath, { prepareOnly: true });
86
86
  } else if (command === "build") {
87
87
  sendTelemetryEvent("cli:command", { command });
@@ -197,13 +197,13 @@ if (command === "dev") {
197
197
  const configPath = parseNamedArg("--config");
198
198
  const positionalArgs = stripNamedArgs("--outdir", "--outfile", "--config");
199
199
  const serverEntry = positionalArgs[0] ?? DEFAULT_SERVER_ENTRY;
200
- const { compile } = await import("./compile-9y36k8z1.js");
200
+ const { compile } = await import("./compile-4xbpm6hf.js");
201
201
  await compile(serverEntry, outdir, outfile, configPath);
202
202
  } else if (command === "mobile") {
203
203
  sendTelemetryEvent("cli:command", {
204
204
  command: `mobile:${workspaceCommand ?? "unknown"}`
205
205
  });
206
- const { runMobile } = await import("./mobile-b1mh7ms3.js");
206
+ const { runMobile } = await import("./mobile-6xe6zysv.js");
207
207
  try {
208
208
  await runMobile(args);
209
209
  } catch (error) {