103 lines
3.0 KiB
JavaScript
103 lines
3.0 KiB
JavaScript
const APP_NAMESPACE = "ca-frontend";
|
|
|
|
export const STORAGE_REGISTRY = Object.freeze({
|
|
COLOR_SCHEME: defineStorageKey({
|
|
logicalName: "COLOR_SCHEME",
|
|
scope: "preference",
|
|
name: "color-scheme",
|
|
backend: "localStorage",
|
|
classification: "public-preference",
|
|
schemaVersion: 1,
|
|
ttl: null,
|
|
migration: "discard",
|
|
quotaFallback: "memory",
|
|
}),
|
|
CHUNK_RELOAD_GUARD: defineStorageKey({
|
|
logicalName: "CHUNK_RELOAD_GUARD",
|
|
scope: "release",
|
|
name: "chunk-reload-guard",
|
|
backend: "sessionStorage",
|
|
classification: "opaque-cache",
|
|
schemaVersion: 1,
|
|
ttl: "session",
|
|
migration: "discard",
|
|
quotaFallback: "no-persist",
|
|
}),
|
|
QUERY_PERSISTENCE: defineStorageKey({
|
|
logicalName: "QUERY_PERSISTENCE",
|
|
scope: "cache",
|
|
name: "query-persistence",
|
|
backend: "disabled",
|
|
classification: "sensitive-forbidden",
|
|
schemaVersion: 1,
|
|
ttl: null,
|
|
migration: "discard",
|
|
quotaFallback: "feature-disable",
|
|
}),
|
|
AUTH_TOKEN: defineStorageKey({
|
|
logicalName: "AUTH_TOKEN",
|
|
scope: "auth",
|
|
name: "auth-token",
|
|
backend: "forbidden",
|
|
classification: "sensitive-forbidden",
|
|
schemaVersion: 1,
|
|
ttl: null,
|
|
migration: "discard",
|
|
quotaFallback: "feature-disable",
|
|
}),
|
|
});
|
|
|
|
/**
|
|
* @typedef {{
|
|
* logicalName: string,
|
|
* scope: string,
|
|
* name: string,
|
|
* backend: "memory" | "sessionStorage" | "localStorage" | "indexedDB" |
|
|
* "disabled" | "forbidden",
|
|
* classification: "public-preference" | "opaque-cache" | "sensitive-forbidden",
|
|
* schemaVersion: number,
|
|
* ttl: number | "session" | null,
|
|
* migration: "discard" | ((value: unknown) => unknown),
|
|
* quotaFallback: "memory" | "no-persist" | "feature-disable"
|
|
* }} StorageKeyInput
|
|
*/
|
|
|
|
/** @param {StorageKeyInput} definition */
|
|
export function defineStorageKey(definition) {
|
|
if (definition.classification === "sensitive-forbidden") {
|
|
if (!["disabled", "forbidden"].includes(definition.backend)) {
|
|
throw new Error("Sensitive client storage registration is forbidden");
|
|
}
|
|
}
|
|
if (!Number.isInteger(definition.schemaVersion) || definition.schemaVersion < 1) {
|
|
throw new Error("Storage schemaVersion must be a positive integer");
|
|
}
|
|
|
|
return Object.freeze({
|
|
...definition,
|
|
physicalKey: buildPhysicalKey(
|
|
definition.scope,
|
|
definition.schemaVersion,
|
|
definition.name,
|
|
),
|
|
});
|
|
}
|
|
|
|
/** @param {string} scope @param {number} schemaVersion @param {string} name */
|
|
export function buildPhysicalKey(scope, schemaVersion, name) {
|
|
return `${APP_NAMESPACE}:${scope}:v${schemaVersion}:${name}`;
|
|
}
|
|
|
|
/** @param {string} logicalName */
|
|
export function getStorageDefinition(logicalName) {
|
|
const registry = /** @type {Record<string, ReturnType<typeof defineStorageKey>>} */ (
|
|
STORAGE_REGISTRY
|
|
);
|
|
const definition = registry[logicalName];
|
|
if (!definition) throw new Error(`Unregistered storage key: ${logicalName}`);
|
|
if (definition.classification === "sensitive-forbidden") {
|
|
throw new Error(`Forbidden storage key: ${logicalName}`);
|
|
}
|
|
return definition;
|
|
}
|