@absolutejs/absolute 0.20.0-beta.83 → 0.20.0-beta.84

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/index.js CHANGED
@@ -203,7 +203,7 @@ if (command === "dev") {
203
203
  sendTelemetryEvent("cli:command", {
204
204
  command: `mobile:${workspaceCommand ?? "unknown"}`
205
205
  });
206
- const { runMobile } = await import("./mobile-9dx39bd3.js");
206
+ const { runMobile } = await import("./mobile-pdck6a35.js");
207
207
  try {
208
208
  await runMobile(args);
209
209
  } catch (error) {
@@ -21994,6 +21994,7 @@ var lifecycleMethod = (publisher, name) => {
21994
21994
  throw new TypeError(`Mobile update registry does not support ${name}. Re-run \`absolute mobile update provision --force\` after upgrading @absolutejs/deploy.`);
21995
21995
  return method;
21996
21996
  };
21997
+ var validOptionalCounters = (values) => values.every((value) => value === undefined) || values.every((value) => Number.isSafeInteger(value) && (value ?? -1) >= 0);
21997
21998
  var validateStorageIdentity = (result, appId) => {
21998
21999
  if (!object3(result) || result.appId !== appId || !Array.isArray(result.releases) || ![
21999
22000
  result.channelCount,
@@ -22003,7 +22004,11 @@ var validateStorageIdentity = (result, appId) => {
22003
22004
  result.totalBytes,
22004
22005
  result.totalObjectCount,
22005
22006
  result.untrackedBytes
22006
- ].every((value) => Number.isSafeInteger(value) && value >= 0))
22007
+ ].every((value) => Number.isSafeInteger(value) && value >= 0) || !validOptionalCounters([
22008
+ result.contentBlobBytes,
22009
+ result.contentBlobCount,
22010
+ result.reclaimableContentBytes
22011
+ ]))
22007
22012
  throw new TypeError("Mobile update registry returned an invalid storage report.");
22008
22013
  return result;
22009
22014
  };
@@ -22023,7 +22028,7 @@ var pruneAbsoluteMobileUpdates = async (options) => {
22023
22028
  ...options.signal ? { signal: options.signal } : {}
22024
22029
  });
22025
22030
  validateStorageIdentity(result, options.appId);
22026
- if (!Array.isArray(result.marked) || !Array.isArray(result.restored) || !Array.isArray(result.swept) || typeof result.dryRun !== "boolean" || !Number.isSafeInteger(result.reclaimedBytes) || result.reclaimedBytes < 0)
22031
+ if (!Array.isArray(result.marked) || !Array.isArray(result.restored) || !Array.isArray(result.swept) || result.sweptContentBlobs !== undefined && !Array.isArray(result.sweptContentBlobs) || typeof result.dryRun !== "boolean" || !Number.isSafeInteger(result.reclaimedBytes) || result.reclaimedBytes < 0)
22027
22032
  throw new TypeError("Mobile update registry returned an invalid collection report.");
22028
22033
  return result;
22029
22034
  };
@@ -22069,7 +22074,12 @@ var publishAbsoluteMobileUpdate = async (options) => {
22069
22074
  rollout: options.rollout,
22070
22075
  signal: options.signal
22071
22076
  });
22072
- if (result.appId !== manifest.appId || result.channel !== manifest.channel || result.releaseId !== manifest.releaseId || result.rollout !== options.rollout || result.stage !== "published" || typeof result.reused !== "boolean")
22077
+ if (result.appId !== manifest.appId || result.channel !== manifest.channel || result.releaseId !== manifest.releaseId || result.rollout !== options.rollout || result.stage !== "published" || typeof result.reused !== "boolean" || !validOptionalCounters([
22078
+ result.storedBytes,
22079
+ result.storedFiles,
22080
+ result.reusedBytes,
22081
+ result.reusedFiles
22082
+ ]))
22073
22083
  throw new TypeError("Mobile update registry returned a different publication identity.");
22074
22084
  return result;
22075
22085
  };
@@ -22832,6 +22842,8 @@ var publishMobileUpdate = async (args) => {
22832
22842
  rollout: updateRollout(args, 0.05)
22833
22843
  });
