@hot-updater/protocol 1.1.3 → 1.2.0-rc.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 +12 -256
- package/dist/index.mjs +1 -245
- package/dist/native-artifact.cjs +1098 -0
- package/dist/native-artifact.d.cts +179 -0
- package/dist/native-artifact.d.mts +179 -0
- package/dist/native-artifact.mjs +1090 -0
- package/dist/uuid-DC9FQNxo.cjs +299 -0
- package/dist/uuid-kZvLA0Ly.mjs +246 -0
- package/package.json +6 -1
package/dist/index.cjs
CHANGED
|
@@ -1,122 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
3
|
-
const LETTER_DASH_NUMBER = "[a-zA-Z0-9-]";
|
|
4
|
-
const NUMERIC_IDENTIFIER = String.raw`0|[1-9]\d*`;
|
|
5
|
-
const NUMERIC_IDENTIFIER_LOOSE = String.raw`\d+`;
|
|
6
|
-
const NON_NUMERIC_IDENTIFIER = String.raw`\d*[a-zA-Z-]${LETTER_DASH_NUMBER}*`;
|
|
7
|
-
const MAIN_VERSION = String.raw`(${NUMERIC_IDENTIFIER})\.(${NUMERIC_IDENTIFIER})\.(${NUMERIC_IDENTIFIER})`;
|
|
8
|
-
const MAIN_VERSION_LOOSE = String.raw`(${NUMERIC_IDENTIFIER_LOOSE})\.(${NUMERIC_IDENTIFIER_LOOSE})\.(${NUMERIC_IDENTIFIER_LOOSE})`;
|
|
9
|
-
const PRERELEASE_IDENTIFIER = `(?:${NON_NUMERIC_IDENTIFIER}|${NUMERIC_IDENTIFIER})`;
|
|
10
|
-
const PRERELEASE_IDENTIFIER_LOOSE = `(?:${NON_NUMERIC_IDENTIFIER}|${NUMERIC_IDENTIFIER_LOOSE})`;
|
|
11
|
-
const PRERELEASE = String.raw`(?:-(${PRERELEASE_IDENTIFIER}(?:\.${PRERELEASE_IDENTIFIER})*))`;
|
|
12
|
-
const PRERELEASE_LOOSE = String.raw`(?:-?(${PRERELEASE_IDENTIFIER_LOOSE}(?:\.${PRERELEASE_IDENTIFIER_LOOSE})*))`;
|
|
13
|
-
const BUILD_IDENTIFIER = `${LETTER_DASH_NUMBER}+`;
|
|
14
|
-
const BUILD = String.raw`(?:\+(${BUILD_IDENTIFIER}(?:\.${BUILD_IDENTIFIER})*))`;
|
|
15
|
-
const FULL_PLAIN = `v?${MAIN_VERSION}${PRERELEASE}?${BUILD}?`;
|
|
16
|
-
const LOOSE_PLAIN = String.raw`[v=\s]*${MAIN_VERSION_LOOSE}${PRERELEASE_LOOSE}?${BUILD}?`;
|
|
17
|
-
const XRANGE_IDENTIFIER = String.raw`${NUMERIC_IDENTIFIER}|x|X|\*`;
|
|
18
|
-
const XRANGE_IDENTIFIER_LOOSE = String.raw`${NUMERIC_IDENTIFIER_LOOSE}|x|X|\*`;
|
|
19
|
-
String.raw`[v=\s]*(${XRANGE_IDENTIFIER})(?:\.(${XRANGE_IDENTIFIER})(?:\.(${XRANGE_IDENTIFIER})(?:${PRERELEASE})?${BUILD}?)?)?`;
|
|
20
|
-
String.raw`[v=\s]*(${XRANGE_IDENTIFIER_LOOSE})(?:\.(${XRANGE_IDENTIFIER_LOOSE})(?:\.(${XRANGE_IDENTIFIER_LOOSE})(?:${PRERELEASE_LOOSE})?${BUILD}?)?)?`;
|
|
21
|
-
String.raw`(?:\^)`;
|
|
22
|
-
const COERCE_PLAIN = String.raw`(^|[^\d])(\d{1,${16}})(?:\.(\d{1,${16}}))?(?:\.(\d{1,${16}}))?`;
|
|
23
|
-
const COERCE = String.raw`${COERCE_PLAIN}(?:$|[^\d])`;
|
|
24
|
-
const COERCE_FULL = String.raw`${COERCE_PLAIN}(?:${PRERELEASE})?(?:${BUILD})?(?:$|[^\d])`;
|
|
25
|
-
function makeSafeRegexSource(source) {
|
|
26
|
-
const replacements = [
|
|
27
|
-
[String.raw`\s`, 1],
|
|
28
|
-
[String.raw`\d`, 256],
|
|
29
|
-
[LETTER_DASH_NUMBER, 250]
|
|
30
|
-
];
|
|
31
|
-
for (const [token, maximum] of replacements) source = source.split(`${token}*`).join(`${token}{0,${maximum}}`).split(`${token}+`).join(`${token}{1,${maximum}}`);
|
|
32
|
-
return source;
|
|
33
|
-
}
|
|
34
|
-
function safeRegex(source, flags) {
|
|
35
|
-
return new RegExp(makeSafeRegexSource(source), flags);
|
|
36
|
-
}
|
|
37
|
-
const FULL = safeRegex(`^${FULL_PLAIN}$`);
|
|
38
|
-
const LOOSE = safeRegex(`^${LOOSE_PLAIN}$`);
|
|
39
|
-
const NUMERIC$1 = /^\d+$/;
|
|
40
|
-
function formatComparableVersion(version) {
|
|
41
|
-
const base = `${version.major}.${version.minor}.${version.patch}`;
|
|
42
|
-
return version.prerelease?.length ? `${base}-${version.prerelease.join(".")}` : base;
|
|
43
|
-
}
|
|
44
|
-
function formatFullVersion(version) {
|
|
45
|
-
const comparable = formatComparableVersion(version);
|
|
46
|
-
return version.build?.length ? `${comparable}+${version.build.join(".")}` : comparable;
|
|
47
|
-
}
|
|
48
|
-
function parse(version, options = {}) {
|
|
49
|
-
if (typeof version !== "string") return version;
|
|
50
|
-
if (version.length > 256) throw new TypeError(`Version exceeds the maximum length of 256 characters`);
|
|
51
|
-
const match = version.trim().match(options.loose ? LOOSE : FULL);
|
|
52
|
-
if (!match) throw new TypeError(`Invalid version syntax: ${version}`);
|
|
53
|
-
const major = Number(match[1]);
|
|
54
|
-
const minor = Number(match[2]);
|
|
55
|
-
const patch = Number(match[3]);
|
|
56
|
-
if (major > Number.MAX_SAFE_INTEGER || major < 0) throw new TypeError(`Invalid major version: ${match[1]}`);
|
|
57
|
-
if (minor > Number.MAX_SAFE_INTEGER || minor < 0) throw new TypeError(`Invalid minor version: ${match[2]}`);
|
|
58
|
-
if (patch > Number.MAX_SAFE_INTEGER || patch < 0) throw new TypeError(`Invalid patch version: ${match[3]}`);
|
|
59
|
-
const prerelease = match[4] ? match[4].split(".").map((identifier) => {
|
|
60
|
-
if (NUMERIC$1.test(identifier)) {
|
|
61
|
-
const numeric = Number(identifier);
|
|
62
|
-
if (numeric >= 0 && numeric < Number.MAX_SAFE_INTEGER) return numeric;
|
|
63
|
-
}
|
|
64
|
-
return identifier;
|
|
65
|
-
}) : void 0;
|
|
66
|
-
return {
|
|
67
|
-
build: match[5]?.split("."),
|
|
68
|
-
major,
|
|
69
|
-
minor,
|
|
70
|
-
patch,
|
|
71
|
-
prerelease
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
function tryParse(version, options = {}) {
|
|
75
|
-
try {
|
|
76
|
-
return parse(version, options);
|
|
77
|
-
} catch {
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
//#endregion
|
|
82
|
-
//#region ../../node_modules/.pnpm/verkit@0.4.0/node_modules/verkit/dist/version-CQ98ZBpL.js
|
|
83
|
-
const COERCE_EXACT = safeRegex(COERCE);
|
|
84
|
-
const COERCE_FULL_EXACT = safeRegex(COERCE_FULL);
|
|
85
|
-
safeRegex(`^${PRERELEASE}$`);
|
|
86
|
-
safeRegex(`^${PRERELEASE_LOOSE}$`);
|
|
87
|
-
function normalizeFull(version, options = {}) {
|
|
88
|
-
const parsed = tryParse(version, options);
|
|
89
|
-
return parsed ? formatFullVersion(parsed) : null;
|
|
90
|
-
}
|
|
91
|
-
function coerce(value, options = {}) {
|
|
92
|
-
if (typeof value === "object") return value;
|
|
93
|
-
const input = typeof value === "number" ? String(value) : value;
|
|
94
|
-
let match = null;
|
|
95
|
-
if (options.rtl) {
|
|
96
|
-
const expression = safeRegex(options.includePrerelease ? COERCE_FULL : COERCE, "g");
|
|
97
|
-
let next;
|
|
98
|
-
while ((next = expression.exec(input)) && (!match || match.index + match[0].length !== input.length)) {
|
|
99
|
-
if (!match || next.index + next[0].length !== match.index + match[0].length) match = next;
|
|
100
|
-
expression.lastIndex = next.index + next[1].length + next[2].length;
|
|
101
|
-
}
|
|
102
|
-
} else match = (options.includePrerelease ? COERCE_FULL_EXACT : COERCE_EXACT).exec(input);
|
|
103
|
-
if (!match) return null;
|
|
104
|
-
const major = match[2];
|
|
105
|
-
return tryParse(`${major}.${match[3] || "0"}.${match[4] || "0"}${options.includePrerelease && match[5] ? `-${match[5]}` : ""}${options.includePrerelease && match[6] ? `+${match[6]}` : ""}`, options);
|
|
106
|
-
}
|
|
107
|
-
//#endregion
|
|
108
|
-
//#region src/appVersion.ts
|
|
109
|
-
/**
|
|
110
|
-
* The form of an app version that the device and the server compare:
|
|
111
|
-
* `major.minor.patch` of the first version in `appVersion`, such as `1.4.0`
|
|
112
|
-
* for `v1.4`, or null when it holds none. Prerelease and build parts are
|
|
113
|
-
* dropped.
|
|
114
|
-
*/
|
|
115
|
-
function canonicalizeAppVersion(appVersion) {
|
|
116
|
-
const version = coerce(appVersion);
|
|
117
|
-
return version ? normalizeFull(version) : null;
|
|
118
|
-
}
|
|
119
|
-
//#endregion
|
|
2
|
+
const require_uuid = require("./uuid-DC9FQNxo.cjs");
|
|
120
3
|
//#region src/baseURL.ts
|
|
121
4
|
/** Resolves a functional baseURL and drops trailing slashes. */
|
|
122
5
|
const resolveBaseURL = async (baseURL) => {
|
|
@@ -593,133 +476,6 @@ function authorizeReleaseTransition(input) {
|
|
|
593
476
|
};
|
|
594
477
|
}
|
|
595
478
|
//#endregion
|
|
596
|
-
//#region src/releaseCatalogScope.ts
|
|
597
|
-
const BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
598
|
-
const MAX_CATALOG_SEGMENT_LENGTH = 255;
|
|
599
|
-
function assertCatalogSegment(value, name) {
|
|
600
|
-
if (value.length === 0 || value.length > MAX_CATALOG_SEGMENT_LENGTH || !/^[A-Za-z0-9._~-]+$/.test(value)) throw new Error(`${name} must be 1-${MAX_CATALOG_SEGMENT_LENGTH} URL-safe ASCII characters`);
|
|
601
|
-
}
|
|
602
|
-
function encodeUtf8(value) {
|
|
603
|
-
const bytes = [];
|
|
604
|
-
for (const codePointText of value) {
|
|
605
|
-
const codePoint = codePointText.codePointAt(0);
|
|
606
|
-
if (codePoint <= 127) bytes.push(codePoint);
|
|
607
|
-
else if (codePoint <= 2047) bytes.push(192 | codePoint >> 6, 128 | codePoint & 63);
|
|
608
|
-
else if (codePoint <= 65535) bytes.push(224 | codePoint >> 12, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
|
|
609
|
-
else bytes.push(240 | codePoint >> 18, 128 | codePoint >> 12 & 63, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
|
|
610
|
-
}
|
|
611
|
-
return bytes;
|
|
612
|
-
}
|
|
613
|
-
function decodeUtf8(bytes) {
|
|
614
|
-
let result = "";
|
|
615
|
-
for (let index = 0; index < bytes.length;) {
|
|
616
|
-
const first = bytes[index++];
|
|
617
|
-
let codePoint;
|
|
618
|
-
let continuationCount;
|
|
619
|
-
if (first <= 127) {
|
|
620
|
-
codePoint = first;
|
|
621
|
-
continuationCount = 0;
|
|
622
|
-
} else if ((first & 224) === 192) {
|
|
623
|
-
codePoint = first & 31;
|
|
624
|
-
continuationCount = 1;
|
|
625
|
-
} else if ((first & 240) === 224) {
|
|
626
|
-
codePoint = first & 15;
|
|
627
|
-
continuationCount = 2;
|
|
628
|
-
} else if ((first & 248) === 240) {
|
|
629
|
-
codePoint = first & 7;
|
|
630
|
-
continuationCount = 3;
|
|
631
|
-
} else throw new Error("Invalid UTF-8 channel key");
|
|
632
|
-
for (let offset = 0; offset < continuationCount; offset += 1) {
|
|
633
|
-
const continuation = bytes[index++];
|
|
634
|
-
if (continuation === void 0 || (continuation & 192) !== 128) throw new Error("Invalid UTF-8 channel key");
|
|
635
|
-
codePoint = codePoint << 6 | continuation & 63;
|
|
636
|
-
}
|
|
637
|
-
if (codePoint > 1114111 || codePoint >= 55296 && codePoint <= 57343 || continuationCount === 1 && codePoint < 128 || continuationCount === 2 && codePoint < 2048 || continuationCount === 3 && codePoint < 65536) throw new Error("Invalid UTF-8 channel key");
|
|
638
|
-
result += String.fromCodePoint(codePoint);
|
|
639
|
-
}
|
|
640
|
-
return result;
|
|
641
|
-
}
|
|
642
|
-
function base64UrlEncode(bytes) {
|
|
643
|
-
let result = "";
|
|
644
|
-
for (let index = 0; index < bytes.length; index += 3) {
|
|
645
|
-
const first = bytes[index];
|
|
646
|
-
const second = bytes[index + 1];
|
|
647
|
-
const third = bytes[index + 2];
|
|
648
|
-
const value = first << 16 | (second ?? 0) << 8 | (third ?? 0);
|
|
649
|
-
result += BASE64URL_ALPHABET[value >> 18 & 63];
|
|
650
|
-
result += BASE64URL_ALPHABET[value >> 12 & 63];
|
|
651
|
-
if (second !== void 0) result += BASE64URL_ALPHABET[value >> 6 & 63];
|
|
652
|
-
if (third !== void 0) result += BASE64URL_ALPHABET[value & 63];
|
|
653
|
-
}
|
|
654
|
-
return result;
|
|
655
|
-
}
|
|
656
|
-
function base64UrlDecode(value) {
|
|
657
|
-
if (!/^[A-Za-z0-9_-]*$/.test(value) || value.length % 4 === 1) throw new Error("Invalid channel key");
|
|
658
|
-
const bytes = [];
|
|
659
|
-
for (let index = 0; index < value.length; index += 4) {
|
|
660
|
-
const chunk = value.slice(index, index + 4);
|
|
661
|
-
const encoded = [...chunk].map((character) => BASE64URL_ALPHABET.indexOf(character));
|
|
662
|
-
if (encoded.some((part) => part < 0)) throw new Error("Invalid channel key");
|
|
663
|
-
const bits = encoded[0] << 18 | encoded[1] << 12 | (encoded[2] ?? 0) << 6 | (encoded[3] ?? 0);
|
|
664
|
-
bytes.push(bits >> 16 & 255);
|
|
665
|
-
if (chunk.length >= 3) bytes.push(bits >> 8 & 255);
|
|
666
|
-
if (chunk.length === 4) bytes.push(bits & 255);
|
|
667
|
-
}
|
|
668
|
-
return bytes;
|
|
669
|
-
}
|
|
670
|
-
function normalizeChannelName(channel) {
|
|
671
|
-
return channel.trim().normalize("NFC");
|
|
672
|
-
}
|
|
673
|
-
function assertCanonicalChannelName(channel) {
|
|
674
|
-
const normalized = normalizeChannelName(channel);
|
|
675
|
-
if (normalized.length === 0 || normalized !== channel) throw new Error("Channel name must be non-empty, trimmed, and NFC-normalized");
|
|
676
|
-
let codePointCount = 0;
|
|
677
|
-
for (const _codePoint of normalized) {
|
|
678
|
-
codePointCount += 1;
|
|
679
|
-
if (codePointCount > 255) throw new Error("Channel name must not exceed 255 characters");
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
function encodeChannelKey(channel) {
|
|
683
|
-
assertCanonicalChannelName(channel);
|
|
684
|
-
return base64UrlEncode(encodeUtf8(channel));
|
|
685
|
-
}
|
|
686
|
-
function decodeChannelKey(channelKey) {
|
|
687
|
-
const channel = decodeUtf8(base64UrlDecode(channelKey));
|
|
688
|
-
assertCanonicalChannelName(channel);
|
|
689
|
-
if (encodeChannelKey(channel) !== channelKey) throw new Error("Channel key is not canonically encoded");
|
|
690
|
-
return channel;
|
|
691
|
-
}
|
|
692
|
-
function createReleaseCatalogScopeKey(input) {
|
|
693
|
-
decodeChannelKey(input.channelKey);
|
|
694
|
-
if (input.strategy === "APP_VERSION") return `v1:app-version:${input.platform}:${input.channelKey}`;
|
|
695
|
-
assertCatalogSegment(input.fingerprintHash, "Fingerprint hash");
|
|
696
|
-
return `v1:fingerprint:${input.platform}:${input.channelKey}:${input.fingerprintHash}`;
|
|
697
|
-
}
|
|
698
|
-
function parseReleaseCatalogScopeKey(scopeKey) {
|
|
699
|
-
const segments = scopeKey.split(":");
|
|
700
|
-
const [version, strategy, platform, channelKey] = segments;
|
|
701
|
-
if (version !== "v1" || platform !== "ios" && platform !== "android" || channelKey === void 0) throw new Error("Invalid release catalog scope key");
|
|
702
|
-
const input = strategy === "app-version" && segments.length === 4 ? {
|
|
703
|
-
channelKey,
|
|
704
|
-
platform,
|
|
705
|
-
strategy: "APP_VERSION"
|
|
706
|
-
} : strategy === "fingerprint" && segments.length === 5 && segments[4] !== void 0 ? {
|
|
707
|
-
channelKey,
|
|
708
|
-
fingerprintHash: segments[4],
|
|
709
|
-
platform,
|
|
710
|
-
strategy: "FINGERPRINT"
|
|
711
|
-
} : (() => {
|
|
712
|
-
throw new Error("Invalid release catalog scope key");
|
|
713
|
-
})();
|
|
714
|
-
if (createReleaseCatalogScopeKey(input) !== scopeKey) throw new Error("Release catalog scope key is not canonical");
|
|
715
|
-
return input;
|
|
716
|
-
}
|
|
717
|
-
//#endregion
|
|
718
|
-
//#region src/uuid.ts
|
|
719
|
-
const NIL_UUID = "00000000-0000-0000-0000-000000000000";
|
|
720
|
-
const UUID_V7_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
721
|
-
const isUUIDv7 = (value) => typeof value === "string" && UUID_V7_PATTERN.test(value);
|
|
722
|
-
//#endregion
|
|
723
479
|
//#region src/releaseCatalogWire.ts
|
|
724
480
|
/** The largest release catalog response body a client accepts, in UTF-8 bytes. */
|
|
725
481
|
const MAX_RELEASE_CATALOG_WIRE_BYTES = 528384;
|
|
@@ -741,12 +497,12 @@ const isStringArray = (value) => Array.isArray(value) && value.every((entry) =>
|
|
|
741
497
|
const isValidReleaseDescriptor = (value) => {
|
|
742
498
|
if (value === null || typeof value !== "object") return false;
|
|
743
499
|
const descriptor = value;
|
|
744
|
-
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");
|
|
500
|
+
return require_uuid.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");
|
|
745
501
|
};
|
|
746
502
|
/** Whether the catalog is the expected scope's. */
|
|
747
503
|
const hasExpectedReleaseCatalogScope = (catalog, expected) => {
|
|
748
504
|
try {
|
|
749
|
-
const parsed = parseReleaseCatalogScopeKey(catalog.scopeKey);
|
|
505
|
+
const parsed = require_uuid.parseReleaseCatalogScopeKey(catalog.scopeKey);
|
|
750
506
|
return parsed.channelKey === expected.channelKey && parsed.platform === expected.platform && parsed.strategy === expected.strategy && (parsed.strategy === "APP_VERSION" || expected.strategy === "FINGERPRINT" && parsed.fingerprintHash === expected.fingerprintHash);
|
|
751
507
|
} catch {
|
|
752
508
|
return false;
|
|
@@ -792,20 +548,20 @@ exports.MAX_CRASHED_BUNDLES = MAX_CRASHED_BUNDLES;
|
|
|
792
548
|
exports.MAX_DISTINCT_TARGET_COHORTS_PER_SCOPE = MAX_DISTINCT_TARGET_COHORTS_PER_SCOPE;
|
|
793
549
|
exports.MAX_RELEASE_CATALOG_WIRE_BYTES = MAX_RELEASE_CATALOG_WIRE_BYTES;
|
|
794
550
|
exports.MAX_TARGET_COHORTS_PER_RELEASE = MAX_TARGET_COHORTS_PER_RELEASE;
|
|
795
|
-
exports.NIL_UUID = NIL_UUID;
|
|
551
|
+
exports.NIL_UUID = require_uuid.NIL_UUID;
|
|
796
552
|
exports.NUMERIC_COHORT_SIZE = NUMERIC_COHORT_SIZE;
|
|
797
553
|
exports.RELEASE_CATALOG_FALLBACK_POLICY = RELEASE_CATALOG_FALLBACK_POLICY;
|
|
798
554
|
exports.RELEASE_CATALOG_SCHEMA_VERSION = RELEASE_CATALOG_SCHEMA_VERSION;
|
|
799
|
-
exports.assertCanonicalChannelName = assertCanonicalChannelName;
|
|
555
|
+
exports.assertCanonicalChannelName = require_uuid.assertCanonicalChannelName;
|
|
800
556
|
exports.assessCatalogAcceptance = assessCatalogAcceptance;
|
|
801
557
|
exports.authorizeReleaseTransition = authorizeReleaseTransition;
|
|
802
|
-
exports.canonicalizeAppVersion = canonicalizeAppVersion;
|
|
558
|
+
exports.canonicalizeAppVersion = require_uuid.canonicalizeAppVersion;
|
|
803
559
|
exports.createPluginHost = createPluginHost;
|
|
804
|
-
exports.createReleaseCatalogScopeKey = createReleaseCatalogScopeKey;
|
|
560
|
+
exports.createReleaseCatalogScopeKey = require_uuid.createReleaseCatalogScopeKey;
|
|
805
561
|
exports.createReleaseSelectionContextHash = createReleaseSelectionContextHash;
|
|
806
|
-
exports.decodeChannelKey = decodeChannelKey;
|
|
562
|
+
exports.decodeChannelKey = require_uuid.decodeChannelKey;
|
|
807
563
|
exports.defineClientPlugin = defineClientPlugin;
|
|
808
|
-
exports.encodeChannelKey = encodeChannelKey;
|
|
564
|
+
exports.encodeChannelKey = require_uuid.encodeChannelKey;
|
|
809
565
|
exports.getAssetBaseStorageUri = getAssetBaseStorageUri;
|
|
810
566
|
exports.getBundlePatch = getBundlePatch;
|
|
811
567
|
exports.getBundlePatches = getBundlePatches;
|
|
@@ -825,13 +581,13 @@ exports.isCohortEligibleForUpdate = isCohortEligibleForUpdate;
|
|
|
825
581
|
exports.isCustomCohort = isCustomCohort;
|
|
826
582
|
exports.isNumericCohort = isNumericCohort;
|
|
827
583
|
exports.isReleaseEligibleForCohort = isReleaseEligibleForCohort;
|
|
828
|
-
exports.isUUIDv7 = isUUIDv7;
|
|
584
|
+
exports.isUUIDv7 = require_uuid.isUUIDv7;
|
|
829
585
|
exports.isValidCohort = isValidCohort;
|
|
830
|
-
exports.normalizeChannelName = normalizeChannelName;
|
|
586
|
+
exports.normalizeChannelName = require_uuid.normalizeChannelName;
|
|
831
587
|
exports.normalizeCohortValue = normalizeCohortValue;
|
|
832
588
|
exports.normalizeRolloutCohortCount = normalizeRolloutCohortCount;
|
|
833
589
|
exports.parseReleaseCatalog = parseReleaseCatalog;
|
|
834
|
-
exports.parseReleaseCatalogScopeKey = parseReleaseCatalogScopeKey;
|
|
590
|
+
exports.parseReleaseCatalogScopeKey = require_uuid.parseReleaseCatalogScopeKey;
|
|
835
591
|
exports.pluginStorageKey = pluginStorageKey;
|
|
836
592
|
exports.resolveBaseURL = resolveBaseURL;
|
|
837
593
|
exports.selectDesiredRelease = selectDesiredRelease;
|
package/dist/index.mjs
CHANGED
|
@@ -1,121 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const LETTER_DASH_NUMBER = "[a-zA-Z0-9-]";
|
|
3
|
-
const NUMERIC_IDENTIFIER = String.raw`0|[1-9]\d*`;
|
|
4
|
-
const NUMERIC_IDENTIFIER_LOOSE = String.raw`\d+`;
|
|
5
|
-
const NON_NUMERIC_IDENTIFIER = String.raw`\d*[a-zA-Z-]${LETTER_DASH_NUMBER}*`;
|
|
6
|
-
const MAIN_VERSION = String.raw`(${NUMERIC_IDENTIFIER})\.(${NUMERIC_IDENTIFIER})\.(${NUMERIC_IDENTIFIER})`;
|
|
7
|
-
const MAIN_VERSION_LOOSE = String.raw`(${NUMERIC_IDENTIFIER_LOOSE})\.(${NUMERIC_IDENTIFIER_LOOSE})\.(${NUMERIC_IDENTIFIER_LOOSE})`;
|
|
8
|
-
const PRERELEASE_IDENTIFIER = `(?:${NON_NUMERIC_IDENTIFIER}|${NUMERIC_IDENTIFIER})`;
|
|
9
|
-
const PRERELEASE_IDENTIFIER_LOOSE = `(?:${NON_NUMERIC_IDENTIFIER}|${NUMERIC_IDENTIFIER_LOOSE})`;
|
|
10
|
-
const PRERELEASE = String.raw`(?:-(${PRERELEASE_IDENTIFIER}(?:\.${PRERELEASE_IDENTIFIER})*))`;
|
|
11
|
-
const PRERELEASE_LOOSE = String.raw`(?:-?(${PRERELEASE_IDENTIFIER_LOOSE}(?:\.${PRERELEASE_IDENTIFIER_LOOSE})*))`;
|
|
12
|
-
const BUILD_IDENTIFIER = `${LETTER_DASH_NUMBER}+`;
|
|
13
|
-
const BUILD = String.raw`(?:\+(${BUILD_IDENTIFIER}(?:\.${BUILD_IDENTIFIER})*))`;
|
|
14
|
-
const FULL_PLAIN = `v?${MAIN_VERSION}${PRERELEASE}?${BUILD}?`;
|
|
15
|
-
const LOOSE_PLAIN = String.raw`[v=\s]*${MAIN_VERSION_LOOSE}${PRERELEASE_LOOSE}?${BUILD}?`;
|
|
16
|
-
const XRANGE_IDENTIFIER = String.raw`${NUMERIC_IDENTIFIER}|x|X|\*`;
|
|
17
|
-
const XRANGE_IDENTIFIER_LOOSE = String.raw`${NUMERIC_IDENTIFIER_LOOSE}|x|X|\*`;
|
|
18
|
-
String.raw`[v=\s]*(${XRANGE_IDENTIFIER})(?:\.(${XRANGE_IDENTIFIER})(?:\.(${XRANGE_IDENTIFIER})(?:${PRERELEASE})?${BUILD}?)?)?`;
|
|
19
|
-
String.raw`[v=\s]*(${XRANGE_IDENTIFIER_LOOSE})(?:\.(${XRANGE_IDENTIFIER_LOOSE})(?:\.(${XRANGE_IDENTIFIER_LOOSE})(?:${PRERELEASE_LOOSE})?${BUILD}?)?)?`;
|
|
20
|
-
String.raw`(?:\^)`;
|
|
21
|
-
const COERCE_PLAIN = String.raw`(^|[^\d])(\d{1,${16}})(?:\.(\d{1,${16}}))?(?:\.(\d{1,${16}}))?`;
|
|
22
|
-
const COERCE = String.raw`${COERCE_PLAIN}(?:$|[^\d])`;
|
|
23
|
-
const COERCE_FULL = String.raw`${COERCE_PLAIN}(?:${PRERELEASE})?(?:${BUILD})?(?:$|[^\d])`;
|
|
24
|
-
function makeSafeRegexSource(source) {
|
|
25
|
-
const replacements = [
|
|
26
|
-
[String.raw`\s`, 1],
|
|
27
|
-
[String.raw`\d`, 256],
|
|
28
|
-
[LETTER_DASH_NUMBER, 250]
|
|
29
|
-
];
|
|
30
|
-
for (const [token, maximum] of replacements) source = source.split(`${token}*`).join(`${token}{0,${maximum}}`).split(`${token}+`).join(`${token}{1,${maximum}}`);
|
|
31
|
-
return source;
|
|
32
|
-
}
|
|
33
|
-
function safeRegex(source, flags) {
|
|
34
|
-
return new RegExp(makeSafeRegexSource(source), flags);
|
|
35
|
-
}
|
|
36
|
-
const FULL = safeRegex(`^${FULL_PLAIN}$`);
|
|
37
|
-
const LOOSE = safeRegex(`^${LOOSE_PLAIN}$`);
|
|
38
|
-
const NUMERIC$1 = /^\d+$/;
|
|
39
|
-
function formatComparableVersion(version) {
|
|
40
|
-
const base = `${version.major}.${version.minor}.${version.patch}`;
|
|
41
|
-
return version.prerelease?.length ? `${base}-${version.prerelease.join(".")}` : base;
|
|
42
|
-
}
|
|
43
|
-
function formatFullVersion(version) {
|
|
44
|
-
const comparable = formatComparableVersion(version);
|
|
45
|
-
return version.build?.length ? `${comparable}+${version.build.join(".")}` : comparable;
|
|
46
|
-
}
|
|
47
|
-
function parse(version, options = {}) {
|
|
48
|
-
if (typeof version !== "string") return version;
|
|
49
|
-
if (version.length > 256) throw new TypeError(`Version exceeds the maximum length of 256 characters`);
|
|
50
|
-
const match = version.trim().match(options.loose ? LOOSE : FULL);
|
|
51
|
-
if (!match) throw new TypeError(`Invalid version syntax: ${version}`);
|
|
52
|
-
const major = Number(match[1]);
|
|
53
|
-
const minor = Number(match[2]);
|
|
54
|
-
const patch = Number(match[3]);
|
|
55
|
-
if (major > Number.MAX_SAFE_INTEGER || major < 0) throw new TypeError(`Invalid major version: ${match[1]}`);
|
|
56
|
-
if (minor > Number.MAX_SAFE_INTEGER || minor < 0) throw new TypeError(`Invalid minor version: ${match[2]}`);
|
|
57
|
-
if (patch > Number.MAX_SAFE_INTEGER || patch < 0) throw new TypeError(`Invalid patch version: ${match[3]}`);
|
|
58
|
-
const prerelease = match[4] ? match[4].split(".").map((identifier) => {
|
|
59
|
-
if (NUMERIC$1.test(identifier)) {
|
|
60
|
-
const numeric = Number(identifier);
|
|
61
|
-
if (numeric >= 0 && numeric < Number.MAX_SAFE_INTEGER) return numeric;
|
|
62
|
-
}
|
|
63
|
-
return identifier;
|
|
64
|
-
}) : void 0;
|
|
65
|
-
return {
|
|
66
|
-
build: match[5]?.split("."),
|
|
67
|
-
major,
|
|
68
|
-
minor,
|
|
69
|
-
patch,
|
|
70
|
-
prerelease
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
function tryParse(version, options = {}) {
|
|
74
|
-
try {
|
|
75
|
-
return parse(version, options);
|
|
76
|
-
} catch {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region ../../node_modules/.pnpm/verkit@0.4.0/node_modules/verkit/dist/version-CQ98ZBpL.js
|
|
82
|
-
const COERCE_EXACT = safeRegex(COERCE);
|
|
83
|
-
const COERCE_FULL_EXACT = safeRegex(COERCE_FULL);
|
|
84
|
-
safeRegex(`^${PRERELEASE}$`);
|
|
85
|
-
safeRegex(`^${PRERELEASE_LOOSE}$`);
|
|
86
|
-
function normalizeFull(version, options = {}) {
|
|
87
|
-
const parsed = tryParse(version, options);
|
|
88
|
-
return parsed ? formatFullVersion(parsed) : null;
|
|
89
|
-
}
|
|
90
|
-
function coerce(value, options = {}) {
|
|
91
|
-
if (typeof value === "object") return value;
|
|
92
|
-
const input = typeof value === "number" ? String(value) : value;
|
|
93
|
-
let match = null;
|
|
94
|
-
if (options.rtl) {
|
|
95
|
-
const expression = safeRegex(options.includePrerelease ? COERCE_FULL : COERCE, "g");
|
|
96
|
-
let next;
|
|
97
|
-
while ((next = expression.exec(input)) && (!match || match.index + match[0].length !== input.length)) {
|
|
98
|
-
if (!match || next.index + next[0].length !== match.index + match[0].length) match = next;
|
|
99
|
-
expression.lastIndex = next.index + next[1].length + next[2].length;
|
|
100
|
-
}
|
|
101
|
-
} else match = (options.includePrerelease ? COERCE_FULL_EXACT : COERCE_EXACT).exec(input);
|
|
102
|
-
if (!match) return null;
|
|
103
|
-
const major = match[2];
|
|
104
|
-
return tryParse(`${major}.${match[3] || "0"}.${match[4] || "0"}${options.includePrerelease && match[5] ? `-${match[5]}` : ""}${options.includePrerelease && match[6] ? `+${match[6]}` : ""}`, options);
|
|
105
|
-
}
|
|
106
|
-
//#endregion
|
|
107
|
-
//#region src/appVersion.ts
|
|
108
|
-
/**
|
|
109
|
-
* The form of an app version that the device and the server compare:
|
|
110
|
-
* `major.minor.patch` of the first version in `appVersion`, such as `1.4.0`
|
|
111
|
-
* for `v1.4`, or null when it holds none. Prerelease and build parts are
|
|
112
|
-
* dropped.
|
|
113
|
-
*/
|
|
114
|
-
function canonicalizeAppVersion(appVersion) {
|
|
115
|
-
const version = coerce(appVersion);
|
|
116
|
-
return version ? normalizeFull(version) : null;
|
|
117
|
-
}
|
|
118
|
-
//#endregion
|
|
1
|
+
import { a as decodeChannelKey, c as parseReleaseCatalogScopeKey, i as createReleaseCatalogScopeKey, l as canonicalizeAppVersion, n as isUUIDv7, o as encodeChannelKey, r as assertCanonicalChannelName, s as normalizeChannelName, t as NIL_UUID } from "./uuid-kZvLA0Ly.mjs";
|
|
119
2
|
//#region src/baseURL.ts
|
|
120
3
|
/** Resolves a functional baseURL and drops trailing slashes. */
|
|
121
4
|
const resolveBaseURL = async (baseURL) => {
|
|
@@ -592,133 +475,6 @@ function authorizeReleaseTransition(input) {
|
|
|
592
475
|
};
|
|
593
476
|
}
|
|
594
477
|
//#endregion
|
|
595
|
-
//#region src/releaseCatalogScope.ts
|
|
596
|
-
const BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
597
|
-
const MAX_CATALOG_SEGMENT_LENGTH = 255;
|
|
598
|
-
function assertCatalogSegment(value, name) {
|
|
599
|
-
if (value.length === 0 || value.length > MAX_CATALOG_SEGMENT_LENGTH || !/^[A-Za-z0-9._~-]+$/.test(value)) throw new Error(`${name} must be 1-${MAX_CATALOG_SEGMENT_LENGTH} URL-safe ASCII characters`);
|
|
600
|
-
}
|
|
601
|
-
function encodeUtf8(value) {
|
|
602
|
-
const bytes = [];
|
|
603
|
-
for (const codePointText of value) {
|
|
604
|
-
const codePoint = codePointText.codePointAt(0);
|
|
605
|
-
if (codePoint <= 127) bytes.push(codePoint);
|
|
606
|
-
else if (codePoint <= 2047) bytes.push(192 | codePoint >> 6, 128 | codePoint & 63);
|
|
607
|
-
else if (codePoint <= 65535) bytes.push(224 | codePoint >> 12, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
|
|
608
|
-
else bytes.push(240 | codePoint >> 18, 128 | codePoint >> 12 & 63, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
|
|
609
|
-
}
|
|
610
|
-
return bytes;
|
|
611
|
-
}
|
|
612
|
-
function decodeUtf8(bytes) {
|
|
613
|
-
let result = "";
|
|
614
|
-
for (let index = 0; index < bytes.length;) {
|
|
615
|
-
const first = bytes[index++];
|
|
616
|
-
let codePoint;
|
|
617
|
-
let continuationCount;
|
|
618
|
-
if (first <= 127) {
|
|
619
|
-
codePoint = first;
|
|
620
|
-
continuationCount = 0;
|
|
621
|
-
} else if ((first & 224) === 192) {
|
|
622
|
-
codePoint = first & 31;
|
|
623
|
-
continuationCount = 1;
|
|
624
|
-
} else if ((first & 240) === 224) {
|
|
625
|
-
codePoint = first & 15;
|
|
626
|
-
continuationCount = 2;
|
|
627
|
-
} else if ((first & 248) === 240) {
|
|
628
|
-
codePoint = first & 7;
|
|
629
|
-
continuationCount = 3;
|
|
630
|
-
} else throw new Error("Invalid UTF-8 channel key");
|
|
631
|
-
for (let offset = 0; offset < continuationCount; offset += 1) {
|
|
632
|
-
const continuation = bytes[index++];
|
|
633
|
-
if (continuation === void 0 || (continuation & 192) !== 128) throw new Error("Invalid UTF-8 channel key");
|
|
634
|
-
codePoint = codePoint << 6 | continuation & 63;
|
|
635
|
-
}
|
|
636
|
-
if (codePoint > 1114111 || codePoint >= 55296 && codePoint <= 57343 || continuationCount === 1 && codePoint < 128 || continuationCount === 2 && codePoint < 2048 || continuationCount === 3 && codePoint < 65536) throw new Error("Invalid UTF-8 channel key");
|
|
637
|
-
result += String.fromCodePoint(codePoint);
|
|
638
|
-
}
|
|
639
|
-
return result;
|
|
640
|
-
}
|
|
641
|
-
function base64UrlEncode(bytes) {
|
|
642
|
-
let result = "";
|
|
643
|
-
for (let index = 0; index < bytes.length; index += 3) {
|
|
644
|
-
const first = bytes[index];
|
|
645
|
-
const second = bytes[index + 1];
|
|
646
|
-
const third = bytes[index + 2];
|
|
647
|
-
const value = first << 16 | (second ?? 0) << 8 | (third ?? 0);
|
|
648
|
-
result += BASE64URL_ALPHABET[value >> 18 & 63];
|
|
649
|
-
result += BASE64URL_ALPHABET[value >> 12 & 63];
|
|
650
|
-
if (second !== void 0) result += BASE64URL_ALPHABET[value >> 6 & 63];
|
|
651
|
-
if (third !== void 0) result += BASE64URL_ALPHABET[value & 63];
|
|
652
|
-
}
|
|
653
|
-
return result;
|
|
654
|
-
}
|
|
655
|
-
function base64UrlDecode(value) {
|
|
656
|
-
if (!/^[A-Za-z0-9_-]*$/.test(value) || value.length % 4 === 1) throw new Error("Invalid channel key");
|
|
657
|
-
const bytes = [];
|
|
658
|
-
for (let index = 0; index < value.length; index += 4) {
|
|
659
|
-
const chunk = value.slice(index, index + 4);
|
|
660
|
-
const encoded = [...chunk].map((character) => BASE64URL_ALPHABET.indexOf(character));
|
|
661
|
-
if (encoded.some((part) => part < 0)) throw new Error("Invalid channel key");
|
|
662
|
-
const bits = encoded[0] << 18 | encoded[1] << 12 | (encoded[2] ?? 0) << 6 | (encoded[3] ?? 0);
|
|
663
|
-
bytes.push(bits >> 16 & 255);
|
|
664
|
-
if (chunk.length >= 3) bytes.push(bits >> 8 & 255);
|
|
665
|
-
if (chunk.length === 4) bytes.push(bits & 255);
|
|
666
|
-
}
|
|
667
|
-
return bytes;
|
|
668
|
-
}
|
|
669
|
-
function normalizeChannelName(channel) {
|
|
670
|
-
return channel.trim().normalize("NFC");
|
|
671
|
-
}
|
|
672
|
-
function assertCanonicalChannelName(channel) {
|
|
673
|
-
const normalized = normalizeChannelName(channel);
|
|
674
|
-
if (normalized.length === 0 || normalized !== channel) throw new Error("Channel name must be non-empty, trimmed, and NFC-normalized");
|
|
675
|
-
let codePointCount = 0;
|
|
676
|
-
for (const _codePoint of normalized) {
|
|
677
|
-
codePointCount += 1;
|
|
678
|
-
if (codePointCount > 255) throw new Error("Channel name must not exceed 255 characters");
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
function encodeChannelKey(channel) {
|
|
682
|
-
assertCanonicalChannelName(channel);
|
|
683
|
-
return base64UrlEncode(encodeUtf8(channel));
|
|
684
|
-
}
|
|
685
|
-
function decodeChannelKey(channelKey) {
|
|
686
|
-
const channel = decodeUtf8(base64UrlDecode(channelKey));
|
|
687
|
-
assertCanonicalChannelName(channel);
|
|
688
|
-
if (encodeChannelKey(channel) !== channelKey) throw new Error("Channel key is not canonically encoded");
|
|
689
|
-
return channel;
|
|
690
|
-
}
|
|
691
|
-
function createReleaseCatalogScopeKey(input) {
|
|
692
|
-
decodeChannelKey(input.channelKey);
|
|
693
|
-
if (input.strategy === "APP_VERSION") return `v1:app-version:${input.platform}:${input.channelKey}`;
|
|
694
|
-
assertCatalogSegment(input.fingerprintHash, "Fingerprint hash");
|
|
695
|
-
return `v1:fingerprint:${input.platform}:${input.channelKey}:${input.fingerprintHash}`;
|
|
696
|
-
}
|
|
697
|
-
function parseReleaseCatalogScopeKey(scopeKey) {
|
|
698
|
-
const segments = scopeKey.split(":");
|
|
699
|
-
const [version, strategy, platform, channelKey] = segments;
|
|
700
|
-
if (version !== "v1" || platform !== "ios" && platform !== "android" || channelKey === void 0) throw new Error("Invalid release catalog scope key");
|
|
701
|
-
const input = strategy === "app-version" && segments.length === 4 ? {
|
|
702
|
-
channelKey,
|
|
703
|
-
platform,
|
|
704
|
-
strategy: "APP_VERSION"
|
|
705
|
-
} : strategy === "fingerprint" && segments.length === 5 && segments[4] !== void 0 ? {
|
|
706
|
-
channelKey,
|
|
707
|
-
fingerprintHash: segments[4],
|
|
708
|
-
platform,
|
|
709
|
-
strategy: "FINGERPRINT"
|
|
710
|
-
} : (() => {
|
|
711
|
-
throw new Error("Invalid release catalog scope key");
|
|
712
|
-
})();
|
|
713
|
-
if (createReleaseCatalogScopeKey(input) !== scopeKey) throw new Error("Release catalog scope key is not canonical");
|
|
714
|
-
return input;
|
|
715
|
-
}
|
|
716
|
-
//#endregion
|
|
717
|
-
//#region src/uuid.ts
|
|
718
|
-
const NIL_UUID = "00000000-0000-0000-0000-000000000000";
|
|
719
|
-
const UUID_V7_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
720
|
-
const isUUIDv7 = (value) => typeof value === "string" && UUID_V7_PATTERN.test(value);
|
|
721
|
-
//#endregion
|
|
722
478
|
//#region src/releaseCatalogWire.ts
|
|
723
479
|
/** The largest release catalog response body a client accepts, in UTF-8 bytes. */
|
|
724
480
|
const MAX_RELEASE_CATALOG_WIRE_BYTES = 528384;
|