73 lines
2.2 KiB
JavaScript
73 lines
2.2 KiB
JavaScript
|
|
export function defineDriver(factory) {
|
||
|
|
return factory;
|
||
|
|
}
|
||
|
|
export function normalizeKey(key, sep = ":") {
|
||
|
|
if (!key) {
|
||
|
|
return "";
|
||
|
|
}
|
||
|
|
return key.replace(/[:/\\]/g, sep).replace(/^[:/\\]|[:/\\]$/g, "");
|
||
|
|
}
|
||
|
|
export function joinKeys(...keys) {
|
||
|
|
return keys.map((key) => normalizeKey(key)).filter(Boolean).join(":");
|
||
|
|
}
|
||
|
|
export function encodeURLSegment(driver, segment, key = segment) {
|
||
|
|
if (!segment || segment === "." || segment === "..") {
|
||
|
|
throw createError(
|
||
|
|
driver,
|
||
|
|
`Invalid key: ${JSON.stringify(key)}. Empty, "." and ".." segments are not allowed`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
try {
|
||
|
|
return encodeURIComponent(segment);
|
||
|
|
} catch {
|
||
|
|
throw createError(
|
||
|
|
driver,
|
||
|
|
`Invalid key: ${JSON.stringify(key)}. It contains malformed unicode`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
export function encodeURLKey(driver, key) {
|
||
|
|
return (key || "").split(/[:/\\]/).filter(Boolean).map((segment) => encodeURLSegment(driver, segment, key)).join("/");
|
||
|
|
}
|
||
|
|
export function assertURLPathKey(driver, key) {
|
||
|
|
const invalid = (reason) => createError(driver, `Invalid key: ${JSON.stringify(key)}. ${reason}`);
|
||
|
|
if (!key) {
|
||
|
|
throw invalid("Empty keys are not allowed");
|
||
|
|
}
|
||
|
|
if (/[?#]/.test(key)) {
|
||
|
|
throw invalid(`"?" and "#" are not allowed`);
|
||
|
|
}
|
||
|
|
if (/[\u0000-\u001F]|^ | $/.test(key)) {
|
||
|
|
throw invalid(
|
||
|
|
"Control characters and leading/trailing spaces are not allowed"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
const hasDotSegment = key.split(/[/\\]|%2f|%5c/i).some((segment) => {
|
||
|
|
segment = segment.replace(/%2e/gi, ".");
|
||
|
|
return segment === "." || segment === "..";
|
||
|
|
});
|
||
|
|
if (hasDotSegment) {
|
||
|
|
throw invalid(`"." and ".." segments are not allowed`);
|
||
|
|
}
|
||
|
|
return key;
|
||
|
|
}
|
||
|
|
export function escapeRedisGlob(pattern) {
|
||
|
|
return pattern.replace(/[*?[\]\\]/g, String.raw`\$&`);
|
||
|
|
}
|
||
|
|
export function createError(driver, message, opts) {
|
||
|
|
const err = new Error(`[unstorage] [${driver}] ${message}`, opts);
|
||
|
|
if (Error.captureStackTrace) {
|
||
|
|
Error.captureStackTrace(err, createError);
|
||
|
|
}
|
||
|
|
return err;
|
||
|
|
}
|
||
|
|
export function createRequiredError(driver, name) {
|
||
|
|
if (Array.isArray(name)) {
|
||
|
|
return createError(
|
||
|
|
driver,
|
||
|
|
`Missing some of the required options ${name.map((n) => "`" + n + "`").join(", ")}`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
return createError(driver, `Missing required option \`${name}\`.`);
|
||
|
|
}
|