@hot-updater/protocol 1.0.0-rc.46 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +5 -13
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +5 -13
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -502,7 +502,7 @@ function selectDesiredRelease(catalog, input) {
|
|
|
502
502
|
const crashedBundleIds = new Set(input.crashedBundleIds);
|
|
503
503
|
const activeReleaseId = input.activeReleaseId ?? null;
|
|
504
504
|
const hasActiveBundle = input.currentBundleId !== input.builtInBundleId;
|
|
505
|
-
const isSafeBundleRelease = (release) => release.
|
|
505
|
+
const isSafeBundleRelease = (release) => release.bundleId !== null && !crashedBundleIds.has(release.bundleId) && release.bundleId >= input.minimumReleaseId;
|
|
506
506
|
const desiredBundle = (release, status) => ({
|
|
507
507
|
bundleId: release.bundleId,
|
|
508
508
|
kind: "BUNDLE",
|
|
@@ -514,17 +514,9 @@ function selectDesiredRelease(catalog, input) {
|
|
|
514
514
|
if (!isReleaseEligibleForCohort(release, input.cohort)) continue;
|
|
515
515
|
if (activeReleaseId !== null && release.releaseId <= activeReleaseId || activeReleaseId === null && hasActiveBundle && (release.bundleId === null || release.bundleId <= input.currentBundleId)) continue;
|
|
516
516
|
if (isSafeBundleRelease(release)) return desiredBundle(release, "UPDATE");
|
|
517
|
-
if (release.bundleId !== null) continue;
|
|
518
|
-
return {
|
|
519
|
-
bundleId: input.builtInBundleId,
|
|
520
|
-
kind: "EMBEDDED",
|
|
521
|
-
release,
|
|
522
|
-
releaseId: release.releaseId,
|
|
523
|
-
status: "ROLLBACK"
|
|
524
|
-
};
|
|
525
517
|
}
|
|
526
518
|
if (activeReleaseId !== null || hasActiveBundle) {
|
|
527
|
-
const rollbackReleases = catalog
|
|
519
|
+
const { rollbackReleases } = catalog;
|
|
528
520
|
const current = rollbackReleases.find((release) => release.releaseId === activeReleaseId || activeReleaseId === null && release.bundleId === input.currentBundleId);
|
|
529
521
|
if (current !== void 0 && isSafeBundleRelease(current) && isReleaseEligibleForCohort(current, input.cohort)) return desiredBundle(current, "UPDATE");
|
|
530
522
|
const rollback = rollbackReleases.find((release) => isSafeBundleRelease(release) && (activeReleaseId !== null ? release.releaseId < activeReleaseId : release.bundleId < input.currentBundleId));
|
|
@@ -744,7 +736,7 @@ const isStringArray = (value) => Array.isArray(value) && value.every((entry) =>
|
|
|
744
736
|
const isValidReleaseDescriptor = (value) => {
|
|
745
737
|
if (value === null || typeof value !== "object") return false;
|
|
746
738
|
const descriptor = value;
|
|
747
|
-
return isUUIDv7(descriptor.releaseId) &&
|
|
739
|
+
return isUUIDv7(descriptor.releaseId) && descriptor.kind === "BUNDLE" && typeof descriptor.bundleId === "string" && Number.isSafeInteger(descriptor.rolloutCohortCount) && descriptor.rolloutCohortCount >= 0 && descriptor.rolloutCohortCount <= 1e3 && isStringArray(descriptor.targetCohorts) && descriptor.targetCohorts.length <= 100 && typeof descriptor.shouldForceUpdate === "boolean" && (descriptor.message === null || typeof descriptor.message === "string");
|
|
748
740
|
};
|
|
749
741
|
/** Whether the catalog is the expected scope's. */
|
|
750
742
|
const hasExpectedReleaseCatalogScope = (catalog, expected) => {
|
|
@@ -765,9 +757,9 @@ const parseReleaseCatalog = (body, expectedScope) => {
|
|
|
765
757
|
if (getUtf8ByteLength(body) > MAX_RELEASE_CATALOG_WIRE_BYTES) return null;
|
|
766
758
|
try {
|
|
767
759
|
const catalog = JSON.parse(body);
|
|
768
|
-
if (catalog.schemaVersion !== 1 || typeof catalog.catalogId !== "string" || catalog.catalogId.length === 0 || typeof catalog.scopeKey !== "string" || !Number.isSafeInteger(catalog.generation) || (catalog.generation ?? 0) < 1 || typeof catalog.catalogHash !== "string" || !/^sha256:[0-9a-f]{64}$/.test(catalog.catalogHash) || catalog.fallbackPolicy !== "BUILTIN_IF_ACTIVE_INELIGIBLE" || !Array.isArray(catalog.releases) || !catalog.releases.every(isValidReleaseDescriptor) ||
|
|
760
|
+
if (catalog.schemaVersion !== 1 || typeof catalog.catalogId !== "string" || catalog.catalogId.length === 0 || typeof catalog.scopeKey !== "string" || !Number.isSafeInteger(catalog.generation) || (catalog.generation ?? 0) < 1 || typeof catalog.catalogHash !== "string" || !/^sha256:[0-9a-f]{64}$/.test(catalog.catalogHash) || catalog.fallbackPolicy !== "BUILTIN_IF_ACTIVE_INELIGIBLE" || !Array.isArray(catalog.releases) || !catalog.releases.every(isValidReleaseDescriptor) || !Array.isArray(catalog.rollbackReleases) || !catalog.rollbackReleases.every(isValidReleaseDescriptor)) return null;
|
|
769
761
|
if (!hasExpectedReleaseCatalogScope(catalog, expectedScope)) return null;
|
|
770
|
-
if (new Set([...catalog.releases, ...catalog.rollbackReleases
|
|
762
|
+
if (new Set([...catalog.releases, ...catalog.rollbackReleases].flatMap((release) => release.targetCohorts)).size > 512) return null;
|
|
771
763
|
return catalog;
|
|
772
764
|
} catch {
|
|
773
765
|
return null;
|
package/dist/index.d.cts
CHANGED
|
@@ -130,7 +130,7 @@ declare const getPatchStorageUri: (bundle: Pick<Bundle, "patches">) => string;
|
|
|
130
130
|
*/
|
|
131
131
|
type UpdateStrategy = "fingerprint" | "appVersion";
|
|
132
132
|
/** How an update moves the app's selection. */
|
|
133
|
-
type ReleaseTransitionKind = "INSTALL" | "ADOPT_RELEASE" | "
|
|
133
|
+
type ReleaseTransitionKind = "INSTALL" | "ADOPT_RELEASE" | "USE_BUILTIN";
|
|
134
134
|
/** The launch outcome native reports once per JavaScript runtime. */
|
|
135
135
|
type AppReadyResult = {
|
|
136
136
|
/** No update was applied or recovered at this launch. */
|
|
@@ -403,7 +403,7 @@ declare const MAX_CRASHED_BUNDLES = 10;
|
|
|
403
403
|
declare const MAX_TARGET_COHORTS_PER_RELEASE = 100;
|
|
404
404
|
declare const MAX_DISTINCT_TARGET_COHORTS_PER_SCOPE = 512;
|
|
405
405
|
declare const MAX_COMPILED_CATALOG_BYTES: number;
|
|
406
|
-
type ReleaseKind = "BUNDLE"
|
|
406
|
+
type ReleaseKind = "BUNDLE";
|
|
407
407
|
type ReleaseStrategy = "APP_VERSION" | "FINGERPRINT";
|
|
408
408
|
type ReleaseOperation = "DEPLOY" | "PROMOTE" | "ROLLBACK";
|
|
409
409
|
type SelectionKind = ReleaseKind | "BUILTIN";
|
|
@@ -449,7 +449,7 @@ interface ReleaseCatalog {
|
|
|
449
449
|
* Enabled compatible Releases ordered newest first, where a device keeps its
|
|
450
450
|
* active Release or rolls back to the newest Release before it.
|
|
451
451
|
*/
|
|
452
|
-
readonly rollbackReleases
|
|
452
|
+
readonly rollbackReleases: readonly ReleaseCatalogDescriptor[];
|
|
453
453
|
}
|
|
454
454
|
interface CatalogHighWater {
|
|
455
455
|
readonly generation: number;
|
package/dist/index.d.mts
CHANGED
|
@@ -130,7 +130,7 @@ declare const getPatchStorageUri: (bundle: Pick<Bundle, "patches">) => string;
|
|
|
130
130
|
*/
|
|
131
131
|
type UpdateStrategy = "fingerprint" | "appVersion";
|
|
132
132
|
/** How an update moves the app's selection. */
|
|
133
|
-
type ReleaseTransitionKind = "INSTALL" | "ADOPT_RELEASE" | "
|
|
133
|
+
type ReleaseTransitionKind = "INSTALL" | "ADOPT_RELEASE" | "USE_BUILTIN";
|
|
134
134
|
/** The launch outcome native reports once per JavaScript runtime. */
|
|
135
135
|
type AppReadyResult = {
|
|
136
136
|
/** No update was applied or recovered at this launch. */
|
|
@@ -403,7 +403,7 @@ declare const MAX_CRASHED_BUNDLES = 10;
|
|
|
403
403
|
declare const MAX_TARGET_COHORTS_PER_RELEASE = 100;
|
|
404
404
|
declare const MAX_DISTINCT_TARGET_COHORTS_PER_SCOPE = 512;
|
|
405
405
|
declare const MAX_COMPILED_CATALOG_BYTES: number;
|
|
406
|
-
type ReleaseKind = "BUNDLE"
|
|
406
|
+
type ReleaseKind = "BUNDLE";
|
|
407
407
|
type ReleaseStrategy = "APP_VERSION" | "FINGERPRINT";
|
|
408
408
|
type ReleaseOperation = "DEPLOY" | "PROMOTE" | "ROLLBACK";
|
|
409
409
|
type SelectionKind = ReleaseKind | "BUILTIN";
|
|
@@ -449,7 +449,7 @@ interface ReleaseCatalog {
|
|
|
449
449
|
* Enabled compatible Releases ordered newest first, where a device keeps its
|
|
450
450
|
* active Release or rolls back to the newest Release before it.
|
|
451
451
|
*/
|
|
452
|
-
readonly rollbackReleases
|
|
452
|
+
readonly rollbackReleases: readonly ReleaseCatalogDescriptor[];
|
|
453
453
|
}
|
|
454
454
|
interface CatalogHighWater {
|
|
455
455
|
readonly generation: number;
|
package/dist/index.mjs
CHANGED
|
@@ -501,7 +501,7 @@ function selectDesiredRelease(catalog, input) {
|
|
|
501
501
|
const crashedBundleIds = new Set(input.crashedBundleIds);
|
|
502
502
|
const activeReleaseId = input.activeReleaseId ?? null;
|
|
503
503
|
const hasActiveBundle = input.currentBundleId !== input.builtInBundleId;
|
|
504
|
-
const isSafeBundleRelease = (release) => release.
|
|
504
|
+
const isSafeBundleRelease = (release) => release.bundleId !== null && !crashedBundleIds.has(release.bundleId) && release.bundleId >= input.minimumReleaseId;
|
|
505
505
|
const desiredBundle = (release, status) => ({
|
|
506
506
|
bundleId: release.bundleId,
|
|
507
507
|
kind: "BUNDLE",
|
|
@@ -513,17 +513,9 @@ function selectDesiredRelease(catalog, input) {
|
|
|
513
513
|
if (!isReleaseEligibleForCohort(release, input.cohort)) continue;
|
|
514
514
|
if (activeReleaseId !== null && release.releaseId <= activeReleaseId || activeReleaseId === null && hasActiveBundle && (release.bundleId === null || release.bundleId <= input.currentBundleId)) continue;
|
|
515
515
|
if (isSafeBundleRelease(release)) return desiredBundle(release, "UPDATE");
|
|
516
|
-
if (release.bundleId !== null) continue;
|
|
517
|
-
return {
|
|
518
|
-
bundleId: input.builtInBundleId,
|
|
519
|
-
kind: "EMBEDDED",
|
|
520
|
-
release,
|
|
521
|
-
releaseId: release.releaseId,
|
|
522
|
-
status: "ROLLBACK"
|
|
523
|
-
};
|
|
524
516
|
}
|
|
525
517
|
if (activeReleaseId !== null || hasActiveBundle) {
|
|
526
|
-
const rollbackReleases = catalog
|
|
518
|
+
const { rollbackReleases } = catalog;
|
|
527
519
|
const current = rollbackReleases.find((release) => release.releaseId === activeReleaseId || activeReleaseId === null && release.bundleId === input.currentBundleId);
|
|
528
520
|
if (current !== void 0 && isSafeBundleRelease(current) && isReleaseEligibleForCohort(current, input.cohort)) return desiredBundle(current, "UPDATE");
|
|
529
521
|
const rollback = rollbackReleases.find((release) => isSafeBundleRelease(release) && (activeReleaseId !== null ? release.releaseId < activeReleaseId : release.bundleId < input.currentBundleId));
|
|
@@ -743,7 +735,7 @@ const isStringArray = (value) => Array.isArray(value) && value.every((entry) =>
|
|
|
743
735
|
const isValidReleaseDescriptor = (value) => {
|
|
744
736
|
if (value === null || typeof value !== "object") return false;
|
|
745
737
|
const descriptor = value;
|
|
746
|
-
return isUUIDv7(descriptor.releaseId) &&
|
|
738
|
+
return isUUIDv7(descriptor.releaseId) && descriptor.kind === "BUNDLE" && typeof descriptor.bundleId === "string" && Number.isSafeInteger(descriptor.rolloutCohortCount) && descriptor.rolloutCohortCount >= 0 && descriptor.rolloutCohortCount <= 1e3 && isStringArray(descriptor.targetCohorts) && descriptor.targetCohorts.length <= 100 && typeof descriptor.shouldForceUpdate === "boolean" && (descriptor.message === null || typeof descriptor.message === "string");
|
|
747
739
|
};
|
|
748
740
|
/** Whether the catalog is the expected scope's. */
|
|
749
741
|
const hasExpectedReleaseCatalogScope = (catalog, expected) => {
|
|
@@ -764,9 +756,9 @@ const parseReleaseCatalog = (body, expectedScope) => {
|
|
|
764
756
|
if (getUtf8ByteLength(body) > MAX_RELEASE_CATALOG_WIRE_BYTES) return null;
|
|
765
757
|
try {
|
|
766
758
|
const catalog = JSON.parse(body);
|
|
767
|
-
if (catalog.schemaVersion !== 1 || typeof catalog.catalogId !== "string" || catalog.catalogId.length === 0 || typeof catalog.scopeKey !== "string" || !Number.isSafeInteger(catalog.generation) || (catalog.generation ?? 0) < 1 || typeof catalog.catalogHash !== "string" || !/^sha256:[0-9a-f]{64}$/.test(catalog.catalogHash) || catalog.fallbackPolicy !== "BUILTIN_IF_ACTIVE_INELIGIBLE" || !Array.isArray(catalog.releases) || !catalog.releases.every(isValidReleaseDescriptor) ||
|
|
759
|
+
if (catalog.schemaVersion !== 1 || typeof catalog.catalogId !== "string" || catalog.catalogId.length === 0 || typeof catalog.scopeKey !== "string" || !Number.isSafeInteger(catalog.generation) || (catalog.generation ?? 0) < 1 || typeof catalog.catalogHash !== "string" || !/^sha256:[0-9a-f]{64}$/.test(catalog.catalogHash) || catalog.fallbackPolicy !== "BUILTIN_IF_ACTIVE_INELIGIBLE" || !Array.isArray(catalog.releases) || !catalog.releases.every(isValidReleaseDescriptor) || !Array.isArray(catalog.rollbackReleases) || !catalog.rollbackReleases.every(isValidReleaseDescriptor)) return null;
|
|
768
760
|
if (!hasExpectedReleaseCatalogScope(catalog, expectedScope)) return null;
|
|
769
|
-
if (new Set([...catalog.releases, ...catalog.rollbackReleases
|
|
761
|
+
if (new Set([...catalog.releases, ...catalog.rollbackReleases].flatMap((release) => release.targetCohorts)).size > 512) return null;
|
|
770
762
|
return catalog;
|
|
771
763
|
} catch {
|
|
772
764
|
return null;
|