22834
22844
  console.log(`${result.reused ? "Reused" : "Published"} mobile update ${result.releaseId} to ${result.channel} at ${Math.round(result.rollout * 100)}%.`);
22845
+ if (result.storedBytes !== undefined && result.reusedBytes !== undefined && result.storedFiles !== undefined && result.reusedFiles !== undefined)
22846
+ console.log(`Stored ${formatBytes(result.storedBytes)} in ${result.storedFiles} new content blobs; reused ${formatBytes(result.reusedBytes)} across ${result.reusedFiles} files.`);
22835
22847
  return result;
22836
22848
  };
22837
22849
  var promoteMobileUpdate = async (args) => {
@@ -22889,6 +22901,8 @@ var mobileUpdateRetention = (args) => {
22889
22901
  };
22890
22902
  var printMobileUpdateStorage = (report) => {
22891
22903
  console.log(`${report.appId}: ${report.releaseCount} releases use ${formatBytes(report.releaseBytes)}; ${formatBytes(report.reclaimableBytes)} is eligible across ${report.totalObjectCount} stored objects.`);
22904
+ if (typeof report.contentBlobCount === "number" && typeof report.contentBlobBytes === "number" && typeof report.reclaimableContentBytes === "number" && report.contentBlobCount > 0)
22905
+ console.log(` Shared content: ${report.contentBlobCount} blobs use ${formatBytes(report.contentBlobBytes)}; ${formatBytes(report.reclaimableContentBytes)} becomes reclaimable with the eligible releases.`);
22892
22906
  for (const release of report.releases) {
22893
22907
  let state = "eligible";
22894
22908
  if (release.protectedBy.length > 0)
package/dist/index.js CHANGED
@@ -12455,6 +12455,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12455
12455
  const releaseRoot = (manifest) => `${root(manifest.appId)}/releases/${manifest.releaseId}`;
12456
12456
  const manifestKey = (manifest) => `${releaseRoot(manifest)}/update.json`;
12457
12457
  const fileKey = (manifest, file2) => `${releaseRoot(manifest)}/files/${file2.path}`;
12458
+ const contentBlobKey = (appId, sha256) => `${root(appId)}/blobs/${sha256}`;
12458
12459
  const tombstoneKey = (appId, releaseId) => `${root(appId)}/gc/${releaseId}.json`;
12459
12460
  const channelKey = (appId, channel) => {
12460
12461
  if (!APP_ID.test(appId) || !NAME.test(channel))
@@ -12601,9 +12602,19 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12601
12602
  const releasePrefix = `${appRoot}releases/`;
12602
12603
  const channelPrefix = `${appRoot}channels/`;
12603
12604
  const markerPrefix = `${appRoot}gc/`;
12605
+ const blobPrefix = `${appRoot}blobs/`;
12604
12606
  const objectKeysByRelease = new Map;
12605
12607
  const objectBytesByRelease = new Map;
12608
+ const objectKeysByDigest = new Map;
12609
+ const objectBytesByDigest = new Map;
12606
12610
  for (const blobObject of objects) {
12611
+ if (blobObject.key.startsWith(blobPrefix)) {
12612
+ const sha256 = blobObject.key.slice(blobPrefix.length);
12613
+ if (HASH.test(sha256)) {
12614
+ objectKeysByDigest.set(sha256, blobObject.key);
12615
+ objectBytesByDigest.set(sha256, blobObject.size);
12616
+ }
12617
+ }
12607
12618
  if (!blobObject.key.startsWith(releasePrefix))
12608
12619
  continue;
12609
12620
  const suffix = blobObject.key.slice(releasePrefix.length);
@@ -12682,20 +12693,28 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12682
12693
  releaseId: manifest.releaseId
12683
12694
  };
12684
12695
  }).toSorted((left, right) => right.createdAt.localeCompare(left.createdAt));
12696
+ const protectedReleaseIds = new Set(releases.filter((release) => release.protectedBy.length > 0).map((release) => release.releaseId));
12697
+ const protectedDigests = new Set(manifests.filter((manifest) => protectedReleaseIds.has(manifest.releaseId)).flatMap((manifest) => manifest.files.map((file2) => file2.sha256)));
12698
+ const reclaimableContentBytes = [...objectBytesByDigest].filter(([sha256]) => !protectedDigests.has(sha256)).reduce((total, [, bytes]) => total + bytes, 0);
12699
+ const contentBlobBytes = [...objectBytesByDigest.values()].reduce((total, bytes) => total + bytes, 0);
12685
12700
  const releaseBytes = releases.reduce((total, release) => total + release.bytes, 0);
12686
12701
  const totalBytes = objects.reduce((total, object22) => total + object22.size, 0);
12687
12702
  return {
12688
12703
  objectKeysByRelease,
12704
+ objectKeysByDigest,
12689
12705
  report: {
12690
12706
  appId: input.appId,
12691
12707
  channelCount: channels.length,
12692
- reclaimableBytes: releases.filter((release) => release.protectedBy.length === 0).reduce((total, release) => total + release.bytes, 0),
12708
+ contentBlobBytes,
12709
+ contentBlobCount: objectKeysByDigest.size,
12710
+ reclaimableBytes: releases.filter((release) => release.protectedBy.length === 0).reduce((total, release) => total + release.bytes, 0) + reclaimableContentBytes,
12711
+ reclaimableContentBytes,
12693
12712
  releaseBytes,
12694
12713
  releaseCount: releases.length,
12695
12714
  releases,
12696
12715
  totalBytes,
12697
12716
  totalObjectCount: objects.length,
12698
- untrackedBytes: totalBytes - releaseBytes
12717
+ untrackedBytes: totalBytes - releaseBytes - contentBlobBytes
12699
12718
  }
12700
12719
  };
12701
12720
  };
@@ -12707,7 +12726,8 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12707
12726
  marked: [],
12708
12727
  reclaimedBytes: 0,
12709
12728
  restored: [],
12710
- swept: []
12729
+ swept: [],
12730
+ sweptContentBlobs: []
12711
12731
  };
