{"version":3,"file":"verify.mjs","names":["formatter","licenseFormatter"],"sources":["../../../src/services/license/verify.ts"],"sourcesContent":["import formatter, { licenseFormatter } from \"../../libs/formatters/index.js\";\nimport { verifyCmsLicense } from \"../../libs/lucid-remote/services/index.js\";\nimport { OptionsRepository } from \"../../libs/repositories/index.js\";\nimport { decrypt } from \"../../utils/helpers/encrypt-decrypt.js\";\nimport { getUnixTimeSeconds } from \"../../utils/helpers/time.js\";\nimport type { ServiceFn } from \"../../utils/services/types.js\";\nimport {\n\tgetLicenseOptionBaseName,\n\tgetLicenseOptionName,\n\tgetLicenseOptionNames,\n} from \"./helpers/option-names.js\";\n\ntype LicenseSnapshot = {\n\tvalid: boolean;\n\taiEnabled: boolean;\n\terrorMessage: string | null;\n};\n\n/**\n * Verifies and persists license state for a single tenant scope.\n * The tenant key is passed in so cron checks do not need to reshape request context.\n */\nconst verifyLicense: ServiceFn<\n\t[\n\t\t{\n\t\t\ttenantKey: string | null | undefined;\n\t\t},\n\t],\n\t{\n\t\tkey: string | null;\n\t\tvalid: boolean;\n\t\tlastChecked: number;\n\t\terrorMessage: string | null;\n\t\taiEnabled: boolean;\n\t}\n> = async (context, data) => {\n\tconst Options = new OptionsRepository(context.db.client, context.config.db);\n\tconst now = getUnixTimeSeconds();\n\tconst tenantKey = data.tenantKey ?? null;\n\n\tconst existingStateRes = await Options.selectMultiple({\n\t\tselect: [\"name\", \"value_bool\", \"value_text\"],\n\t\twhere: [\n\t\t\t{\n\t\t\t\tkey: \"name\",\n\t\t\t\toperator: \"in\",\n\t\t\t\tvalue: getLicenseOptionNames(tenantKey, [\n\t\t\t\t\t\"license_valid\",\n\t\t\t\t\t\"license_error_message\",\n\t\t\t\t\t\"license_ai_enabled\",\n\t\t\t\t]),\n\t\t\t},\n\t\t],\n\t});\n\tif (existingStateRes.error) return existingStateRes;\n\n\tconst existingSnapshot: LicenseSnapshot = {\n\t\tvalid:\n\t\t\tformatter.formatBoolean(\n\t\t\t\texistingStateRes.data?.find(\n\t\t\t\t\t(o) => getLicenseOptionBaseName(o.name) === \"license_valid\",\n\t\t\t\t)?.value_bool,\n\t\t\t) ?? false,\n\t\taiEnabled:\n\t\t\tformatter.formatBoolean(\n\t\t\t\texistingStateRes.data?.find(\n\t\t\t\t\t(o) => getLicenseOptionBaseName(o.name) === \"license_ai_enabled\",\n\t\t\t\t)?.value_bool,\n\t\t\t) ?? false,\n\t\terrorMessage:\n\t\t\texistingStateRes.data?.find(\n\t\t\t\t(o) => getLicenseOptionBaseName(o.name) === \"license_error_message\",\n\t\t\t)?.value_text ?? null,\n\t};\n\n\t/**\n\t * Stores the latest verification state under the same tenant-scoped option names.\n\t */\n\tconst persistSnapshot = async (snapshot: LicenseSnapshot) => {\n\t\tconst [validRes, lastCheckedRes, errorMsgRes, aiEnabledRes] =\n\t\t\tawait Promise.all([\n\t\t\t\tOptions.upsertSingle({\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tname: getLicenseOptionName(tenantKey, \"license_valid\"),\n\t\t\t\t\t\tvalue_bool: snapshot.valid,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tOptions.upsertSingle({\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tname: getLicenseOptionName(tenantKey, \"license_last_checked\"),\n\t\t\t\t\t\tvalue_int: now,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tOptions.upsertSingle({\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tname: getLicenseOptionName(tenantKey, \"license_error_message\"),\n\t\t\t\t\t\tvalue_text: snapshot.errorMessage,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\tOptions.upsertSingle({\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tname: getLicenseOptionName(tenantKey, \"license_ai_enabled\"),\n\t\t\t\t\t\tvalue_bool: snapshot.aiEnabled,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t]);\n\t\tif (validRes.error) return validRes;\n\t\tif (lastCheckedRes.error) return lastCheckedRes;\n\t\tif (errorMsgRes.error) return errorMsgRes;\n\t\tif (aiEnabledRes.error) return aiEnabledRes;\n\n\t\treturn {\n\t\t\terror: undefined,\n\t\t\tdata: undefined,\n\t\t};\n\t};\n\tconst licenseKeyRes = await Options.selectSingle({\n\t\tselect: [\"name\", \"value_text\"],\n\t\twhere: [\n\t\t\t{\n\t\t\t\tkey: \"name\",\n\t\t\t\toperator: \"=\",\n\t\t\t\tvalue: getLicenseOptionName(tenantKey, \"license_key\"),\n\t\t\t},\n\t\t],\n\t});\n\tif (licenseKeyRes.error) return licenseKeyRes;\n\n\tif (!licenseKeyRes.data) {\n\t\tconst persistRes = await persistSnapshot({\n\t\t\tvalid: false,\n\t\t\taiEnabled: false,\n\t\t\terrorMessage: context.translate(\"server:core.license.is.not.set\"),\n\t\t});\n\t\tif (persistRes.error) return persistRes;\n\n\t\treturn {\n\t\t\terror: undefined,\n\t\t\tdata: {\n\t\t\t\tkey: null,\n\t\t\t\tvalid: false,\n\t\t\t\tlastChecked: now,\n\t\t\t\terrorMessage: context.translate(\"server:core.license.is.not.set\"),\n\t\t\t\taiEnabled: false,\n\t\t\t},\n\t\t};\n\t}\n\n\tconst encryptedKey = licenseKeyRes.data?.value_text;\n\tconst key = encryptedKey\n\t\t? decrypt(encryptedKey, context.config.secrets.encryption)\n\t\t: undefined;\n\tconst displayKey = licenseFormatter.createLicenseKeyDisplay(key);\n\n\tif (!key?.trim()) {\n\t\tconst persistRes = await persistSnapshot({\n\t\t\tvalid: false,\n\t\t\taiEnabled: false,\n\t\t\terrorMessage: context.translate(\"server:core.license.is.not.set\"),\n\t\t});\n\t\tif (persistRes.error) return persistRes;\n\n\t\treturn {\n\t\t\terror: undefined,\n\t\t\tdata: {\n\t\t\t\tkey: null,\n\t\t\t\tvalid: false,\n\t\t\t\tlastChecked: now,\n\t\t\t\terrorMessage: context.translate(\"server:core.license.is.not.set\"),\n\t\t\t\taiEnabled: false,\n\t\t\t},\n\t\t};\n\t}\n\n\tlet snapshot: LicenseSnapshot;\n\n\tconst verifyRes = await verifyCmsLicense(context, {\n\t\tlicenseKey: key,\n\t});\n\n\tif (verifyRes.error) {\n\t\tconst errorMessage =\n\t\t\tcontext.translate(verifyRes.error.message) ||\n\t\t\tcontext.translate(\"server:core.license.verification.failed\");\n\t\tsnapshot = {\n\t\t\t...existingSnapshot,\n\t\t\terrorMessage,\n\t\t};\n\t} else {\n\t\tconst ok = verifyRes.data.json.data;\n\t\tconst valid = !!ok.valid;\n\t\tsnapshot = {\n\t\t\tvalid,\n\t\t\taiEnabled: valid && ok.ai.enabled,\n\t\t\terrorMessage:\n\t\t\t\tok.message ||\n\t\t\t\t(valid ? null : context.translate(\"server:core.license.is.invalid\")),\n\t\t};\n\t}\n\n\tconst persistRes = await persistSnapshot(snapshot);\n\tif (persistRes.error) return persistRes;\n\n\treturn {\n\t\terror: undefined,\n\t\tdata: {\n\t\t\tkey: displayKey,\n\t\t\tvalid: snapshot.valid,\n\t\t\tlastChecked: now,\n\t\t\terrorMessage: snapshot.errorMessage,\n\t\t\taiEnabled: snapshot.aiEnabled,\n\t\t},\n\t};\n};\n\nexport default verifyLicense;\n"],"mappings":"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"}