UNPKG

@lucidcms/core

Version:

The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.

1 lines 7.39 kB
{"version":3,"file":"data.mjs","names":["constants"],"sources":["../../../../src/libs/email/storage/data.ts"],"sourcesContent":["import constants from \"../../../constants/constants.js\";\nimport type { ServiceResponse } from \"../../../utils/services/types.js\";\nimport { parseEmailStorageRules } from \"./config.js\";\nimport {\n\tdecryptEmailStorageValue,\n\tencryptEmailStorageValue,\n} from \"./encryption.js\";\nimport {\n\tcloneValue,\n\temailStorageSegmentsToPath,\n\tgetValueAtEmailStoragePath,\n\tremoveValueAtEmailStoragePath,\n\tresolveExistingEmailStoragePaths,\n\tsetValueAtEmailStoragePath,\n} from \"./paths.js\";\nimport type { EmailStorageConfig, ParsedEmailStorageRule } from \"./types.js\";\n\nconst sortRules = (\n\trules: ParsedEmailStorageRule[],\n\tdirection: \"specific\" | \"broad\",\n) =>\n\t[...rules].sort((a, b) => {\n\t\tconst specificityDiff =\n\t\t\tdirection === \"specific\"\n\t\t\t\t? b.specificity - a.specificity\n\t\t\t\t: a.specificity - b.specificity;\n\n\t\tif (specificityDiff !== 0) return specificityDiff;\n\t\treturn a.index - b.index;\n\t});\n\n/**\n * Builds the DB-safe email data payload, encrypting configured fields first.\n */\nexport const createStoredEmailData = (props: {\n\tdata: Record<string, unknown> | null;\n\tstorage?: EmailStorageConfig | null;\n\tencryptionKey: string;\n\toptions?: {\n\t\tencryptNeverStore?: boolean;\n\t};\n}): Awaited<ServiceResponse<Record<string, unknown> | null>> => {\n\tif (props.data === null) return { error: undefined, data: null };\n\n\tconst rulesRes = parseEmailStorageRules(props.storage);\n\tif (rulesRes.error) return rulesRes;\n\n\tconst data = cloneValue(props.data);\n\tconst rules = sortRules(rulesRes.data, \"specific\");\n\n\tfor (const { rule, segments } of rules) {\n\t\tif (\n\t\t\trule.encrypt !== true &&\n\t\t\t(rule.neverStore !== true || props.options?.encryptNeverStore === false)\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const path of resolveExistingEmailStoragePaths(data, segments)) {\n\t\t\tconst encryptedValueRes = encryptEmailStorageValue(\n\t\t\t\tgetValueAtEmailStoragePath(data, path),\n\t\t\t\tprops.encryptionKey,\n\t\t\t);\n\t\t\tif (encryptedValueRes.error) return encryptedValueRes;\n\n\t\t\tsetValueAtEmailStoragePath(data, path, encryptedValueRes.data);\n\t\t}\n\t}\n\n\treturn {\n\t\terror: undefined,\n\t\tdata,\n\t};\n};\n\n/**\n * Resolves stored data for preview or send without using fallbacks for sends.\n */\nexport const resolveEmailData = (props: {\n\tdata: Record<string, unknown> | null;\n\tstorage?: EmailStorageConfig | null;\n\tencryptionKey: string;\n\tmode: \"preview\" | \"send\";\n}): Awaited<ServiceResponse<Record<string, unknown> | null>> => {\n\tif (props.data === null) return { error: undefined, data: null };\n\n\tconst rulesRes = parseEmailStorageRules(props.storage);\n\tif (rulesRes.error) return rulesRes;\n\n\tconst data = cloneValue(props.data);\n\tconst rules = rulesRes.data;\n\n\tfor (const { rule, segments } of sortRules(rules, \"broad\")) {\n\t\tif (rule.encrypt !== true && rule.neverStore !== true) continue;\n\t\tif (\n\t\t\tprops.mode === \"preview\" &&\n\t\t\t(rule.redact === true || rule.neverStore === true)\n\t\t) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const path of resolveExistingEmailStoragePaths(data, segments)) {\n\t\t\tconst decryptedValueRes = decryptEmailStorageValue(\n\t\t\t\tgetValueAtEmailStoragePath(data, path),\n\t\t\t\tprops.encryptionKey,\n\t\t\t);\n\t\t\tif (decryptedValueRes.error) return decryptedValueRes;\n\n\t\t\tsetValueAtEmailStoragePath(data, path, decryptedValueRes.data);\n\t\t}\n\t}\n\n\tif (props.mode === \"send\") {\n\t\treturn {\n\t\t\terror: undefined,\n\t\t\tdata,\n\t\t};\n\t}\n\n\tfor (const { rule, segments } of sortRules(rules, \"broad\")) {\n\t\tif (rule.redact !== true && rule.neverStore !== true) continue;\n\n\t\tconst fallback =\n\t\t\trule.previewFallback ?? constants.email.storage.defaultPreviewFallback;\n\t\tconst paths = resolveExistingEmailStoragePaths(data, segments);\n\t\tconst selectorHasWildcard = segments.some(\n\t\t\t(segment) => segment.type === \"wildcard\",\n\t\t);\n\n\t\tif (paths.length === 0 && !selectorHasWildcard) {\n\t\t\tsetValueAtEmailStoragePath(\n\t\t\t\tdata,\n\t\t\t\temailStorageSegmentsToPath(segments),\n\t\t\t\tcloneValue(fallback),\n\t\t\t\t{\n\t\t\t\t\tcreateMissing: true,\n\t\t\t\t},\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const path of paths) {\n\t\t\tsetValueAtEmailStoragePath(data, path, cloneValue(fallback));\n\t\t}\n\t}\n\n\treturn {\n\t\terror: undefined,\n\t\tdata,\n\t};\n};\n\n/**\n * Removes fields that are only allowed to exist until a successful send.\n */\nexport const stripNeverStoreEmailData = (props: {\n\tdata: Record<string, unknown> | null;\n\tstorage?: EmailStorageConfig | null;\n}): Awaited<ServiceResponse<Record<string, unknown> | null>> => {\n\tif (props.data === null) return { error: undefined, data: null };\n\n\tconst rulesRes = parseEmailStorageRules(props.storage);\n\tif (rulesRes.error) return rulesRes;\n\n\tconst data = cloneValue(props.data);\n\tconst rules = sortRules(rulesRes.data, \"specific\");\n\n\tfor (const { rule, segments } of rules) {\n\t\tif (rule.neverStore !== true) continue;\n\n\t\tfor (const path of resolveExistingEmailStoragePaths(data, segments)) {\n\t\t\tremoveValueAtEmailStoragePath(data, path);\n\t\t}\n\t}\n\n\treturn {\n\t\terror: undefined,\n\t\tdata,\n\t};\n};\n"],"mappings":"kZAiBA,MAAM,GACL,EACA,IAEA,CAAC,GAAG,CAAK,CAAC,CAAC,MAAM,EAAG,IAAM,CACzB,IAAM,EACL,IAAc,WACX,EAAE,YAAc,EAAE,YAClB,EAAE,YAAc,EAAE,YAGtB,OADI,IAAoB,EACjB,EAAE,MAAQ,EAAE,MADe,CAEnC,CAAC,EAKW,EAAyB,GAO0B,CAC/D,GAAI,EAAM,OAAS,KAAM,MAAO,CAAE,MAAO,IAAA,GAAW,KAAM,IAAK,EAE/D,IAAM,EAAW,EAAuB,EAAM,OAAO,EACrD,GAAI,EAAS,MAAO,OAAO,EAE3B,IAAM,EAAO,EAAW,EAAM,IAAI,EAC5B,EAAQ,EAAU,EAAS,KAAM,UAAU,EAEjD,IAAK,GAAM,CAAE,OAAM,cAAc,EAE/B,OAAK,UAAY,KAChB,EAAK,aAAe,IAAQ,EAAM,SAAS,oBAAsB,KAKnE,IAAK,IAAM,KAAQ,EAAiC,EAAM,CAAQ,EAAG,CACpE,IAAM,EAAoB,EACzB,EAA2B,EAAM,CAAI,EACrC,EAAM,aACP,EACA,GAAI,EAAkB,MAAO,OAAO,EAEpC,EAA2B,EAAM,EAAM,EAAkB,IAAI,CAC9D,CAGD,MAAO,CACN,MAAO,IAAA,GACP,MACD,CACD,EAKa,EAAoB,GAK+B,CAC/D,GAAI,EAAM,OAAS,KAAM,MAAO,CAAE,MAAO,IAAA,GAAW,KAAM,IAAK,EAE/D,IAAM,EAAW,EAAuB,EAAM,OAAO,EACrD,GAAI,EAAS,MAAO,OAAO,EAE3B,IAAM,EAAO,EAAW,EAAM,IAAI,EAC5B,EAAQ,EAAS,KAEvB,IAAK,GAAM,CAAE,OAAM,cAAc,EAAU,EAAO,OAAO,EACpD,OAAK,UAAY,IAAQ,EAAK,aAAe,KAEhD,IAAM,OAAS,YACd,EAAK,SAAW,IAAQ,EAAK,aAAe,KAK9C,IAAK,IAAM,KAAQ,EAAiC,EAAM,CAAQ,EAAG,CACpE,IAAM,EAAoB,EACzB,EAA2B,EAAM,CAAI,EACrC,EAAM,aACP,EACA,GAAI,EAAkB,MAAO,OAAO,EAEpC,EAA2B,EAAM,EAAM,EAAkB,IAAI,CAC9D,CAGD,GAAI,EAAM,OAAS,OAClB,MAAO,CACN,MAAO,IAAA,GACP,MACD,EAGD,IAAK,GAAM,CAAE,OAAM,cAAc,EAAU,EAAO,OAAO,EAAG,CAC3D,GAAI,EAAK,SAAW,IAAQ,EAAK,aAAe,GAAM,SAEtD,IAAM,EACL,EAAK,iBAAmBA,EAAU,MAAM,QAAQ,uBAC3C,EAAQ,EAAiC,EAAM,CAAQ,EACvD,EAAsB,EAAS,KACnC,GAAY,EAAQ,OAAS,UAC/B,EAEA,GAAI,EAAM,SAAW,GAAK,CAAC,EAAqB,CAC/C,EACC,EACA,EAA2B,CAAQ,EACnC,EAAW,CAAQ,EACnB,CACC,cAAe,EAChB,CACD,EACA,QACD,CAEA,IAAK,IAAM,KAAQ,EAClB,EAA2B,EAAM,EAAM,EAAW,CAAQ,CAAC,CAE7D,CAEA,MAAO,CACN,MAAO,IAAA,GACP,MACD,CACD,EAKa,EAA4B,GAGuB,CAC/D,GAAI,EAAM,OAAS,KAAM,MAAO,CAAE,MAAO,IAAA,GAAW,KAAM,IAAK,EAE/D,IAAM,EAAW,EAAuB,EAAM,OAAO,EACrD,GAAI,EAAS,MAAO,OAAO,EAE3B,IAAM,EAAO,EAAW,EAAM,IAAI,EAC5B,EAAQ,EAAU,EAAS,KAAM,UAAU,EAEjD,IAAK,GAAM,CAAE,OAAM,cAAc,EAC5B,KAAK,aAAe,GAExB,IAAK,IAAM,KAAQ,EAAiC,EAAM,CAAQ,EACjE,EAA8B,EAAM,CAAI,EAI1C,MAAO,CACN,MAAO,IAAA,GACP,MACD,CACD"}