12712
12732
  if (input.apply !== true)
12713
12733
  return result;
@@ -12765,6 +12785,21 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12765
12785
  result.reclaimedBytes += candidate.bytes;
12766
12786
  result.swept.push(release.releaseId);
12767
12787
  }
12788
+ const afterReleaseSweep = await inventory(input);
12789
+ const referencedDigests = new Set;
12790
+ for (const release of afterReleaseSweep.report.releases) {
12791
+ const manifest = await readManifest(input.appId, release.releaseId);
12792
+ for (const file2 of manifest?.manifest.files ?? [])
12793
+ referencedDigests.add(file2.sha256);
12794
+ }
12795
+ for (const [sha256, key] of afterReleaseSweep.objectKeysByDigest) {
12796
+ if (referencedDigests.has(sha256))
12797
+ continue;
12798
+ const head = await options.store.head(key);
12799
+ await remove(key);
12800
+ result.reclaimedBytes += head?.size ?? 0;
12801
+ result.sweptContentBlobs.push(sha256);
12802
+ }
12768
12803
  return result;
12769
12804
  };
12770
12805
  return {
@@ -12781,8 +12816,16 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12781
12816
  throw new MobileUpdateRegistryError("Local mobile update manifest changed");
12782
12817
  const existing = await readManifest(manifest.appId, manifest.releaseId);
12783
12818
  let reused = existing !== null;
12819
+ let storedBytes = 0;
12820
+ let storedFiles = 0;
12821
+ let reusedBytes = 0;
12822
+ let reusedFiles = 0;
12784
12823
  if (existing && JSON.stringify(existing.manifest) !== JSON.stringify(manifest))
12785
12824
  throw new MobileUpdateRegistryError("Published mobile update is immutable");
12825
+ if (existing) {
12826
+ reusedBytes = manifest.files.reduce((total, file2) => total + file2.bytes, 0);
12827
+ reusedFiles = manifest.files.length;
12828
+ }
12786
12829
  if (!existing) {
12787
12830
  for (const file2 of manifest.files) {
12788
12831
  const local = path.join(localRoot, "files", file2.path);
@@ -12791,18 +12834,24 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12791
12834
  throw new MobileUpdateRegistryError(`Mobile update file ${file2.path} size changed`);
12792
12835
  if (await fileDigest(Bun.file(local)) !== file2.sha256)
12793
12836
  throw new MobileUpdateRegistryError(`Mobile update file ${file2.path} integrity failed`);
12794
- const key = fileKey(manifest, file2);
12837
+ const key = contentBlobKey(manifest.appId, file2.sha256);
12795
12838
  const stored = await options.store.head(key);
12796
12839
  if (!stored) {
12797
12840
  await options.store.put(key, Bun.file(local).stream(), {
12798
12841
  cacheControl: "public, max-age=31536000, immutable",
12799
12842
  contentType: "application/octet-stream",
12800
12843
  maxBytes: file2.bytes,
12801
- metadata: { releaseid: manifest.releaseId, sha256: file2.sha256 },
12844
+ metadata: { sha256: file2.sha256 },
12802
12845
  signal: input.signal
12803
12846
  });
12804
- } else if (stored.size !== file2.bytes || stored.metadata?.sha256 !== file2.sha256 || (stored.metadata?.releaseid ?? stored.metadata?.releaseId) !== manifest.releaseId)
12805
- throw new MobileUpdateRegistryError("Stored mobile update file identity changed");
12847
+ storedBytes += file2.bytes;
12848
+ storedFiles += 1;
12849
+ } else if (stored.size !== file2.bytes || stored.metadata?.sha256 !== file2.sha256)
12850
+ throw new MobileUpdateRegistryError("Stored mobile update content identity changed");
12851
+ else {
12852
+ reusedBytes += file2.bytes;
12853
+ reusedFiles += 1;
12854
+ }
12806
12855
  }
12807
12856
  const bytes = json(manifest);
12808
12857
  await options.store.put(manifestKey(manifest), bytes, {
@@ -12826,8 +12875,12 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12826
12875
  return {
12827
12876
  appId: manifest.appId,
12828
12877
  channel: manifest.channel,
12878
+ storedBytes,
12879
+ storedFiles,
12829
12880
  releaseId: manifest.releaseId,
12830
12881
  reused,
12882
+ reusedBytes,
12883
+ reusedFiles,
12831
12884
  rollout: input.rollout,
12832
12885
  stage: "published"
12833
12886
  };
@@ -12876,14 +12929,16 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
12876
12929
  const file2 = release.manifest.files.find((candidate) => candidate.path === requested);
12877
12930
  if (!file2)
12878
12931
  return null;
12879
- const key = fileKey(release.manifest, file2);
12932
+ const legacyKey = fileKey(release.manifest, file2);
12933
+ const legacyHead = await options.store.head(legacyKey);
12934
+ const key = legacyHead ? legacyKey : contentBlobKey(release.manifest.appId, file2.sha256);
12880
12935
  const [bytes, head] = await Promise.all([
12881
12936
  options.store.get(key),
12882
- options.store.head(key)
12937
+ legacyHead ? Promise.resolve(legacyHead) : options.store.head(key)
12883
12938
  ]);
12884
12939
  if (!bytes || !head)
12885
12940
  return null;
12886
- if (bytes.byteLength !== file2.bytes || head.size !== file2.bytes || head.metadata?.sha256 !== file2.sha256 || (head.metadata?.releaseid ?? head.metadata?.releaseId) !== release.manifest.releaseId || digest(bytes) !== file2.sha256)
12941
+ if (bytes.byteLength !== file2.bytes || head.size !== file2.bytes || head.metadata?.sha256 !== file2.sha256 || legacyHead && (head.metadata?.releaseid ?? head.metadata?.releaseId) !== release.manifest.releaseId || digest(bytes) !== file2.sha256)
12887
12942
  throw new MobileUpdateRegistryError("Stored mobile update file integrity failed");
12888
12943
  return { bytes, file: file2 };
12889
12944
  }
@@ -44809,5 +44864,5 @@ export {
44809
44864
  wrapPageHandlerWithStreamingSlots
44810
44865
  };
44811
44866
 
44812
- //# debugId=F0D48E431F12D4EB64756E2164756E21
44867
+ //# debugId=CE82990F0B81B09764756E2164756E21
44813
44868
  //# sourceMappingURL=index.js.map