@absolutejs/absolute 0.20.0-beta.82 → 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/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/build.js +286 -9
- package/dist/build.js.map +3 -3
- package/dist/cli/index.js +1 -1
- package/dist/cli/{mobile-hkxh2ab5.js → mobile-pdck6a35.js} +158 -3
- package/dist/index.js +286 -9
- package/dist/index.js.map +3 -3
- package/dist/mobile/index.js +366 -17
- package/dist/mobile/index.js.map +5 -5
- package/dist/mobile/shellUpdate.js +46 -8
- package/dist/src/mobile/updateClient.d.ts +11 -0
- package/dist/src/mobile/updatePublisher.d.ts +23 -0
- package/package.json +2 -2
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-
|
|
206
|
+
const { runMobile } = await import("./mobile-pdck6a35.js");
|
|
207
207
|
try {
|
|
208
208
|
await runMobile(args);
|
|
209
209
|
} catch (error) {
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
installPackages
|
|
4
4
|
} from "./index-zh6hhrwy.js";
|
|
5
|
+
import {
|
|
6
|
+
formatBytes
|
|
7
|
+
} from "./index-9r7n9dqp.js";
|
|
5
8
|
import {
|
|
6
9
|
start
|
|
7
10
|
} from "./index-q78x1k9q.js";
|
|
@@ -21985,6 +21988,50 @@ var generateAbsoluteExpoCodeSigning = async (options) => {
|
|
|
21985
21988
|
import { access as access11 } from "fs/promises";
|
|
21986
21989
|
import { isAbsolute as isAbsolute5, relative as relative10, resolve as resolve11, sep as sep6 } from "path";
|
|
21987
21990
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
21991
|
+
var lifecycleMethod = (publisher, name) => {
|
|
21992
|
+
const method = publisher[name];
|
|
21993
|
+
if (typeof method !== "function")
|
|
21994
|
+
throw new TypeError(`Mobile update registry does not support ${name}. Re-run \`absolute mobile update provision --force\` after upgrading @absolutejs/deploy.`);
|
|
21995
|
+
return method;
|
|
21996
|
+
};
|
|
21997
|
+
var validOptionalCounters = (values) => values.every((value) => value === undefined) || values.every((value) => Number.isSafeInteger(value) && (value ?? -1) >= 0);
|
|
21998
|
+
var validateStorageIdentity = (result, appId) => {
|
|
21999
|
+
if (!object3(result) || result.appId !== appId || !Array.isArray(result.releases) || ![
|
|
22000
|
+
result.channelCount,
|
|
22001
|
+
result.reclaimableBytes,
|
|
22002
|
+
result.releaseBytes,
|
|
22003
|
+
result.releaseCount,
|
|
22004
|
+
result.totalBytes,
|
|
22005
|
+
result.totalObjectCount,
|
|
22006
|
+
result.untrackedBytes
|
|
22007
|
+
].every((value) => Number.isSafeInteger(value) && value >= 0) || !validOptionalCounters([
|
|
22008
|
+
result.contentBlobBytes,
|
|
22009
|
+
result.contentBlobCount,
|
|
22010
|
+
result.reclaimableContentBytes
|
|
22011
|
+
]))
|
|
22012
|
+
throw new TypeError("Mobile update registry returned an invalid storage report.");
|
|
22013
|
+
return result;
|
|
22014
|
+
};
|
|
22015
|
+
var inspectAbsoluteMobileUpdateStorage = async (options) => validateStorageIdentity(await lifecycleMethod(options.publisher, "inspectUpdateStorage")({
|
|
22016
|
+
appId: options.appId,
|
|
22017
|
+
...options.minAgeMs === undefined ? {} : { minAgeMs: options.minAgeMs },
|
|
22018
|
+
...options.retainRecent === undefined ? {} : { retainRecent: options.retainRecent },
|
|
22019
|
+
...options.signal ? { signal: options.signal } : {}
|
|
22020
|
+
}), options.appId);
|
|
22021
|
+
var pruneAbsoluteMobileUpdates = async (options) => {
|
|
22022
|
+
const result = await lifecycleMethod(options.publisher, "pruneUpdates")({
|
|
22023
|
+
appId: options.appId,
|
|
22024
|
+
...options.apply === undefined ? {} : { apply: options.apply },
|
|
22025
|
+
...options.gracePeriodMs === undefined ? {} : { gracePeriodMs: options.gracePeriodMs },
|
|
22026
|
+
...options.minAgeMs === undefined ? {} : { minAgeMs: options.minAgeMs },
|
|
22027
|
+
...options.retainRecent === undefined ? {} : { retainRecent: options.retainRecent },
|
|
22028
|
+
...options.signal ? { signal: options.signal } : {}
|
|
22029
|
+
});
|
|
22030
|
+
validateStorageIdentity(result, options.appId);
|
|
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)
|
|
22032
|
+
throw new TypeError("Mobile update registry returned an invalid collection report.");
|
|
22033
|
+
return result;
|
|
22034
|
+
};
|
|
21988
22035
|
var object3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21989
22036
|
var isPublisher2 = (value) => object3(value) && typeof value.publishUpdate === "function" && typeof value.promoteUpdate === "function" && typeof value.rollbackUpdate === "function";
|
|
21990
22037
|
var projectPath3 = (projectRoot, requested, label) => {
|
|
@@ -22027,7 +22074,12 @@ var publishAbsoluteMobileUpdate = async (options) => {
|
|
|
22027
22074
|
rollout: options.rollout,
|
|
22028
22075
|
signal: options.signal
|
|
22029
22076
|
});
|
|
22030
|
-
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
|
+
]))
|
|
22031
22083
|
throw new TypeError("Mobile update registry returned a different publication identity.");
|
|
22032
22084
|
return result;
|
|
22033
22085
|
};
|
|
@@ -22741,7 +22793,7 @@ var provisionMobileUpdate = async (args) => {
|
|
|
22741
22793
|
throw new TypeError("--storage must be local or s3.");
|
|
22742
22794
|
const modulePath = valueAfter(args, "--registry") ?? mobile.updateServer.registryModule;
|
|
22743
22795
|
const packages = [
|
|
22744
|
-
"@absolutejs/deploy@0.25.
|
|
22796
|
+
"@absolutejs/deploy@0.25.7",
|
|
22745
22797
|
"@absolutejs/blob@0.5.2",
|
|
22746
22798
|
...requestedStorage === "s3" ? [
|
|
22747
22799
|
"@aws-sdk/client-s3@3.1095.0",
|
|
@@ -22790,6 +22842,8 @@ var publishMobileUpdate = async (args) => {
|
|
|
22790
22842
|
rollout: updateRollout(args, 0.05)
|
|
22791
22843
|
});
|
|
22792
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.`);
|
|
22793
22847
|
return result;
|
|
22794
22848
|
};
|
|
22795
22849
|
var promoteMobileUpdate = async (args) => {
|
|
@@ -22825,6 +22879,99 @@ var rollbackMobileUpdate = async (args) => {
|
|
|
22825
22879
|
console.log(result.releaseId ? `Rolled ${result.channel} back to ${result.releaseId}.` : `Rolled ${result.channel} back to the embedded store build.`);
|
|
22826
22880
|
return result;
|
|
22827
22881
|
};
|
|
22882
|
+
var mobileUpdateDays = (args, flag) => {
|
|
22883
|
+
const value = valueAfter(args, flag);
|
|
22884
|
+
if (value === undefined)
|
|
22885
|
+
return;
|
|
22886
|
+
const parsed = Number(value);
|
|
22887
|
+
const milliseconds = parsed * 24 * 60 * 60 * 1000;
|
|
22888
|
+
if (!Number.isFinite(parsed) || parsed < 0 || !Number.isSafeInteger(milliseconds))
|
|
22889
|
+
throw new TypeError(`${flag} must be a non-negative number of days.`);
|
|
22890
|
+
return milliseconds;
|
|
22891
|
+
};
|
|
22892
|
+
var mobileUpdateRetention = (args) => {
|
|
22893
|
+
const retainedValue = valueAfter(args, "--retain");
|
|
22894
|
+
const retainRecent = retainedValue === undefined ? undefined : Number(retainedValue);
|
|
22895
|
+
if (retainRecent !== undefined && (!Number.isSafeInteger(retainRecent) || retainRecent < 0))
|
|
22896
|
+
throw new TypeError("--retain must be a non-negative integer.");
|
|
22897
|
+
return {
|
|
22898
|
+
minAgeMs: mobileUpdateDays(args, "--min-age-days"),
|
|
22899
|
+
retainRecent
|
|
22900
|
+
};
|
|
22901
|
+
};
|
|
22902
|
+
var printMobileUpdateStorage = (report) => {
|
|
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.`);
|
|
22906
|
+
for (const release of report.releases) {
|
|
22907
|
+
let state = "eligible";
|
|
22908
|
+
if (release.protectedBy.length > 0)
|
|
22909
|
+
state = `kept: ${release.protectedBy.join(", ")}`;
|
|
22910
|
+
else if (release.markedAt)
|
|
22911
|
+
state = `marked ${release.markedAt}`;
|
|
22912
|
+
console.log(` ${release.releaseId} ${release.channel} ${formatBytes(release.bytes)} (${state})`);
|
|
22913
|
+
}
|
|
22914
|
+
if (report.untrackedBytes > 0)
|
|
22915
|
+
console.log(`${formatBytes(report.untrackedBytes)} is used by channels, collection markers, or incomplete/unrecognized objects and will not be swept as a release.`);
|
|
22916
|
+
};
|
|
22917
|
+
var inspectMobileUpdateStorage = async (args) => {
|
|
22918
|
+
const startedAt = performance.now();
|
|
22919
|
+
const { mobile } = await loadMobile(valueAfter(args, "--config"));
|
|
22920
|
+
if (!mobile.updates)
|
|
22921
|
+
throw new TypeError("mobile update storage requires mobile.updates config.");
|
|
22922
|
+
const policy = mobileUpdateRetention(args);
|
|
22923
|
+
const { publisher } = await mobileUpdatePublisher(args);
|
|
22924
|
+
const report = await inspectAbsoluteMobileUpdateStorage({
|
|
22925
|
+
appId: mobile.appId,
|
|
22926
|
+
publisher,
|
|
22927
|
+
...policy.minAgeMs === undefined ? {} : { minAgeMs: policy.minAgeMs },
|
|
22928
|
+
...policy.retainRecent === undefined ? {} : { retainRecent: policy.retainRecent }
|
|
22929
|
+
});
|
|
22930
|
+
if (args.includes("--json"))
|
|
22931
|
+
console.log(JSON.stringify(report, null, 2));
|
|
22932
|
+
else
|
|
22933
|
+
printMobileUpdateStorage(report);
|
|
22934
|
+
sendTelemetryEvent("mobile:update-storage", {
|
|
22935
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
22936
|
+
reclaimableReleaseCount: report.releases.filter((release) => release.protectedBy.length === 0).length,
|
|
22937
|
+
releaseCount: report.releaseCount
|
|
22938
|
+
});
|
|
22939
|
+
return report;
|
|
22940
|
+
};
|
|
22941
|
+
var collectMobileUpdates = async (args) => {
|
|
22942
|
+
const startedAt = performance.now();
|
|
22943
|
+
const { mobile } = await loadMobile(valueAfter(args, "--config"));
|
|
22944
|
+
if (!mobile.updates)
|
|
22945
|
+
throw new TypeError("mobile update gc requires mobile.updates config.");
|
|
22946
|
+
const policy = mobileUpdateRetention(args);
|
|
22947
|
+
const gracePeriodMs = mobileUpdateDays(args, "--grace-days");
|
|
22948
|
+
const { publisher } = await mobileUpdatePublisher(args);
|
|
22949
|
+
const result = await pruneAbsoluteMobileUpdates({
|
|
22950
|
+
appId: mobile.appId,
|
|
22951
|
+
apply: args.includes("--apply"),
|
|
22952
|
+
publisher,
|
|
22953
|
+
...gracePeriodMs === undefined ? {} : { gracePeriodMs },
|
|
22954
|
+
...policy.minAgeMs === undefined ? {} : { minAgeMs: policy.minAgeMs },
|
|
22955
|
+
...policy.retainRecent === undefined ? {} : { retainRecent: policy.retainRecent }
|
|
22956
|
+
});
|
|
22957
|
+
if (args.includes("--json"))
|
|
22958
|
+
console.log(JSON.stringify(result, null, 2));
|
|
22959
|
+
else {
|
|
22960
|
+
printMobileUpdateStorage(result);
|
|
22961
|
+
if (result.dryRun)
|
|
22962
|
+
console.log("No storage was changed. Re-run with --apply to mark eligible releases and sweep releases whose grace period has elapsed.");
|
|
22963
|
+
else
|
|
22964
|
+
console.log(`Collection applied: ${result.marked.length} marked, ${result.restored.length} restored, ${result.swept.length} swept, ${formatBytes(result.reclaimedBytes)} reclaimed.`);
|
|
22965
|
+
}
|
|
22966
|
+
sendTelemetryEvent("mobile:update-gc", {
|
|
22967
|
+
applied: !result.dryRun,
|
|
22968
|
+
durationMs: Math.round(performance.now() - startedAt),
|
|
22969
|
+
markedCount: result.marked.length,
|
|
22970
|
+
restoredCount: result.restored.length,
|
|
22971
|
+
sweptCount: result.swept.length
|
|
22972
|
+
});
|
|
22973
|
+
return result;
|
|
22974
|
+
};
|
|
22828
22975
|
var requireValueAfter = (args, flag) => {
|
|
22829
22976
|
const value = valueAfter(args, flag);
|
|
22830
22977
|
if (!value || value.startsWith("-")) {
|
|
@@ -24165,6 +24312,14 @@ var runMobile = async (args) => {
|
|
|
24165
24312
|
await rollbackMobileUpdate(args.slice(2));
|
|
24166
24313
|
return;
|
|
24167
24314
|
}
|
|
24315
|
+
if (command === "update" && args[1] === "storage") {
|
|
24316
|
+
await inspectMobileUpdateStorage(args.slice(2));
|
|
24317
|
+
return;
|
|
24318
|
+
}
|
|
24319
|
+
if (command === "update" && args[1] === "gc") {
|
|
24320
|
+
await collectMobileUpdates(args.slice(2));
|
|
24321
|
+
return;
|
|
24322
|
+
}
|
|
24168
24323
|
if (command === "publish" && args[1] === "android") {
|
|
24169
24324
|
await publishAndroid(args.slice(2));
|
|
24170
24325
|
return;
|
|
@@ -24173,7 +24328,7 @@ var runMobile = async (args) => {
|
|
|
24173
24328
|
await publishIos(args.slice(2));
|
|
24174
24329
|
return;
|
|
24175
24330
|
}
|
|
24176
|
-
throw new TypeError("Usage: absolute mobile <pair mac <name> <user@host> [--port n] [--workspace path] | remotes [inspect [name] [--json] | clean [name] --yes | --json] | unpair mac <name> | init [--no-native] [--force] | sync [ios|android] | inspect [--json] [--require-bundle] | associations [--outdir dir] [--verify] | ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] | doctor [ios|android|release [ios|android]] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--remote name] [--outdir dir] [--web-outdir dir] [--unsigned] | update provision [--storage local|s3] [--registry module] [--force] [--yes] | update signing generate --private-key path [--certificate path] [--public-key path] [--key-id id] [--common-name name] [--validity-years n] | update build [server-entry] --classification bug-fix|content|security --key-id id --signing-key path --within-submitted-purpose [--outdir dir] [--web-outdir dir] | update publish <release-directory> [--rollout fraction] [--registry module] | update promote --release id --rollout fraction [--registry module] | update rollback [--release id] [--registry module] | publish android [server-entry] [--registry module] [--channel name] [--play-track track] [--play-status completed|draft|halted|in-progress] [--play-rollout fraction] [--play-name name] [--play-notes language=text] [--play-update-priority 0..5] [--play-hold-review] [--play-cancel-existing-review] [--outdir dir] [--web-outdir dir] [--unsigned] | publish ios [server-entry] [--remote name] [--registry module] [--channel name] [--testflight-group name-or-id] [--testflight-notes locale=text] [--testflight-submit-review] [--outdir dir] [--web-outdir dir] [--unsigned] | test android [--route path] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--serial id] [--artifacts dir] [--json] | test ios [--device identifier [--remote name] | --udid id] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--artifacts dir] [--json]> [--config path]");
|
|
24331
|
+
throw new TypeError("Usage: absolute mobile <pair mac <name> <user@host> [--port n] [--workspace path] | remotes [inspect [name] [--json] | clean [name] --yes | --json] | unpair mac <name> | init [--no-native] [--force] | sync [ios|android] | inspect [--json] [--require-bundle] | associations [--outdir dir] [--verify] | ci github [server-entry] [--publish] [--registry module] [--secret-env NAME] [--output path] [--force] [--json] | doctor [ios|android|release [ios|android]] [--remote name] [--json|--fix [--yes]] | build <android|ios> [server-entry] [--remote name] [--outdir dir] [--web-outdir dir] [--unsigned] | update provision [--storage local|s3] [--registry module] [--force] [--yes] | update signing generate --private-key path [--certificate path] [--public-key path] [--key-id id] [--common-name name] [--validity-years n] | update build [server-entry] --classification bug-fix|content|security --key-id id --signing-key path --within-submitted-purpose [--outdir dir] [--web-outdir dir] | update publish <release-directory> [--rollout fraction] [--registry module] | update promote --release id --rollout fraction [--registry module] | update rollback [--release id] [--registry module] | update storage [--retain count] [--min-age-days days] [--registry module] [--json] | update gc [--retain count] [--min-age-days days] [--grace-days days] [--apply] [--registry module] [--json] | publish android [server-entry] [--registry module] [--channel name] [--play-track track] [--play-status completed|draft|halted|in-progress] [--play-rollout fraction] [--play-name name] [--play-notes language=text] [--play-update-priority 0..5] [--play-hold-review] [--play-cancel-existing-review] [--outdir dir] [--web-outdir dir] [--unsigned] | publish ios [server-entry] [--remote name] [--registry module] [--channel name] [--testflight-group name-or-id] [--testflight-notes locale=text] [--testflight-submit-review] [--outdir dir] [--web-outdir dir] [--unsigned] | test android [--route path] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--serial id] [--artifacts dir] [--json] | test ios [--device identifier [--remote name] | --udid id] [--wait-for-hmr] [--report [dir]] [--timeout ms] [--port n] [--artifacts dir] [--json]> [--config path]");
|
|
24177
24332
|
};
|
|
24178
24333
|
export {
|
|
24179
24334
|
runMobile
|
package/dist/index.js
CHANGED
|
@@ -12288,7 +12288,7 @@ import {
|
|
|
12288
12288
|
} from "crypto";
|
|
12289
12289
|
import { readFile as readFile4, stat as stat2 } from "fs/promises";
|
|
12290
12290
|
import path from "path";
|
|
12291
|
-
var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updates", MAX_FILE_BYTES, MAX_TOTAL_BYTES, HASH, RELEASE, APP_ID, NAME, EXPO_DESCRIPTOR = "_absolute/expo-update.json", EXPO_CODE_SIGNING_ALGORITHM = "rsa-v1_5-sha256", MobileUpdateRegistryError, object3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), text2 = (value, field) => {
|
|
12291
|
+
var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updates", MAX_FILE_BYTES, MAX_TOTAL_BYTES, DAY_MS, DEFAULT_MIN_AGE_MS, DEFAULT_GRACE_PERIOD_MS, DEFAULT_RETAIN_RECENT = 5, HASH, RELEASE, APP_ID, NAME, EXPO_DESCRIPTOR = "_absolute/expo-update.json", EXPO_CODE_SIGNING_ALGORITHM = "rsa-v1_5-sha256", MobileUpdateRegistryError, object3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), text2 = (value, field) => {
|
|
12292
12292
|
if (typeof value !== "string" || value.length === 0)
|
|
12293
12293
|
throw new MobileUpdateRegistryError(`Mobile update ${field} is invalid`);
|
|
12294
12294
|
return value;
|
|
@@ -12455,6 +12455,8 @@ 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}`;
|
|
12459
|
+
const tombstoneKey = (appId, releaseId) => `${root(appId)}/gc/${releaseId}.json`;
|
|
12458
12460
|
const channelKey = (appId, channel) => {
|
|
12459
12461
|
if (!APP_ID.test(appId) || !NAME.test(channel))
|
|
12460
12462
|
throw new MobileUpdateRegistryError("Mobile update channel identity is invalid");
|
|
@@ -12483,6 +12485,12 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
12483
12485
|
throw new MobileUpdateRegistryError("Stored mobile update channel identity changed");
|
|
12484
12486
|
return value;
|
|
12485
12487
|
};
|
|
12488
|
+
const assertNotMarked = async (appId, releaseId) => {
|
|
12489
|
+
if (!APP_ID.test(appId) || !RELEASE.test(releaseId))
|
|
12490
|
+
throw new MobileUpdateRegistryError("Mobile update release identity is invalid");
|
|
12491
|
+
if (await options.store.head(tombstoneKey(appId, releaseId)))
|
|
12492
|
+
throw new MobileUpdateRegistryError("Mobile update release is marked for collection. Increase retention and apply garbage collection to restore it before promotion");
|
|
12493
|
+
};
|
|
12486
12494
|
const writeChannel = async (input, signal) => {
|
|
12487
12495
|
const value = {
|
|
12488
12496
|
...input,
|
|
@@ -12507,6 +12515,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
12507
12515
|
input.signal?.throwIfAborted();
|
|
12508
12516
|
if (input.rollout <= 0 || input.rollout > 1)
|
|
12509
12517
|
throw new MobileUpdateRegistryError("Mobile update rollout is invalid");
|
|
12518
|
+
await assertNotMarked(input.appId, input.releaseId);
|
|
12510
12519
|
const release = await readManifest(input.appId, input.releaseId);
|
|
12511
12520
|
if (!release || release.manifest.channel !== input.channel)
|
|
12512
12521
|
throw new MobileUpdateRegistryError("Mobile update was not published to this channel");
|
|
@@ -12552,19 +12561,271 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
12552
12561
|
status: "selected"
|
|
12553
12562
|
};
|
|
12554
12563
|
};
|
|
12564
|
+
const retentionValues = (input) => {
|
|
12565
|
+
if (!APP_ID.test(input.appId))
|
|
12566
|
+
throw new MobileUpdateRegistryError("Mobile update appId is invalid");
|
|
12567
|
+
const retainRecent = input.retainRecent ?? DEFAULT_RETAIN_RECENT;
|
|
12568
|
+
const minAgeMs = input.minAgeMs ?? DEFAULT_MIN_AGE_MS;
|
|
12569
|
+
if (!Number.isSafeInteger(retainRecent) || retainRecent < 0)
|
|
12570
|
+
throw new MobileUpdateRegistryError("Mobile update retained release count is invalid");
|
|
12571
|
+
if (!Number.isSafeInteger(minAgeMs) || minAgeMs < 0)
|
|
12572
|
+
throw new MobileUpdateRegistryError("Mobile update minimum release age is invalid");
|
|
12573
|
+
return { minAgeMs, retainRecent };
|
|
12574
|
+
};
|
|
12575
|
+
const listObjects = async (appId, signal) => {
|
|
12576
|
+
const list = options.store.list;
|
|
12577
|
+
if (!list)
|
|
12578
|
+
throw new MobileUpdateRegistryError("Mobile update storage does not support lifecycle listing");
|
|
12579
|
+
const objects = [];
|
|
12580
|
+
const cursors = new Set;
|
|
12581
|
+
let cursor;
|
|
12582
|
+
do {
|
|
12583
|
+
signal?.throwIfAborted();
|
|
12584
|
+
const page = await list({
|
|
12585
|
+
...cursor ? { cursor } : {},
|
|
12586
|
+
prefix: `${root(appId)}/`
|
|
12587
|
+
});
|
|
12588
|
+
objects.push(...page.objects);
|
|
12589
|
+
if (!page.truncated)
|
|
12590
|
+
break;
|
|
12591
|
+
if (!page.cursor || cursors.has(page.cursor))
|
|
12592
|
+
throw new MobileUpdateRegistryError("Mobile update storage returned an invalid lifecycle cursor");
|
|
12593
|
+
cursors.add(page.cursor);
|
|
12594
|
+
cursor = page.cursor;
|
|
12595
|
+
} while (true);
|
|
12596
|
+
return objects;
|
|
12597
|
+
};
|
|
12598
|
+
const inventory = async (input) => {
|
|
12599
|
+
const { minAgeMs, retainRecent } = retentionValues(input);
|
|
12600
|
+
const objects = await listObjects(input.appId, input.signal);
|
|
12601
|
+
const appRoot = `${root(input.appId)}/`;
|
|
12602
|
+
const releasePrefix = `${appRoot}releases/`;
|
|
12603
|
+
const channelPrefix = `${appRoot}channels/`;
|
|
12604
|
+
const markerPrefix = `${appRoot}gc/`;
|
|
12605
|
+
const blobPrefix = `${appRoot}blobs/`;
|
|
12606
|
+
const objectKeysByRelease = new Map;
|
|
12607
|
+
const objectBytesByRelease = new Map;
|
|
12608
|
+
const objectKeysByDigest = new Map;
|
|
12609
|
+
const objectBytesByDigest = new Map;
|
|
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
|
+
}
|
|
12618
|
+
if (!blobObject.key.startsWith(releasePrefix))
|
|
12619
|
+
continue;
|
|
12620
|
+
const suffix = blobObject.key.slice(releasePrefix.length);
|
|
12621
|
+
const releaseId = suffix.slice(0, suffix.indexOf("/"));
|
|
12622
|
+
if (!RELEASE.test(releaseId))
|
|
12623
|
+
continue;
|
|
12624
|
+
objectKeysByRelease.set(releaseId, [
|
|
12625
|
+
...objectKeysByRelease.get(releaseId) ?? [],
|
|
12626
|
+
blobObject.key
|
|
12627
|
+
]);
|
|
12628
|
+
objectBytesByRelease.set(releaseId, (objectBytesByRelease.get(releaseId) ?? 0) + blobObject.size);
|
|
12629
|
+
}
|
|
12630
|
+
const channels = [];
|
|
12631
|
+
for (const blobObject of objects) {
|
|
12632
|
+
if (!blobObject.key.startsWith(channelPrefix) || !blobObject.key.endsWith(".json"))
|
|
12633
|
+
continue;
|
|
12634
|
+
const bytes = await options.store.get(blobObject.key);
|
|
12635
|
+
if (!bytes)
|
|
12636
|
+
throw new MobileUpdateRegistryError("Mobile update channel disappeared during lifecycle inspection");
|
|
12637
|
+
const channel = parseChannel(decode(bytes));
|
|
12638
|
+
if (channel.appId !== input.appId)
|
|
12639
|
+
throw new MobileUpdateRegistryError("Stored mobile update channel identity changed");
|
|
12640
|
+
channels.push(channel);
|
|
12641
|
+
}
|
|
12642
|
+
const markedAt = new Map;
|
|
12643
|
+
for (const blobObject of objects) {
|
|
12644
|
+
if (!blobObject.key.startsWith(markerPrefix) || !blobObject.key.endsWith(".json"))
|
|
12645
|
+
continue;
|
|
12646
|
+
const releaseId = blobObject.key.slice(markerPrefix.length, -".json".length);
|
|
12647
|
+
if (!RELEASE.test(releaseId))
|
|
12648
|
+
continue;
|
|
12649
|
+
const bytes = await options.store.get(blobObject.key);
|
|
12650
|
+
if (!bytes)
|
|
12651
|
+
continue;
|
|
12652
|
+
const marker = decode(bytes);
|
|
12653
|
+
if (!object3(marker) || marker.format !== 1 || marker.appId !== input.appId || marker.releaseId !== releaseId || !iso(marker.markedAt))
|
|
12654
|
+
throw new MobileUpdateRegistryError("Mobile update collection marker is invalid");
|
|
12655
|
+
markedAt.set(releaseId, marker.markedAt);
|
|
12656
|
+
}
|
|
12657
|
+
const active = new Set(channels.flatMap((channel) => channel.releaseId ? [channel.releaseId] : []));
|
|
12658
|
+
const fallback = new Set(channels.flatMap((channel) => channel.fallbackReleaseId ? [channel.fallbackReleaseId] : []));
|
|
12659
|
+
const manifests = [];
|
|
12660
|
+
for (const releaseId of objectKeysByRelease.keys()) {
|
|
12661
|
+
const release = await readManifest(input.appId, releaseId);
|
|
12662
|
+
if (release)
|
|
12663
|
+
manifests.push(release.manifest);
|
|
12664
|
+
}
|
|
12665
|
+
const recent = new Set;
|
|
12666
|
+
const manifestsByChannel = new Map;
|
|
12667
|
+
for (const manifest of manifests)
|
|
12668
|
+
manifestsByChannel.set(manifest.channel, [
|
|
12669
|
+
...manifestsByChannel.get(manifest.channel) ?? [],
|
|
12670
|
+
manifest
|
|
12671
|
+
]);
|
|
12672
|
+
for (const releases2 of manifestsByChannel.values())
|
|
12673
|
+
for (const manifest of releases2.toSorted((left, right) => right.createdAt.localeCompare(left.createdAt)).slice(0, retainRecent))
|
|
12674
|
+
recent.add(manifest.releaseId);
|
|
12675
|
+
const now = clock().getTime();
|
|
12676
|
+
const releases = manifests.map((manifest) => {
|
|
12677
|
+
const protectedBy = [];
|
|
12678
|
+
if (active.has(manifest.releaseId))
|
|
12679
|
+
protectedBy.push("active");
|
|
12680
|
+
if (fallback.has(manifest.releaseId))
|
|
12681
|
+
protectedBy.push("fallback");
|
|
12682
|
+
if (recent.has(manifest.releaseId))
|
|
12683
|
+
protectedBy.push("recent");
|
|
12684
|
+
if (now - Date.parse(manifest.createdAt) < minAgeMs)
|
|
12685
|
+
protectedBy.push("age");
|
|
12686
|
+
return {
|
|
12687
|
+
bytes: objectBytesByRelease.get(manifest.releaseId) ?? 0,
|
|
12688
|
+
channel: manifest.channel,
|
|
12689
|
+
createdAt: manifest.createdAt,
|
|
12690
|
+
...markedAt.has(manifest.releaseId) ? { markedAt: markedAt.get(manifest.releaseId) } : {},
|
|
12691
|
+
objectCount: objectKeysByRelease.get(manifest.releaseId)?.length ?? 0,
|
|
12692
|
+
protectedBy,
|
|
12693
|
+
releaseId: manifest.releaseId
|
|
12694
|
+
};
|
|
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);
|
|
12700
|
+
const releaseBytes = releases.reduce((total, release) => total + release.bytes, 0);
|
|
12701
|
+
const totalBytes = objects.reduce((total, object22) => total + object22.size, 0);
|
|
12702
|
+
return {
|
|
12703
|
+
objectKeysByRelease,
|
|
12704
|
+
objectKeysByDigest,
|
|
12705
|
+
report: {
|
|
12706
|
+
appId: input.appId,
|
|
12707
|
+
channelCount: channels.length,
|
|
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,
|
|
12712
|
+
releaseBytes,
|
|
12713
|
+
releaseCount: releases.length,
|
|
12714
|
+
releases,
|
|
12715
|
+
totalBytes,
|
|
12716
|
+
totalObjectCount: objects.length,
|
|
12717
|
+
untrackedBytes: totalBytes - releaseBytes - contentBlobBytes
|
|
12718
|
+
}
|
|
12719
|
+
};
|
|
12720
|
+
};
|
|
12721
|
+
const pruneUpdates = async (input) => {
|
|
12722
|
+
const initial = await inventory(input);
|
|
12723
|
+
const result = {
|
|
12724
|
+
...initial.report,
|
|
12725
|
+
dryRun: input.apply !== true,
|
|
12726
|
+
marked: [],
|
|
12727
|
+
reclaimedBytes: 0,
|
|
12728
|
+
restored: [],
|
|
12729
|
+
swept: [],
|
|
12730
|
+
sweptContentBlobs: []
|
|
12731
|
+
};
|
|
12732
|
+
if (input.apply !== true)
|
|
12733
|
+
return result;
|
|
12734
|
+
const remove = options.store.delete;
|
|
12735
|
+
if (!remove)
|
|
12736
|
+
throw new MobileUpdateRegistryError("Mobile update storage does not support lifecycle deletion");
|
|
12737
|
+
const gracePeriodMs = input.gracePeriodMs ?? DEFAULT_GRACE_PERIOD_MS;
|
|
12738
|
+
if (!Number.isSafeInteger(gracePeriodMs) || gracePeriodMs < 0)
|
|
12739
|
+
throw new MobileUpdateRegistryError("Mobile update collection grace period is invalid");
|
|
12740
|
+
const now = clock();
|
|
12741
|
+
for (const release of initial.report.releases) {
|
|
12742
|
+
input.signal?.throwIfAborted();
|
|
12743
|
+
const marker = tombstoneKey(input.appId, release.releaseId);
|
|
12744
|
+
if (release.protectedBy.length > 0) {
|
|
12745
|
+
if (release.markedAt) {
|
|
12746
|
+
await remove(marker);
|
|
12747
|
+
result.restored.push(release.releaseId);
|
|
12748
|
+
}
|
|
12749
|
+
continue;
|
|
12750
|
+
}
|
|
12751
|
+
if (!release.markedAt) {
|
|
12752
|
+
const bytes = json({
|
|
12753
|
+
appId: input.appId,
|
|
12754
|
+
format: 1,
|
|
12755
|
+
markedAt: now.toISOString(),
|
|
12756
|
+
releaseId: release.releaseId
|
|
12757
|
+
});
|
|
12758
|
+
await options.store.put(marker, bytes, {
|
|
12759
|
+
cacheControl: "no-cache",
|
|
12760
|
+
contentType: "application/json",
|
|
12761
|
+
maxBytes: bytes.byteLength,
|
|
12762
|
+
metadata: { releaseid: release.releaseId, sha256: digest(bytes) },
|
|
12763
|
+
signal: input.signal
|
|
12764
|
+
});
|
|
12765
|
+
result.marked.push(release.releaseId);
|
|
12766
|
+
}
|
|
12767
|
+
}
|
|
12768
|
+
const current = await inventory(input);
|
|
12769
|
+
for (const release of current.report.releases) {
|
|
12770
|
+
input.signal?.throwIfAborted();
|
|
12771
|
+
if (release.protectedBy.length > 0 || !release.markedAt || now.getTime() - Date.parse(release.markedAt) < gracePeriodMs || result.marked.includes(release.releaseId))
|
|
12772
|
+
continue;
|
|
12773
|
+
const checked = await inventory(input);
|
|
12774
|
+
const candidate = checked.report.releases.find((value) => value.releaseId === release.releaseId);
|
|
12775
|
+
if (!candidate || candidate.protectedBy.length > 0 || !candidate.markedAt)
|
|
12776
|
+
continue;
|
|
12777
|
+
const keys = checked.objectKeysByRelease.get(release.releaseId) ?? [];
|
|
12778
|
+
for (const key of keys.toSorted((left, right) => {
|
|
12779
|
+
const leftManifest = left.endsWith("/update.json");
|
|
12780
|
+
const rightManifest = right.endsWith("/update.json");
|
|
12781
|
+
return Number(leftManifest) - Number(rightManifest);
|
|
12782
|
+
}))
|
|
12783
|
+
await remove(key);
|
|
12784
|
+
await remove(tombstoneKey(input.appId, release.releaseId));
|
|
12785
|
+
result.reclaimedBytes += candidate.bytes;
|
|
12786
|
+
result.swept.push(release.releaseId);
|
|
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
|
+
}
|
|
12803
|
+
return result;
|
|
12804
|
+
};
|
|
12555
12805
|
return {
|
|
12806
|
+
inspectUpdateStorage: async (input) => (await inventory(input)).report,
|
|
12807
|
+
pruneUpdates,
|
|
12556
12808
|
publishUpdate: async (input) => {
|
|
12557
12809
|
input.signal?.throwIfAborted();
|
|
12558
12810
|
const manifest = parseMobileUpdateManifest(input.manifest);
|
|
12559
12811
|
verifyManifestSignature(manifest, options.publicKeys);
|
|
12812
|
+
await assertNotMarked(manifest.appId, manifest.releaseId);
|
|
12560
12813
|
const localRoot = path.resolve(input.releaseDirectory);
|
|
12561
12814
|
const localManifest = parseMobileUpdateManifest(JSON.parse(await readFile4(path.join(localRoot, "update.json"), "utf8")));
|
|
12562
12815
|
if (JSON.stringify(localManifest) !== JSON.stringify(manifest))
|
|
12563
12816
|
throw new MobileUpdateRegistryError("Local mobile update manifest changed");
|
|
12564
12817
|
const existing = await readManifest(manifest.appId, manifest.releaseId);
|
|
12565
12818
|
let reused = existing !== null;
|
|
12819
|
+
let storedBytes = 0;
|
|
12820
|
+
let storedFiles = 0;
|
|
12821
|
+
let reusedBytes = 0;
|
|
12822
|
+
let reusedFiles = 0;
|
|
12566
12823
|
if (existing && JSON.stringify(existing.manifest) !== JSON.stringify(manifest))
|
|
12567
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
|
+
}
|
|
12568
12829
|
if (!existing) {
|
|
12569
12830
|
for (const file2 of manifest.files) {
|
|
12570
12831
|
const local = path.join(localRoot, "files", file2.path);
|
|
@@ -12573,18 +12834,24 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
12573
12834
|
throw new MobileUpdateRegistryError(`Mobile update file ${file2.path} size changed`);
|
|
12574
12835
|
if (await fileDigest(Bun.file(local)) !== file2.sha256)
|
|
12575
12836
|
throw new MobileUpdateRegistryError(`Mobile update file ${file2.path} integrity failed`);
|
|
12576
|
-
const key =
|
|
12837
|
+
const key = contentBlobKey(manifest.appId, file2.sha256);
|
|
12577
12838
|
const stored = await options.store.head(key);
|
|
12578
12839
|
if (!stored) {
|
|
12579
12840
|
await options.store.put(key, Bun.file(local).stream(), {
|
|
12580
12841
|
cacheControl: "public, max-age=31536000, immutable",
|
|
12581
12842
|
contentType: "application/octet-stream",
|
|
12582
12843
|
maxBytes: file2.bytes,
|
|
12583
|
-
metadata: {
|
|
12844
|
+
metadata: { sha256: file2.sha256 },
|
|
12584
12845
|
signal: input.signal
|
|
12585
12846
|
});
|
|
12586
|
-
|
|
12587
|
-
|
|
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
|
+
}
|
|
12588
12855
|
}
|
|
12589
12856
|
const bytes = json(manifest);
|
|
12590
12857
|
await options.store.put(manifestKey(manifest), bytes, {
|
|
@@ -12608,8 +12875,12 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
12608
12875
|
return {
|
|
12609
12876
|
appId: manifest.appId,
|
|
12610
12877
|
channel: manifest.channel,
|
|
12878
|
+
storedBytes,
|
|
12879
|
+
storedFiles,
|
|
12611
12880
|
releaseId: manifest.releaseId,
|
|
12612
12881
|
reused,
|
|
12882
|
+
reusedBytes,
|
|
12883
|
+
reusedFiles,
|
|
12613
12884
|
rollout: input.rollout,
|
|
12614
12885
|
stage: "published"
|
|
12615
12886
|
};
|
|
@@ -12621,6 +12892,7 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
12621
12892
|
if (!existing)
|
|
12622
12893
|
throw new MobileUpdateRegistryError("Mobile update channel does not exist");
|
|
12623
12894
|
if (input.releaseId) {
|
|
12895
|
+
await assertNotMarked(input.appId, input.releaseId);
|
|
12624
12896
|
const release = await readManifest(input.appId, input.releaseId);
|
|
12625
12897
|
if (!release || release.manifest.channel !== input.channel)
|
|
12626
12898
|
throw new MobileUpdateRegistryError("Mobile rollback release was not published");
|
|
@@ -12657,14 +12929,16 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
12657
12929
|
const file2 = release.manifest.files.find((candidate) => candidate.path === requested);
|
|
12658
12930
|
if (!file2)
|
|
12659
12931
|
return null;
|
|
12660
|
-
const
|
|
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);
|
|
12661
12935
|
const [bytes, head] = await Promise.all([
|
|
12662
12936
|
options.store.get(key),
|
|
12663
|
-
options.store.head(key)
|
|
12937
|
+
legacyHead ? Promise.resolve(legacyHead) : options.store.head(key)
|
|
12664
12938
|
]);
|
|
12665
12939
|
if (!bytes || !head)
|
|
12666
12940
|
return null;
|
|
12667
|
-
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)
|
|
12668
12942
|
throw new MobileUpdateRegistryError("Stored mobile update file integrity failed");
|
|
12669
12943
|
return { bytes, file: file2 };
|
|
12670
12944
|
}
|
|
@@ -12953,6 +13227,9 @@ var MOBILE_UPDATE_REGISTRY_FORMAT = 1, DEFAULT_PREFIX = "absolutejs/mobile-updat
|
|
|
12953
13227
|
var init_mobileUpdate = __esm(() => {
|
|
12954
13228
|
MAX_FILE_BYTES = 32 * 1024 * 1024;
|
|
12955
13229
|
MAX_TOTAL_BYTES = 128 * 1024 * 1024;
|
|
13230
|
+
DAY_MS = 24 * 60 * 60 * 1000;
|
|
13231
|
+
DEFAULT_MIN_AGE_MS = 30 * DAY_MS;
|
|
13232
|
+
DEFAULT_GRACE_PERIOD_MS = 7 * DAY_MS;
|
|
12956
13233
|
HASH = /^[a-f0-9]{64}$/;
|
|
12957
13234
|
RELEASE = /^amu_[a-f0-9]{64}$/;
|
|
12958
13235
|
APP_ID = /^[A-Za-z][\w]*(?:\.[A-Za-z][\w]*)+$/;
|
|
@@ -44587,5 +44864,5 @@ export {
|
|
|
44587
44864
|
wrapPageHandlerWithStreamingSlots
|
|
44588
44865
|
};
|
|
44589
44866
|
|
|
44590
|
-
//# debugId=
|
|
44867
|
+
//# debugId=CE82990F0B81B09764756E2164756E21
|
|
44591
44868
|
//# sourceMappingURL=index.js.map
|