@hot-updater/plugin-core 0.36.7 → 1.0.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/assetStorageLayout.cjs +36 -18
- package/dist/assetStorageLayout.d.cts +21 -6
- package/dist/assetStorageLayout.d.mts +21 -6
- package/dist/assetStorageLayout.mjs +36 -18
- package/dist/bundleStorageLayout.cjs +2 -3
- package/dist/bundleStorageLayout.mjs +2 -3
- package/dist/contentAddressedAssets.cjs +5 -0
- package/dist/contentAddressedAssets.d.cts +2 -1
- package/dist/contentAddressedAssets.d.mts +2 -1
- package/dist/contentAddressedAssets.mjs +5 -1
- package/dist/createDatabasePlugin.cjs +775 -284
- package/dist/createDatabasePlugin.d.cts +20 -64
- package/dist/createDatabasePlugin.d.mts +20 -64
- package/dist/createDatabasePlugin.mjs +773 -284
- package/dist/createStorageKeyBuilder.cjs +9 -2
- package/dist/createStorageKeyBuilder.mjs +9 -2
- package/dist/createStoragePlugin.cjs +6 -145
- package/dist/createStoragePlugin.d.cts +7 -52
- package/dist/createStoragePlugin.d.mts +7 -52
- package/dist/createStoragePlugin.mjs +5 -143
- package/dist/databaseClient.cjs +112 -0
- package/dist/databaseClient.d.cts +33 -0
- package/dist/databaseClient.d.mts +33 -0
- package/dist/databaseClient.mjs +110 -0
- package/dist/databaseClientReads.cjs +113 -0
- package/dist/databaseClientReads.mjs +112 -0
- package/dist/databaseClientUpdates.cjs +39 -0
- package/dist/databaseClientUpdates.d.cts +11 -0
- package/dist/databaseClientUpdates.d.mts +11 -0
- package/dist/databaseClientUpdates.mjs +36 -0
- package/dist/databaseJsonValue.cjs +37 -0
- package/dist/databaseJsonValue.d.cts +5 -0
- package/dist/databaseJsonValue.d.mts +5 -0
- package/dist/databaseJsonValue.mjs +37 -0
- package/dist/databaseMetadata.cjs +13 -0
- package/dist/databaseMetadata.mjs +12 -0
- package/dist/databasePluginCrud.cjs +86 -0
- package/dist/databasePluginCrud.d.cts +1 -0
- package/dist/databasePluginCrud.d.mts +1 -0
- package/dist/databasePluginCrud.mjs +86 -0
- package/dist/databasePluginCrudValidation.d.cts +1 -0
- package/dist/databasePluginCrudValidation.d.mts +1 -0
- package/dist/databasePluginCrudValidationErrors.cjs +10 -0
- package/dist/databasePluginCrudValidationErrors.d.cts +9 -0
- package/dist/databasePluginCrudValidationErrors.d.mts +9 -0
- package/dist/databasePluginCrudValidationErrors.mjs +10 -0
- package/dist/databasePluginCrudValidationFields.cjs +291 -0
- package/dist/databasePluginCrudValidationFields.d.cts +1 -0
- package/dist/databasePluginCrudValidationFields.d.mts +1 -0
- package/dist/databasePluginCrudValidationFields.mjs +281 -0
- package/dist/databasePluginCrudValidationMutations.cjs +88 -0
- package/dist/databasePluginCrudValidationMutations.d.cts +1 -0
- package/dist/databasePluginCrudValidationMutations.d.mts +1 -0
- package/dist/databasePluginCrudValidationMutations.mjs +82 -0
- package/dist/databasePluginCrudValidationQueries.cjs +103 -0
- package/dist/databasePluginCrudValidationQueries.d.cts +1 -0
- package/dist/databasePluginCrudValidationQueries.d.mts +1 -0
- package/dist/databasePluginCrudValidationQueries.mjs +97 -0
- package/dist/databasePluginCrudValidationRows.cjs +55 -0
- package/dist/databasePluginCrudValidationRows.d.cts +1 -0
- package/dist/databasePluginCrudValidationRows.d.mts +1 -0
- package/dist/databasePluginCrudValidationRows.mjs +53 -0
- package/dist/databasePluginTransaction.cjs +7 -0
- package/dist/databasePluginTransaction.mjs +7 -0
- package/dist/databaseRows.cjs +149 -0
- package/dist/databaseRows.d.cts +34 -0
- package/dist/databaseRows.d.mts +34 -0
- package/dist/databaseRows.mjs +141 -0
- package/dist/index.cjs +76 -24
- package/dist/index.d.cts +22 -12
- package/dist/index.d.mts +22 -12
- package/dist/index.mjs +21 -14
- package/dist/internal.cjs +6 -0
- package/dist/internal.d.cts +9 -0
- package/dist/internal.d.mts +9 -0
- package/dist/internal.mjs +3 -0
- package/dist/node_modules/.pnpm/verkit@0.3.2/node_modules/verkit/dist/index.cjs +345 -0
- package/dist/node_modules/.pnpm/verkit@0.3.2/node_modules/verkit/dist/index.mjs +341 -0
- package/dist/paginateBundles.d.cts +6 -4
- package/dist/paginateBundles.d.mts +6 -4
- package/dist/parseStorageUri.cjs +46 -30
- package/dist/parseStorageUri.d.cts +20 -17
- package/dist/parseStorageUri.d.mts +20 -17
- package/dist/parseStorageUri.mjs +46 -30
- package/dist/queryBundles.cjs +1 -7
- package/dist/queryBundles.d.cts +3 -1
- package/dist/queryBundles.d.mts +3 -1
- package/dist/queryBundles.mjs +1 -7
- package/dist/releaseCatalogCompiler.cjs +391 -0
- package/dist/releaseCatalogCompiler.d.cts +55 -0
- package/dist/releaseCatalogCompiler.d.mts +55 -0
- package/dist/releaseCatalogCompiler.mjs +386 -0
- package/dist/releaseCatalogMutation.cjs +303 -0
- package/dist/releaseCatalogMutation.d.cts +86 -0
- package/dist/releaseCatalogMutation.d.mts +86 -0
- package/dist/releaseCatalogMutation.mjs +297 -0
- package/dist/releaseManagement.cjs +231 -0
- package/dist/releaseManagement.d.cts +48 -0
- package/dist/releaseManagement.d.mts +48 -0
- package/dist/releaseManagement.mjs +224 -0
- package/dist/remoteBundleSigning.cjs +296 -0
- package/dist/remoteBundleSigning.d.cts +43 -0
- package/dist/remoteBundleSigning.d.mts +43 -0
- package/dist/remoteBundleSigning.mjs +291 -0
- package/dist/requestBundleCache.cjs +22 -0
- package/dist/requestBundleCache.d.cts +9 -0
- package/dist/requestBundleCache.d.mts +9 -0
- package/dist/requestBundleCache.mjs +22 -0
- package/dist/semverSatisfies.cjs +3 -4
- package/dist/semverSatisfies.mjs +1 -1
- package/dist/storageDownloadPath.cjs +48 -0
- package/dist/storageDownloadPath.d.cts +15 -0
- package/dist/storageDownloadPath.d.mts +15 -0
- package/dist/storageDownloadPath.mjs +46 -0
- package/dist/types/database.d.cts +4 -0
- package/dist/types/database.d.mts +4 -0
- package/dist/types/databaseFields.cjs +92 -0
- package/dist/types/databaseFields.d.cts +12 -0
- package/dist/types/databaseFields.d.mts +12 -0
- package/dist/types/databaseFields.mjs +92 -0
- package/dist/types/databaseOperations.d.cts +173 -0
- package/dist/types/databaseOperations.d.mts +173 -0
- package/dist/types/databasePlugin.d.cts +240 -0
- package/dist/types/databasePlugin.d.mts +240 -0
- package/dist/types/databaseQuery.d.cts +47 -0
- package/dist/types/databaseQuery.d.mts +47 -0
- package/dist/types/databaseRows.d.cts +120 -0
- package/dist/types/databaseRows.d.mts +120 -0
- package/dist/types/index.d.cts +120 -162
- package/dist/types/index.d.mts +120 -162
- package/dist/types/internal.d.cts +7 -0
- package/dist/types/internal.d.mts +7 -0
- package/dist/types/public.d.cts +3 -0
- package/dist/types/public.d.mts +3 -0
- package/dist/uuidv7.cjs +9 -0
- package/dist/uuidv7.d.cts +4 -1
- package/dist/uuidv7.d.mts +4 -1
- package/dist/uuidv7.mjs +8 -1
- package/package.json +10 -5
- package/dist/bundleUnitOfWork.cjs +0 -158
- package/dist/bundleUnitOfWork.mjs +0 -158
- package/dist/bundleUnitOfWorkStore.cjs +0 -15
- package/dist/bundleUnitOfWorkStore.mjs +0 -15
- package/dist/createBlobDatabasePlugin.cjs +0 -382
- package/dist/createBlobDatabasePlugin.d.cts +0 -29
- package/dist/createBlobDatabasePlugin.d.mts +0 -29
- package/dist/createBlobDatabasePlugin.mjs +0 -381
- package/dist/legacyAssetStorageLayout.cjs +0 -12
- package/dist/legacyAssetStorageLayout.mjs +0 -12
- package/dist/requestUpdateBundleState.cjs +0 -26
- package/dist/requestUpdateBundleState.d.cts +0 -12
- package/dist/requestUpdateBundleState.d.mts +0 -12
- package/dist/requestUpdateBundleState.mjs +0 -24
- package/dist/resolveUpdateInfoFromBundles.cjs +0 -14
- package/dist/resolveUpdateInfoFromBundles.d.cts +0 -16
- package/dist/resolveUpdateInfoFromBundles.d.mts +0 -16
- package/dist/resolveUpdateInfoFromBundles.mjs +0 -13
- package/dist/storageProfile.cjs +0 -15
- package/dist/storageProfile.d.cts +0 -9
- package/dist/storageProfile.d.mts +0 -9
- package/dist/storageProfile.mjs +0 -12
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
//#region ../../node_modules/.pnpm/verkit@0.3.2/node_modules/verkit/dist/index.js
|
|
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 GREATER_LESS_THAN = "((?:<|>)?=?)";
|
|
17
|
+
const XRANGE_IDENTIFIER = String.raw`${NUMERIC_IDENTIFIER}|x|X|\*`;
|
|
18
|
+
const XRANGE_IDENTIFIER_LOOSE = String.raw`${NUMERIC_IDENTIFIER_LOOSE}|x|X|\*`;
|
|
19
|
+
const XRANGE_PLAIN = String.raw`[v=\s]*(${XRANGE_IDENTIFIER})(?:\.(${XRANGE_IDENTIFIER})(?:\.(${XRANGE_IDENTIFIER})(?:${PRERELEASE})?${BUILD}?)?)?`;
|
|
20
|
+
const XRANGE_PLAIN_LOOSE = String.raw`[v=\s]*(${XRANGE_IDENTIFIER_LOOSE})(?:\.(${XRANGE_IDENTIFIER_LOOSE})(?:\.(${XRANGE_IDENTIFIER_LOOSE})(?:${PRERELEASE_LOOSE})?${BUILD}?)?)?`;
|
|
21
|
+
const LONE_TILDE = "(?:~>?)";
|
|
22
|
+
const LONE_CARET = String.raw`(?:\^)`;
|
|
23
|
+
const COERCE_PLAIN = String.raw`(^|[^\d])(\d{1,${16}})(?:\.(\d{1,${16}}))?(?:\.(\d{1,${16}}))?`;
|
|
24
|
+
const COERCE = String.raw`${COERCE_PLAIN}(?:$|[^\d])`;
|
|
25
|
+
const COERCE_FULL = String.raw`${COERCE_PLAIN}(?:${PRERELEASE})?(?:${BUILD})?(?:$|[^\d])`;
|
|
26
|
+
function makeSafeRegexSource(source) {
|
|
27
|
+
const replacements = [
|
|
28
|
+
[String.raw`\s`, 1],
|
|
29
|
+
[String.raw`\d`, 256],
|
|
30
|
+
[LETTER_DASH_NUMBER, 250]
|
|
31
|
+
];
|
|
32
|
+
for (const [token, maximum] of replacements) source = source.split(`${token}*`).join(`${token}{0,${maximum}}`).split(`${token}+`).join(`${token}{1,${maximum}}`);
|
|
33
|
+
return source;
|
|
34
|
+
}
|
|
35
|
+
function safeRegex(source, flags) {
|
|
36
|
+
return new RegExp(makeSafeRegexSource(source), flags);
|
|
37
|
+
}
|
|
38
|
+
const NUMERIC$1 = /^\d+$/;
|
|
39
|
+
function compareIdentifiers(left, right) {
|
|
40
|
+
if (typeof left === "number" && typeof right === "number") return left === right ? 0 : left < right ? -1 : 1;
|
|
41
|
+
const leftNumeric = NUMERIC$1.test(String(left));
|
|
42
|
+
const rightNumeric = NUMERIC$1.test(String(right));
|
|
43
|
+
const normalizedLeft = leftNumeric ? Number(left) : left;
|
|
44
|
+
const normalizedRight = rightNumeric ? Number(right) : right;
|
|
45
|
+
return normalizedLeft === normalizedRight ? 0 : leftNumeric && !rightNumeric ? -1 : rightNumeric && !leftNumeric ? 1 : normalizedLeft < normalizedRight ? -1 : 1;
|
|
46
|
+
}
|
|
47
|
+
const FULL = safeRegex(`^${FULL_PLAIN}$`);
|
|
48
|
+
const LOOSE = safeRegex(`^${LOOSE_PLAIN}$`);
|
|
49
|
+
safeRegex(`^${PRERELEASE}$`);
|
|
50
|
+
safeRegex(`^${PRERELEASE_LOOSE}$`);
|
|
51
|
+
const COERCE_EXACT = safeRegex(COERCE);
|
|
52
|
+
const COERCE_FULL_EXACT = safeRegex(COERCE_FULL);
|
|
53
|
+
const NUMERIC = /^\d+$/;
|
|
54
|
+
function formatComparableVersion(version) {
|
|
55
|
+
const base = `${version.major}.${version.minor}.${version.patch}`;
|
|
56
|
+
return version.prerelease?.length ? `${base}-${version.prerelease.join(".")}` : base;
|
|
57
|
+
}
|
|
58
|
+
function formatFullVersion(version) {
|
|
59
|
+
const comparable = formatComparableVersion(version);
|
|
60
|
+
return version.build?.length ? `${comparable}+${version.build.join(".")}` : comparable;
|
|
61
|
+
}
|
|
62
|
+
function parse(version, options = {}) {
|
|
63
|
+
if (typeof version !== "string") return version;
|
|
64
|
+
if (version.length > 256) throw new TypeError(`Version exceeds the maximum length of 256 characters`);
|
|
65
|
+
const match = version.trim().match(options.loose ? LOOSE : FULL);
|
|
66
|
+
if (!match) throw new TypeError(`Invalid version syntax: ${version}`);
|
|
67
|
+
const major = Number(match[1]);
|
|
68
|
+
const minor = Number(match[2]);
|
|
69
|
+
const patch = Number(match[3]);
|
|
70
|
+
if (major > Number.MAX_SAFE_INTEGER || major < 0) throw new TypeError(`Invalid major version: ${match[1]}`);
|
|
71
|
+
if (minor > Number.MAX_SAFE_INTEGER || minor < 0) throw new TypeError(`Invalid minor version: ${match[2]}`);
|
|
72
|
+
if (patch > Number.MAX_SAFE_INTEGER || patch < 0) throw new TypeError(`Invalid patch version: ${match[3]}`);
|
|
73
|
+
const prerelease = match[4] ? match[4].split(".").map((identifier) => {
|
|
74
|
+
if (NUMERIC.test(identifier)) {
|
|
75
|
+
const numeric = Number(identifier);
|
|
76
|
+
if (numeric >= 0 && numeric < Number.MAX_SAFE_INTEGER) return numeric;
|
|
77
|
+
}
|
|
78
|
+
return identifier;
|
|
79
|
+
}) : void 0;
|
|
80
|
+
return {
|
|
81
|
+
build: match[5]?.split("."),
|
|
82
|
+
major,
|
|
83
|
+
minor,
|
|
84
|
+
patch,
|
|
85
|
+
prerelease
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function tryParse(version, options = {}) {
|
|
89
|
+
try {
|
|
90
|
+
return parse(version, options);
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function compareMainParsed(left, right) {
|
|
96
|
+
return left.major === right.major ? left.minor === right.minor ? left.patch === right.patch ? 0 : left.patch < right.patch ? -1 : 1 : left.minor < right.minor ? -1 : 1 : left.major < right.major ? -1 : 1;
|
|
97
|
+
}
|
|
98
|
+
function comparePrereleaseParsed(left, right) {
|
|
99
|
+
const leftPrerelease = left.prerelease;
|
|
100
|
+
const rightPrerelease = right.prerelease;
|
|
101
|
+
if (leftPrerelease?.length && !rightPrerelease?.length) return -1;
|
|
102
|
+
if (!leftPrerelease?.length && rightPrerelease?.length) return 1;
|
|
103
|
+
if (!leftPrerelease?.length && !rightPrerelease?.length) return 0;
|
|
104
|
+
for (let index = 0;; index++) {
|
|
105
|
+
const leftIdentifier = leftPrerelease?.[index];
|
|
106
|
+
const rightIdentifier = rightPrerelease?.[index];
|
|
107
|
+
if (leftIdentifier === void 0 && rightIdentifier === void 0) return 0;
|
|
108
|
+
if (rightIdentifier === void 0) return 1;
|
|
109
|
+
if (leftIdentifier === void 0) return -1;
|
|
110
|
+
if (leftIdentifier !== rightIdentifier) return compareIdentifiers(leftIdentifier, rightIdentifier);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function compareParsed(left, right) {
|
|
114
|
+
return compareMainParsed(left, right) || comparePrereleaseParsed(left, right);
|
|
115
|
+
}
|
|
116
|
+
function coerceParsedVersion(value, options = {}) {
|
|
117
|
+
if (typeof value === "object") return value;
|
|
118
|
+
const input = typeof value === "number" ? String(value) : value;
|
|
119
|
+
if (typeof input !== "string") return null;
|
|
120
|
+
let match = null;
|
|
121
|
+
if (options.rtl) {
|
|
122
|
+
const expression = safeRegex(options.includePrerelease ? COERCE_FULL : COERCE, "g");
|
|
123
|
+
let next;
|
|
124
|
+
while ((next = expression.exec(input)) && (!match || match.index + match[0].length !== input.length)) {
|
|
125
|
+
if (!match || next.index + next[0].length !== match.index + match[0].length) match = next;
|
|
126
|
+
expression.lastIndex = next.index + next[1].length + next[2].length;
|
|
127
|
+
}
|
|
128
|
+
} else match = (options.includePrerelease ? COERCE_FULL_EXACT : COERCE_EXACT).exec(input);
|
|
129
|
+
if (!match) return null;
|
|
130
|
+
const major = match[2];
|
|
131
|
+
return tryParse(`${major}.${match[3] || "0"}.${match[4] || "0"}${options.includePrerelease && match[5] ? `-${match[5]}` : ""}${options.includePrerelease && match[6] ? `+${match[6]}` : ""}`, options);
|
|
132
|
+
}
|
|
133
|
+
const STRICT_COMPARATOR = safeRegex(String.raw`^${GREATER_LESS_THAN}\s*(${FULL_PLAIN})$|^$`);
|
|
134
|
+
const LOOSE_COMPARATOR$1 = safeRegex(String.raw`^${GREATER_LESS_THAN}\s*(${LOOSE_PLAIN})$|^$`);
|
|
135
|
+
function parseComparator(comparator, options = {}) {
|
|
136
|
+
const normalized = comparator.trim().replaceAll(/\s+/g, " ");
|
|
137
|
+
const match = normalized.match(options.loose ? LOOSE_COMPARATOR$1 : STRICT_COMPARATOR);
|
|
138
|
+
if (!match) throw new TypeError(`Invalid comparator: ${normalized}`);
|
|
139
|
+
const operator = match[1] === "=" ? "" : match[1] || "";
|
|
140
|
+
const version = match[2] ? parse(match[2], options) : null;
|
|
141
|
+
return {
|
|
142
|
+
operator,
|
|
143
|
+
options,
|
|
144
|
+
value: version ? `${operator}${formatComparableVersion(version)}` : "",
|
|
145
|
+
version
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
function testParsedComparator(comparator, version) {
|
|
149
|
+
if (!comparator.version) return true;
|
|
150
|
+
const comparison = compareParsed(version, comparator.version);
|
|
151
|
+
switch (comparator.operator) {
|
|
152
|
+
case "": return comparison === 0;
|
|
153
|
+
case ">": return comparison > 0;
|
|
154
|
+
case ">=": return comparison >= 0;
|
|
155
|
+
case "<": return comparison < 0;
|
|
156
|
+
case "<=": return comparison <= 0;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function comparatorAllowsPrerelease(comparator, version) {
|
|
160
|
+
const allowed = comparator.version;
|
|
161
|
+
return allowed !== null && !!allowed.prerelease?.length && allowed.major === version.major && allowed.minor === version.minor && allowed.patch === version.patch;
|
|
162
|
+
}
|
|
163
|
+
function testComparatorSet(set, version, options) {
|
|
164
|
+
if (set.some((comparator) => !testParsedComparator(comparator, version))) return false;
|
|
165
|
+
return !version.prerelease?.length || !!options.includePrerelease || set.some((comparator) => comparatorAllowsPrerelease(comparator, version));
|
|
166
|
+
}
|
|
167
|
+
function compare(left, right, options = {}) {
|
|
168
|
+
return compareParsed(parse(left, options), parse(right, options));
|
|
169
|
+
}
|
|
170
|
+
const BUILD_STRIP = new RegExp(BUILD, "g");
|
|
171
|
+
const BUILD_SAFE = safeRegex(BUILD);
|
|
172
|
+
const STRICT_HYPHEN = safeRegex(String.raw`^\s*(${XRANGE_PLAIN})\s+-\s+(${XRANGE_PLAIN})\s*$`);
|
|
173
|
+
const LOOSE_HYPHEN = safeRegex(String.raw`^\s*(${XRANGE_PLAIN_LOOSE})\s+-\s+(${XRANGE_PLAIN_LOOSE})\s*$`);
|
|
174
|
+
const COMPARATOR_TRIM = safeRegex(String.raw`(\s*)${GREATER_LESS_THAN}\s*(${LOOSE_PLAIN}|${XRANGE_PLAIN})`, "g");
|
|
175
|
+
const TILDE_TRIM = safeRegex(String.raw`(\s*)${LONE_TILDE}\s+`, "g");
|
|
176
|
+
const CARET_TRIM = safeRegex(String.raw`(\s*)${LONE_CARET}\s+`, "g");
|
|
177
|
+
const STRICT_TILDE = safeRegex(`^${LONE_TILDE}${XRANGE_PLAIN}$`);
|
|
178
|
+
const LOOSE_TILDE = safeRegex(`^${LONE_TILDE}${XRANGE_PLAIN_LOOSE}$`);
|
|
179
|
+
const STRICT_CARET = safeRegex(`^${LONE_CARET}${XRANGE_PLAIN}$`);
|
|
180
|
+
const LOOSE_CARET = safeRegex(`^${LONE_CARET}${XRANGE_PLAIN_LOOSE}$`);
|
|
181
|
+
const STRICT_XRANGE = safeRegex(String.raw`^${GREATER_LESS_THAN}\s*${XRANGE_PLAIN}$`);
|
|
182
|
+
const LOOSE_XRANGE = safeRegex(String.raw`^${GREATER_LESS_THAN}\s*${XRANGE_PLAIN_LOOSE}$`);
|
|
183
|
+
const STAR = safeRegex(String.raw`(<|>)?=?\s*\*`);
|
|
184
|
+
const GTE_ZERO = /^\s*>=\s*0\.0\.0\s*$/;
|
|
185
|
+
const GTE_ZERO_PRERELEASE = /^\s*>=\s*0\.0\.0-0\s*$/;
|
|
186
|
+
const LOOSE_COMPARATOR = safeRegex(String.raw`^${GREATER_LESS_THAN}\s*(${LOOSE_PLAIN})$|^$`);
|
|
187
|
+
function isWildcard(value) {
|
|
188
|
+
return !value || String(value).toLowerCase() === "x" || String(value) === "*";
|
|
189
|
+
}
|
|
190
|
+
function hasInvalidWildcardOrder(major, minor, patch) {
|
|
191
|
+
return isWildcard(major) && !isWildcard(minor) || isWildcard(minor) && Boolean(patch) && !isWildcard(patch);
|
|
192
|
+
}
|
|
193
|
+
function replaceTilde(comparator, options) {
|
|
194
|
+
const expression = options.loose ? LOOSE_TILDE : STRICT_TILDE;
|
|
195
|
+
const lowerPrerelease = options.includePrerelease ? "-0" : "";
|
|
196
|
+
return comparator.replace(expression, (_match, major, minor, patch, prerelease) => {
|
|
197
|
+
if (isWildcard(major)) return "";
|
|
198
|
+
if (isWildcard(minor)) return `>=${major}.0.0${lowerPrerelease} <${Number(major) + 1}.0.0-0`;
|
|
199
|
+
if (isWildcard(patch)) return `>=${major}.${minor}.0${lowerPrerelease} <${major}.${Number(minor) + 1}.0-0`;
|
|
200
|
+
return prerelease ? `>=${major}.${minor}.${patch}-${prerelease} <${major}.${Number(minor) + 1}.0-0` : `>=${major}.${minor}.${patch} <${major}.${Number(minor) + 1}.0-0`;
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
function replaceTildes(comparator, options) {
|
|
204
|
+
return comparator.trim().split(/\s+/).map((part) => replaceTilde(part, options)).join(" ");
|
|
205
|
+
}
|
|
206
|
+
function replaceCaret(comparator, options) {
|
|
207
|
+
const expression = options.loose ? LOOSE_CARET : STRICT_CARET;
|
|
208
|
+
const lowerPrerelease = options.includePrerelease ? "-0" : "";
|
|
209
|
+
return comparator.replace(expression, (_match, major, minor, patch, prerelease) => {
|
|
210
|
+
if (isWildcard(major)) return "";
|
|
211
|
+
if (isWildcard(minor)) return `>=${major}.0.0${lowerPrerelease} <${Number(major) + 1}.0.0-0`;
|
|
212
|
+
if (isWildcard(patch)) return major === "0" ? `>=${major}.${minor}.0${lowerPrerelease} <${major}.${Number(minor) + 1}.0-0` : `>=${major}.${minor}.0${lowerPrerelease} <${Number(major) + 1}.0.0-0`;
|
|
213
|
+
if (prerelease) return major === "0" ? minor === "0" ? `>=${major}.${minor}.${patch}-${prerelease} <${major}.${minor}.${Number(patch) + 1}-0` : `>=${major}.${minor}.${patch}-${prerelease} <${major}.${Number(minor) + 1}.0-0` : `>=${major}.${minor}.${patch}-${prerelease} <${Number(major) + 1}.0.0-0`;
|
|
214
|
+
return major === "0" ? minor === "0" ? `>=${major}.${minor}.${patch} <${major}.${minor}.${Number(patch) + 1}-0` : `>=${major}.${minor}.${patch} <${major}.${Number(minor) + 1}.0-0` : `>=${major}.${minor}.${patch} <${Number(major) + 1}.0.0-0`;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
function replaceCarets(comparator, options) {
|
|
218
|
+
return comparator.trim().split(/\s+/).map((part) => replaceCaret(part, options)).join(" ");
|
|
219
|
+
}
|
|
220
|
+
function replaceXRange(comparator, options) {
|
|
221
|
+
const expression = options.loose ? LOOSE_XRANGE : STRICT_XRANGE;
|
|
222
|
+
return comparator.trim().replace(expression, (match, rawOperator, rawMajor, rawMinor, rawPatch) => {
|
|
223
|
+
let operator = rawOperator;
|
|
224
|
+
let major = rawMajor;
|
|
225
|
+
let minor = rawMinor;
|
|
226
|
+
let patch = rawPatch;
|
|
227
|
+
if (hasInvalidWildcardOrder(String(major), minor === void 0 ? void 0 : String(minor), patch === void 0 ? void 0 : String(patch))) return comparator;
|
|
228
|
+
const wildcardMajor = isWildcard(major);
|
|
229
|
+
const wildcardMinor = wildcardMajor || isWildcard(minor);
|
|
230
|
+
const wildcardPatch = wildcardMinor || isWildcard(patch);
|
|
231
|
+
if (operator === "=" && wildcardPatch) operator = "";
|
|
232
|
+
if (wildcardMajor) return operator === ">" || operator === "<" ? "<0.0.0-0" : "*";
|
|
233
|
+
let prerelease = options.includePrerelease ? "-0" : "";
|
|
234
|
+
if (operator && wildcardPatch) {
|
|
235
|
+
if (wildcardMinor) minor = 0;
|
|
236
|
+
patch = 0;
|
|
237
|
+
if (operator === ">") {
|
|
238
|
+
operator = ">=";
|
|
239
|
+
if (wildcardMinor) {
|
|
240
|
+
major = Number(major) + 1;
|
|
241
|
+
minor = 0;
|
|
242
|
+
} else minor = Number(minor) + 1;
|
|
243
|
+
} else if (operator === "<=") {
|
|
244
|
+
operator = "<";
|
|
245
|
+
if (wildcardMinor) major = Number(major) + 1;
|
|
246
|
+
else minor = Number(minor) + 1;
|
|
247
|
+
}
|
|
248
|
+
if (operator === "<") prerelease = "-0";
|
|
249
|
+
return `${operator}${major}.${minor}.${patch}${prerelease}`;
|
|
250
|
+
}
|
|
251
|
+
if (wildcardMinor) return `>=${major}.0.0${prerelease} <${Number(major) + 1}.0.0-0`;
|
|
252
|
+
if (wildcardPatch) return `>=${major}.${minor}.0${prerelease} <${major}.${Number(minor) + 1}.0-0`;
|
|
253
|
+
return match;
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
function replaceXRanges(comparator, options) {
|
|
257
|
+
return comparator.split(/\s+/).map((part) => replaceXRange(part, options)).join(" ");
|
|
258
|
+
}
|
|
259
|
+
function replaceHyphenRange(range, options) {
|
|
260
|
+
const expression = options.loose ? LOOSE_HYPHEN : STRICT_HYPHEN;
|
|
261
|
+
return range.replace(expression, (_match, rawFrom, fromMajor, fromMinor, fromPatch, fromPrerelease, _fromBuild, rawTo, toMajor, toMinor, toPatch, toPrerelease) => {
|
|
262
|
+
let from = rawFrom;
|
|
263
|
+
let to = rawTo;
|
|
264
|
+
if (isWildcard(fromMajor)) from = "";
|
|
265
|
+
else if (isWildcard(fromMinor)) from = `>=${fromMajor}.0.0${options.includePrerelease ? "-0" : ""}`;
|
|
266
|
+
else if (isWildcard(fromPatch)) from = `>=${fromMajor}.${fromMinor}.0${options.includePrerelease ? "-0" : ""}`;
|
|
267
|
+
else if (fromPrerelease) from = `>=${from}`;
|
|
268
|
+
else from = `>=${from}${options.includePrerelease ? "-0" : ""}`;
|
|
269
|
+
if (isWildcard(toMajor)) to = "";
|
|
270
|
+
else if (isWildcard(toMinor)) to = `<${Number(toMajor) + 1}.0.0-0`;
|
|
271
|
+
else if (isWildcard(toPatch)) to = `<${toMajor}.${Number(toMinor) + 1}.0-0`;
|
|
272
|
+
else if (toPrerelease) to = `<=${toMajor}.${toMinor}.${toPatch}-${toPrerelease}`;
|
|
273
|
+
else if (options.includePrerelease) to = `<${toMajor}.${toMinor}.${Number(toPatch) + 1}-0`;
|
|
274
|
+
else to = `<=${to}`;
|
|
275
|
+
return `${from} ${to}`.trim();
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
function expandComparator(comparator, options) {
|
|
279
|
+
return replaceXRanges(replaceTildes(replaceCarets(comparator.replace(BUILD_SAFE, ""), options), options), options).trim().replace(STAR, "");
|
|
280
|
+
}
|
|
281
|
+
function parseSimpleRange(input, options) {
|
|
282
|
+
let parts = replaceHyphenRange(input.replace(BUILD_STRIP, ""), options).replace(COMPARATOR_TRIM, "$1$2$3").replace(TILDE_TRIM, "$1~").replace(CARET_TRIM, "$1^").split(" ").map((part) => expandComparator(part, options)).join(" ").split(/\s+/).map((part) => part.trim().replace(options.includePrerelease ? GTE_ZERO_PRERELEASE : GTE_ZERO, ""));
|
|
283
|
+
if (options.loose) parts = parts.filter((part) => LOOSE_COMPARATOR.test(part));
|
|
284
|
+
const unique = /* @__PURE__ */ new Map();
|
|
285
|
+
for (const comparator of parts.map((part) => parseComparator(part, options))) {
|
|
286
|
+
if (comparator.value === "<0.0.0-0") return [comparator];
|
|
287
|
+
unique.set(comparator.value, comparator);
|
|
288
|
+
}
|
|
289
|
+
if (unique.size > 1) unique.delete("");
|
|
290
|
+
return [...unique.values()];
|
|
291
|
+
}
|
|
292
|
+
function parseRange(range, options = {}) {
|
|
293
|
+
if (typeof range !== "string") return range;
|
|
294
|
+
const parsedOptions = { ...options };
|
|
295
|
+
const raw = range.trim().replaceAll(/\s+/g, " ");
|
|
296
|
+
let sets = raw.split("||").map((part) => parseSimpleRange(part.trim(), parsedOptions)).filter((set) => set.length);
|
|
297
|
+
if (!sets.length) throw new TypeError(`Range contains no valid comparator sets: ${raw}`);
|
|
298
|
+
if (sets.length > 1) {
|
|
299
|
+
const first = sets[0];
|
|
300
|
+
sets = sets.filter((set) => set[0]?.value !== "<0.0.0-0");
|
|
301
|
+
if (!sets.length) sets = [first];
|
|
302
|
+
else if (sets.length > 1) {
|
|
303
|
+
const any = sets.find((set) => set.length === 1 && set[0]?.value === "");
|
|
304
|
+
if (any) sets = [any];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
normalized: sets.map((set) => set.map((comparator) => comparator.value).join(" ")).join("||"),
|
|
309
|
+
options: parsedOptions,
|
|
310
|
+
raw,
|
|
311
|
+
sets
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
function tryParseRange(range, options = {}) {
|
|
315
|
+
try {
|
|
316
|
+
return parseRange(range, options);
|
|
317
|
+
} catch {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function testParsedRange(range, version) {
|
|
322
|
+
return range.sets.some((set) => testComparatorSet(set, version, range.options));
|
|
323
|
+
}
|
|
324
|
+
function testRangeVersion(range, version) {
|
|
325
|
+
const parsed = tryParse(version, range.options);
|
|
326
|
+
return parsed ? testParsedRange(range, parsed) : false;
|
|
327
|
+
}
|
|
328
|
+
function satisfies(version, range, options = {}) {
|
|
329
|
+
const parsed = tryParseRange(range, options);
|
|
330
|
+
return parsed ? testRangeVersion(parsed, version) : false;
|
|
331
|
+
}
|
|
332
|
+
function normalize(version, options = {}) {
|
|
333
|
+
const parsed = tryParse(version, options);
|
|
334
|
+
return parsed ? formatComparableVersion(parsed) : null;
|
|
335
|
+
}
|
|
336
|
+
function coerce(value, options = {}) {
|
|
337
|
+
const parsed = coerceParsedVersion(value, options);
|
|
338
|
+
return parsed ? formatFullVersion(parsed) : null;
|
|
339
|
+
}
|
|
340
|
+
//#endregion
|
|
341
|
+
export { coerce, compare, normalize, parseRange, satisfies };
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DatabaseBundleCursor, DatabaseBundleQueryOrder, Paginated } from "./types/index.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/paginateBundles.d.ts
|
|
4
|
-
declare function paginateBundles
|
|
4
|
+
declare function paginateBundles<TBundle extends {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
}>({
|
|
5
7
|
bundles,
|
|
6
8
|
limit,
|
|
7
9
|
offset,
|
|
8
10
|
cursor,
|
|
9
11
|
orderBy
|
|
10
12
|
}: {
|
|
11
|
-
bundles:
|
|
13
|
+
bundles: readonly TBundle[];
|
|
12
14
|
limit: number;
|
|
13
15
|
offset?: number;
|
|
14
16
|
cursor?: DatabaseBundleCursor;
|
|
15
17
|
orderBy?: DatabaseBundleQueryOrder;
|
|
16
|
-
}): Paginated<
|
|
18
|
+
}): Paginated<TBundle[]>;
|
|
17
19
|
//#endregion
|
|
18
20
|
export { paginateBundles };
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DatabaseBundleCursor, DatabaseBundleQueryOrder, Paginated } from "./types/index.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/paginateBundles.d.ts
|
|
4
|
-
declare function paginateBundles
|
|
4
|
+
declare function paginateBundles<TBundle extends {
|
|
5
|
+
readonly id: string;
|
|
6
|
+
}>({
|
|
5
7
|
bundles,
|
|
6
8
|
limit,
|
|
7
9
|
offset,
|
|
8
10
|
cursor,
|
|
9
11
|
orderBy
|
|
10
12
|
}: {
|
|
11
|
-
bundles:
|
|
13
|
+
bundles: readonly TBundle[];
|
|
12
14
|
limit: number;
|
|
13
15
|
offset?: number;
|
|
14
16
|
cursor?: DatabaseBundleCursor;
|
|
15
17
|
orderBy?: DatabaseBundleQueryOrder;
|
|
16
|
-
}): Paginated<
|
|
18
|
+
}): Paginated<TBundle[]>;
|
|
17
19
|
//#endregion
|
|
18
20
|
export { paginateBundles };
|
package/dist/parseStorageUri.cjs
CHANGED
|
@@ -1,41 +1,57 @@
|
|
|
1
1
|
//#region src/parseStorageUri.ts
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
const PROTOCOL_PATTERN = /^[a-z][a-z\d+.-]*$/;
|
|
3
|
+
const INVALID_BUCKET_CHARACTER_PATTERN = /[\s/?#%@:\\]/;
|
|
4
|
+
const assertProtocol = (protocol) => {
|
|
5
|
+
if (!PROTOCOL_PATTERN.test(protocol)) throw new Error(`Invalid storage URI protocol: ${protocol}`);
|
|
6
|
+
};
|
|
7
|
+
const assertBucket = (bucket) => {
|
|
8
|
+
if (bucket.length === 0 || INVALID_BUCKET_CHARACTER_PATTERN.test(bucket)) throw new Error(`Invalid storage URI bucket: ${bucket}`);
|
|
9
|
+
};
|
|
10
|
+
const getKeySegments = (key) => {
|
|
11
|
+
if (key.length === 0) throw new Error("Invalid storage URI key: key must not be empty");
|
|
12
|
+
const segments = key.split("/");
|
|
13
|
+
if (segments.some((segment) => segment.length === 0 || segment === "." || segment === ".." || segment.includes("\\"))) throw new Error("Invalid storage URI key: segments must not be empty, '.', '..' or contain '\\'");
|
|
14
|
+
return segments;
|
|
8
15
|
};
|
|
9
16
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
* Creates a hierarchical storage identifier in the form
|
|
18
|
+
* `protocol://bucket/slash-separated-encoded-key`.
|
|
19
|
+
*/
|
|
20
|
+
const createStorageUri = ({ protocol, bucket, key }) => {
|
|
21
|
+
assertProtocol(protocol);
|
|
22
|
+
assertBucket(bucket);
|
|
23
|
+
return `${protocol}://${bucket}/${getKeySegments(key).map(encodeURIComponent).join("/")}`;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Parses a hierarchical storage identifier and decodes each key segment.
|
|
16
27
|
*
|
|
17
|
-
*
|
|
18
|
-
* ```typescript
|
|
19
|
-
* const { bucket, key } = parseStorageUri("s3://my-bucket/path/to/file.zip", "s3");
|
|
20
|
-
* // bucket: "my-bucket"
|
|
21
|
-
* // key: "path/to/file.zip"
|
|
22
|
-
* ```
|
|
28
|
+
* Search parameters and fragments are not part of a storage identifier.
|
|
23
29
|
*/
|
|
24
30
|
function parseStorageUri(storageUri, expectedProtocol) {
|
|
31
|
+
assertProtocol(expectedProtocol);
|
|
32
|
+
if (storageUri.includes("?") || storageUri.includes("#")) throw new Error(`Invalid storage URI format: ${storageUri}`);
|
|
33
|
+
const match = /^([a-z][a-z\d+.-]*):\/\/([^/]+)\/(.*)$/.exec(storageUri);
|
|
34
|
+
if (!match) throw new Error(`Invalid storage URI format: ${storageUri}`);
|
|
35
|
+
const [, protocol, bucket, encodedKey] = match;
|
|
36
|
+
if (protocol !== expectedProtocol) throw new Error(`Invalid storage URI protocol. Expected ${expectedProtocol}, got ${protocol}`);
|
|
37
|
+
assertBucket(bucket);
|
|
38
|
+
let segments;
|
|
25
39
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
} catch (error) {
|
|
35
|
-
if (error instanceof TypeError) throw new Error(`Invalid storage URI format: ${storageUri}`);
|
|
36
|
-
throw error;
|
|
40
|
+
segments = getKeySegments(encodedKey).map((segment) => {
|
|
41
|
+
const decoded = decodeURIComponent(segment);
|
|
42
|
+
if (decoded.includes("/") || decoded.includes("\\")) throw new Error("encoded hierarchy separator");
|
|
43
|
+
if (encodeURIComponent(decoded) !== segment) throw new Error("non-canonical segment");
|
|
44
|
+
return decoded;
|
|
45
|
+
});
|
|
46
|
+
} catch {
|
|
47
|
+
throw new Error(`Invalid storage URI format: ${storageUri}`);
|
|
37
48
|
}
|
|
49
|
+
return {
|
|
50
|
+
protocol,
|
|
51
|
+
bucket,
|
|
52
|
+
key: segments.join("/")
|
|
53
|
+
};
|
|
38
54
|
}
|
|
39
55
|
//#endregion
|
|
40
|
-
exports.
|
|
56
|
+
exports.createStorageUri = createStorageUri;
|
|
41
57
|
exports.parseStorageUri = parseStorageUri;
|
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
//#region src/parseStorageUri.d.ts
|
|
2
2
|
interface ParsedStorageUri {
|
|
3
|
-
protocol: string;
|
|
4
|
-
bucket: string;
|
|
5
|
-
key: string;
|
|
3
|
+
readonly protocol: string;
|
|
4
|
+
readonly bucket: string;
|
|
5
|
+
readonly key: string;
|
|
6
|
+
}
|
|
7
|
+
interface CreateStorageUriInput {
|
|
8
|
+
readonly protocol: string;
|
|
9
|
+
readonly bucket: string;
|
|
10
|
+
readonly key: string;
|
|
6
11
|
}
|
|
7
|
-
declare const decodeStorageObjectKey: (key: string) => string;
|
|
8
12
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
* Creates a hierarchical storage identifier in the form
|
|
14
|
+
* `protocol://bucket/slash-separated-encoded-key`.
|
|
15
|
+
*/
|
|
16
|
+
declare const createStorageUri: ({
|
|
17
|
+
protocol,
|
|
18
|
+
bucket,
|
|
19
|
+
key
|
|
20
|
+
}: CreateStorageUriInput) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Parses a hierarchical storage identifier and decodes each key segment.
|
|
15
23
|
*
|
|
16
|
-
*
|
|
17
|
-
* ```typescript
|
|
18
|
-
* const { bucket, key } = parseStorageUri("s3://my-bucket/path/to/file.zip", "s3");
|
|
19
|
-
* // bucket: "my-bucket"
|
|
20
|
-
* // key: "path/to/file.zip"
|
|
21
|
-
* ```
|
|
24
|
+
* Search parameters and fragments are not part of a storage identifier.
|
|
22
25
|
*/
|
|
23
26
|
declare function parseStorageUri(storageUri: string, expectedProtocol: string): ParsedStorageUri;
|
|
24
27
|
//#endregion
|
|
25
|
-
export { ParsedStorageUri,
|
|
28
|
+
export { CreateStorageUriInput, ParsedStorageUri, createStorageUri, parseStorageUri };
|
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
//#region src/parseStorageUri.d.ts
|
|
2
2
|
interface ParsedStorageUri {
|
|
3
|
-
protocol: string;
|
|
4
|
-
bucket: string;
|
|
5
|
-
key: string;
|
|
3
|
+
readonly protocol: string;
|
|
4
|
+
readonly bucket: string;
|
|
5
|
+
readonly key: string;
|
|
6
|
+
}
|
|
7
|
+
interface CreateStorageUriInput {
|
|
8
|
+
readonly protocol: string;
|
|
9
|
+
readonly bucket: string;
|
|
10
|
+
readonly key: string;
|
|
6
11
|
}
|
|
7
|
-
declare const decodeStorageObjectKey: (key: string) => string;
|
|
8
12
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
* Creates a hierarchical storage identifier in the form
|
|
14
|
+
* `protocol://bucket/slash-separated-encoded-key`.
|
|
15
|
+
*/
|
|
16
|
+
declare const createStorageUri: ({
|
|
17
|
+
protocol,
|
|
18
|
+
bucket,
|
|
19
|
+
key
|
|
20
|
+
}: CreateStorageUriInput) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Parses a hierarchical storage identifier and decodes each key segment.
|
|
15
23
|
*
|
|
16
|
-
*
|
|
17
|
-
* ```typescript
|
|
18
|
-
* const { bucket, key } = parseStorageUri("s3://my-bucket/path/to/file.zip", "s3");
|
|
19
|
-
* // bucket: "my-bucket"
|
|
20
|
-
* // key: "path/to/file.zip"
|
|
21
|
-
* ```
|
|
24
|
+
* Search parameters and fragments are not part of a storage identifier.
|
|
22
25
|
*/
|
|
23
26
|
declare function parseStorageUri(storageUri: string, expectedProtocol: string): ParsedStorageUri;
|
|
24
27
|
//#endregion
|
|
25
|
-
export { ParsedStorageUri,
|
|
28
|
+
export { CreateStorageUriInput, ParsedStorageUri, createStorageUri, parseStorageUri };
|
package/dist/parseStorageUri.mjs
CHANGED
|
@@ -1,40 +1,56 @@
|
|
|
1
1
|
//#region src/parseStorageUri.ts
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
const PROTOCOL_PATTERN = /^[a-z][a-z\d+.-]*$/;
|
|
3
|
+
const INVALID_BUCKET_CHARACTER_PATTERN = /[\s/?#%@:\\]/;
|
|
4
|
+
const assertProtocol = (protocol) => {
|
|
5
|
+
if (!PROTOCOL_PATTERN.test(protocol)) throw new Error(`Invalid storage URI protocol: ${protocol}`);
|
|
6
|
+
};
|
|
7
|
+
const assertBucket = (bucket) => {
|
|
8
|
+
if (bucket.length === 0 || INVALID_BUCKET_CHARACTER_PATTERN.test(bucket)) throw new Error(`Invalid storage URI bucket: ${bucket}`);
|
|
9
|
+
};
|
|
10
|
+
const getKeySegments = (key) => {
|
|
11
|
+
if (key.length === 0) throw new Error("Invalid storage URI key: key must not be empty");
|
|
12
|
+
const segments = key.split("/");
|
|
13
|
+
if (segments.some((segment) => segment.length === 0 || segment === "." || segment === ".." || segment.includes("\\"))) throw new Error("Invalid storage URI key: segments must not be empty, '.', '..' or contain '\\'");
|
|
14
|
+
return segments;
|
|
8
15
|
};
|
|
9
16
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
* Creates a hierarchical storage identifier in the form
|
|
18
|
+
* `protocol://bucket/slash-separated-encoded-key`.
|
|
19
|
+
*/
|
|
20
|
+
const createStorageUri = ({ protocol, bucket, key }) => {
|
|
21
|
+
assertProtocol(protocol);
|
|
22
|
+
assertBucket(bucket);
|
|
23
|
+
return `${protocol}://${bucket}/${getKeySegments(key).map(encodeURIComponent).join("/")}`;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Parses a hierarchical storage identifier and decodes each key segment.
|
|
16
27
|
*
|
|
17
|
-
*
|
|
18
|
-
* ```typescript
|
|
19
|
-
* const { bucket, key } = parseStorageUri("s3://my-bucket/path/to/file.zip", "s3");
|
|
20
|
-
* // bucket: "my-bucket"
|
|
21
|
-
* // key: "path/to/file.zip"
|
|
22
|
-
* ```
|
|
28
|
+
* Search parameters and fragments are not part of a storage identifier.
|
|
23
29
|
*/
|
|
24
30
|
function parseStorageUri(storageUri, expectedProtocol) {
|
|
31
|
+
assertProtocol(expectedProtocol);
|
|
32
|
+
if (storageUri.includes("?") || storageUri.includes("#")) throw new Error(`Invalid storage URI format: ${storageUri}`);
|
|
33
|
+
const match = /^([a-z][a-z\d+.-]*):\/\/([^/]+)\/(.*)$/.exec(storageUri);
|
|
34
|
+
if (!match) throw new Error(`Invalid storage URI format: ${storageUri}`);
|
|
35
|
+
const [, protocol, bucket, encodedKey] = match;
|
|
36
|
+
if (protocol !== expectedProtocol) throw new Error(`Invalid storage URI protocol. Expected ${expectedProtocol}, got ${protocol}`);
|
|
37
|
+
assertBucket(bucket);
|
|
38
|
+
let segments;
|
|
25
39
|
try {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
} catch (error) {
|
|
35
|
-
if (error instanceof TypeError) throw new Error(`Invalid storage URI format: ${storageUri}`);
|
|
36
|
-
throw error;
|
|
40
|
+
segments = getKeySegments(encodedKey).map((segment) => {
|
|
41
|
+
const decoded = decodeURIComponent(segment);
|
|
42
|
+
if (decoded.includes("/") || decoded.includes("\\")) throw new Error("encoded hierarchy separator");
|
|
43
|
+
if (encodeURIComponent(decoded) !== segment) throw new Error("non-canonical segment");
|
|
44
|
+
return decoded;
|
|
45
|
+
});
|
|
46
|
+
} catch {
|
|
47
|
+
throw new Error(`Invalid storage URI format: ${storageUri}`);
|
|
37
48
|
}
|
|
49
|
+
return {
|
|
50
|
+
protocol,
|
|
51
|
+
bucket,
|
|
52
|
+
key: segments.join("/")
|
|
53
|
+
};
|
|
38
54
|
}
|
|
39
55
|
//#endregion
|
|
40
|
-
export {
|
|
56
|
+
export { createStorageUri, parseStorageUri };
|