92 lines
3.1 KiB
JavaScript
92 lines
3.1 KiB
JavaScript
export const MAX_CHUNK_SIZE = 3180;
|
|
const CHUNK_LIKE_REGEX = /^(.*)[.](0|[1-9][0-9]*)$/;
|
|
export function isChunkLike(cookieName, key) {
|
|
if (cookieName === key) {
|
|
return true;
|
|
}
|
|
const chunkLike = cookieName.match(CHUNK_LIKE_REGEX);
|
|
if (chunkLike && chunkLike[1] === key) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
/**
|
|
* create chunks from a string and return an array of object
|
|
*/
|
|
export function createChunks(key, value, chunkSize) {
|
|
const resolvedChunkSize = chunkSize ?? MAX_CHUNK_SIZE;
|
|
let encodedValue = encodeURIComponent(value);
|
|
if (encodedValue.length <= resolvedChunkSize) {
|
|
return [{ name: key, value }];
|
|
}
|
|
const chunks = [];
|
|
while (encodedValue.length > 0) {
|
|
let encodedChunkHead = encodedValue.slice(0, resolvedChunkSize);
|
|
const lastEscapePos = encodedChunkHead.lastIndexOf("%");
|
|
// Check if the last escaped character is truncated.
|
|
if (lastEscapePos > resolvedChunkSize - 3) {
|
|
// If so, reslice the string to exclude the whole escape sequence.
|
|
// We only reduce the size of the string as the chunk must
|
|
// be smaller than the chunk size.
|
|
encodedChunkHead = encodedChunkHead.slice(0, lastEscapePos);
|
|
}
|
|
let valueHead = "";
|
|
// Check if the chunk was split along a valid unicode boundary.
|
|
while (encodedChunkHead.length > 0) {
|
|
try {
|
|
// Try to decode the chunk back and see if it is valid.
|
|
// Stop when the chunk is valid.
|
|
valueHead = decodeURIComponent(encodedChunkHead);
|
|
break;
|
|
}
|
|
catch (error) {
|
|
if (error instanceof URIError &&
|
|
encodedChunkHead.at(-3) === "%" &&
|
|
encodedChunkHead.length > 3) {
|
|
encodedChunkHead = encodedChunkHead.slice(0, encodedChunkHead.length - 3);
|
|
}
|
|
else {
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
chunks.push(valueHead);
|
|
encodedValue = encodedValue.slice(encodedChunkHead.length);
|
|
}
|
|
return chunks.map((value, i) => ({ name: `${key}.${i}`, value }));
|
|
}
|
|
// Get fully constructed chunks
|
|
export async function combineChunks(key, retrieveChunk) {
|
|
const value = await retrieveChunk(key);
|
|
if (value) {
|
|
return value;
|
|
}
|
|
let values = [];
|
|
for (let i = 0;; i++) {
|
|
const chunkName = `${key}.${i}`;
|
|
const chunk = await retrieveChunk(chunkName);
|
|
if (!chunk) {
|
|
break;
|
|
}
|
|
values.push(chunk);
|
|
}
|
|
if (values.length > 0) {
|
|
return values.join("");
|
|
}
|
|
return null;
|
|
}
|
|
export async function deleteChunks(key, retrieveChunk, removeChunk) {
|
|
const value = await retrieveChunk(key);
|
|
if (value) {
|
|
await removeChunk(key);
|
|
}
|
|
for (let i = 0;; i++) {
|
|
const chunkName = `${key}.${i}`;
|
|
const chunk = await retrieveChunk(chunkName);
|
|
if (!chunk) {
|
|
break;
|
|
}
|
|
await removeChunk(chunkName);
|
|
}
|
|
}
|
|
//# sourceMappingURL=chunker.js.map
|