@intlayer/config
Version:
Retrieve Intlayer configurations and manage environment variables for both server-side and client-side environments.
1 lines • 10.2 kB
Source Map (JSON)
{"version":3,"file":"getStorageAttributes.mjs","names":[],"sources":["../../../src/utils/getStorageAttributes.ts"],"sourcesContent":["import type {\n CookiesAttributes,\n ProcessedCookieAttributes,\n ProcessedStorageAttributes,\n RoutingStorageInput,\n StorageAttributes,\n} from '@intlayer/types/config';\nimport {\n COOKIE_NAME,\n HEADER_NAME,\n LOCALE_STORAGE_NAME,\n} from '../defaultValues/routing';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ntype CookieEntry = {\n name: string;\n attributes: ProcessedCookieAttributes;\n};\n\n/** Number of seconds in a day, used to convert a `number` of days. */\nconst SECONDS_PER_DAY = 60 * 60 * 24;\n\ntype WebStorageEntry = {\n name: string;\n};\n\ntype HeaderEntry = {\n name: string;\n};\n\ntype StorageEntry =\n | 'cookie'\n | 'localStorage'\n | 'sessionStorage'\n | 'header'\n | CookiesAttributes\n | StorageAttributes;\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Merges the user-facing `expires` and `maxAge` into a single, normalized and\n * serialization-safe expiry consumed by the client runtime.\n *\n * Precedence and normalization:\n * - `maxAge` (seconds) wins when set and is the internal unit (relative);\n * - `expires` as a `number` is interpreted as **days** and converted to\n * seconds (relative);\n * - `expires` as a `Date` (possibly a cross-realm instance, since config files\n * run in a `node:vm` sandbox) or an ISO string becomes an ISO **string**\n * (absolute). Strings survive `JSON.stringify`, unlike a `Date`.\n *\n * The result is therefore: a `number` = seconds from creation, a `string` =\n * absolute ISO date, or `undefined` for a session cookie.\n */\nconst normalizeCookieExpiry = (\n expires: CookiesAttributes['expires'],\n maxAge: CookiesAttributes['maxAge']\n): number | string | undefined => {\n if (typeof maxAge === 'number') return maxAge;\n if (expires === undefined) return undefined;\n if (\n expires instanceof Date ||\n Object.prototype.toString.call(expires) === '[object Date]'\n ) {\n return (expires as Date).toISOString();\n }\n if (typeof expires === 'string') return expires;\n return expires * SECONDS_PER_DAY;\n};\n\nconst createCookieEntry = (\n options?: Partial<CookiesAttributes>\n): CookieEntry => {\n const {\n name,\n path = '/',\n expires,\n maxAge,\n domain,\n secure,\n sameSite,\n httpOnly,\n } = options ?? {};\n return {\n name: name ?? COOKIE_NAME,\n attributes: {\n path,\n expires: normalizeCookieExpiry(expires, maxAge),\n domain,\n secure,\n sameSite,\n httpOnly,\n },\n };\n};\n\nconst createWebStorageEntry = (\n options?: Partial<StorageAttributes>\n): WebStorageEntry => ({\n name: options?.name ?? LOCALE_STORAGE_NAME,\n});\n\nconst createHeaderEntry = (\n options?: Partial<StorageAttributes>\n): HeaderEntry => ({\n name: options?.name ?? HEADER_NAME,\n});\n\nconst isCookieEntry = (entry: unknown): boolean => {\n if (typeof entry !== 'object' || entry === null) return false;\n const e = entry as Record<string, unknown>;\n return (\n e['type'] === 'cookie' ||\n 'sameSite' in e ||\n 'httpOnly' in e ||\n 'secure' in e\n );\n};\n\nconst isStorageType = (\n value: string\n): value is 'cookie' | 'localStorage' | 'sessionStorage' | 'header' =>\n value === 'cookie' ||\n value === 'localStorage' ||\n value === 'sessionStorage' ||\n value === 'header';\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\nconst processStorageEntry = (\n entry: StorageEntry\n): Partial<ProcessedStorageAttributes> => {\n if (typeof entry === 'string') {\n if (!isStorageType(entry)) {\n return { cookies: [], localStorage: [], sessionStorage: [], headers: [] };\n }\n if (entry === 'cookie') return { cookies: [createCookieEntry()] };\n if (entry === 'localStorage')\n return { localStorage: [createWebStorageEntry()] };\n if (entry === 'sessionStorage')\n return { sessionStorage: [createWebStorageEntry()] };\n if (entry === 'header') return { headers: [createHeaderEntry()] };\n }\n\n if (typeof entry === 'object' && entry !== null) {\n const typedEntry = entry as CookiesAttributes | StorageAttributes;\n\n if (isCookieEntry(typedEntry)) {\n return { cookies: [createCookieEntry(typedEntry as CookiesAttributes)] };\n }\n if ('type' in typedEntry && typedEntry.type === 'localStorage') {\n return {\n localStorage: [createWebStorageEntry(typedEntry as StorageAttributes)],\n };\n }\n if ('type' in typedEntry && typedEntry.type === 'sessionStorage') {\n return {\n sessionStorage: [\n createWebStorageEntry(typedEntry as StorageAttributes),\n ],\n };\n }\n if ('type' in typedEntry && typedEntry.type === 'header') {\n return { headers: [createHeaderEntry(typedEntry as StorageAttributes)] };\n }\n // Default to localStorage for ambiguous objects\n return {\n localStorage: [\n createWebStorageEntry(typedEntry as Omit<StorageAttributes, 'type'>),\n ],\n };\n }\n\n return { cookies: [], localStorage: [], sessionStorage: [], headers: [] };\n};\n\nconst mergeStorageAttributes = (\n accumulated: ProcessedStorageAttributes,\n partial: Partial<ProcessedStorageAttributes>\n): ProcessedStorageAttributes => ({\n cookies: [...(accumulated.cookies ?? []), ...(partial.cookies ?? [])],\n localStorage: [\n ...(accumulated.localStorage ?? []),\n ...(partial.localStorage ?? []),\n ],\n sessionStorage: [\n ...(accumulated.sessionStorage ?? []),\n ...(partial.sessionStorage ?? []),\n ],\n headers: [...(accumulated.headers ?? []), ...(partial.headers ?? [])],\n});\n\n/**\n * Extracts and normalizes storage configuration into separate arrays for each storage type.\n * Called at config-build time so the result is pre-computed and stored in the config.\n *\n * @param options - The storage configuration from IntlayerConfig\n * @returns An object containing arrays for cookies, localStorage, sessionStorage and headers\n */\nexport const getStorageAttributes = (\n options: RoutingStorageInput\n): ProcessedStorageAttributes => {\n const emptyResult: ProcessedStorageAttributes = {\n cookies: [],\n localStorage: [],\n sessionStorage: [],\n headers: [],\n };\n\n if (options === false || options === undefined) return {};\n\n const result = Array.isArray(options)\n ? options.reduce<ProcessedStorageAttributes>((acc, entry) => {\n const partial = processStorageEntry(entry);\n return mergeStorageAttributes(acc, partial);\n }, emptyResult)\n : mergeStorageAttributes(emptyResult, processStorageEntry(options));\n\n // Remove empty arrays\n const cleanedResult: ProcessedStorageAttributes = {};\n\n if (result.cookies && result.cookies.length > 0) {\n cleanedResult.cookies = result.cookies;\n }\n\n if (result.localStorage && result.localStorage.length > 0) {\n cleanedResult.localStorage = result.localStorage;\n }\n\n if (result.sessionStorage && result.sessionStorage.length > 0) {\n cleanedResult.sessionStorage = result.sessionStorage;\n }\n\n if (result.headers && result.headers.length > 0) {\n cleanedResult.headers = result.headers;\n }\n\n return cleanedResult;\n};\n"],"mappings":"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"}