@absolutejs/absolute 0.20.0-beta.87 → 0.20.0-beta.89

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 ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@absolutejs/absolute`.
4
+
5
+ This file is generated by `absolute-changelog` from the entries in
6
+ `changelog/`. Edit an entry, not this file — and add new ones under
7
+ `changelog/unreleased/`.
8
+
9
+ ## 0.20.0-beta.89 — 2026-09-13
10
+
11
+ ### Added
12
+
13
+ - **Installed Expo Android apps now exercise staged cohorts, automatic advancement, pause, resume, cancellation, fleet recovery, and restart-safe health reporting in the native conformance suite.**
package/changelog.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "contract": 1,
3
+ "name": "@absolutejs/absolute",
4
+ "releases": [
5
+ {
6
+ "changes": [
7
+ {
8
+ "kind": "added",
9
+ "summary": "Installed Expo Android apps now exercise staged cohorts, automatic advancement, pause, resume, cancellation, fleet recovery, and restart-safe health reporting in the native conformance suite."
10
+ }
11
+ ],
12
+ "date": "2026-09-13",
13
+ "version": "0.20.0-beta.89"
14
+ }
15
+ ]
16
+ }
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // .angular-partial-tmp-Fz4wlA/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-Zx4zp1/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-Fz4wlA/src/core/streamingSlotRegistrar.ts
4
+ // .angular-partial-tmp-Zx4zp1/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-Fz4wlA/src/core/streamingSlotRegistry.ts
51
+ // .angular-partial-tmp-Zx4zp1/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";
package/dist/build.js CHANGED
@@ -28914,6 +28914,17 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
28914
28914
  });
28915
28915
  return value;
28916
28916
  };
28917
+ const readHealthPause = async (channel) => {
28918
+ if (!channel.releaseId)
28919
+ return null;
28920
+ const promotionId = healthPromotionId(channel);
28921
+ const value = await readVerifiedObject(pauseKey(channel.appId, promotionId, channel.releaseId), "health pause");
28922
+ if (value === null)
28923
+ return null;
28924
+ if (!object3(value) || value.format !== 1 || value.appId !== channel.appId || value.channel !== channel.channel || value.promotionId !== promotionId || value.releaseId !== channel.releaseId || typeof value.failureRate !== "number" || !Number.isFinite(value.failureRate) || value.failureRate < 0 || value.failureRate > 1 || !Number.isSafeInteger(value.failures) || Number(value.failures) < 0 || !Number.isSafeInteger(value.reports) || Number(value.reports) < 1 || !iso(value.pausedAt))
28925
+ throw new MobileUpdateRegistryError("Stored mobile update health pause is invalid");
28926
+ return value;
28927
+ };
28917
28928
  const rolloutContext = async (channel) => {
28918
28929
  if (!options.store.list || !channel.releaseId)
28919
28930
  return null;
@@ -28945,18 +28956,31 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
28945
28956
  throw new MobileUpdateRegistryError("Stored mobile update rollout control is invalid");
28946
28957
  parsedControls.push(value);
28947
28958
  }
28959
+ parsedControls.sort((left, right) => left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id));
28948
28960
  const cancelled = parsedControls.some(({ action }) => action === "cancel");
28949
28961
  const resumedPauseIds = new Set(parsedControls.flatMap((control) => control.resumedPauseIds ?? []));
28950
- const activePauseIds = parsedControls.filter(({ action, id }) => action === "pause" && !resumedPauseIds.has(id)).map(({ id }) => id);
28962
+ const activePauseControls = parsedControls.filter(({ action, id }) => action === "pause" && !resumedPauseIds.has(id));
28963
+ const activePauseIds = activePauseControls.map(({ id }) => id);
28951
28964
  const operatorPaused = activePauseIds.length > 0;
28952
- const fleetPaused = Boolean(await options.store.head(pauseKey(channel.appId, promotionId, channel.releaseId)));
28965
+ const fleetPause = await readHealthPause(channel);
28966
+ const fleetPaused = fleetPause !== null;
28967
+ const transitionControl = parsedControls.find(({ action }) => action === "cancel") ?? activePauseControls.at(-1) ?? parsedControls.findLast(({ action }) => action === "resume");
28968
+ const latestTransition = fleetPause && (!transitionControl || fleetPause.pausedAt > transitionControl.createdAt) ? {
28969
+ activatedAt: fleetPause.pausedAt,
28970
+ activationId: digest(new TextEncoder().encode(`${promotionId}\x00fleet-pause\x00${fleetPause.pausedAt}`))
28971
+ } : transitionControl ? {
28972
+ activatedAt: transitionControl.createdAt,
28973
+ activationId: digest(new TextEncoder().encode(`${promotionId}\x00control\x00${transitionControl.id}\x00${transitionControl.action}`))
28974
+ } : undefined;
28953
28975
  return {
28976
+ ...latestTransition,
28954
28977
  cancelled,
28955
28978
  activePauseIds,
28956
28979
  channel,
28957
28980
  currentStage,
28958
28981
  enteredAt,
28959
28982
  fleetPaused,
28983
+ fleetPause,
28960
28984
  operatorPaused,
28961
28985
  plan,
28962
28986
  promotionId,
@@ -29025,6 +29049,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
29025
29049
  if (!channel?.releaseId)
29026
29050
  return { status: "empty" };
29027
29051
  const rolloutState = await rolloutContext(channel);
29052
+ const healthPause = rolloutState?.fleetPause ?? (health ? await readHealthPause(channel) : null);
29028
29053
  let selected = rolloutMember({
29029
29054
  appId: input.appId,
29030
29055
  channel: input.channel,
@@ -29032,7 +29057,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
29032
29057
  releaseId: channel.releaseId,
29033
29058
  rollout: rolloutState?.rollout ?? channel.rollout
29034
29059
  }) ? channel.releaseId : channel.fallbackReleaseId;
29035
- if (selected === channel.releaseId && (rolloutState?.cancelled || rolloutState?.fleetPaused || rolloutState?.operatorPaused || health && await options.store.head(pauseKey(input.appId, healthPromotionId(channel), channel.releaseId))))
29060
+ if (selected === channel.releaseId && (rolloutState?.cancelled || rolloutState?.fleetPaused || rolloutState?.operatorPaused || healthPause))
29036
29061
  selected = channel.fallbackReleaseId;
29037
29062
  if (!selected)
29038
29063
  return { status: "empty" };
@@ -29040,7 +29065,13 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
29040
29065
  if (!release || release.manifest.runtimeFingerprint !== input.runtimeFingerprint)
29041
29066
  return { status: "incompatible" };
29042
29067
  return {
29043
- ...selected === channel.releaseId && channel.activationId && channel.activatedAt ? {
29068
+ ...rolloutState?.activationId && rolloutState.activatedAt ? {
29069
+ activationId: rolloutState.activationId,
29070
+ activatedAt: rolloutState.activatedAt
29071
+ } : healthPause ? {
29072
+ activatedAt: healthPause.pausedAt,
29073
+ activationId: digest(new TextEncoder().encode(`${healthPromotionId(channel)}\x00fleet-pause\x00${healthPause.pausedAt}`))
29074
+ } : selected === channel.releaseId && channel.activationId && channel.activatedAt ? {
29044
29075
  activationId: channel.activationId,
29045
29076
  activatedAt: channel.activatedAt
29046
29077
  } : {},
@@ -29924,7 +29955,9 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
29924
29955
  const platform2 = request.headers.get("expo-platform");
29925
29956
  if (platform2 !== "android" && platform2 !== "ios")
29926
29957
  return new Response(null, { status: 400 });
29927
- const updateId = expoUpdateId((resolution?.status === "selected" ? resolution.activationId : undefined) ?? selected.manifest.releaseId);
29958
+ const activationId = resolution?.status === "selected" ? resolution.activationId : undefined;
29959
+ const activatedAt = resolution?.status === "selected" ? resolution.activatedAt : undefined;
29960
+ const updateId = expoUpdateId(activationId ?? selected.manifest.releaseId);
29928
29961
  if (request.headers.get("expo-current-update-id") === updateId)
29929
29962
  return new Response(null, { status: 204 });
29930
29963
  const descriptorFile = await options.registry.readUpdateFile({
@@ -29954,7 +29987,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
29954
29987
  };
29955
29988
  const manifest = JSON.stringify({
29956
29989
  assets: platformUpdate.assets.map((asset) => protocolAsset(asset)),
29957
- createdAt: (resolution?.status === "selected" ? resolution.activatedAt : undefined) ?? selected.manifest.createdAt,
29990
+ createdAt: activatedAt ?? selected.manifest.createdAt,
29958
29991
  extra: {
29959
29992
  absolutejs: {
29960
29993
  channel: selected.manifest.channel,
@@ -37916,5 +37949,5 @@ export {
37916
37949
  devBuild
37917
37950
  };
37918
37951
 
37919
- //# debugId=EAFB7DB04FFF880464756E2164756E21
37952
+ //# debugId=5D4C20D73CC0DA3264756E2164756E21
37920
37953
  //# sourceMappingURL=build.js.map