@infuro/cms-core 1.0.34 → 1.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/OrderTrackPage-W3J6WIG2.js +426 -0
- package/dist/OrderTrackPage-Z6FCJQYY.cjs +428 -0
- package/dist/admin.cjs +34329 -20923
- package/dist/admin.d.cts +186 -9
- package/dist/admin.d.ts +186 -9
- package/dist/admin.js +34140 -20829
- package/dist/api.cjs +120 -17515
- package/dist/api.d.cts +633 -3
- package/dist/api.d.ts +633 -3
- package/dist/api.js +14 -17528
- package/dist/auth.cjs +192 -1034
- package/dist/auth.d.cts +194 -51
- package/dist/auth.d.ts +194 -51
- package/dist/auth.js +4 -966
- package/dist/chunk-2XE4X74C.js +29602 -0
- package/dist/chunk-3DZRIZOD.cjs +52 -0
- package/dist/chunk-3KPNTQBV.cjs +620 -0
- package/dist/chunk-46GKADYE.cjs +84 -0
- package/dist/chunk-4TRPKBKO.js +589 -0
- package/dist/chunk-5ELSW2UP.js +150 -0
- package/dist/chunk-6KPQWRFW.js +171 -0
- package/dist/chunk-7NMT3GBR.cjs +29 -0
- package/dist/chunk-7YIBMQDR.cjs +86 -0
- package/dist/chunk-BGJAV67S.cjs +29710 -0
- package/dist/chunk-CNTSLED2.cjs +559 -0
- package/dist/chunk-CRFV5WJK.js +16 -0
- package/dist/chunk-D5FBNKQM.cjs +104 -0
- package/dist/chunk-EF2JBPDM.js +114 -0
- package/dist/chunk-EQPITOP6.js +543 -0
- package/dist/chunk-GO7PPYNU.js +76 -0
- package/dist/chunk-HF3L2GIT.cjs +194 -0
- package/dist/chunk-J7XHLOLO.js +830 -0
- package/dist/chunk-JBRR5UYL.js +87 -0
- package/dist/chunk-JC6DLWTE.js +21 -0
- package/dist/chunk-JHF4YYRC.cjs +188 -0
- package/dist/chunk-JXF23MPG.js +25 -0
- package/dist/chunk-MQBT33IV.js +48 -0
- package/dist/chunk-N44BJZ4C.cjs +123 -0
- package/dist/chunk-OOTLNH63.cjs +18 -0
- package/dist/chunk-PAMVINEX.cjs +577 -0
- package/dist/chunk-PNOKNSG2.cjs +222 -0
- package/dist/chunk-QM733NUK.js +186 -0
- package/dist/chunk-R73BKDRO.cjs +90 -0
- package/dist/chunk-SHUYVCID.js +4 -0
- package/dist/chunk-SYBOCAWB.js +97 -0
- package/dist/chunk-TDV6EJHV.js +192 -0
- package/dist/chunk-TFUOHI37.cjs +839 -0
- package/dist/chunk-TIAEXJLI.cjs +182 -0
- package/dist/chunk-UPLVMVRX.cjs +23 -0
- package/dist/chunk-USNT2KNT.cjs +6 -0
- package/dist/chunk-WEMDMVHQ.js +216 -0
- package/dist/chunk-XDSNZUW7.js +564 -0
- package/dist/chunk-XQ3QUHWR.cjs +83 -0
- package/dist/chunk-XW5ATPRW.cjs +155 -0
- package/dist/chunk-ZQ4X6OAU.js +82 -0
- package/dist/chunk-ZSVCP6N3.js +83 -0
- package/dist/cli.cjs +103 -84
- package/dist/cli.js +62 -27
- package/dist/email-FKR4FXFI.js +5 -0
- package/dist/email-KVKVPNCL.cjs +58 -0
- package/dist/email-queue-CGZBVVAS.js +2 -0
- package/dist/email-queue-TPZWLTIV.cjs +23 -0
- package/dist/erp-config-enabled-CUMQ6N2V.cjs +11 -0
- package/dist/erp-config-enabled-T37X7T34.js +2 -0
- package/dist/erp-order-invoice-3YISSOWW.js +3 -0
- package/dist/erp-order-invoice-ZR5F2KTA.cjs +12 -0
- package/dist/event-order-defaults-6E543227.js +2 -0
- package/dist/event-order-defaults-DUGDVGJI.cjs +39 -0
- package/dist/event-order-notifications-5GSAOYVS.cjs +27 -0
- package/dist/event-order-notifications-IIIF23D5.js +10 -0
- package/dist/hooks.cjs +259 -132
- package/dist/hooks.d.cts +42 -1
- package/dist/hooks.d.ts +42 -1
- package/dist/hooks.js +234 -91
- package/dist/index.cjs +3884 -22307
- package/dist/index.d.cts +2203 -772
- package/dist/index.d.ts +2203 -772
- package/dist/index.js +2871 -22064
- package/dist/interpolate-WAKPN56R.cjs +11 -0
- package/dist/interpolate-WDUWDF3I.js +2 -0
- package/dist/layout-36UFTHC5.cjs +11 -0
- package/dist/layout-AOBN26XG.js +2 -0
- package/dist/migrations/1779400000000-ConvertStatusToEnum.ts +142 -0
- package/dist/migrations/1779400000000-SeedDefaultCurrencies.ts +33 -0
- package/dist/migrations/1779500000000-VendorRolesAndPermissions.ts +102 -0
- package/dist/migrations/1779600000000-VendorRegistrationProfile.ts +52 -0
- package/dist/migrations/1779700000000-CollectionIsCatalog.ts +22 -0
- package/dist/migrations/1779710000000-CollectionPlatformCatalog.ts +60 -0
- package/dist/migrations/1779720000000-ProductCategoryPlatformCatalog.ts +157 -0
- package/dist/migrations/1779800000000-EventsAndEventProducts.ts +173 -0
- package/dist/migrations/1779810000000-BackfillVendorRoleEventsPermissions.ts +38 -0
- package/dist/migrations/1779820000000-FixProductsCategoryForeignKey.ts +70 -0
- package/dist/migrations/1779830000000-ProductTitleColumn.ts +32 -0
- package/dist/migrations/1779840000000-EventAboutAndVisibilityFields.ts +34 -0
- package/dist/migrations/1779850000000-EventCityCountrySplit.ts +43 -0
- package/dist/migrations/1779860000000-CreateCombos.ts +140 -0
- package/dist/migrations/1780100000000-OrderAttendeesEventId.ts +55 -0
- package/dist/migrations/1780110000000-EventContactFormId.ts +49 -0
- package/dist/migrations/1780130000000-ProductVariants.ts +54 -0
- package/dist/migrations/1780140000000-EventManagementEnhancements.ts +44 -0
- package/dist/migrations/1780160000000-EventRegistrationGstProductContactForm.ts +79 -0
- package/dist/migrations/1780170000000-ComboCurrencyPrices.ts +20 -0
- package/dist/migrations/1781110000000-VendorOwnerCombosPermission.ts +38 -0
- package/dist/migrations/1781120000000-RefundPoliciesAndRequests.ts +225 -0
- package/dist/migrations/1781130000000-CreateAttendees.ts +44 -0
- package/dist/migrations/1781140000000-EventOrderNotifications.ts +29 -0
- package/dist/migrations/1781150000000-EventNamedLists.ts +28 -0
- package/dist/migrations/1781160000000-RefundPolicyEventTiers.ts +27 -0
- package/dist/migrations/1781170000000-EventRefundPolicy.ts +42 -0
- package/dist/migrations/1781180000000-RemoveCartItemsUniqueConstraint.ts +15 -0
- package/dist/migrations/1781190000000-RenameProductTaxesToProductConfig.ts +84 -0
- package/dist/migrations/1781200000000-VendorOwnerProductConfigPermissions.ts +51 -0
- package/dist/migrations/1781210000000-VendorRoleProductConfigPermissions.ts +46 -0
- package/dist/migrations/helpers/vendor-role-seed.ts +243 -0
- package/dist/paid-order-erp-3USEG6WL.js +3 -0
- package/dist/paid-order-erp-FSQ3GSXE.cjs +12 -0
- package/dist/pg-boss-service-4XF2TQ2E.js +2 -0
- package/dist/pg-boss-service-L6MTF4EQ.cjs +15 -0
- package/dist/razorpay-KLO2KNCB.js +49 -0
- package/dist/razorpay-U23LGY72.cjs +56 -0
- package/dist/rbac-debug-db-D7ME7QUY.cjs +35 -0
- package/dist/rbac-debug-db-MTCTVNNM.js +33 -0
- package/dist/sms-defaults-2NL24H57.js +2 -0
- package/dist/sms-defaults-KCOPKQBA.cjs +19 -0
- package/dist/stripe-4FD27QVJ.js +51 -0
- package/dist/stripe-VU6OEG2D.cjs +57 -0
- package/dist/theme.cjs +31 -59
- package/dist/theme.d.cts +78 -3
- package/dist/theme.d.ts +78 -3
- package/dist/theme.js +23 -20
- package/dist/vendor-invite-status-77O7ZQ3U.cjs +19 -0
- package/dist/vendor-invite-status-PWJ3DE76.js +2 -0
- package/dist/whatsapp-queue-3DXA4MXU.js +2 -0
- package/dist/whatsapp-queue-KG65MXD5.cjs +15 -0
- package/package.json +147 -142
- package/dist/admin.cjs.map +0 -1
- package/dist/admin.js.map +0 -1
- package/dist/api.cjs.map +0 -1
- package/dist/api.js.map +0 -1
- package/dist/auth.cjs.map +0 -1
- package/dist/auth.js.map +0 -1
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config-DJ5CmQvS.d.cts +0 -8
- package/dist/config-DJ5CmQvS.d.ts +0 -8
- package/dist/hooks.cjs.map +0 -1
- package/dist/hooks.js.map +0 -1
- package/dist/index-Bf5GO8fu.d.cts +0 -583
- package/dist/index-DOiJuMQA.d.ts +0 -583
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/theme.cjs.map +0 -1
- package/dist/theme.js.map +0 -1
- package/dist/types-DCVaXlPV.d.cts +0 -78
- package/dist/types-DCVaXlPV.d.ts +0 -78
- package/dist/vendor-scope-DTYhJk_I.d.cts +0 -129
- package/dist/vendor-scope-DTYhJk_I.d.ts +0 -129
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugins/erp/erp-log.ts","../src/plugins/erp/erp-queue.ts","../src/plugins/erp/paid-order-erp.ts","../src/plugins/erp/erp-response-map.ts","../src/plugins/erp/erp-config-enabled.ts","../src/plugins/erp/erp-order-invoice.ts","../src/plugins/email/email-queue.ts","../src/message-templates/sms-defaults.ts","../src/message-templates/interpolate.ts","../src/plugins/payment/stripe.ts","../src/plugins/payment/razorpay.ts","../src/plugins/pg-boss/pg-boss-service.ts","../src/lib/vendor-invite-status.ts","../src/auth/permission-entities.ts","../src/auth/role-helpers.ts","../src/auth/vendor-scope.ts","../src/auth/rbac-debug-db.ts","../src/auth/rbac-debug.ts","../src/admin/pages/OrderTrackPage.ts","../src/index.ts","../src/plugins/registry.ts","../src/plugins/erp/erp-submission.ts","../src/plugins/erp/index.ts","../src/plugins/erp/erp-contact-sync.ts","../src/lib/order-number.ts","../src/lib/order-storefront-metadata.ts","../src/plugins/erp/erp-order-status-map.ts","../src/plugins/erp/erp-order-sync.ts","../src/plugins/erp/erp-product-sync.ts","../src/plugins/email/email-service.ts","../src/plugins/email/templates/layout.ts","../src/plugins/email/templates/types.ts","../src/plugins/email/templates/inline-cta.ts","../src/plugins/email/templates/signup.ts","../src/plugins/email/templates/passwordReset.ts","../src/plugins/email/templates/passwordChange.ts","../src/plugins/email/templates/orderPlaced.ts","../src/plugins/email/templates/returnInitiated.ts","../src/plugins/email/templates/shippingUpdate.ts","../src/plugins/email/templates/invite.ts","../src/plugins/email/templates/formSubmission.ts","../src/plugins/email/templates/otp.ts","../src/plugins/email/templates/chatLead.ts","../src/plugins/email/templates/vendorOnboarded.ts","../src/plugins/email/templates/index.ts","../src/plugins/email/renderer.ts","../src/plugins/email/index.ts","../src/plugins/email/chat-lead-email.ts","../src/lib/email-recipients.ts","../src/plugins/llm/chat-email-intent.ts","../src/plugins/analytics/analytics-service.ts","../src/plugins/analytics/index.ts","../src/plugins/sms/sms-service.ts","../src/plugins/sms/sms-queue.ts","../src/plugins/sms/index.ts","../src/plugins/payment/index.ts","../src/plugins/storage/s3.ts","../src/plugins/storage/local.ts","../src/plugins/llm/llm-service.ts","../src/plugins/llm/llm-agent-scope.ts","../src/plugins/llm/find-llm-agent-by-scope.ts","../src/plugins/llm/index.ts","../src/plugins/cache/index.ts","../src/plugins/cache/memory-cache.ts","../src/plugins/cache/redis-cache.ts","../src/plugins/queue/bullmq-queue.ts","../src/plugins/queue/memory-queue.ts","../src/plugins/queue/index.ts","../src/plugins/pg-boss/index.ts","../src/entities/job-schedule.entity.ts","../src/entities/job-schedule-run.entity.ts","../src/plugins/jobs/job-runner.ts","../src/plugins/jobs/blog-generate-job.ts","../src/entities/llm-agent.entity.ts","../src/plugins/blog-generator/blog-generator-persist.ts","../src/api/rss-feed-blog-api.ts","../src/plugins/jobs/schedule-cron.ts","../src/plugins/jobs/schedule-sync.ts","../src/plugins/jobs/schedule-next-run.ts","../src/api/job-schedule-handlers.ts","../src/plugins/captcha/captcha-service.ts","../src/plugins/captcha/captcha-plugin.ts","../src/plugins/captcha/assert.ts","../src/plugins/blog-generator/blog-generator-service.ts","../src/lib/link-contact-to-user.ts","../src/api/cms-handlers.ts","../src/lib/media-folder-path.ts","../src/lib/media-parent-path.ts","../src/lib/media-zip-extract.ts","../src/plugins/blog-generator/blog-generator-agent-defaults.ts","../src/plugins/blog-generator/blog-generator-metadata-defaults.ts","../src/plugins/blog-generator/blog-generator-social-defaults.ts","../src/plugins/blog-generator/index.ts","../src/plugins/social-media/social-media-api-handlers.ts","../src/plugins/social-media/linkedin-client.ts","../src/plugins/social-media/meta-service.ts","../src/plugins/social-media/index.ts","../src/lib/utils.ts","../src/lib/seo-metadata.ts","../src/lib/otp-challenge.ts","../src/lib/rate-limit.ts","../src/lib/send-order-placed-emails.ts","../src/lib/send-vendor-onboard-emails.ts","../src/lib/data-source.ts","../src/lib/seed-admin.ts","../src/lib/load-user-vendor-context.ts","../src/lib/enrich-user-vendor-context.ts","../src/lib/hydrate-vendor-session-user.ts","../src/lib/public-theme-settings.ts","../src/lib/vendor-rls-context.ts","../src/lib/vendor-customer-contacts.ts","../src/entities/user.entity.ts","../src/entities/user-group.entity.ts","../src/entities/permission.entity.ts","../src/entities/otp-challenge.entity.ts","../src/entities/password-reset-token.entity.ts","../src/entities/blog.entity.ts","../src/entities/category.entity.ts","../src/entities/seo.entity.ts","../src/entities/comment.entity.ts","../src/entities/tag.entity.ts","../src/entities/contact.entity.ts","../src/entities/form-submission.entity.ts","../src/entities/form.entity.ts","../src/entities/form-field.entity.ts","../src/entities/address.entity.ts","../src/entities/order.entity.ts","../src/entities/vendor.entity.ts","../src/entities/order_addresses.entity.ts","../src/entities/customer_contacts.entity.ts","../src/entities/customer.entity.ts","../src/entities/payment.entity.ts","../src/entities/chat-conversation.entity.ts","../src/entities/chat-message.entity.ts","../src/entities/config.entity.ts","../src/entities/message-template.entity.ts","../src/entities/media.entity.ts","../src/entities/page.entity.ts","../src/entities/product-category.entity.ts","../src/entities/collection.entity.ts","../src/entities/brand.entity.ts","../src/entities/product.entity.ts","../src/entities/attribute.entity.ts","../src/entities/product-attribute.entity.ts","../src/entities/tax.entity.ts","../src/entities/product-tax.entity.ts","../src/entities/order-item.entity.ts","../src/entities/knowledge-base-document.entity.ts","../src/entities/knowledge-base-chunk.entity.ts","../src/entities/cart.entity.ts","../src/entities/cart-item.entity.ts","../src/entities/wishlist.entity.ts","../src/entities/wishlist-item.entity.ts","../src/entities/llm-agent-knowledge-document.entity.ts","../src/entities/currency.entity.ts","../src/entities/currency_exchange.entity.ts","../src/entities/discount.entity.ts","../src/entities/discount_rules.entity.ts","../src/entities/order_discounts.entity.ts","../src/entities/rss-feed.entity.ts","../src/entities/rss-article.entity.ts","../src/entities/vendor-user.entity.ts","../src/entities/vendor-customer.entity.ts","../src/entities/index.ts","../src/auth/helpers.ts","../src/auth/index.ts","../src/auth/seed-permissions.ts","../src/auth/middleware.ts","../src/auth/auth-debug.ts","../src/auth/nextauth-options.ts","../src/api/crud.ts","../src/api/vendor-scope-crud.ts","../src/lib/default-vendor-id.ts","../src/lib/address-geo-validation.ts","../src/plugins/llm/llm-agent-scope-crud.ts","../src/api/auth-handlers.ts","../src/api/llm-agent-knowledge-handlers.ts","../src/api/message-template-admin-handlers.ts","../src/api/cms-api-handler.ts","../src/api/admin-roles-handlers.ts","../src/api/vendor-handlers.ts","../src/api/storefront-handlers.ts","../src/lib/is-valid-signup-email.ts","../src/admin/config.ts"],"sourcesContent":["/** Server-side ERP integration traces (no secrets). */\r\nexport const ERP_LOG = '[webcore:erp]';\r\n\r\nexport function logErp(event: string, detail?: Record<string, unknown>): void {\r\n if (detail && Object.keys(detail).length) console.info(ERP_LOG, event, detail);\r\n else console.info(ERP_LOG, event);\r\n}\r\n\r\nexport function warnErp(event: string, detail: Record<string, unknown>): void {\r\n console.warn(ERP_LOG, event, detail);\r\n}\r\n\r\nexport function errorErp(event: string, detail: Record<string, unknown>): void {\r\n console.error(ERP_LOG, event, detail);\r\n}\r\n\r\n/** Origin + pathname only; drops query (e.g. token=). */\r\nexport function erpSafeWebhookUrl(url: string): string {\r\n try {\r\n const u = new URL(url);\r\n return `${u.origin}${u.pathname}`;\r\n } catch {\r\n return '(invalid webhook URL)';\r\n }\r\n}\r\n","import { errorErp, logErp, warnErp } from './erp-log';\r\nimport type { ERPSubmissionService } from './erp-submission';\r\nimport type { ContactFormData, ErpCreateContactPayload } from './erp-submission';\r\n\r\nexport interface CmsAppLike {\r\n getPlugin(name: string): unknown;\r\n}\r\n\r\nconst ERP_QUEUE_NAME = 'erp';\r\n\r\nexport type ErpJobPayload =\r\n | { kind: 'lead'; contact: ContactFormData }\r\n | { kind: 'formOpportunity'; contact: ContactFormData }\r\n | { kind: 'createContact'; contact: ErpCreateContactPayload }\r\n | { kind: 'order'; order: Record<string, unknown> }\r\n | { kind: 'productUpsert'; product: Record<string, unknown> };\r\n\r\nfunction queuePayloadSummary(payload: ErpJobPayload): Record<string, unknown> {\r\n if (payload.kind === 'order') {\r\n const o = payload.order;\r\n return {\r\n kind: payload.kind,\r\n platformOrderId: o.platformOrderId ?? o.platformOrderNumber,\r\n itemCount: Array.isArray(o.items) ? o.items.length : 0,\r\n };\r\n }\r\n return { kind: payload.kind };\r\n}\r\n\r\nexport async function queueErp(cms: CmsAppLike, payload: ErpJobPayload): Promise<void> {\r\n const queue = cms.getPlugin('queue') as { add: (name: string, data: object) => Promise<void> } | undefined;\r\n if (!queue) {\r\n warnErp('queue:add_skipped', { reason: 'queue_plugin_missing', ...queuePayloadSummary(payload) });\r\n return;\r\n }\r\n logErp('queue:add', { job: ERP_QUEUE_NAME, ...queuePayloadSummary(payload) });\r\n await queue.add(ERP_QUEUE_NAME, payload as object);\r\n}\r\n\r\nexport function registerErpQueueProcessor(cms: CmsAppLike): void {\r\n const queue = cms.getPlugin('queue') as\r\n | { registerProcessor: (name: string, fn: (data: object) => Promise<void>) => void }\r\n | undefined;\r\n if (!queue) return;\r\n queue.registerProcessor(ERP_QUEUE_NAME, async (data: object) => {\r\n const erp = cms.getPlugin('erp') as { submission: ERPSubmissionService } | undefined;\r\n if (!erp) {\r\n warnErp('queue:processor_skip', { reason: 'erp_plugin_missing' });\r\n return;\r\n }\r\n const payload = data as ErpJobPayload;\r\n logErp('queue:job_start', queuePayloadSummary(payload));\r\n try {\r\n if (payload.kind === 'lead') {\r\n await erp.submission.submitContact(payload.contact);\r\n } else if (payload.kind === 'formOpportunity') {\r\n await erp.submission.submitFormOpportunity(payload.contact);\r\n } else if (payload.kind === 'createContact') {\r\n await erp.submission.submitCreateContact(payload.contact);\r\n } else if (payload.kind === 'order') {\r\n await erp.submission.submitOrder(payload.order);\r\n } else if (payload.kind === 'productUpsert') {\r\n await erp.submission.submitProductUpsert(payload.product);\r\n }\r\n logErp('queue:job_done', queuePayloadSummary(payload));\r\n } catch (e) {\r\n errorErp('queue:job_failed', {\r\n ...queuePayloadSummary(payload),\r\n message: e instanceof Error ? e.message : String(e),\r\n });\r\n throw e;\r\n }\r\n });\r\n}\r\n","import type { ObjectLiteral } from 'typeorm';\r\nimport { errorErp, logErp } from './erp-log';\r\nimport { queueErp, type CmsAppLike } from './erp-queue';\r\n\r\n/**\r\n * Duck-typed DataSource so host apps (e.g. Next) can pass their own TypeORM instance\r\n * without duplicate-package type errors vs core’s node_modules/typeorm.\r\n */\r\nexport type ErpPaidOrderDataSource = {\r\n getRepository(entity: unknown): {\r\n find(options?: object): Promise<unknown[]>;\r\n findOne(options?: object): Promise<unknown | null>;\r\n };\r\n};\r\n\r\n/**\r\n * Entity map with `configs` and `orders` entries (e.g. ENTITY_MAP).\r\n * Typed as `Record<string, unknown>` so apps that cast their map to `Record<string, EntityTarget<…>>` still pass.\r\n */\r\nexport type ErpPaidOrderEntityMap = Record<string, unknown>;\r\n\r\nfunction roundMoney(major: number): number {\r\n return Math.round(major * 100) / 100;\r\n}\r\n\r\nfunction addressToWebhookDto(a: ObjectLiteral | null | undefined): Record<string, unknown> {\r\n if (!a) return {};\r\n return {\r\n line1: a.line1 ?? '',\r\n line2: a.line2 ?? '',\r\n city: a.city ?? '',\r\n state: a.state ?? '',\r\n postalCode: a.postalCode ?? '',\r\n country: a.country ?? '',\r\n };\r\n}\r\n\r\nfunction orderStatusLabel(status: string | undefined): string {\r\n const s = (status || '').toLowerCase();\r\n if (s === 'confirmed') return 'Confirmed';\r\n if (s === 'pending') return 'Pending';\r\n if (!status) return 'Pending';\r\n return status.charAt(0).toUpperCase() + status.slice(1);\r\n}\r\n\r\nfunction paymentRowToWebhookDto(p: ObjectLiteral, amountMajorOverride?: number): Record<string, unknown> {\r\n const currency = String(p.currency || 'INR');\r\n const amountMajor =\r\n amountMajorOverride != null && Number.isFinite(amountMajorOverride)\r\n ? amountMajorOverride\r\n : Number(p.amount);\r\n const meta = { ...((p.metadata as Record<string, unknown>) || {}) };\r\n delete meta.amount;\r\n delete meta.currency;\r\n return {\r\n id: String(p.externalReference || `payment_${p.id}`),\r\n amount: roundMoney(amountMajor),\r\n currency_code: currency,\r\n captured_at: p.paidAt\r\n ? new Date(p.paidAt as Date | string).toISOString()\r\n : new Date().toISOString(),\r\n provider_id: String(p.method || 'unknown'),\r\n data: { status: 'captured', ...meta },\r\n };\r\n}\r\n\r\n/**\r\n * Enqueues ERP `order.created` only when the order has at least one **completed** payment.\r\n * Include `payments` in the payload.\r\n */\r\nexport async function queueErpPaidOrderForOrderId(\r\n cms: CmsAppLike,\r\n dataSource: ErpPaidOrderDataSource,\r\n entityMap: ErpPaidOrderEntityMap,\r\n orderId: number\r\n): Promise<void> {\r\n try {\r\n const configRepo = dataSource.getRepository(entityMap.configs);\r\n const cfgRows = await configRepo.find({ where: { settings: 'erp', deleted: false } as ObjectLiteral });\r\n for (const row of cfgRows) {\r\n const r = row as { key: string; value: string };\r\n if (r.key === 'enabled' && r.value === 'false') {\r\n logErp('paid-order:skip', { orderId, reason: 'erp_config_disabled' });\r\n return;\r\n }\r\n }\r\n if (!cms.getPlugin('erp')) {\r\n logErp('paid-order:skip', { orderId, reason: 'erp_plugin_missing' });\r\n return;\r\n }\r\n\r\n const orderRepo = dataSource.getRepository(entityMap.orders);\r\n const ord = await orderRepo.findOne({\r\n where: { id: orderId } as ObjectLiteral,\r\n relations: ['items', 'items.product', 'contact', 'billingAddress', 'shippingAddress', 'payments'],\r\n });\r\n if (!ord) {\r\n logErp('paid-order:skip', { orderId, reason: 'order_not_found' });\r\n return;\r\n }\r\n const o = ord as ObjectLiteral;\r\n const okKind = o.orderKind === undefined || o.orderKind === null || o.orderKind === 'sale';\r\n if (!okKind) {\r\n logErp('paid-order:skip', { orderId, reason: 'order_kind_not_sale', orderKind: o.orderKind });\r\n return;\r\n }\r\n const rawPayments = (o.payments as ObjectLiteral[]) ?? [];\r\n const completedPayments = rawPayments.filter((pay) => pay.status === 'completed' && pay.deleted !== true);\r\n if (!completedPayments.length) {\r\n logErp('paid-order:skip', { orderId, reason: 'no_completed_payments' });\r\n return;\r\n }\r\n\r\n const rawItems = (o.items as ObjectLiteral[]) ?? [];\r\n const lines = rawItems\r\n .filter((it) => it.product)\r\n .map((it) => {\r\n const p = it.product as ObjectLiteral;\r\n const sku = (p.sku as string) || `SKU-${p.id}`;\r\n const itemType =\r\n typeof it.productType === 'string' && it.productType.trim()\r\n ? String(it.productType).trim()\r\n : p.type === 'service'\r\n ? 'service'\r\n : 'product';\r\n return {\r\n sku,\r\n quantity: Number(it.quantity) || 1,\r\n unitPrice: Number(it.unitPrice),\r\n title: (p.name as string) || sku,\r\n discount: 0,\r\n tax: Number(it.tax) || 0,\r\n uom: (typeof it.uom === 'string' && it.uom.trim() ? it.uom : p.uom) || undefined,\r\n tax_code:\r\n typeof it.taxCode === 'string' && it.taxCode.trim() ? String(it.taxCode).trim() : undefined,\r\n hsn_number:\r\n (typeof it.hsn === 'string' && it.hsn.trim() ? it.hsn : p.hsn) || undefined,\r\n type: itemType,\r\n };\r\n });\r\n if (!lines.length) {\r\n logErp('paid-order:skip', { orderId, reason: 'no_line_items_with_product' });\r\n return;\r\n }\r\n\r\n const contact = o.contact as ObjectLiteral | undefined;\r\n const orderTotalMajor = Number(o.total);\r\n const paymentDtos =\r\n completedPayments.length === 1 && Number.isFinite(orderTotalMajor)\r\n ? [paymentRowToWebhookDto(completedPayments[0]!, orderTotalMajor)]\r\n : completedPayments.map((pay) => paymentRowToWebhookDto(pay));\r\n const baseMeta =\r\n o.metadata && typeof o.metadata === 'object' && !Array.isArray(o.metadata)\r\n ? { ...(o.metadata as Record<string, unknown>) }\r\n : {};\r\n\r\n const orderDto: Record<string, unknown> = {\r\n platformType: 'website',\r\n platformOrderId: String(o.orderNumber),\r\n platformOrderNumber: String(o.orderNumber),\r\n order_date: o.createdAt ? new Date(o.createdAt as Date | string).toISOString() : undefined,\r\n status: orderStatusLabel(o.status as string | undefined),\r\n customer: {\r\n name: (contact?.name as string) || '',\r\n email: (contact?.email as string) || '',\r\n phone: (contact?.phone as string) || '',\r\n },\r\n shippingAddress: addressToWebhookDto(o.shippingAddress as ObjectLiteral),\r\n billingAddress: addressToWebhookDto(o.billingAddress as ObjectLiteral),\r\n items: lines,\r\n payments: paymentDtos,\r\n metadata: { ...baseMeta, source: 'storefront' },\r\n };\r\n\r\n logErp('paid-order:payload_built', {\r\n orderId,\r\n platformOrderId: orderDto.platformOrderId,\r\n status: orderDto.status,\r\n itemCount: lines.length,\r\n skus: lines.map((l) => l.sku),\r\n paymentCount: paymentDtos.length,\r\n paymentIds: paymentDtos.map((p) => p.id),\r\n total: orderTotalMajor,\r\n });\r\n\r\n await queueErp(cms, { kind: 'order', order: orderDto });\r\n } catch (e) {\r\n errorErp('paid-order:enqueue_failed', {\r\n orderId,\r\n message: e instanceof Error ? e.message : String(e),\r\n });\r\n }\r\n}\r\n","import type { OrderFulfillmentEvent, OrderFulfillmentMetadata } from '../../lib/order-storefront-metadata';\r\n\r\nfunction pickString(o: Record<string, unknown>, keys: string[]): string | undefined {\r\n for (const k of keys) {\r\n const v = o[k];\r\n if (typeof v === 'string' && v.trim()) return v.trim();\r\n }\r\n return undefined;\r\n}\r\n\r\nexport function unwrapErpReadData(json: unknown): Record<string, unknown> | null {\r\n if (!json || typeof json !== 'object') return null;\r\n const o = json as Record<string, unknown>;\r\n const d = o.data;\r\n if (d && typeof d === 'object' && !Array.isArray(d)) return d as Record<string, unknown>;\r\n return o;\r\n}\r\n\r\nfunction firstObject(\r\n data: Record<string, unknown>,\r\n keys: string[]\r\n): Record<string, unknown> | null {\r\n for (const k of keys) {\r\n const v = data[k];\r\n if (v && typeof v === 'object' && !Array.isArray(v)) return v as Record<string, unknown>;\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractEvents(src: Record<string, unknown>): OrderFulfillmentEvent[] | undefined {\r\n const timeline = src.timeline ?? src.events ?? src.history ?? src.trackingEvents;\r\n if (!Array.isArray(timeline) || !timeline.length) return undefined;\r\n const events: OrderFulfillmentEvent[] = [];\r\n for (const row of timeline) {\r\n if (!row || typeof row !== 'object') continue;\r\n const r = row as Record<string, unknown>;\r\n const at =\r\n pickString(r, ['at', 'timestamp', 'date', 'occurredAt']) ??\r\n (r.at instanceof Date ? (r.at as Date).toISOString() : undefined);\r\n const label = pickString(r, ['label', 'status', 'title', 'message', 'description']);\r\n const detail = pickString(r, ['detail', 'notes', 'description']);\r\n if (at || label || detail) events.push({ at, label, detail });\r\n }\r\n return events.length ? events : undefined;\r\n}\r\n\r\nexport function mapErpPayloadToFulfillment(data: Record<string, unknown>): OrderFulfillmentMetadata | undefined {\r\n const nested = firstObject(data, ['fulfillment', 'packaging', 'shipment', 'shipping', 'delivery']);\r\n const src = nested || data;\r\n const status = pickString(src, ['status', 'fulfillmentStatus', 'state', 'label', 'packagingStatus']);\r\n const trackingId = pickString(src, ['trackingId', 'tracking_id', 'trackingNumber', 'awb', 'trackingUrl']);\r\n const events = extractEvents(src);\r\n if (!status && !trackingId && !(events && events.length)) return undefined;\r\n return { status, trackingId, events };\r\n}\r\n\r\nexport function mapErpPayloadToInvoiceNumber(data: Record<string, unknown>): string | undefined {\r\n const nested = firstObject(data, ['invoice', 'latestInvoice', 'postedInvoice']);\r\n const src = nested || data;\r\n return pickString(src, ['invoiceNumber', 'invoice_number', 'number', 'name', 'id']);\r\n}\r\n\r\nexport type ErpChildOrderRef = { ref: string; orderKind: 'return' | 'replacement' };\r\n\r\nexport function extractChildOrderRefsFromSalePayload(data: Record<string, unknown>): ErpChildOrderRef[] {\r\n const lists = [data.returns, data.returnOrders, data.relatedReturns, data.childOrders, data.children];\r\n const seen = new Set<string>();\r\n const out: ErpChildOrderRef[] = [];\r\n for (const list of lists) {\r\n if (!Array.isArray(list)) continue;\r\n for (const item of list) {\r\n if (!item || typeof item !== 'object') continue;\r\n const o = item as Record<string, unknown>;\r\n const ref =\r\n pickString(o, ['platformReturnId', 'platform_return_id', 'refId', 'ref_id']) ??\r\n (typeof o.id === 'string' ? o.id : undefined);\r\n if (!ref || seen.has(ref)) continue;\r\n seen.add(ref);\r\n const t = (pickString(o, ['kind', 'type', 'orderKind']) || '').toLowerCase();\r\n const orderKind: 'return' | 'replacement' = /replac/.test(t) ? 'replacement' : 'return';\r\n out.push({ ref, orderKind });\r\n }\r\n }\r\n return out;\r\n}\r\n","import type { ObjectLiteral } from 'typeorm';\r\n\r\nexport type CmsAppLike = { getPlugin(name: string): unknown };\r\n\r\nexport type ErpConfigDataSource = {\r\n getRepository(entity: unknown): {\r\n find(options?: object): Promise<unknown[]>;\r\n };\r\n};\r\n\r\n/** True when ERP plugin is loaded and config `erp.enabled` is not `'false'`. */\r\nexport async function isErpIntegrationEnabled(\r\n cms: CmsAppLike,\r\n dataSource: ErpConfigDataSource,\r\n entityMap: Record<string, unknown>\r\n): Promise<boolean> {\r\n if (!cms.getPlugin('erp')) return false;\r\n const configRepo = dataSource.getRepository(entityMap.configs);\r\n const cfgRows = await configRepo.find({ where: { settings: 'erp', deleted: false } as ObjectLiteral });\r\n for (const row of cfgRows) {\r\n const r = row as { key: string; value: string };\r\n if (r.key === 'enabled' && r.value === 'false') return false;\r\n }\r\n return true;\r\n}\r\n","import type { ObjectLiteral, Repository } from 'typeorm';\r\nimport { unwrapErpReadData } from './erp-response-map';\r\nimport type { ERPSubmissionService } from './erp-submission';\r\nimport { isErpIntegrationEnabled, type CmsAppLike, type ErpConfigDataSource } from './erp-config-enabled';\r\n\r\nfunction pickInvoiceId(data: Record<string, unknown>): string | undefined {\r\n const nested =\r\n data.invoice && typeof data.invoice === 'object' && !Array.isArray(data.invoice)\r\n ? (data.invoice as Record<string, unknown>)\r\n : null;\r\n const src = nested || data;\r\n for (const k of ['invoiceId', 'invoice_id', 'id']) {\r\n const v = src[k];\r\n if (typeof v === 'string' && v.trim()) return v.trim();\r\n }\r\n return undefined;\r\n}\r\n\r\n/**\r\n * Streams invoice PDF for a **sale** order. Resolves `invoiceId` from order metadata or `get-invoice`.\r\n */\r\nexport async function streamOrderInvoicePdf(\r\n cms: CmsAppLike,\r\n dataSource: ErpConfigDataSource,\r\n entityMap: Record<string, unknown>,\r\n orderId: number,\r\n options: { ownerContactId?: number }\r\n): Promise<Response> {\r\n const jsonErr = (msg: string, status: number) =>\r\n new Response(JSON.stringify({ error: msg }), {\r\n status,\r\n headers: { 'Content-Type': 'application/json' },\r\n });\r\n\r\n const on = await isErpIntegrationEnabled(cms, dataSource, entityMap);\r\n if (!on) return jsonErr('Invoice not available', 503);\r\n\r\n const erp = cms.getPlugin('erp') as { submission: ERPSubmissionService } | undefined;\r\n if (!erp?.submission) return jsonErr('Invoice not available', 503);\r\n\r\n const orderRepo = dataSource.getRepository(entityMap.orders) as Repository<ObjectLiteral>;\r\n const order = await orderRepo.findOne({ where: { id: orderId, deleted: false } as ObjectLiteral });\r\n if (!order) return jsonErr('Not found', 404);\r\n\r\n const kind = (order.orderKind as string) || 'sale';\r\n if (kind !== 'sale') return jsonErr('Invoice only for sale orders', 400);\r\n\r\n if (options.ownerContactId != null && order.contactId !== options.ownerContactId) {\r\n return jsonErr('Not found', 404);\r\n }\r\n\r\n const meta =\r\n order.metadata && typeof order.metadata === 'object' && !Array.isArray(order.metadata)\r\n ? (order.metadata as Record<string, unknown>)\r\n : {};\r\n const inv = meta.invoice && typeof meta.invoice === 'object' && !Array.isArray(meta.invoice)\r\n ? (meta.invoice as Record<string, unknown>)\r\n : {};\r\n let invoiceId = typeof inv.invoiceId === 'string' ? inv.invoiceId.trim() : '';\r\n\r\n if (!invoiceId) {\r\n const refId = String(order.orderNumber || '');\r\n const r = await erp.submission.postErpReadAction('get-invoice', { platformOrderId: refId });\r\n const d = r.ok ? unwrapErpReadData(r.json) : null;\r\n invoiceId = d ? pickInvoiceId(d) || '' : '';\r\n }\r\n\r\n if (!invoiceId) return jsonErr('Invoice not ready', 404);\r\n\r\n const pdf = await erp.submission.fetchInvoicePdf(invoiceId);\r\n if (!pdf.ok || !pdf.buffer) return jsonErr(pdf.error || 'PDF fetch failed', 502);\r\n\r\n const filename = `invoice-${orderId}.pdf`;\r\n return new Response(pdf.buffer, {\r\n status: 200,\r\n headers: {\r\n 'Content-Type': pdf.contentType || 'application/pdf',\r\n 'Content-Disposition': `attachment; filename=\"${filename}\"`,\r\n },\r\n });\r\n}\r\n","import type { CompanyDetails, EmailTemplateName, OrderPlacedLineItem } from './templates/types';\r\n\r\nexport interface CmsAppLike {\r\n getPlugin(name: string): unknown;\r\n}\r\n\r\n/** Context for template rendering: at least companyDetails; template-specific fields (formName, etc.) are allowed. */\r\nexport interface EmailJobPayload {\r\n to: string;\r\n templateName?: EmailTemplateName;\r\n ctx?: Record<string, unknown> & { companyDetails: CompanyDetails };\r\n subject?: string;\r\n html?: string;\r\n text?: string;\r\n}\r\n\r\nconst EMAIL_QUEUE_NAME = 'email';\r\n\r\nexport function registerEmailQueueProcessor(cms: CmsAppLike): void {\r\n const queue = cms.getPlugin('queue') as { add: (name: string, data: object) => Promise<void>; registerProcessor: (name: string, fn: (data: object) => Promise<void>) => void } | undefined;\r\n const email = cms.getPlugin('email') as { send: (opts: { to: string; subject: string; html: string; text?: string }) => Promise<boolean>; renderTemplate: (name: string, ctx: unknown) => { subject: string; html: string; text?: string } } | undefined;\r\n if (!queue || !email) return;\r\n queue.registerProcessor(EMAIL_QUEUE_NAME, async (data: object) => {\r\n const payload = data as EmailJobPayload;\r\n const { to, templateName, ctx, subject, html, text } = payload;\r\n if (!to) return;\r\n if (templateName && ctx) {\r\n const rendered = email.renderTemplate(templateName, ctx);\r\n await email.send({ to, subject: rendered.subject, html: rendered.html, text: rendered.text });\r\n } else if (subject != null && html != null) {\r\n await email.send({ to, subject, html, text });\r\n }\r\n });\r\n}\r\n\r\nexport async function queueEmail(cms: CmsAppLike, payload: EmailJobPayload): Promise<void> {\r\n const queue = cms.getPlugin('queue') as { add: (name: string, data: object) => Promise<void> } | undefined;\r\n if (queue) {\r\n await queue.add(EMAIL_QUEUE_NAME, payload);\r\n return;\r\n }\r\n const email = cms.getPlugin('email') as { send: (opts: { to: string; subject: string; html: string; text?: string }) => Promise<boolean>; renderTemplate: (name: string, ctx: unknown) => { subject: string; html: string; text?: string } } | undefined;\r\n if (email && payload.templateName && payload.ctx) {\r\n const rendered = email.renderTemplate(payload.templateName, payload.ctx);\r\n await email.send({ to: payload.to, subject: rendered.subject, html: rendered.html, text: rendered.text });\r\n } else if (email && payload.subject != null && payload.html != null) {\r\n await email.send({ to: payload.to, subject: payload.subject, html: payload.html, text: payload.text });\r\n }\r\n}\r\n\r\nexport interface OrderPlacedEmailPayload {\r\n orderNumber: string;\r\n total?: string | number;\r\n subtotal?: string | number;\r\n tax?: string | number;\r\n currency?: string;\r\n customerName?: string;\r\n /** Customer receipt; omitted if empty */\r\n customerEmail?: string | null;\r\n /** Parsed list from email plugin “Sales team” settings */\r\n salesTeamEmails: string[];\r\n companyDetails: CompanyDetails;\r\n lineItems: OrderPlacedLineItem[];\r\n billingAddress?: Record<string, string>;\r\n shippingAddress?: Record<string, string>;\r\n}\r\n\r\n/** Queues one `orderPlaced` email per recipient (customer + each unique sales address; skips sales if same as customer). */\r\nexport async function queueOrderPlacedEmails(cms: CmsAppLike, payload: OrderPlacedEmailPayload): Promise<void> {\r\n const {\r\n orderNumber,\r\n total,\r\n subtotal,\r\n tax,\r\n currency,\r\n customerName,\r\n customerEmail,\r\n salesTeamEmails,\r\n companyDetails,\r\n lineItems,\r\n billingAddress,\r\n shippingAddress,\r\n } = payload;\r\n const base = {\r\n orderNumber,\r\n total: total != null ? String(total) : undefined,\r\n subtotal: subtotal != null ? String(subtotal) : undefined,\r\n tax: tax != null ? String(tax) : undefined,\r\n currency,\r\n customerName,\r\n companyDetails: companyDetails ?? {},\r\n lineItems: lineItems ?? [],\r\n billingAddress,\r\n shippingAddress,\r\n };\r\n const customerLower = customerEmail?.trim().toLowerCase() ?? '';\r\n const jobs: Promise<void>[] = [];\r\n if (customerEmail?.trim()) {\r\n jobs.push(\r\n queueEmail(cms, {\r\n to: customerEmail.trim(),\r\n templateName: 'orderPlaced',\r\n ctx: { ...base, audience: 'customer' as const },\r\n })\r\n );\r\n }\r\n const seen = new Set<string>();\r\n for (const raw of salesTeamEmails) {\r\n const to = raw.trim();\r\n if (!to) continue;\r\n const key = to.toLowerCase();\r\n if (seen.has(key)) continue;\r\n seen.add(key);\r\n if (customerLower && key === customerLower) continue;\r\n jobs.push(\r\n queueEmail(cms, {\r\n to,\r\n templateName: 'orderPlaced',\r\n ctx: {\r\n ...base,\r\n audience: 'sales' as const,\r\n internalCustomerEmail: customerEmail?.trim() || undefined,\r\n },\r\n })\r\n );\r\n }\r\n await Promise.all(jobs);\r\n}\r\n\r\nexport interface VendorOnboardEmailPayload {\r\n vendorName: string;\r\n vendorSlug?: string;\r\n ownerName: string;\r\n ownerEmail: string;\r\n activation: 'invite' | 'password';\r\n inviteLink?: string;\r\n signInLink: string;\r\n kind?: 'vendor_onboard' | 'team_invite';\r\n notifyEmails: string[];\r\n companyDetails: CompanyDetails;\r\n sendToOwner?: boolean;\r\n}\r\n\r\n/** Queues `vendorOnboarded` email to owner and each unique notify address (sales team settings). */\r\nexport async function queueVendorOnboardEmails(\r\n cms: CmsAppLike,\r\n payload: VendorOnboardEmailPayload\r\n): Promise<void> {\r\n const {\r\n vendorName,\r\n vendorSlug,\r\n ownerName,\r\n ownerEmail,\r\n activation,\r\n inviteLink,\r\n signInLink,\r\n kind = 'vendor_onboard',\r\n notifyEmails,\r\n companyDetails,\r\n sendToOwner = true,\r\n } = payload;\r\n\r\n const base = {\r\n vendorName,\r\n vendorSlug,\r\n ownerName,\r\n ownerEmail,\r\n activation,\r\n inviteLink,\r\n signInLink,\r\n kind,\r\n companyDetails: companyDetails ?? {},\r\n };\r\n\r\n const ownerLower = ownerEmail?.trim().toLowerCase() ?? '';\r\n const jobs: Promise<void>[] = [];\r\n\r\n if (sendToOwner && ownerEmail?.trim()) {\r\n jobs.push(\r\n queueEmail(cms, {\r\n to: ownerEmail.trim(),\r\n templateName: 'vendorOnboarded',\r\n ctx: { ...base, audience: 'owner' as const },\r\n })\r\n );\r\n }\r\n\r\n const seen = new Set<string>();\r\n for (const raw of notifyEmails) {\r\n const to = raw.trim();\r\n if (!to) continue;\r\n const key = to.toLowerCase();\r\n if (seen.has(key)) continue;\r\n seen.add(key);\r\n if (ownerLower && key === ownerLower) continue;\r\n jobs.push(\r\n queueEmail(cms, {\r\n to,\r\n templateName: 'vendorOnboarded',\r\n ctx: { ...base, audience: 'internal' as const },\r\n })\r\n );\r\n }\r\n\r\n await Promise.all(jobs);\r\n}\r\n","export type SmsMessageTemplateDefault = {\r\n templateKey: string;\r\n name: string;\r\n body: string;\r\n externalTemplateRef?: string;\r\n providerMeta?: { otpVarKey?: string };\r\n};\r\n\r\nexport const SMS_MESSAGE_TEMPLATE_DEFAULTS: SmsMessageTemplateDefault[] = [\r\n {\r\n templateKey: 'auth.otp_login',\r\n name: 'Sign-in OTP (SMS)',\r\n body: 'Your sign-in code is {{code}}. Valid 10 minutes.',\r\n providerMeta: { otpVarKey: 'var1' },\r\n },\r\n {\r\n templateKey: 'auth.otp_verify_phone',\r\n name: 'Verify phone OTP (SMS)',\r\n body: 'Your verification code is {{code}}. Valid 10 minutes.',\r\n providerMeta: { otpVarKey: 'var1' },\r\n },\r\n];\r\n\r\nexport function getSmsTemplateDefault(templateKey: string): SmsMessageTemplateDefault | undefined {\r\n return SMS_MESSAGE_TEMPLATE_DEFAULTS.find((d) => d.templateKey === templateKey);\r\n}\r\n\r\nexport type ResolvedSmsTemplate = {\r\n body: string;\r\n externalTemplateRef: string | undefined;\r\n otpVarKey: string;\r\n};\r\n\r\nexport async function resolveSmsTemplateForSend(\r\n templateKey: string,\r\n getRow: (channel: string, key: string) => Promise<{\r\n body: string;\r\n externalTemplateRef: string | null;\r\n providerMeta: Record<string, unknown> | null;\r\n enabled: boolean;\r\n } | null>\r\n): Promise<ResolvedSmsTemplate | null> {\r\n const def = getSmsTemplateDefault(templateKey);\r\n if (!def) return null;\r\n\r\n const row = await getRow('sms', templateKey);\r\n let body = def.body;\r\n let ref = def.externalTemplateRef;\r\n let otpVarKey = def.providerMeta?.otpVarKey ?? 'var1';\r\n\r\n if (row && row.enabled !== false) {\r\n if (row.body.trim()) body = row.body;\r\n if (row.externalTemplateRef?.trim()) ref = row.externalTemplateRef.trim();\r\n const pm = row.providerMeta;\r\n const k = pm && typeof pm.otpVarKey === 'string' ? pm.otpVarKey.trim() : '';\r\n if (k) otpVarKey = k;\r\n }\r\n\r\n return {\r\n body,\r\n externalTemplateRef: ref?.trim() || undefined,\r\n otpVarKey: otpVarKey || 'var1',\r\n };\r\n}\r\n","/** Replace `{{key}}` placeholders (also accepts legacy `{{otp}}` as alias for `code` when code is set). */\r\nexport function applyTemplateVars(template: string, variables: Record<string, string>): string {\r\n let out = template;\r\n for (const [k, v] of Object.entries(variables)) {\r\n out = out.split(`{{${k}}}`).join(v);\r\n }\r\n if (variables.code !== undefined) {\r\n out = out.split('{{otp}}').join(variables.code);\r\n }\r\n return out;\r\n}\r\n","import Stripe from 'stripe';\r\nimport type { PaymentServiceInterface, PaymentIntent } from './index';\r\n\r\nexport interface StripeServiceConfig {\r\n secretKey: string;\r\n webhookSecret?: string;\r\n}\r\n\r\nexport class StripePaymentService implements PaymentServiceInterface {\r\n private stripe: Stripe;\r\n private webhookSecret?: string;\r\n\r\n constructor(config: StripeServiceConfig) {\r\n this.stripe = new Stripe(config.secretKey, { apiVersion: '2026-02-25.clover' });\r\n this.webhookSecret = config.webhookSecret;\r\n }\r\n\r\n async createPaymentIntent(\r\n amount: number,\r\n currency: string,\r\n metadata?: Record<string, string>\r\n ): Promise<PaymentIntent> {\r\n const intent = await this.stripe.paymentIntents.create({\r\n amount: Math.round(amount * 100),\r\n currency: currency.toLowerCase(),\r\n metadata,\r\n });\r\n\r\n return {\r\n id: intent.id,\r\n clientSecret: intent.client_secret || '',\r\n amount,\r\n currency,\r\n status: intent.status,\r\n };\r\n }\r\n\r\n async capturePayment(paymentId: string, amount?: number): Promise<boolean> {\r\n try {\r\n await this.stripe.paymentIntents.capture(paymentId, {\r\n amount_to_capture: amount ? Math.round(amount * 100) : undefined,\r\n });\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n verifyWebhookSignature(payload: string | Buffer, signature: string): boolean {\r\n if (!this.webhookSecret) return false;\r\n try {\r\n this.stripe.webhooks.constructEvent(payload, signature, this.webhookSecret);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n}\r\n","import Razorpay from 'razorpay';\r\nimport crypto from 'crypto';\r\nimport type { PaymentServiceInterface, PaymentIntent } from './index';\r\n\r\nexport interface RazorpayServiceConfig {\r\n keyId: string;\r\n keySecret: string;\r\n webhookSecret?: string;\r\n}\r\n\r\nexport class RazorpayPaymentService implements PaymentServiceInterface {\r\n private razorpay: Razorpay;\r\n private keySecret: string;\r\n private webhookSecret?: string;\r\n\r\n constructor(config: RazorpayServiceConfig) {\r\n this.razorpay = new Razorpay({\r\n key_id: config.keyId,\r\n key_secret: config.keySecret,\r\n });\r\n this.keySecret = config.keySecret;\r\n this.webhookSecret = config.webhookSecret;\r\n }\r\n\r\n async createPaymentIntent(\r\n amount: number,\r\n currency: string,\r\n metadata?: Record<string, string>\r\n ): Promise<PaymentIntent> {\r\n const order = await this.razorpay.orders.create({\r\n amount: Math.round(amount * 100),\r\n currency: currency.toUpperCase(),\r\n notes: metadata,\r\n });\r\n\r\n return {\r\n id: order.id,\r\n clientSecret: order.id,\r\n amount,\r\n currency,\r\n status: order.status,\r\n };\r\n }\r\n\r\n async capturePayment(paymentId: string, amount?: number): Promise<boolean> {\r\n try {\r\n await this.razorpay.payments.capture(paymentId, amount ? Math.round(amount * 100) : 0, 'INR');\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n verifyWebhookSignature(payload: string | Buffer, signature: string): boolean {\r\n const secret = this.webhookSecret || this.keySecret;\r\n const expectedSignature = crypto\r\n .createHmac('sha256', secret)\r\n .update(typeof payload === 'string' ? payload : payload.toString('utf8'))\r\n .digest('hex');\r\n return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));\r\n }\r\n}\r\n","import PgBoss from 'pg-boss';\r\n\r\nexport const JOB_RUNNER_QUEUE = 'job-runner';\r\n\r\nexport type JobRunnerPayload = {\r\n scheduleId: string;\r\n triggeredBy?: 'schedule' | 'manual';\r\n};\r\n\r\nexport class PgBossService {\r\n private readonly boss: PgBoss;\r\n private started = false;\r\n private readonly workRegistered = new Set<string>();\r\n\r\n constructor(connectionString: string, schema?: string) {\r\n this.boss = new PgBoss({\r\n connectionString,\r\n ...(schema?.trim() ? { schema: schema.trim() } : {}),\r\n schedule: true,\r\n });\r\n this.boss.on('error', (err) => {\r\n console.error('[pg-boss]', err);\r\n });\r\n }\r\n\r\n async start(): Promise<void> {\r\n if (this.started) return;\r\n await this.boss.start();\r\n await this.ensureQueue(JOB_RUNNER_QUEUE);\r\n this.started = true;\r\n }\r\n\r\n async stop(): Promise<void> {\r\n if (!this.started) return;\r\n await this.boss.stop({ graceful: true, timeout: 10000 });\r\n this.started = false;\r\n this.workRegistered.clear();\r\n }\r\n\r\n get raw(): PgBoss {\r\n return this.boss;\r\n }\r\n\r\n async ensureQueue(name: string): Promise<void> {\r\n const existing = await this.boss.getQueue(name);\r\n if (!existing) {\r\n await this.boss.createQueue(name);\r\n }\r\n }\r\n\r\n async send(queue: string, data: object): Promise<string | null> {\r\n await this.ensureQueue(queue);\r\n return this.boss.send(queue, data, { retryLimit: 2 });\r\n }\r\n\r\n async schedule(\r\n name: string,\r\n cron: string,\r\n data: object,\r\n options?: { tz?: string }\r\n ): Promise<void> {\r\n await this.ensureQueue(name);\r\n await this.boss.schedule(name, cron, data, options);\r\n }\r\n\r\n async unschedule(name: string): Promise<void> {\r\n try {\r\n await this.boss.unschedule(name);\r\n } catch {\r\n /* schedule may not exist */\r\n }\r\n }\r\n\r\n async registerWork<T extends object>(\r\n queue: string,\r\n handler: (data: T) => Promise<void>\r\n ): Promise<void> {\r\n if (this.workRegistered.has(queue)) return;\r\n await this.ensureQueue(queue);\r\n await this.boss.work(queue, async (jobs) => {\r\n for (const job of jobs) {\r\n await handler(job.data as T);\r\n }\r\n });\r\n this.workRegistered.add(queue);\r\n }\r\n}\r\n","import type { DataSource, EntityTarget } from 'typeorm';\r\nimport type { VendorInviteStatus } from '../entities/vendor.entity';\r\n\r\nexport function inviteStatusForActivation(activation: 'invite' | 'password'): VendorInviteStatus {\r\n return activation === 'invite' ? 'pending' : 'accepted';\r\n}\r\n\r\nexport async function markVendorInviteAcceptedForUser(\r\n dataSource: DataSource,\r\n vendorEntity: EntityTarget<object>,\r\n userId: number\r\n): Promise<void> {\r\n await dataSource.getRepository(vendorEntity).update({ userId }, { inviteStatus: 'accepted' });\r\n}\r\n\r\nexport async function markVendorInvitePendingForUser(\r\n dataSource: DataSource,\r\n vendorEntity: EntityTarget<object>,\r\n userId: number\r\n): Promise<void> {\r\n await dataSource.getRepository(vendorEntity).update({ userId }, { inviteStatus: 'pending' });\r\n}\r\n","/** API resource keys excluded from the permission matrix (internal / not admin-CRUD). */\r\nexport const PERMISSION_ENTITY_INTERNAL_EXCLUDE = new Set([\r\n 'users',\r\n 'password_reset_tokens',\r\n 'user_groups',\r\n 'permissions',\r\n 'comments',\r\n 'form_fields',\r\n 'configs',\r\n 'knowledge_base_chunks',\r\n 'carts',\r\n 'cart_items',\r\n 'wishlists',\r\n 'wishlist_items',\r\n 'message_templates',\r\n 'vendor_users',\r\n]);\r\n\r\n/** Non-CRUD admin surfaces mapped to entity keys for RBAC. */\r\nexport const PERMISSION_LOGICAL_ENTITIES = [\r\n 'users',\r\n 'forms',\r\n 'form_submissions',\r\n 'dashboard',\r\n 'upload',\r\n 'settings',\r\n 'analytics',\r\n 'chat',\r\n] as const;\r\n\r\n/** Canonical name for new installs / migrations */\r\nexport const ADMIN_GROUP_NAME = 'Administrator';\r\n\r\n/** System administrator group (roles UI + users / user_groups / permissions bypass). */\r\nexport function isSuperAdminGroupName(name: string | null | undefined): boolean {\r\n return name === ADMIN_GROUP_NAME;\r\n}\r\n\r\nexport type EntityCrudAction = 'create' | 'read' | 'update' | 'delete';\r\n\r\nexport type EntityPermissionFlags = { c: boolean; r: boolean; u: boolean; d: boolean };\r\n\r\nexport function getPermissionableEntityKeys(entityMap: Record<string, unknown>): string[] {\r\n const fromMap = Object.keys(entityMap).filter((k) => !PERMISSION_ENTITY_INTERNAL_EXCLUDE.has(k));\r\n const logical = PERMISSION_LOGICAL_ENTITIES.filter((k) => !fromMap.includes(k));\r\n return [...fromMap.sort(), ...logical].filter((k, i, a) => a.indexOf(k) === i);\r\n}\r\n\r\nexport function permissionRowsToRecord(\r\n rows: Array<{ entity: string; canCreate: boolean; canRead: boolean; canUpdate: boolean; canDelete: boolean }> | undefined\r\n): Record<string, EntityPermissionFlags> {\r\n const out: Record<string, EntityPermissionFlags> = {};\r\n if (!rows?.length) return out;\r\n for (const p of rows) {\r\n out[p.entity] = {\r\n c: !!p.canCreate,\r\n r: !!p.canRead,\r\n u: !!p.canUpdate,\r\n d: !!p.canDelete,\r\n };\r\n }\r\n return out;\r\n}\r\n\r\nexport function hasEntityPermission(\r\n record: Record<string, EntityPermissionFlags> | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): boolean {\r\n const p = record?.[entity];\r\n if (!p) return false;\r\n if (action === 'create') return p.c;\r\n if (action === 'read') return p.r;\r\n if (action === 'update') return p.u;\r\n return p.d;\r\n}\r\n","import type { SessionUser } from './helpers';\r\nimport { isSuperAdminGroupName } from './permission-entities';\r\nimport { isVendorGroupName } from './vendor-scope';\r\n\r\n/** Platform super admin (`user_groups.id = 1` or Administrator group). */\r\nexport const SUPER_ADMIN_GROUP_ID = 1;\r\n\r\n/** Vendor store admin (`user_groups.id = 5` or vendor-linked portal users). */\r\nexport const VENDOR_ADMIN_GROUP_ID = 5;\r\n\r\nexport function isSuperAdmin(user: SessionUser | null | undefined): boolean {\r\n if (!user) return false;\r\n if (user.groupId === SUPER_ADMIN_GROUP_ID) return true;\r\n if (user.isRBACAdmin === true) return true;\r\n return isSuperAdminGroupName(user.groupName);\r\n}\r\n\r\nexport function isVendorAdmin(user: SessionUser | null | undefined): boolean {\r\n if (!user?.email || isSuperAdmin(user)) return false;\r\n if (user.groupId === VENDOR_ADMIN_GROUP_ID) return true;\r\n if ((user.vendorIds?.length ?? 0) > 0) return true;\r\n return isVendorGroupName(user.groupName);\r\n}\r\n","import type { SessionUser } from './helpers';\r\nimport { isSuperAdmin, isVendorAdmin } from './role-helpers';\r\n\r\n/** Entities with a `vendorId` column (store data). */\r\nexport const VENDOR_SCOPED_STORE_ENTITIES = new Set([\r\n 'products',\r\n 'collections',\r\n 'brands',\r\n 'product_categories',\r\n 'orders',\r\n 'payments',\r\n 'taxes',\r\n 'attributes',\r\n 'vendor_customers',\r\n 'discounts',\r\n]);\r\n\r\n/**\r\n * Store admin RBAC for vendor portal users (read/create/update/delete fallbacks in rbac-debug).\r\n * Includes entities without `vendorId` that are still part of the store admin UI.\r\n */\r\nexport const VENDOR_STORE_RBAC_ENTITIES = new Set<string>([\r\n ...VENDOR_SCOPED_STORE_ENTITIES,\r\n 'order_discounts',\r\n 'order_addresses',\r\n]);\r\n\r\nexport type VendorScope =\r\n | { type: 'all' }\r\n | { type: 'vendor'; vendorId: number; vendorIds: number[] }\r\n | { type: 'deny' };\r\n\r\nexport const VENDOR_OWNER_GROUP_NAME = 'Vendor Owner';\r\n\r\n/** User groups treated as vendor store staff (sidebar + scoped admin). */\r\nexport function isVendorGroupName(name: string | null | undefined): boolean {\r\n if (!name?.trim()) return false;\r\n const n = name.trim().toLowerCase();\r\n return n === VENDOR_OWNER_GROUP_NAME.toLowerCase() || n.includes('vendor');\r\n}\r\n\r\nexport function isPlatformAdministrator(user: SessionUser | null | undefined): boolean {\r\n if (!user?.email) return false;\r\n return isSuperAdmin(user);\r\n}\r\n\r\n/** Vendor portal UI (store + store admin), not platform admin. */\r\nexport function isVendorPortalUser(user: SessionUser | null | undefined): boolean {\r\n if (user?.isVendorPortal === true) return true;\r\n if (!user?.email || isPlatformAdministrator(user)) return false;\r\n if (isVendorAdmin(user)) return true;\r\n return isVendorGroupName(user.groupName);\r\n}\r\n\r\nexport function isVendorStaff(user: SessionUser | null | undefined): boolean {\r\n return isVendorPortalUser(user);\r\n}\r\n\r\n/** Vendor store owner (manages team + role permissions for their group). */\r\nexport function isVendorOwner(user: SessionUser | null | undefined): boolean {\r\n if (user?.isVendorOwner === true) return true;\r\n if (!user?.email || isPlatformAdministrator(user)) return false;\r\n if (user.vendorRole === 'staff') return false;\r\n if (user.vendorRole === 'owner') return true;\r\n if (!isVendorPortalUser(user)) return false;\r\n return user.groupName?.trim().toLowerCase() === VENDOR_OWNER_GROUP_NAME.toLowerCase();\r\n}\r\n\r\nexport function canManageVendorTeam(user: SessionUser | null | undefined): boolean {\r\n return isPlatformAdministrator(user) || isVendorOwner(user);\r\n}\r\n\r\nexport function canManageVendorRoles(user: SessionUser | null | undefined): boolean {\r\n return isPlatformAdministrator(user) || isVendorOwner(user);\r\n}\r\n\r\n/** Platform admins (Administrator group) can onboard vendors. */\r\nexport function canOnboardVendors(user: SessionUser | null | undefined): boolean {\r\n return isPlatformAdministrator(user);\r\n}\r\n\r\nexport function resolveVendorScopeFromSessionUser(user: SessionUser | null | undefined): VendorScope {\r\n if (!user?.email) return { type: 'deny' };\r\n if (isPlatformAdministrator(user)) return { type: 'all' };\r\n const vendorIds = user.vendorIds ?? [];\r\n if (vendorIds.length === 0) return { type: 'deny' };\r\n const preferred = user.activeVendorId ?? vendorIds[0]!;\r\n const vendorId = vendorIds.includes(preferred) ? preferred : vendorIds[0]!;\r\n return { type: 'vendor', vendorId, vendorIds };\r\n}\r\n\r\n/** Compute portal flags at login (persist on JWT). */\r\nexport function vendorPortalFlagsFromUser(input: {\r\n email: string;\r\n isRBACAdmin: boolean;\r\n groupName?: string | null;\r\n vendorIds?: number[];\r\n vendorRole?: 'owner' | 'staff' | null;\r\n}): { isVendorPortal: boolean; isVendorOwner: boolean } {\r\n const vendorIds = input.vendorIds ?? [];\r\n const isVendorPortal =\r\n !input.isRBACAdmin &&\r\n (vendorIds.length > 0 || isVendorGroupName(input.groupName));\r\n const isVendorOwner =\r\n isVendorPortal &&\r\n input.vendorRole !== 'staff' &&\r\n (input.vendorRole === 'owner' ||\r\n input.groupName?.trim().toLowerCase() === VENDOR_OWNER_GROUP_NAME.toLowerCase());\r\n return { isVendorPortal, isVendorOwner };\r\n}\r\n","import { permissionRowsToRecord } from './permission-entities';\r\nimport type { RbacDebugDataSource } from './rbac-debug';\r\nimport { summarizeEntityPerms } from './rbac-debug';\r\n\r\n/** Load permission rows from DB for debug (server/API only — do not import from `@infuro/cms-core/auth`). */\r\nexport async function loadDbPermissionsForUser(\r\n dataSource: RbacDebugDataSource,\r\n userId: number\r\n): Promise<{\r\n groupId: number | null;\r\n groupName: string | null;\r\n dbEntityPerms: Record<string, { c: boolean; r: boolean; u: boolean; d: boolean }>;\r\n}> {\r\n const rows = (await dataSource.query(\r\n `\r\n SELECT u.\"groupId\" AS \"groupId\", g.name AS \"groupName\",\r\n p.entity, p.\"canCreate\", p.\"canRead\", p.\"canUpdate\", p.\"canDelete\"\r\n FROM users u\r\n LEFT JOIN user_groups g ON g.id = u.\"groupId\" AND g.deleted = false\r\n LEFT JOIN permissions p ON p.\"groupId\" = g.id\r\n WHERE u.id = $1\r\n `,\r\n [userId]\r\n )) as Array<{\r\n groupId: number | null;\r\n groupName: string | null;\r\n entity: string | null;\r\n canCreate: boolean | null;\r\n canRead: boolean | null;\r\n canUpdate: boolean | null;\r\n canDelete: boolean | null;\r\n }>;\r\n\r\n const groupId = rows[0]?.groupId ?? null;\r\n const groupName = rows[0]?.groupName ?? null;\r\n const permRows = rows\r\n .filter((r) => r.entity)\r\n .map((r) => ({\r\n entity: r.entity!,\r\n canCreate: !!r.canCreate,\r\n canRead: !!r.canRead,\r\n canUpdate: !!r.canUpdate,\r\n canDelete: !!r.canDelete,\r\n }));\r\n\r\n return {\r\n groupId,\r\n groupName,\r\n dbEntityPerms: summarizeEntityPerms(permissionRowsToRecord(permRows)),\r\n };\r\n}\r\n","import type { EntityCrudAction, EntityPermissionFlags } from './permission-entities';\r\nimport { hasEntityPermission } from './permission-entities';\r\nimport type { SessionUser } from './helpers';\r\nimport { isVendorOwner, isVendorPortalUser, VENDOR_STORE_RBAC_ENTITIES } from './vendor-scope';\r\n\r\nconst LOG_PREFIX = '[cms-rbac]';\r\n\r\n/** Minimal DB handle for RBAC debug (avoids importing `typeorm` in the auth bundle). */\r\nexport type RbacDebugDataSource = {\r\n query: (sql: string, parameters?: unknown[]) => Promise<unknown>;\r\n};\r\n\r\n/** Set `CMS_RBAC_DEBUG=true` in `.env` to log permission decisions (server console). */\r\nexport function isRbacDebugEnabled(): boolean {\r\n const v = process.env.CMS_RBAC_DEBUG?.trim().toLowerCase();\r\n if (v === '1' || v === 'true' || v === 'yes') return true;\r\n if (v === '0' || v === 'false' || v === 'no') return false;\r\n return process.env.NODE_ENV === 'development';\r\n}\r\n\r\nexport function logRbac(message: string, data?: Record<string, unknown>): void {\r\n if (!isRbacDebugEnabled()) return;\r\n if (data) console.info(LOG_PREFIX, message, data);\r\n else console.info(LOG_PREFIX, message);\r\n}\r\n\r\nexport function summarizeEntityPerms(\r\n entityPerms: Record<string, EntityPermissionFlags> | undefined\r\n): Record<string, { c: boolean; r: boolean; u: boolean; d: boolean }> {\r\n const out: Record<string, { c: boolean; r: boolean; u: boolean; d: boolean }> = {};\r\n if (!entityPerms) return out;\r\n for (const [entity, p] of Object.entries(entityPerms)) {\r\n out[entity] = { c: p.c, r: p.r, u: p.u, d: p.d };\r\n }\r\n return out;\r\n}\r\n\r\nexport interface EntityAccessExplanation {\r\n allowed: boolean;\r\n reason: string;\r\n userSnapshot: Record<string, unknown>;\r\n}\r\n\r\nfunction vendorPortalFallbackReason(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): string | null {\r\n if (!isVendorPortalUser(user)) return null;\r\n if (entity === 'dashboard' && action === 'read') return 'vendor_portal_dashboard_fallback';\r\n if (entity === 'analytics' && action === 'read') return 'vendor_portal_analytics_fallback';\r\n if (entity === 'settings' && action === 'read') return 'vendor_portal_settings_read_fallback';\r\n if (VENDOR_STORE_RBAC_ENTITIES.has(entity) && action === 'read') return 'vendor_portal_store_read_fallback';\r\n return null;\r\n}\r\n\r\n/** Same rules as `sessionHasEntityAccess`, but returns why access was granted or denied. */\r\nexport function explainSessionEntityAccess(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): EntityAccessExplanation {\r\n const userSnapshot: Record<string, unknown> = {\r\n email: user?.email ?? null,\r\n id: user?.id ?? null,\r\n groupId: user?.groupId ?? null,\r\n groupName: user?.groupName ?? null,\r\n isRBACAdmin: user?.isRBACAdmin ?? false,\r\n adminAccess: user?.adminAccess ?? null,\r\n vendorIds: user?.vendorIds ?? [],\r\n activeVendorId: user?.activeVendorId ?? null,\r\n vendorRole: user?.vendorRole ?? null,\r\n isVendorPortal: user?.isVendorPortal ?? false,\r\n isVendorOwner: user?.isVendorOwner ?? false,\r\n isVendorPortalComputed: isVendorPortalUser(user),\r\n isVendorOwnerComputed: isVendorOwner(user),\r\n jwtEntityPerms: summarizeEntityPerms(user?.entityPerms),\r\n jwtEntityPermForTarget: user?.entityPerms?.[entity] ?? null,\r\n };\r\n\r\n if (!user?.email) {\r\n return { allowed: false, reason: 'no_session_email', userSnapshot };\r\n }\r\n if (user.isRBACAdmin) {\r\n return { allowed: true, reason: 'platform_administrator', userSnapshot };\r\n }\r\n\r\n const vendorIds = user.vendorIds ?? [];\r\n const isStaff = user.vendorRole === 'staff';\r\n\r\n if (vendorIds.length > 0) {\r\n if (entity === 'dashboard' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_link_dashboard_read', userSnapshot };\r\n }\r\n if (entity === 'analytics' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_link_analytics_read', userSnapshot };\r\n }\r\n if (entity === 'settings') {\r\n if (action === 'read') {\r\n return { allowed: true, reason: 'vendor_link_settings_read', userSnapshot };\r\n }\r\n if (action === 'update' && !isStaff) {\r\n return { allowed: true, reason: 'vendor_link_settings_update', userSnapshot };\r\n }\r\n }\r\n if (VENDOR_STORE_RBAC_ENTITIES.has(entity)) {\r\n if (isStaff && action === 'read') {\r\n return { allowed: true, reason: 'vendor_staff_store_read', userSnapshot };\r\n }\r\n if (!isStaff) {\r\n return { allowed: true, reason: 'vendor_link_store_full', userSnapshot };\r\n }\r\n return {\r\n allowed: false,\r\n reason: 'vendor_staff_store_write_denied',\r\n userSnapshot,\r\n };\r\n }\r\n }\r\n\r\n if (isVendorPortalUser(user) && isVendorOwner(user)) {\r\n if (entity === 'dashboard' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_owner_group_dashboard', userSnapshot };\r\n }\r\n if (entity === 'analytics' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_owner_group_analytics', userSnapshot };\r\n }\r\n if (entity === 'settings' && (action === 'read' || action === 'update')) {\r\n return { allowed: true, reason: 'vendor_owner_group_settings', userSnapshot };\r\n }\r\n if (VENDOR_STORE_RBAC_ENTITIES.has(entity)) {\r\n return { allowed: true, reason: 'vendor_owner_group_store', userSnapshot };\r\n }\r\n }\r\n\r\n const vendorPortalReason = vendorPortalFallbackReason(user, entity, action);\r\n if (vendorPortalReason) {\r\n return { allowed: true, reason: vendorPortalReason, userSnapshot };\r\n }\r\n\r\n const explicit = user.entityPerms?.[entity];\r\n if (explicit !== undefined) {\r\n const allowed = hasEntityPermission(user.entityPerms, entity, action);\r\n return {\r\n allowed,\r\n reason: allowed ? 'jwt_entity_perms_allow' : 'jwt_entity_perms_deny',\r\n userSnapshot,\r\n };\r\n }\r\n\r\n const allowed = hasEntityPermission(user.entityPerms, entity, action);\r\n return {\r\n allowed,\r\n reason: allowed ? 'entity_perms_fallback_allow' : 'no_matching_rule',\r\n userSnapshot,\r\n };\r\n}\r\n\r\nexport function sessionHasEntityAccessFromExplanation(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): boolean {\r\n return explainSessionEntityAccess(user, entity, action).allowed;\r\n}\r\n\r\nexport async function logEntityAccessDecision(\r\n dataSource: RbacDebugDataSource | undefined,\r\n context: string,\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction,\r\n extra?: Record<string, unknown>\r\n): Promise<void> {\r\n if (!isRbacDebugEnabled()) return;\r\n\r\n const explanation = explainSessionEntityAccess(user, entity, action);\r\n let dbPermissions: Record<string, unknown> | undefined;\r\n if (dataSource && user?.id) {\r\n const id = Number(user.id);\r\n if (Number.isFinite(id)) {\r\n try {\r\n const { loadDbPermissionsForUser } = await import('./rbac-debug-db');\r\n dbPermissions = await loadDbPermissionsForUser(dataSource, id);\r\n } catch (e) {\r\n dbPermissions = { error: e instanceof Error ? e.message : String(e) };\r\n }\r\n }\r\n }\r\n\r\n logRbac(context, {\r\n entity,\r\n action,\r\n allowed: explanation.allowed,\r\n reason: explanation.reason,\r\n ...explanation.userSnapshot,\r\n dbPermissions,\r\n ...extra,\r\n });\r\n}\r\n","export function renderOrderTrackingPage(order: Record<string, unknown>): string {\r\n const contact = order.contact as Record<string, unknown> | undefined;\r\n const items = (order.items as Array<{\r\n id: number;\r\n quantity: number;\r\n unitPrice: number;\r\n total: number;\r\n product?: { name?: string; sku?: string; collection?: { name?: string } };\r\n }>) ?? [];\r\n const currency = String(order.currency ?? 'INR');\r\n\r\n function formatMoney(amount: number): string {\r\n return new Intl.NumberFormat('en-IN', {\r\n style: 'currency',\r\n currency,\r\n minimumFractionDigits: 2,\r\n }).format(Number(amount));\r\n }\r\n\r\n function formatDate(dateStr: string): string {\r\n return new Date(dateStr).toLocaleDateString('en-IN', {\r\n year: 'numeric', month: 'long', day: 'numeric',\r\n });\r\n }\r\n\r\n const statusConfig: Record<string, { label: string; color: string; step: number }> = {\r\n pending: { label: 'Order Placed', color: '#f59e0b', step: 1 },\r\n confirmed: { label: 'Confirmed', color: '#3b82f6', step: 2 },\r\n processing: { label: 'Processing', color: '#8b5cf6', step: 3 },\r\n completed: { label: 'Completed', color: '#10b981', step: 4 },\r\n cancelled: { label: 'Cancelled', color: '#ef4444', step: 0 },\r\n };\r\n\r\n const status = String(order.status ?? 'pending');\r\n const sc = statusConfig[status] ?? { label: status, color: '#6b7280', step: 1 };\r\n const isCancelled = status === 'cancelled';\r\n\r\n const steps = [\r\n { label: 'Order Placed', icon: '📋' },\r\n { label: 'Confirmed', icon: '✅' },\r\n { label: 'Processing', icon: '⚙️' },\r\n { label: 'Completed', icon: '🎉' },\r\n ];\r\n\r\n const stepsHtml = isCancelled\r\n ? `<div class=\"cancelled-banner\">Order Cancelled</div>`\r\n : steps.map((s, i) => {\r\n const stepNum = i + 1;\r\n const isActive = sc.step === stepNum;\r\n const isDone = sc.step > stepNum;\r\n return `\r\n <div class=\"step ${isDone ? 'done' : ''} ${isActive ? 'active' : ''}\">\r\n <div class=\"step-circle\">${isDone ? '✓' : s.icon}</div>\r\n <div class=\"step-label\">${s.label}</div>\r\n </div>\r\n ${stepNum < 4 ? `<div class=\"step-line ${sc.step > stepNum ? 'done' : ''}\"></div>` : ''}\r\n `;\r\n }).join('');\r\n\r\n const itemsHtml = items.map(item => {\r\n const name = item.product?.collection?.name ?? item.product?.name ?? `Product #${item.id}`;\r\n const sku = item.product?.sku ?? '—';\r\n return `\r\n <div class=\"item-row\">\r\n <div class=\"item-avatar\">${name.charAt(0).toUpperCase()}</div>\r\n <div class=\"item-info\">\r\n <div class=\"item-name\">${name}</div>\r\n <div class=\"item-sku\">SKU: ${sku}</div>\r\n </div>\r\n <div class=\"item-qty\">×${item.quantity}</div>\r\n <div class=\"item-price\">${formatMoney(Number(item.unitPrice))}</div>\r\n </div>\r\n `;\r\n }).join('');\r\n\r\n const discountRow = Number(order.discount) > 0\r\n ? `<div class=\"summary-row discount\"><span>Discount</span><span>−${formatMoney(Number(order.discount))}</span></div>`\r\n : '';\r\n const taxRow = Number(order.tax) > 0\r\n ? `<div class=\"summary-row\"><span>Tax</span><span>${formatMoney(Number(order.tax))}</span></div>`\r\n : '';\r\n\r\n return `<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"UTF-8\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n<title>Order ${order.orderNumber} — Tracking</title>\r\n<link href=\"https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700&family=DM+Sans:wght@400;500;600&display=swap\" rel=\"stylesheet\">\r\n<style>\r\n *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\r\n\r\n :root {\r\n --accent: ${sc.color};\r\n --bg: #f8f7f4;\r\n --card: #ffffff;\r\n --text: #1a1a2e;\r\n --muted: #6b7280;\r\n --border: #e5e7eb;\r\n --radius: 16px;\r\n }\r\n\r\n body {\r\n font-family: 'DM Sans', sans-serif;\r\n background: var(--bg);\r\n color: var(--text);\r\n min-height: 100vh;\r\n padding: 24px 16px 48px;\r\n }\r\n\r\n .container { max-width: 640px; margin: 0 auto; }\r\n\r\n /* Header */\r\n .header {\r\n text-align: center;\r\n margin-bottom: 32px;\r\n animation: fadeDown 0.5s ease both;\r\n }\r\n .header-eyebrow {\r\n font-size: 12px;\r\n font-weight: 600;\r\n letter-spacing: 0.15em;\r\n text-transform: uppercase;\r\n color: var(--accent);\r\n margin-bottom: 8px;\r\n }\r\n .header h1 {\r\n font-family: 'Playfair Display', serif;\r\n font-size: clamp(26px, 6vw, 36px);\r\n color: var(--text);\r\n line-height: 1.2;\r\n }\r\n .header-meta {\r\n font-size: 13px;\r\n color: var(--muted);\r\n margin-top: 6px;\r\n }\r\n\r\n /* Status badge */\r\n .status-badge {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n background: color-mix(in srgb, var(--accent) 12%, transparent);\r\n color: var(--accent);\r\n border: 1.5px solid color-mix(in srgb, var(--accent) 30%, transparent);\r\n border-radius: 100px;\r\n padding: 5px 14px;\r\n font-size: 13px;\r\n font-weight: 600;\r\n margin-top: 14px;\r\n }\r\n .status-dot {\r\n width: 7px; height: 7px;\r\n border-radius: 50%;\r\n background: var(--accent);\r\n animation: pulse 2s ease infinite;\r\n }\r\n\r\n /* Card */\r\n .card {\r\n background: var(--card);\r\n border-radius: var(--radius);\r\n border: 1px solid var(--border);\r\n overflow: hidden;\r\n margin-bottom: 16px;\r\n animation: fadeUp 0.5s ease both;\r\n }\r\n .card:nth-child(2) { animation-delay: 0.08s; }\r\n .card:nth-child(3) { animation-delay: 0.16s; }\r\n .card:nth-child(4) { animation-delay: 0.24s; }\r\n\r\n .card-header {\r\n display: flex; align-items: center; gap: 10px;\r\n padding: 16px 20px;\r\n border-bottom: 1px solid var(--border);\r\n background: #fafafa;\r\n }\r\n .card-header-icon {\r\n width: 32px; height: 32px;\r\n border-radius: 8px;\r\n background: color-mix(in srgb, var(--accent) 12%, transparent);\r\n display: flex; align-items: center; justify-content: center;\r\n font-size: 15px;\r\n }\r\n .card-title {\r\n font-size: 13px;\r\n font-weight: 600;\r\n letter-spacing: 0.05em;\r\n text-transform: uppercase;\r\n color: var(--muted);\r\n }\r\n .card-body { padding: 20px; }\r\n\r\n /* Progress tracker */\r\n .progress-track {\r\n display: flex;\r\n align-items: flex-start;\r\n justify-content: space-between;\r\n padding: 8px 0;\r\n overflow-x: auto;\r\n }\r\n .step {\r\n display: flex; flex-direction: column; align-items: center;\r\n gap: 8px; min-width: 60px;\r\n }\r\n .step-circle {\r\n width: 44px; height: 44px;\r\n border-radius: 50%;\r\n border: 2px solid var(--border);\r\n background: white;\r\n display: flex; align-items: center; justify-content: center;\r\n font-size: 18px;\r\n color: var(--muted);\r\n transition: all 0.3s;\r\n }\r\n .step.done .step-circle {\r\n background: color-mix(in srgb, var(--accent) 15%, white);\r\n border-color: var(--accent);\r\n color: var(--accent);\r\n font-size: 16px;\r\n font-weight: 700;\r\n }\r\n .step.active .step-circle {\r\n background: var(--accent);\r\n border-color: var(--accent);\r\n color: white;\r\n box-shadow: 0 0 0 5px color-mix(in srgb, var(--accent) 20%, transparent);\r\n }\r\n .step-label {\r\n font-size: 11px; font-weight: 500; color: var(--muted);\r\n text-align: center; line-height: 1.3;\r\n }\r\n .step.active .step-label, .step.done .step-label { color: var(--accent); font-weight: 600; }\r\n .step-line {\r\n flex: 1; height: 2px;\r\n background: var(--border);\r\n margin-top: 22px; min-width: 20px;\r\n transition: background 0.3s;\r\n }\r\n .step-line.done { background: var(--accent); }\r\n .cancelled-banner {\r\n text-align: center; padding: 16px;\r\n background: #fef2f2; color: #ef4444;\r\n border-radius: 10px;\r\n font-weight: 600; font-size: 15px;\r\n }\r\n\r\n /* Info grid */\r\n .info-grid {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));\r\n gap: 16px;\r\n }\r\n .info-item dt {\r\n font-size: 11px; font-weight: 600;\r\n text-transform: uppercase; letter-spacing: 0.08em;\r\n color: var(--muted); margin-bottom: 4px;\r\n }\r\n .info-item dd { font-size: 14px; font-weight: 500; color: var(--text); }\r\n\r\n /* Customer */\r\n .customer-row {\r\n display: flex; align-items: center; gap: 14px;\r\n }\r\n .customer-avatar {\r\n width: 46px; height: 46px; border-radius: 50%;\r\n background: color-mix(in srgb, var(--accent) 15%, #f3f4f6);\r\n color: var(--accent);\r\n display: flex; align-items: center; justify-content: center;\r\n font-family: 'Playfair Display', serif;\r\n font-size: 18px; font-weight: 700; flex-shrink: 0;\r\n }\r\n .customer-name { font-size: 15px; font-weight: 600; }\r\n .customer-email { font-size: 13px; color: var(--muted); margin-top: 2px; }\r\n\r\n /* Items */\r\n .item-row {\r\n display: flex; align-items: center; gap: 12px;\r\n padding: 12px 0;\r\n border-bottom: 1px solid var(--border);\r\n }\r\n .item-row:last-child { border-bottom: none; padding-bottom: 0; }\r\n .item-row:first-child { padding-top: 0; }\r\n .item-avatar {\r\n width: 40px; height: 40px; border-radius: 10px;\r\n background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 20%, #e5e7eb), color-mix(in srgb, var(--accent) 5%, #f9fafb));\r\n color: var(--accent);\r\n display: flex; align-items: center; justify-content: center;\r\n font-size: 16px; font-weight: 700; flex-shrink: 0;\r\n }\r\n .item-info { flex: 1; min-width: 0; }\r\n .item-name { font-size: 14px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\r\n .item-sku { font-size: 12px; color: var(--muted); margin-top: 2px; }\r\n .item-qty { font-size: 13px; color: var(--muted); min-width: 28px; text-align: center; }\r\n .item-price { font-size: 14px; font-weight: 600; min-width: 80px; text-align: right; }\r\n\r\n /* Summary */\r\n .summary-row {\r\n display: flex; justify-content: space-between;\r\n font-size: 14px; padding: 7px 0; color: var(--muted);\r\n }\r\n .summary-row.discount { color: #10b981; }\r\n .summary-row.total {\r\n font-size: 17px; font-weight: 700; color: var(--text);\r\n border-top: 2px solid var(--border); margin-top: 6px; padding-top: 14px;\r\n }\r\n\r\n /* Footer */\r\n .footer {\r\n text-align: center; margin-top: 32px;\r\n font-size: 12px; color: #9ca3af;\r\n animation: fadeUp 0.5s ease 0.4s both;\r\n }\r\n\r\n /* Animations */\r\n @keyframes fadeDown {\r\n from { opacity: 0; transform: translateY(-16px); }\r\n to { opacity: 1; transform: translateY(0); }\r\n }\r\n @keyframes fadeUp {\r\n from { opacity: 0; transform: translateY(16px); }\r\n to { opacity: 1; transform: translateY(0); }\r\n }\r\n @keyframes pulse {\r\n 0%, 100% { opacity: 1; }\r\n 50% { opacity: 0.4; }\r\n }\r\n</style>\r\n</head>\r\n<body>\r\n<div class=\"container\">\r\n\r\n <!-- Header -->\r\n <div class=\"header\">\r\n <div class=\"header-eyebrow\">Order Tracking</div>\r\n <h1>${String(order.orderNumber)}</h1>\r\n <div class=\"header-meta\">Placed on ${formatDate(String(order.createdAt))}</div>\r\n <div><span class=\"status-badge\"><span class=\"status-dot\"></span>${sc.label}</span></div>\r\n </div>\r\n\r\n <!-- Progress -->\r\n <div class=\"card\">\r\n <div class=\"card-header\">\r\n <div class=\"card-header-icon\">🚚</div>\r\n <div class=\"card-title\">Order Progress</div>\r\n </div>\r\n <div class=\"card-body\">\r\n <div class=\"progress-track\">${stepsHtml}</div>\r\n </div>\r\n </div>\r\n\r\n ${contact ? `\r\n <!-- Customer -->\r\n <div class=\"card\">\r\n <div class=\"card-header\">\r\n <div class=\"card-header-icon\">👤</div>\r\n <div class=\"card-title\">Customer</div>\r\n </div>\r\n <div class=\"card-body\">\r\n <div class=\"customer-row\">\r\n <div class=\"customer-avatar\">${String(contact.name ?? '?').charAt(0).toUpperCase()}</div>\r\n <div>\r\n <div class=\"customer-name\">${String(contact.name ?? '—')}</div>\r\n <div class=\"customer-email\">${String(contact.email ?? '—')}</div>\r\n ${contact.phone ? `<div class=\"customer-email\">${String(contact.phone)}</div>` : ''}\r\n </div>\r\n </div>\r\n </div>\r\n </div>` : ''}\r\n\r\n <!-- Items -->\r\n <div class=\"card\">\r\n <div class=\"card-header\">\r\n <div class=\"card-header-icon\">📦</div>\r\n <div class=\"card-title\">Items (${items.length})</div>\r\n </div>\r\n <div class=\"card-body\">\r\n ${items.length === 0 ? '<p style=\"color:var(--muted);font-size:14px;\">No items</p>' : itemsHtml}\r\n </div>\r\n </div>\r\n\r\n <!-- Summary -->\r\n <div class=\"card\">\r\n <div class=\"card-header\">\r\n <div class=\"card-header-icon\">🧾</div>\r\n <div class=\"card-title\">Order Summary</div>\r\n </div>\r\n <div class=\"card-body\">\r\n <div class=\"summary-row\"><span>Subtotal</span><span>${formatMoney(Number(order.subtotal))}</span></div>\r\n ${discountRow}\r\n ${taxRow}\r\n <div class=\"summary-row total\"><span>Total</span><span>${formatMoney(Number(order.total))}</span></div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"footer\">Scan the QR code on your receipt to return to this page.</div>\r\n</div>\r\n</body>\r\n</html>`;\r\n}","export * from './plugins/types';\r\nexport * from './plugins/registry';\r\nexport {\r\n erpPlugin,\r\n ERPSubmissionService,\r\n registerErpQueueProcessor,\r\n queueErp,\r\n queueErpPaidOrderForOrderId,\r\n queueErpCreateContactIfEnabled,\r\n type ErpPaidOrderDataSource,\r\n type ErpPaidOrderEntityMap,\r\n type ErpContactSyncInput,\r\n} from './plugins/erp';\r\nexport type {\r\n ERPPluginConfig,\r\n ERPPluginInstance,\r\n ErpJobPayload,\r\n ErpCreateContactPayload,\r\n PipelineNames,\r\n} from './plugins/erp';\r\nexport { emailPlugin, EmailService, emailTemplates, renderEmail, getCompanyDetailsFromSettings, mergeEmailLayoutCompanyDetails, renderLayout, registerEmailQueueProcessor, queueEmail, queueOrderPlacedEmails, queueVendorOnboardEmails } from './plugins/email';\r\nexport type {\r\n EmailPluginConfig,\r\n EmailData,\r\n EmailServiceInterface,\r\n RenderedEmail,\r\n CompanyDetails,\r\n SocialLinkItem,\r\n EmailTemplateName,\r\n EmailTemplateResult,\r\n TemplateContext,\r\n RenderEmailOptions,\r\n EmailJobPayload,\r\n OrderPlacedEmailPayload,\r\n OrderPlacedLineItem,\r\n} from './plugins/email';\r\nexport { analyticsPlugin } from './plugins/analytics';\r\nexport type { AnalyticsPluginConfig } from './plugins/analytics';\r\nexport { smsPlugin, registerSmsQueueProcessor, queueSms } from './plugins/sms';\r\nexport type {\r\n SmsPluginConfig,\r\n SmsServiceInterface,\r\n SmsJobPayload,\r\n SmsProviderId,\r\n SmsProviderChoice,\r\n SmsServiceConfig,\r\n} from './plugins/sms';\r\nexport { paymentPlugin } from './plugins/payment';\r\nexport type { PaymentPluginConfig, PaymentServiceInterface, PaymentIntent } from './plugins/payment';\r\nexport { s3StoragePlugin, localStoragePlugin } from './plugins/storage';\r\nexport type { StorageService, S3StoragePluginConfig, LocalStoragePluginConfig } from './plugins/storage';\r\nexport { llmPlugin, LlmService, parseHfInferenceEmbeddingBody } from './plugins/llm';\r\nexport type {\r\n LlmPluginConfig,\r\n LlmServiceInterface,\r\n LlmServiceEmbedOptions,\r\n LlmEmbeddingProvider,\r\n LlmMessage,\r\n LlmChatOptions,\r\n LlmAgentOptions,\r\n} from './plugins/llm';\r\nexport { cachePlugin } from './plugins/cache';\r\nexport type { CacheService, CachePluginConfig } from './plugins/cache';\r\nexport { queuePlugin } from './plugins/queue';\r\nexport type { QueueService, QueuePluginConfig } from './plugins/queue';\r\nexport { pgBossPlugin, PgBossService, JOB_RUNNER_QUEUE } from './plugins/pg-boss';\r\nexport type { PgBossPluginConfig, JobRunnerPayload } from './plugins/pg-boss';\r\nexport {\r\n registerJobRunnerWorker,\r\n ensureScheduleQueueWorker,\r\n} from './plugins/jobs/job-runner';\r\nexport type { JobRunnerDeps, CmsAppLike as JobRunnerCmsAppLike } from './plugins/jobs/job-runner';\r\nexport { syncJobScheduleToPgBoss, queueJobScheduleNow } from './plugins/jobs/schedule-sync';\r\nexport {\r\n buildCronFromSchedule,\r\n pgBossScheduleNameForId,\r\n validateScheduleInput,\r\n} from './plugins/jobs/schedule-cron';\r\nexport { createJobScheduleHandlers } from './api/job-schedule-handlers';\r\nexport type { JobScheduleApiConfig } from './api/job-schedule-handlers';\r\nexport { captchaPlugin, CaptchaService, buildCaptchaPublicConfig, assertCaptchaOk } from './plugins/captcha';\r\nexport type { CaptchaPublicConfig, CaptchaProviderId, CaptchaVerifyResult } from './plugins/captcha';\r\nexport {\r\n blogGeneratorPlugin,\r\n BlogGeneratorService,\r\n getRssArticleSummaryFromItem,\r\n parseBlogGeneratorAgentContent,\r\n parseBlogGeneratorModelOutput,\r\n buildRssUserPromptFromFeeds,\r\n buildBlogMetadataUserPrompt,\r\n parseBlogMetadataEnrichmentJson,\r\n resolveBlogCategoryIdByName,\r\n BLOG_GENERATOR_AGENT_NAME,\r\n BLOG_GENERATOR_LLM_AGENT_SLUG,\r\n BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR,\r\n BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION,\r\n BLOG_GENERATOR_DEFAULT_VALIDATION_RULES,\r\n BLOG_METADATA_ENRICHER_AGENT_NAME,\r\n BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG,\r\n BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION,\r\n BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES,\r\n} from './plugins/blog-generator';\r\nexport {\r\n socialMediaPlugin,\r\n createSocialMediaHandlers,\r\n metaFetchUserManagedPages,\r\n metaPostPageFeed,\r\n metaPostPagePhoto,\r\n metaResolvePageAccessToken,\r\n} from './plugins/social-media';\r\nexport type {\r\n SocialMediaPluginConfig,\r\n FacebookMeAccountsResponse,\r\n FacebookPageAccount,\r\n MetaGraphMutationResponse,\r\n} from './plugins/social-media';\r\nexport type {\r\n BlogGeneratorPluginConfig,\r\n LatestArticleFromFeed,\r\n BlogGeneratorBlogDraft,\r\n BlogGeneratorSeoDraft,\r\n BlogGeneratorDraftParseMode,\r\n} from './plugins/blog-generator';\r\nexport * from './lib';\r\nexport * from './entities';\r\nexport * from './auth';\r\nexport * from './api';\r\nexport { DEFAULT_ADMIN_NAV } from './admin/config';\r\nexport type { AdminNavItem } from './admin/config';\r\nconsole.log(\"🔥 USING LOCAL CMS CORE(index.ts loaded) 🔥\");\r\n","import type { CmsPlugin, PluginContext } from './types';\n\nexport interface CreateCmsAppOptions {\n dataSource: unknown;\n config?: Record<string, string>;\n plugins?: CmsPlugin[];\n logger?: PluginContext['logger'];\n}\n\nconst noopLogger: PluginContext['logger'] = {\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\nexport interface CmsApp {\n dataSource: unknown;\n getPlugin<T = unknown>(name: string): T | undefined;\n}\n\nexport async function createCmsApp(options: CreateCmsAppOptions): Promise<CmsApp> {\n const { dataSource, config = {}, plugins = [], logger = noopLogger } = options;\n const context: PluginContext = { dataSource, config, logger };\n const registry = new Map<string, unknown>();\n\n for (const plugin of plugins) {\n try {\n const instance = await plugin.init(context);\n registry.set(plugin.name, instance !== undefined ? instance : plugin);\n } catch (err) {\n logger.warn(`Plugin \"${plugin.name}\" failed to init: ${err instanceof Error ? err.message : err}`);\n }\n }\n\n return {\n dataSource,\n getPlugin<T>(name: string): T | undefined {\n return registry.get(name) as T | undefined;\n },\n };\n}\n","import { erpSafeWebhookUrl, errorErp, logErp, warnErp } from './erp-log';\r\n\r\nexport interface ContactFormData {\r\n firstName: string;\r\n lastName: string;\r\n email: string;\r\n phone?: string;\r\n industry?: string;\r\n message?: string;\r\n}\r\n\r\nexport interface ERPSubmissionResult {\r\n success: boolean;\r\n error?: string;\r\n status?: number;\r\n}\r\n\r\nexport type PipelineNames = { pipelineName: string; pipelineStageName: string };\r\n\r\n/** Payload for ERP `create-contact` (§7c) — CRM contact upsert, no lead/opportunity row. */\r\nexport interface ErpCreateContactPayload {\r\n email: string;\r\n firstName: string;\r\n lastName: string;\r\n phone?: string;\r\n companyName?: string;\r\n type?: string;\r\n notes?: string;\r\n tags?: string[];\r\n}\r\n\r\nexport class ERPSubmissionService {\r\n private webhookUrl: string;\r\n private webhookJwt: string;\r\n private getPipelineNames?: () => Promise<PipelineNames>;\r\n\r\n constructor(config: {\r\n webhookUrl: string;\r\n webhookJwt: string;\r\n getPipelineNames?: () => Promise<PipelineNames>;\r\n }) {\r\n this.webhookUrl = config.webhookUrl.replace(/\\/$/, '');\r\n this.webhookJwt = config.webhookJwt;\r\n this.getPipelineNames = config.getPipelineNames;\r\n }\r\n\r\n /** Replace trailing path segment of webhook URL with `action` (e.g. `get-order-status`, `invoice-pdf`). */\r\n resolveErpActionUrl(action: string): string {\r\n const base = this.webhookUrl.replace(/\\/$/, '');\r\n const i = base.lastIndexOf('/');\r\n if (i === -1) return `${base}/${action}`;\r\n return `${base.slice(0, i + 1)}${action}`;\r\n }\r\n\r\n /**\r\n * Synchronous ERP read (§7d): POST JSON to `.../generic-webhook/<action>`.\r\n * Body is sent as-is (or wrap with envelope if ERP expects `event_type` — caller may pass envelope).\r\n */\r\n async postErpReadAction(\r\n action: string,\r\n body: Record<string, unknown>\r\n ): Promise<{ ok: boolean; status?: number; json?: unknown; error?: string }> {\r\n const url = this.resolveErpActionUrl(action);\r\n try {\r\n const res = await fetch(url, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'X-External-Token': this.webhookJwt,\r\n },\r\n body: JSON.stringify(body),\r\n });\r\n const text = await res.text();\r\n let parsed: unknown;\r\n try {\r\n parsed = text ? JSON.parse(text) : null;\r\n } catch {\r\n parsed = null;\r\n }\r\n if (!res.ok) {\r\n return { ok: false, status: res.status, error: `${res.status} ${text.slice(0, 500)}` };\r\n }\r\n return { ok: true, status: res.status, json: parsed };\r\n } catch (e: unknown) {\r\n return { ok: false, error: e instanceof Error ? e.message : 'ERP read request failed' };\r\n }\r\n }\r\n\r\n /** GET PDF bytes for `invoice-pdf` action (§7d). */\r\n async fetchInvoicePdf(invoiceId: string): Promise<{\r\n ok: boolean;\r\n buffer?: ArrayBuffer;\r\n contentType?: string;\r\n error?: string;\r\n }> {\r\n const base = this.resolveErpActionUrl('invoice-pdf');\r\n let u: URL;\r\n try {\r\n u = new URL(base);\r\n } catch {\r\n return { ok: false, error: 'Invalid ERP webhook URL' };\r\n }\r\n u.searchParams.set('invoiceId', invoiceId);\r\n u.searchParams.set('token', this.webhookJwt);\r\n try {\r\n const res = await fetch(u.toString(), { method: 'GET' });\r\n if (!res.ok) {\r\n const t = await res.text();\r\n return { ok: false, error: `${res.status} ${t.slice(0, 200)}` };\r\n }\r\n const buffer = await res.arrayBuffer();\r\n const contentType = res.headers.get('content-type') || 'application/pdf';\r\n return { ok: true, buffer, contentType };\r\n } catch (e: unknown) {\r\n return { ok: false, error: e instanceof Error ? e.message : 'invoice PDF fetch failed' };\r\n }\r\n }\r\n\r\n /** `product.updated` envelope → `update-product` (§7e). */\r\n async submitProductUpsert(productData: Record<string, unknown>): Promise<ERPSubmissionResult> {\r\n const envelope = {\r\n event_type: 'product.updated',\r\n timestamp: new Date().toISOString(),\r\n data: productData,\r\n };\r\n return this.postWebhookJson(envelope);\r\n }\r\n\r\n private summarizeWebhookBody(body: unknown): Record<string, unknown> {\r\n if (!body || typeof body !== 'object' || Array.isArray(body)) {\r\n return { bodyKind: typeof body };\r\n }\r\n const o = body as Record<string, unknown>;\r\n const out: Record<string, unknown> = { event_type: o.event_type, timestamp: o.timestamp };\r\n const data = o.data;\r\n if (data && typeof data === 'object' && !Array.isArray(data)) {\r\n const d = data as Record<string, unknown>;\r\n out.dataKeys = Object.keys(d);\r\n out.platformOrderId = d.platformOrderId ?? d.platformOrderNumber;\r\n out.itemCount = Array.isArray(d.items) ? d.items.length : undefined;\r\n }\r\n return out;\r\n }\r\n\r\n private async postWebhookJson(body: unknown): Promise<ERPSubmissionResult> {\r\n const safeUrl = erpSafeWebhookUrl(this.webhookUrl);\r\n const bodyJson = JSON.stringify(body);\r\n logErp('webhook:post_start', {\r\n url: safeUrl,\r\n bodyBytes: bodyJson.length,\r\n ...this.summarizeWebhookBody(body),\r\n });\r\n try {\r\n const res = await fetch(this.webhookUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'X-External-Token': this.webhookJwt,\r\n },\r\n body: bodyJson,\r\n });\r\n const text = await res.text();\r\n const preview = text.length > 500 ? `${text.slice(0, 500)}…` : text;\r\n if (res.ok) {\r\n logErp('webhook:post_ok', { status: res.status, responsePreview: preview || '(empty body)' });\r\n return { success: true, status: res.status };\r\n }\r\n warnErp('webhook:post_http_error', { status: res.status, responsePreview: preview });\r\n return { success: false, error: `${res.status} ${text.slice(0, 500)}`, status: res.status };\r\n } catch (e: unknown) {\r\n const message = e instanceof Error ? e.message : 'ERP webhook request failed';\r\n errorErp('webhook:post_fetch_failed', { url: safeUrl, message });\r\n return { success: false, error: message };\r\n }\r\n }\r\n\r\n private async resolvePipelineNames(): Promise<PipelineNames> {\r\n let pipelineName = '';\r\n let pipelineStageName = '';\r\n if (this.getPipelineNames) {\r\n try {\r\n const n = await this.getPipelineNames();\r\n pipelineName = (n.pipelineName ?? '').trim();\r\n pipelineStageName = (n.pipelineStageName ?? '').trim();\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n return { pipelineName, pipelineStageName };\r\n }\r\n\r\n /** Generic webhook POST (e.g. order.created envelope). */\r\n async postWebhook(body: unknown): Promise<ERPSubmissionResult> {\r\n return this.postWebhookJson(body);\r\n }\r\n\r\n /** Shared CRM inbound fields (§7a/b in ERP-plugin.md). */\r\n private async buildCrmInboundData(formData: ContactFormData): Promise<{ error?: string; data?: Record<string, unknown> }> {\r\n const email = (formData.email ?? '').trim();\r\n if (!email) {\r\n return { error: 'email is required' };\r\n }\r\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\r\n if (!emailRegex.test(email)) {\r\n return { error: 'Invalid email format' };\r\n }\r\n\r\n const firstName = (formData.firstName ?? '').trim() || email.split('@')[0] || 'Contact';\r\n const lastName = (formData.lastName ?? '').trim() || '';\r\n\r\n const { pipelineName, pipelineStageName } = await this.resolvePipelineNames();\r\n\r\n const data: Record<string, unknown> = {\r\n email,\r\n firstName,\r\n lastName,\r\n phone: formData.phone?.trim() || undefined,\r\n subject: formData.industry?.trim() || undefined,\r\n message: formData.message?.trim() || undefined,\r\n };\r\n if (pipelineName) data.pipelineName = pipelineName;\r\n if (pipelineStageName) data.pipelineStageName = pipelineStageName;\r\n return { data };\r\n }\r\n\r\n /** `lead.created` → ERP create-lead (CRM leads table). */\r\n async submitContact(formData: ContactFormData): Promise<ERPSubmissionResult> {\r\n const built = await this.buildCrmInboundData(formData);\r\n if (built.error || !built.data) {\r\n return { success: false, error: built.error ?? 'invalid payload' };\r\n }\r\n built.data.leadSource = 'Website';\r\n\r\n const envelope = {\r\n event_type: 'lead.created',\r\n timestamp: new Date().toISOString(),\r\n data: built.data,\r\n };\r\n return this.postWebhookJson(envelope);\r\n }\r\n\r\n /** `create-contact` → ERP ContactService upsert (§7c). */\r\n async submitCreateContact(payload: ErpCreateContactPayload): Promise<ERPSubmissionResult> {\r\n const email = (payload.email ?? '').trim();\r\n if (!email) {\r\n return { success: false, error: 'email is required' };\r\n }\r\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\r\n if (!emailRegex.test(email)) {\r\n return { success: false, error: 'Invalid email format' };\r\n }\r\n const firstName = (payload.firstName ?? '').trim() || email.split('@')[0] || 'Contact';\r\n const lastName = (payload.lastName ?? '').trim() || '';\r\n\r\n const data: Record<string, unknown> = {\r\n email,\r\n firstName,\r\n lastName,\r\n phone: payload.phone?.trim() || undefined,\r\n companyName: payload.companyName?.trim() || undefined,\r\n type: payload.type?.trim() || undefined,\r\n message: payload.notes?.trim() || undefined,\r\n metadata: { source: 'cms' },\r\n };\r\n if (payload.tags?.length) {\r\n data.tags = payload.tags;\r\n }\r\n\r\n const envelope = {\r\n event_type: 'create-contact',\r\n timestamp: new Date().toISOString(),\r\n data,\r\n };\r\n return this.postWebhookJson(envelope);\r\n }\r\n\r\n /** `form.submitted` → ERP create-opportunity (pipeline). */\r\n async submitFormOpportunity(formData: ContactFormData): Promise<ERPSubmissionResult> {\r\n const built = await this.buildCrmInboundData(formData);\r\n if (built.error || !built.data) {\r\n return { success: false, error: built.error ?? 'invalid payload' };\r\n }\r\n\r\n const envelope = {\r\n event_type: 'form.submitted',\r\n timestamp: new Date().toISOString(),\r\n data: built.data,\r\n };\r\n return this.postWebhookJson(envelope);\r\n }\r\n\r\n /**\r\n * Order payload aligned with ERP generic webhook create-order (§6).\r\n */\r\n async submitOrder(orderDto: Record<string, unknown>): Promise<ERPSubmissionResult> {\r\n const envelope = {\r\n event_type: 'order.created',\r\n timestamp: new Date().toISOString(),\r\n data: orderDto,\r\n };\r\n logErp('submitOrder:envelope_ready', {\r\n event_type: envelope.event_type,\r\n timestamp: envelope.timestamp,\r\n platformOrderId: orderDto.platformOrderId ?? orderDto.platformOrderNumber,\r\n itemCount: Array.isArray(orderDto.items) ? orderDto.items.length : 0,\r\n paymentCount: Array.isArray(orderDto.payments) ? orderDto.payments.length : 0,\r\n });\r\n const result = await this.postWebhookJson(envelope);\r\n if (result.success) {\r\n logErp('submitOrder:complete', { ok: true, status: result.status });\r\n } else {\r\n warnErp('submitOrder:complete', { ok: false, status: result.status, error: result.error });\r\n }\r\n return result;\r\n }\r\n\r\n extractContactData(formData: Record<string, unknown>, formFields: { id: string | number; type: string; label: string }[]): ContactFormData | null {\r\n const contactData: ContactFormData = {\r\n firstName: '',\r\n lastName: '',\r\n email: '',\r\n phone: '',\r\n industry: '',\r\n message: '',\r\n };\r\n let hasEmail = false;\r\n\r\n for (const field of formFields) {\r\n const fieldValue = formData[field.id.toString()];\r\n if (fieldValue == null) continue;\r\n const label = field.label.toLowerCase();\r\n const value = String(fieldValue).trim();\r\n\r\n if (field.type === 'email') {\r\n contactData.email = value;\r\n hasEmail = true;\r\n } else if (field.type === 'phone') {\r\n contactData.phone = value;\r\n } else if (field.type === 'text' || field.type === 'textarea') {\r\n if (label.includes('first name') || label.includes('firstname')) {\r\n contactData.firstName = value;\r\n } else if (label.includes('last name') || label.includes('lastname')) {\r\n contactData.lastName = value;\r\n } else if (label.includes('name') && !contactData.firstName) {\r\n const nameParts = value.split(' ');\r\n if (nameParts.length >= 2) {\r\n contactData.firstName = nameParts[0]!;\r\n contactData.lastName = nameParts.slice(1).join(' ');\r\n } else {\r\n contactData.firstName = value;\r\n }\r\n } else if (label.includes('industry')) {\r\n contactData.industry = value;\r\n } else if (label.includes('message') || label.includes('comment') || label.includes('description') || label.includes('inquiry')) {\r\n contactData.message = value;\r\n }\r\n }\r\n }\r\n\r\n if (!hasEmail && !contactData.firstName) return null;\r\n if (!contactData.firstName && contactData.email) {\r\n contactData.firstName = contactData.email.split('@')[0] ?? '';\r\n contactData.lastName = '';\r\n }\r\n return contactData;\r\n }\r\n}\r\n","import type { CmsPlugin } from '../types';\r\nimport { ERPSubmissionService } from './erp-submission';\r\nimport type { PipelineNames } from './erp-submission';\r\n\r\nexport interface ERPPluginConfig {\r\n webhookUrl: string;\r\n webhookJwt: string;\r\n getPipelineNames?: () => Promise<PipelineNames>;\r\n}\r\n\r\nexport interface ERPPluginInstance {\r\n submission: ERPSubmissionService;\r\n}\r\n\r\nexport function erpPlugin(config: ERPPluginConfig): CmsPlugin<ERPPluginInstance> {\r\n return {\r\n name: 'erp',\r\n version: '2.0.0',\r\n async init() {\r\n const submission = new ERPSubmissionService({\r\n webhookUrl: config.webhookUrl,\r\n webhookJwt: config.webhookJwt,\r\n getPipelineNames: config.getPipelineNames,\r\n });\r\n return { submission };\r\n },\r\n };\r\n}\r\n\r\nexport { ERPSubmissionService } from './erp-submission';\r\nexport type { ContactFormData, ERPSubmissionResult, ErpCreateContactPayload, PipelineNames } from './erp-submission';\r\nexport { registerErpQueueProcessor, queueErp } from './erp-queue';\r\nexport type { ErpJobPayload } from './erp-queue';\r\nexport { queueErpPaidOrderForOrderId, type ErpPaidOrderDataSource, type ErpPaidOrderEntityMap } from './paid-order-erp';\r\nexport { queueErpCreateContactIfEnabled, type ErpContactSyncInput } from './erp-contact-sync';\r\nexport { tryRefreshOrderFromErpForStorefront, refreshOrderFromErp } from './erp-order-sync';\r\nexport { streamOrderInvoicePdf } from './erp-order-invoice';\r\nexport { isErpIntegrationEnabled, type CmsAppLike, type ErpConfigDataSource } from './erp-config-enabled';\r\nexport { queueErpProductUpsertIfEnabled } from './erp-product-sync';\r\n","import type { ObjectLiteral } from 'typeorm';\r\nimport { queueErp, type CmsAppLike } from './erp-queue';\r\nimport type { ErpPaidOrderDataSource, ErpPaidOrderEntityMap } from './paid-order-erp';\r\n\r\nexport interface ErpContactSyncInput {\r\n name: string;\r\n email: string;\r\n phone?: string | null;\r\n type?: string | null;\r\n company?: string | null;\r\n notes?: string | null;\r\n /** Passed to ERP as `tags` when non-empty (§7c). */\r\n tags?: string[];\r\n}\r\n\r\nfunction splitName(full: string): { firstName: string; lastName: string } {\r\n const t = (full || '').trim();\r\n if (!t) return { firstName: 'Contact', lastName: '' };\r\n const parts = t.split(/\\s+/);\r\n if (parts.length === 1) return { firstName: parts[0]!, lastName: '' };\r\n return { firstName: parts[0]!, lastName: parts.slice(1).join(' ') };\r\n}\r\n\r\n/**\r\n * When ERP is enabled and plugin loaded, enqueue `create-contact` (non-fatal on failure).\r\n * Used for admin CRUD and storefront contact paths — not form submissions (those use lead/opportunity).\r\n */\r\nexport async function queueErpCreateContactIfEnabled(\r\n cms: CmsAppLike,\r\n dataSource: ErpPaidOrderDataSource,\r\n entityMap: ErpPaidOrderEntityMap,\r\n input: ErpContactSyncInput\r\n): Promise<void> {\r\n try {\r\n const configRepo = dataSource.getRepository(entityMap.configs);\r\n const cfgRows = await configRepo.find({ where: { settings: 'erp', deleted: false } as ObjectLiteral });\r\n for (const row of cfgRows) {\r\n const r = row as { key: string; value: string };\r\n if (r.key === 'enabled' && r.value === 'false') return;\r\n }\r\n if (!cms.getPlugin('erp')) return;\r\n\r\n const email = (input.email ?? '').trim();\r\n if (!email) return;\r\n\r\n const { firstName, lastName } = splitName(input.name);\r\n\r\n await queueErp(cms, {\r\n kind: 'createContact',\r\n contact: {\r\n email,\r\n firstName,\r\n lastName,\r\n phone: input.phone?.trim() || undefined,\r\n companyName: input.company?.trim() || undefined,\r\n type: input.type?.trim() || undefined,\r\n notes: input.notes?.trim() || undefined,\r\n tags: input.tags?.length ? [...input.tags] : undefined,\r\n },\r\n });\r\n } catch {\r\n /* non-fatal */\r\n }\r\n}\r\n","export type OrderKind = 'sale' | 'return' | 'replacement';\r\n\r\nconst KIND_PREFIX: Record<OrderKind, string> = {\r\n sale: 'OSL',\r\n return: 'ORT',\r\n replacement: 'ORP',\r\n};\r\n\r\n/** YYMM in UTC (two-digit year + month). */\r\nexport function orderNumberYymmUtc(at: Date): string {\r\n const yy = String(at.getUTCFullYear()).slice(-2);\r\n const mm = String(at.getUTCMonth() + 1).padStart(2, '0');\r\n return yy + mm;\r\n}\r\n\r\n/** Stable 8-char mask from numeric id (not reversible as plain decimal). */\r\nexport function maskOrderIdSegment(id: number): string {\r\n let x = (id >>> 0) ^ 0xa5a5a5a5;\r\n x = Math.imul(x, 2654435761) >>> 0;\r\n return x.toString(36).toUpperCase().padStart(8, '0').slice(-8);\r\n}\r\n\r\nexport function buildCanonicalOrderNumber(kind: OrderKind, id: number, at: Date): string {\r\n return KIND_PREFIX[kind] + orderNumberYymmUtc(at) + maskOrderIdSegment(id);\r\n}\r\n\r\nexport function temporaryOrderNumberPlaceholder(): string {\r\n return `TMP${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`.toUpperCase();\r\n}\r\n","export interface OrderFulfillmentEvent {\r\n at?: string;\r\n label?: string;\r\n detail?: string;\r\n}\r\n\r\nexport interface OrderFulfillmentMetadata {\r\n status?: string;\r\n trackingId?: string;\r\n events?: OrderFulfillmentEvent[];\r\n}\r\n\r\nexport interface OrderInvoiceMetadata {\r\n invoiceNumber?: string;\r\n /** ERP invoice UUID for PDF fetch (no JWT). */\r\n invoiceId?: string;\r\n /** App path for invoice PDF (storefront or site-relative). */\r\n link?: string;\r\n}\r\n\r\nexport interface OrderStorefrontMetadataShape {\r\n fulfillment?: OrderFulfillmentMetadata;\r\n invoice?: OrderInvoiceMetadata;\r\n cartId?: number;\r\n platformRef?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\nexport function mergeOrderMetadataPatch(\r\n existing: Record<string, unknown> | null | undefined,\r\n patch: { fulfillment?: OrderFulfillmentMetadata | null; invoice?: OrderInvoiceMetadata | null }\r\n): Record<string, unknown> {\r\n const base =\r\n existing && typeof existing === 'object' && !Array.isArray(existing) ? { ...existing } : {};\r\n if (patch.fulfillment !== undefined) {\r\n if (patch.fulfillment === null) delete base.fulfillment;\r\n else base.fulfillment = patch.fulfillment;\r\n }\r\n if (patch.invoice !== undefined) {\r\n if (patch.invoice === null) delete base.invoice;\r\n else base.invoice = patch.invoice;\r\n }\r\n return base;\r\n}\r\n","import type { Order } from '../../entities/order.entity';\r\n\r\n/** Map ERP sale-order status labels into CMS `Order.status`. Unknown → undefined (caller keeps existing). */\r\nexport function mapErpSaleStatusToOrderStatus(erpLabel: string | undefined): Order['status'] | undefined {\r\n if (!erpLabel || typeof erpLabel !== 'string') return undefined;\r\n const k = erpLabel.trim().toLowerCase().replace(/\\s+/g, '_');\r\n const map: Record<string, Order['status']> = {\r\n draft: 'pending',\r\n pending: 'pending',\r\n open: 'pending',\r\n new: 'pending',\r\n unconfirmed: 'pending',\r\n confirmed: 'confirmed',\r\n processing: 'processing',\r\n packed: 'processing',\r\n shipped: 'processing',\r\n in_transit: 'processing',\r\n out_for_delivery: 'processing',\r\n delivered: 'completed',\r\n completed: 'completed',\r\n closed: 'completed',\r\n fulfilled: 'completed',\r\n cancelled: 'cancelled',\r\n canceled: 'cancelled',\r\n void: 'cancelled',\r\n };\r\n return map[k];\r\n}\r\n","import type { ObjectLiteral, Repository } from 'typeorm';\r\nimport { buildCanonicalOrderNumber, temporaryOrderNumberPlaceholder, type OrderKind } from '../../lib/order-number';\r\nimport { mergeOrderMetadataPatch, type OrderFulfillmentMetadata, type OrderInvoiceMetadata } from '../../lib/order-storefront-metadata';\r\nimport { mapErpSaleStatusToOrderStatus } from './erp-order-status-map';\r\nimport {\r\n extractChildOrderRefsFromSalePayload,\r\n mapErpPayloadToFulfillment,\r\n mapErpPayloadToInvoiceNumber,\r\n unwrapErpReadData,\r\n} from './erp-response-map';\r\nimport type { ERPSubmissionService } from './erp-submission';\r\nimport { isErpIntegrationEnabled, type CmsAppLike, type ErpConfigDataSource } from './erp-config-enabled';\r\n\r\nfunction pickInvoiceId(data: Record<string, unknown>): string | undefined {\r\n const nested =\r\n data.invoice && typeof data.invoice === 'object' && !Array.isArray(data.invoice)\r\n ? (data.invoice as Record<string, unknown>)\r\n : null;\r\n const src = nested || data;\r\n for (const k of ['invoiceId', 'invoice_id', 'id']) {\r\n const v = src[k];\r\n if (typeof v === 'string' && v.trim()) return v.trim();\r\n }\r\n return undefined;\r\n}\r\n\r\nasync function ensureChildOrdersFromRefs(\r\n orderRepo: Repository<ObjectLiteral>,\r\n parent: ObjectLiteral,\r\n refs: ReturnType<typeof extractChildOrderRefsFromSalePayload>,\r\n contactId: number,\r\n currency: string\r\n): Promise<void> {\r\n for (const { ref, orderKind } of refs) {\r\n const existing = await orderRepo\r\n .createQueryBuilder('o')\r\n .where('o.parentOrderId = :pid', { pid: parent.id as number })\r\n .andWhere('o.deleted = :d', { d: false })\r\n .andWhere(\"o.metadata->>'platformRef' = :ref\", { ref })\r\n .getOne();\r\n if (existing) continue;\r\n const tmp = temporaryOrderNumberPlaceholder();\r\n const row = await orderRepo.save(\r\n orderRepo.create({\r\n vendorId: (parent as { vendorId: number }).vendorId,\r\n orderNumber: tmp,\r\n orderKind,\r\n parentOrderId: parent.id as number,\r\n contactId,\r\n billingAddressId: null,\r\n shippingAddressId: null,\r\n status: 'pending',\r\n subtotal: 0,\r\n tax: 0,\r\n discount: 0,\r\n total: 0,\r\n currency,\r\n metadata: { platformRef: ref },\r\n deleted: false,\r\n } as ObjectLiteral)\r\n );\r\n const r = row as { id: number; createdAt: Date };\r\n await orderRepo.update(r.id, {\r\n orderNumber: buildCanonicalOrderNumber(orderKind as OrderKind, r.id, r.createdAt ?? new Date()),\r\n } as ObjectLiteral);\r\n }\r\n}\r\n\r\nfunction deepMergeFulfillment(\r\n a: OrderFulfillmentMetadata | undefined,\r\n b: OrderFulfillmentMetadata | undefined\r\n): OrderFulfillmentMetadata | undefined {\r\n if (!a) return b;\r\n if (!b) return a;\r\n return {\r\n ...a,\r\n ...b,\r\n events: b.events?.length ? b.events : a.events,\r\n };\r\n}\r\n\r\n/**\r\n * Calls ERP §7d reads for the given order row, updates `status` + `metadata` (fulfillment / invoice),\r\n * and upserts child return/replacement rows when the sale payload lists them.\r\n */\r\nexport async function refreshOrderFromErp(\r\n cms: CmsAppLike,\r\n dataSource: ErpConfigDataSource,\r\n entityMap: Record<string, unknown>,\r\n submission: ERPSubmissionService,\r\n order: ObjectLiteral\r\n): Promise<void> {\r\n const orderRepo = dataSource.getRepository(entityMap.orders) as Repository<ObjectLiteral>;\r\n\r\n const kind = (order.orderKind as string) || 'sale';\r\n const meta =\r\n order.metadata && typeof order.metadata === 'object' && !Array.isArray(order.metadata)\r\n ? { ...(order.metadata as Record<string, unknown>) }\r\n : {};\r\n\r\n if (kind === 'sale') {\r\n const refId = String(order.orderNumber || '');\r\n let fulfillment: OrderFulfillmentMetadata | undefined;\r\n let invoiceNumber: string | undefined;\r\n let invoiceId: string | undefined;\r\n let newStatus: string | undefined;\r\n\r\n const r1 = await submission.postErpReadAction('get-order-status', { platformOrderId: refId });\r\n const d1 = r1.ok ? unwrapErpReadData(r1.json) : null;\r\n if (d1) {\r\n const mapped = mapErpSaleStatusToOrderStatus(\r\n typeof d1.status === 'string'\r\n ? d1.status\r\n : typeof d1.orderStatus === 'string'\r\n ? d1.orderStatus\r\n : typeof d1.state === 'string'\r\n ? d1.state\r\n : undefined\r\n );\r\n if (mapped) newStatus = mapped;\r\n fulfillment = mapErpPayloadToFulfillment(d1);\r\n const refs = extractChildOrderRefsFromSalePayload(d1);\r\n if (refs.length) {\r\n await ensureChildOrdersFromRefs(\r\n orderRepo,\r\n order,\r\n refs,\r\n order.contactId as number,\r\n String(order.currency || 'INR')\r\n );\r\n }\r\n }\r\n\r\n const r2 = await submission.postErpReadAction('get-fulfillment-status', { platformOrderId: refId });\r\n const d2 = r2.ok ? unwrapErpReadData(r2.json) : null;\r\n if (d2) {\r\n fulfillment = deepMergeFulfillment(fulfillment, mapErpPayloadToFulfillment(d2));\r\n }\r\n\r\n const r3 = await submission.postErpReadAction('get-invoice', { platformOrderId: refId });\r\n const d3 = r3.ok ? unwrapErpReadData(r3.json) : null;\r\n if (d3) {\r\n invoiceNumber = mapErpPayloadToInvoiceNumber(d3);\r\n invoiceId = pickInvoiceId(d3);\r\n }\r\n\r\n const oid = order.id as number;\r\n const prevInv =\r\n meta.invoice && typeof meta.invoice === 'object' && !Array.isArray(meta.invoice)\r\n ? { ...(meta.invoice as Record<string, unknown>) }\r\n : {};\r\n const nextInvoice: OrderInvoiceMetadata = {\r\n ...prevInv,\r\n link: `/api/storefront/orders/${oid}/invoice`,\r\n ...(invoiceNumber ? { invoiceNumber } : {}),\r\n ...(invoiceId ? { invoiceId } : {}),\r\n };\r\n\r\n const patch: {\r\n fulfillment?: OrderFulfillmentMetadata | null;\r\n invoice?: OrderInvoiceMetadata | null;\r\n } = { invoice: nextInvoice };\r\n if (fulfillment !== undefined) patch.fulfillment = fulfillment;\r\n\r\n const nextMeta = mergeOrderMetadataPatch(meta, patch);\r\n\r\n await orderRepo.update(oid, {\r\n ...(newStatus ? { status: newStatus } : {}),\r\n metadata: nextMeta,\r\n updatedAt: new Date(),\r\n } as ObjectLiteral);\r\n return;\r\n }\r\n\r\n if (kind === 'return' || kind === 'replacement') {\r\n const platformReturnId = String(order.orderNumber || '');\r\n const r = await submission.postErpReadAction('get-return-status', { platformReturnId });\r\n const d = r.ok ? unwrapErpReadData(r.json) : null;\r\n if (!d) return;\r\n const mapped = mapErpSaleStatusToOrderStatus(\r\n typeof d.status === 'string' ? d.status : typeof d.returnStatus === 'string' ? d.returnStatus : undefined\r\n );\r\n const fulfillment = mapErpPayloadToFulfillment(d);\r\n const patch: { fulfillment?: OrderFulfillmentMetadata | null } = {};\r\n if (fulfillment !== undefined) patch.fulfillment = fulfillment;\r\n const nextMeta = Object.keys(patch).length ? mergeOrderMetadataPatch(meta, patch) : meta;\r\n await orderRepo.update(order.id as number, {\r\n ...(mapped ? { status: mapped } : {}),\r\n metadata: nextMeta,\r\n updatedAt: new Date(),\r\n } as ObjectLiteral);\r\n }\r\n}\r\n\r\nexport async function tryRefreshOrderFromErpForStorefront(\r\n cms: CmsAppLike,\r\n dataSource: ErpConfigDataSource,\r\n entityMap: Record<string, unknown>,\r\n order: ObjectLiteral\r\n): Promise<void> {\r\n try {\r\n const on = await isErpIntegrationEnabled(cms, dataSource, entityMap);\r\n if (!on) return;\r\n const erp = cms.getPlugin('erp') as { submission: ERPSubmissionService } | undefined;\r\n if (!erp?.submission) return;\r\n await refreshOrderFromErp(cms, dataSource, entityMap, erp.submission, order);\r\n } catch {\r\n /* non-fatal */\r\n }\r\n}\r\n","import type { ObjectLiteral } from 'typeorm';\r\nimport { queueErp } from './erp-queue';\r\nimport { isErpIntegrationEnabled, type CmsAppLike, type ErpConfigDataSource } from './erp-config-enabled';\r\n\r\nexport async function queueErpProductUpsertIfEnabled(\r\n cms: CmsAppLike,\r\n dataSource: ErpConfigDataSource,\r\n entityMap: Record<string, unknown>,\r\n product: ObjectLiteral\r\n): Promise<void> {\r\n try {\r\n const sku = typeof product.sku === 'string' ? product.sku.trim() : '';\r\n if (!sku) return;\r\n const on = await isErpIntegrationEnabled(cms, dataSource, entityMap);\r\n if (!on) return;\r\n const rawMeta = product.metadata;\r\n let metadata: Record<string, unknown> | undefined;\r\n if (rawMeta && typeof rawMeta === 'object' && !Array.isArray(rawMeta)) {\r\n const { description: _d, ...rest } = rawMeta as Record<string, unknown>;\r\n metadata = Object.keys(rest).length ? rest : undefined;\r\n }\r\n const payload: Record<string, unknown> = {\r\n sku,\r\n title: (product.name as string) || sku,\r\n name: product.name,\r\n hsn_number: product.hsn,\r\n uom: product.uom != null && String(product.uom).trim() ? String(product.uom).trim() : undefined,\r\n type: product.type === 'service' ? 'service' : 'product',\r\n is_active: product.status === 'available',\r\n metadata,\r\n };\r\n await queueErp(cms, { kind: 'productUpsert', product: payload });\r\n } catch {\r\n /* non-fatal */\r\n }\r\n}\r\n","import { SESClient, SendEmailCommand } from '@aws-sdk/client-ses';\r\nimport nodemailer from 'nodemailer';\r\nimport type { EmailTemplateName, TemplateContext } from './templates/types';\r\nimport type { RenderEmailOptions } from './renderer';\r\nimport { renderEmail } from './renderer';\r\n\r\nexport interface EmailPluginConfig {\r\n type: 'AWS' | 'SMTP' | 'GMAIL' | 'SENDGRID';\r\n user?: string;\r\n password?: string;\r\n from: string;\r\n to: string;\r\n /** When type is SMTP, defaults to env SMTP_HOST or undefined (set host for custom relay). */\r\n host?: string;\r\n port?: number;\r\n secure?: boolean;\r\n region?: string;\r\n /** IAM keys for SES API (SendEmail). Not the same as SES SMTP credentials in SMTP_USER/SMTP_PASSWORD. */\r\n accessKeyId?: string;\r\n secretAccessKey?: string;\r\n templateOptions?: RenderEmailOptions;\r\n}\r\n\r\n/** Regions with SES API but no SMTP endpoint (see AWS General Reference — SES SMTP endpoints). */\r\n/** @see https://docs.aws.amazon.com/general/latest/gr/ses.html — SMTP endpoints section */\r\nexport const SES_REGIONS_WITHOUT_SMTP = new Set([\r\n 'af-south-1',\r\n 'ap-south-2',\r\n 'ap-southeast-3',\r\n 'ap-southeast-5',\r\n 'ca-west-1',\r\n 'eu-central-2',\r\n 'eu-south-1',\r\n 'il-central-1',\r\n 'me-central-1',\r\n 'me-south-1',\r\n]);\r\n\r\n/** Amazon SES SMTP endpoint for a region (SMTP_TYPE=AWS with SMTP_USER/SMTP_PASSWORD). */\r\nexport function sesSmtpHost(region: string): string {\r\n return `email-smtp.${region}.amazonaws.com`;\r\n}\r\n\r\nexport function sesRegionSupportsSmtp(region: string): boolean {\r\n return !SES_REGIONS_WITHOUT_SMTP.has(region.trim());\r\n}\r\n\r\nexport interface EmailData {\r\n subject: string;\r\n html: string;\r\n text?: string;\r\n to?: string;\r\n from?: string;\r\n}\r\n\r\nexport interface EmailServiceInterface {\r\n send(emailData: EmailData): Promise<boolean>;\r\n}\r\n\r\nexport interface RenderedEmail {\r\n subject: string;\r\n html: string;\r\n text?: string;\r\n}\r\n\r\nexport class EmailService implements EmailServiceInterface {\r\n private config: EmailPluginConfig;\r\n private templateOptions?: RenderEmailOptions;\r\n private sesClient?: SESClient;\r\n private transporter?: nodemailer.Transporter;\r\n /** AWS via SMTP (nodemailer) vs SES API SDK. */\r\n private awsViaSmtp = false;\r\n\r\n constructor(config: EmailPluginConfig) {\r\n this.config = config;\r\n this.templateOptions = config.templateOptions;\r\n if (config.type === 'AWS') {\r\n if (!config.region) {\r\n throw new Error('AWS SES configuration incomplete: AWS_REGION is required');\r\n }\r\n if (config.user && config.password) {\r\n this.awsViaSmtp = true;\r\n const host = config.host || sesSmtpHost(config.region);\r\n const port = config.port ?? 587;\r\n const secure = config.secure ?? false;\r\n this.transporter = nodemailer.createTransport({\r\n host,\r\n port,\r\n secure,\r\n auth: { user: config.user, pass: config.password },\r\n });\r\n } else if (config.accessKeyId && config.secretAccessKey) {\r\n this.sesClient = new SESClient({\r\n region: config.region,\r\n credentials: { accessKeyId: config.accessKeyId, secretAccessKey: config.secretAccessKey },\r\n });\r\n } else {\r\n throw new Error(\r\n 'AWS SES configuration incomplete: set SMTP_USER and SMTP_PASSWORD (SES SMTP) or AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (SES API)'\r\n );\r\n }\r\n } else if (config.type === 'SMTP' || config.type === 'GMAIL') {\r\n if (!config.user || !config.password) throw new Error('SMTP configuration incomplete');\r\n const host = config.type === 'GMAIL' ? 'smtp.gmail.com' : config.host;\r\n if (!host) {\r\n throw new Error(\r\n 'SMTP configuration incomplete: SMTP_HOST is required when SMTP_TYPE=SMTP (nodemailer otherwise connects to 127.0.0.1)'\r\n );\r\n }\r\n const port = config.port ?? 587;\r\n const secure = config.secure ?? false;\r\n this.transporter = nodemailer.createTransport({\r\n host,\r\n port,\r\n secure,\r\n auth: { user: config.user, pass: config.password },\r\n });\r\n } else {\r\n throw new Error(`Unsupported email type: ${config.type}`);\r\n }\r\n }\r\n\r\n async send(emailData: EmailData): Promise<boolean> {\r\n try {\r\n if (this.config.type === 'AWS' && this.sesClient) {\r\n await this.sesClient.send(\r\n new SendEmailCommand({\r\n Source: emailData.from || this.config.from,\r\n Destination: { ToAddresses: [emailData.to || this.config.to] },\r\n Message: {\r\n Subject: { Data: emailData.subject, Charset: 'UTF-8' },\r\n Body: {\r\n Html: { Data: emailData.html, Charset: 'UTF-8' },\r\n ...(emailData.text && { Text: { Data: emailData.text, Charset: 'UTF-8' } }),\r\n },\r\n },\r\n })\r\n );\r\n return true;\r\n }\r\n if (\r\n this.transporter &&\r\n (this.config.type === 'SMTP' ||\r\n this.config.type === 'GMAIL' ||\r\n (this.config.type === 'AWS' && this.awsViaSmtp))\r\n ) {\r\n await this.transporter.sendMail({\r\n from: emailData.from || this.config.from,\r\n to: emailData.to || this.config.to,\r\n subject: emailData.subject,\r\n html: emailData.html,\r\n text: emailData.text,\r\n });\r\n return true;\r\n }\r\n return false;\r\n } catch (error) {\r\n console.error('Email sending failed:', error);\r\n return false;\r\n }\r\n }\r\n\r\n renderTemplate(templateName: EmailTemplateName, ctx: TemplateContext<unknown>): RenderedEmail {\r\n return renderEmail(templateName, ctx, this.templateOptions);\r\n }\r\n\r\n /** Default notification recipient from plugin config (SMTP_TO / plugin `to`). */\r\n getDefaultTo(): string {\r\n return this.config.to;\r\n }\r\n}\r\n\r\nexport const emailTemplates = {\r\n formSubmission: (data: { formName: string; contactName: string; contactEmail: string; formData: unknown }) => ({\r\n subject: `New Form Submission: ${data.formName}`,\r\n html: `<h2>New Form Submission</h2><p><strong>Form:</strong> ${data.formName}</p><p><strong>Contact:</strong> ${data.contactName} (${data.contactEmail})</p><pre>${JSON.stringify(data.formData, null, 2)}</pre>`,\r\n text: `New Form Submission\\nForm: ${data.formName}\\nContact: ${data.contactName} (${data.contactEmail})\\n${JSON.stringify(data.formData, null, 2)}`,\r\n }),\r\n contactSubmission: (data: { name: string; email: string; phone?: string; message?: string }) => ({\r\n subject: `New Contact Form Submission from ${data.name}`,\r\n html: `<h2>New Contact Form Submission</h2><p><strong>Name:</strong> ${data.name}</p><p><strong>Email:</strong> ${data.email}</p>${data.phone ? `<p><strong>Phone:</strong> ${data.phone}</p>` : ''}${data.message ? `<p><strong>Message:</strong></p><p>${data.message}</p>` : ''}`,\r\n text: `New Contact Form Submission\\nName: ${data.name}\\nEmail: ${data.email}\\n${data.phone ? `Phone: ${data.phone}\\n` : ''}${data.message ? `Message: ${data.message}` : ''}`,\r\n }),\r\n passwordReset: (data: { resetLink: string }) => ({\r\n subject: 'Reset your password',\r\n html: `<h2>Reset your password</h2><p>Click the link below to set a new password. This link expires in 1 hour.</p><p><a href=\"${data.resetLink}\">${data.resetLink}</a></p>`,\r\n text: `Reset your password: ${data.resetLink}\\n\\nThis link expires in 1 hour.`,\r\n }),\r\n};\r\n","import type { CompanyDetails, SocialLinkItem } from './types';\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"');\r\n}\r\n\r\nfunction socialLinkInnerHtml(s: SocialLinkItem): string {\r\n if (s.iconUrl?.trim()) {\r\n return `<img src=\"${escapeHtml(s.iconUrl.trim())}\" alt=\"\" width=\"20\" height=\"20\" style=\"display:inline-block;vertical-align:middle;border:0;\" />`;\r\n }\r\n const label = (s.icon && s.icon.trim()) || '🔗';\r\n return escapeHtml(label);\r\n}\r\n\r\nfunction supportLinesHtml(supportEmail?: string, supportPhone?: string, opts?: { tightTop?: boolean }): string {\r\n const parts: string[] = [];\r\n const top = opts?.tightTop ? 'margin-top:0;' : 'margin-top:4px;';\r\n if (supportEmail) {\r\n parts.push(`<div style=\"font-size:13px;color:#444;${top}\">📧 ${escapeHtml(supportEmail)}</div>`);\r\n }\r\n if (supportPhone) {\r\n parts.push(`<div style=\"font-size:13px;color:#444;margin-top:2px;\">📞 ${escapeHtml(supportPhone)}</div>`);\r\n }\r\n return parts.join('');\r\n}\r\n\r\nexport function renderLayout(options: {\r\n bodyHtml: string;\r\n companyDetails: CompanyDetails;\r\n}): string {\r\n const { bodyHtml, companyDetails } = options;\r\n const {\r\n logoUrl,\r\n companyName,\r\n supportEmail,\r\n supportPhone,\r\n socialLinks,\r\n footerDisclaimer,\r\n followUsTitle = 'Follow Us',\r\n } = companyDetails;\r\n\r\n const supportFooterHtml = supportLinesHtml(supportEmail, supportPhone, { tightTop: true });\r\n\r\n const hasSocial = Boolean(socialLinks?.length);\r\n const brandFooterInner: string[] = [];\r\n if (logoUrl) {\r\n brandFooterInner.push(\r\n `<img src=\"${escapeHtml(logoUrl)}\" alt=\"\" style=\"max-height:28px;max-width:160px;height:auto;width:auto;display:inline-block;vertical-align:middle;margin-right:10px;border:0;\" />`\r\n );\r\n }\r\n if (companyName) {\r\n brandFooterInner.push(\r\n `<span style=\"font-size:14px;font-weight:600;color:#111;vertical-align:middle;\">${escapeHtml(companyName)}</span>`\r\n );\r\n }\r\n const brandFooterHtml = brandFooterInner.length\r\n ? `<div style=\"line-height:1.4;\">${brandFooterInner.join('')}</div>`\r\n : '';\r\n\r\n const followTitleHtml =\r\n hasSocial && followUsTitle\r\n ? `<div class=\"footer-follow-title\" style=\"font-size:13px;font-weight:600;color:#555;margin:0;\">${escapeHtml(followUsTitle)}</div>`\r\n : '';\r\n\r\n const socialRowHtml =\r\n hasSocial && socialLinks\r\n ? `<div class=\"footer-social-icons\" style=\"margin-top:6px;text-align:left;font-size:0;line-height:0;\">${socialLinks\r\n .map(\r\n (s) =>\r\n `<a href=\"${escapeHtml(s.url)}\" style=\"display:inline-block;margin-right:12px;text-decoration:none;color:#333;font-size:18px;line-height:1;vertical-align:middle;\">${socialLinkInnerHtml(s)}</a>`\r\n )\r\n .join('')}</div>`\r\n : '';\r\n\r\n const rowSupport = supportFooterHtml\r\n ? `<tr><td class=\"footer-support-cell\" colspan=\"2\" valign=\"top\" style=\"padding:0 0 10px 0;\">${supportFooterHtml}</td></tr>`\r\n : '';\r\n\r\n let footerBlock = '';\r\n if (brandFooterHtml || followTitleHtml || socialRowHtml || footerDisclaimer || rowSupport) {\r\n const rowBrand = brandFooterHtml\r\n ? `<tr><td class=\"footer-brand-cell\" colspan=\"2\" valign=\"top\" style=\"padding:0 0 10px 0;\">${brandFooterHtml}</td></tr>`\r\n : '';\r\n const rowFollowTitle = followTitleHtml\r\n ? `<tr><td class=\"footer-follow-cell\" colspan=\"2\" valign=\"top\" style=\"padding:14px 0 0 0;text-align:left;\">${followTitleHtml}</td></tr>`\r\n : '';\r\n const rowSocial = socialRowHtml\r\n ? `<tr><td class=\"footer-social-cell\" colspan=\"2\" style=\"padding:0;text-align:left;\">${socialRowHtml}</td></tr>`\r\n : '';\r\n footerBlock = `<table role=\"presentation\" class=\"footer-main\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"margin-top:28px;padding-top:16px;\">${rowBrand}${rowSupport}${rowFollowTitle}${rowSocial}</table>`;\r\n }\r\n\r\n const disclaimerBlock = footerDisclaimer\r\n ? `<div style=\"margin-top:20px;padding-top:12px;font-size:11px;line-height:1.5;color:#888;\">${escapeHtml(footerDisclaimer).replace(/\\n/g, '<br/>')}</div>`\r\n : '';\r\n\r\n const responsiveCss = `\r\n@media only screen and (max-width: 600px) {\r\n .email-wrap { padding-left: 12px !important; padding-right: 12px !important; }\r\n .footer-follow-cell { padding-top: 12px !important; }\r\n}\r\n`;\r\n\r\n return `<!DOCTYPE html>\r\n<html>\r\n<head>\r\n<meta charset=\"utf-8\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n<style type=\"text/css\">${responsiveCss}</style>\r\n</head>\r\n<body style=\"margin:0;padding:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;font-size:14px;line-height:1.5;color:#333;background:#fff;\">\r\n <table role=\"presentation\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"background:#fff;\">\r\n <tr><td class=\"email-wrap\" style=\"padding:16px;\">\r\n <div>\r\n ${bodyHtml}\r\n </div>\r\n ${footerBlock}\r\n ${disclaimerBlock}\r\n </td></tr>\r\n </table>\r\n</body>\r\n</html>`;\r\n}\r\n","/** Social entry: use `iconUrl` for an image, or `icon` (emoji/text) as fallback when no image. */\r\nexport interface SocialLinkItem {\r\n url: string;\r\n iconUrl?: string;\r\n icon?: string;\r\n}\r\n\r\nexport interface CompanyDetails {\r\n logoUrl?: string;\r\n companyName?: string;\r\n supportEmail?: string;\r\n supportPhone?: string;\r\n socialLinks?: SocialLinkItem[];\r\n /** Shown below footer rows; from email plugin settings */\r\n footerDisclaimer?: string;\r\n /** Heading above social icons (default \"Follow Us\") */\r\n followUsTitle?: string;\r\n}\r\n\r\n/** One row in order-placed transactional emails */\r\nexport interface OrderPlacedLineItem {\r\n productName: string;\r\n quantity: number;\r\n unitPrice: number | string;\r\n lineTotal: number | string;\r\n sku?: string | null;\r\n tax?: number | string | null;\r\n hsn?: string | null;\r\n}\r\n\r\nexport function normalizeSocialLinkItem(o: {\r\n icon?: string;\r\n iconUrl?: string;\r\n icon_image?: string;\r\n url?: string;\r\n}): SocialLinkItem | null {\r\n const url = String(o.url ?? '').trim();\r\n if (!url) return null;\r\n let iconUrl = String(o.iconUrl ?? o.icon_image ?? '').trim();\r\n let icon = String(o.icon ?? '').trim();\r\n if (!iconUrl && /^https?:\\/\\//i.test(icon)) {\r\n iconUrl = icon;\r\n icon = '';\r\n }\r\n const item: SocialLinkItem = { url };\r\n if (iconUrl) item.iconUrl = iconUrl;\r\n if (icon) item.icon = icon;\r\n return item;\r\n}\r\n\r\nexport function parseSocialLinksJson(raw: string | undefined | null): SocialLinkItem[] | undefined {\r\n if (raw == null || raw.trim() === '') return undefined;\r\n try {\r\n const parsed = JSON.parse(raw) as unknown;\r\n if (!Array.isArray(parsed)) return undefined;\r\n const out: SocialLinkItem[] = [];\r\n for (const item of parsed) {\r\n if (item && typeof item === 'object' && 'url' in item) {\r\n const n = normalizeSocialLinkItem(item as { icon?: string; iconUrl?: string; url?: string });\r\n if (n) out.push(n);\r\n }\r\n }\r\n return out.length ? out : undefined;\r\n } catch {\r\n return undefined;\r\n }\r\n}\r\n\r\n/** Merge branding + email plugin settings for layout (email overrides when set). */\r\nexport function mergeEmailLayoutCompanyDetails(\r\n branding: Record<string, string>,\r\n emailSettings: Record<string, string>\r\n): CompanyDetails {\r\n const fromBranding = getCompanyDetailsFromSettings(branding);\r\n const pick = (emailVal: string | undefined, fallback?: string) => {\r\n const t = emailVal?.trim();\r\n return t || fallback?.trim() || undefined;\r\n };\r\n const logoUrl = pick(emailSettings.logoUrl ?? emailSettings.emailLogoUrl, fromBranding.logoUrl);\r\n const companyName = pick(emailSettings.companyName ?? emailSettings.emailCompanyName, fromBranding.companyName);\r\n const supportEmail = pick(emailSettings.supportEmail ?? emailSettings.emailSupportEmail, fromBranding.supportEmail);\r\n const supportPhone = pick(emailSettings.supportPhone, undefined);\r\n const footerDisclaimer = pick(emailSettings.footerDisclaimer, undefined);\r\n const followUsTitle = pick(emailSettings.followUsTitle, 'Follow Us') || 'Follow Us';\r\n const socialFromEmail = parseSocialLinksJson(emailSettings.socialLinks);\r\n const socialLinks = socialFromEmail?.length ? socialFromEmail : fromBranding.socialLinks;\r\n return {\r\n logoUrl,\r\n companyName,\r\n supportEmail,\r\n supportPhone,\r\n socialLinks,\r\n footerDisclaimer,\r\n followUsTitle,\r\n };\r\n}\r\n\r\nexport interface EmailTemplateResult {\r\n subject: string;\r\n bodyHtml: string;\r\n text?: string;\r\n}\r\n\r\nexport type TemplateContext<T = unknown> = T & { companyDetails: CompanyDetails };\r\n\r\nexport const EMAIL_TEMPLATE_NAMES = [\r\n 'signup',\r\n 'passwordReset',\r\n 'passwordChange',\r\n 'orderPlaced',\r\n 'returnInitiated',\r\n 'shippingUpdate',\r\n 'invite',\r\n 'formSubmission',\r\n 'otp',\r\n 'chatLead',\r\n 'vendorOnboarded',\r\n] as const;\r\n\r\nexport type EmailTemplateName = (typeof EMAIL_TEMPLATE_NAMES)[number];\r\n\r\nexport function getCompanyDetailsFromSettings(\r\n settingsGroup: Record<string, string>\r\n): CompanyDetails {\r\n const logoUrl = settingsGroup.logo ?? settingsGroup.logoUrl ?? '';\r\n const companyName = settingsGroup.companyName ?? settingsGroup.company_name ?? '';\r\n const supportEmail = settingsGroup.supportEmail ?? settingsGroup.support_email ?? '';\r\n let socialLinks: SocialLinkItem[] = [];\r\n const raw = settingsGroup.socialLinks ?? settingsGroup.social_links;\r\n if (typeof raw === 'string') {\r\n try {\r\n const arr = JSON.parse(raw) as unknown[];\r\n if (Array.isArray(arr)) {\r\n for (const item of arr) {\r\n if (item && typeof item === 'object') {\r\n const n = normalizeSocialLinkItem(item as { icon?: string; iconUrl?: string; url?: string });\r\n if (n) socialLinks.push(n);\r\n }\r\n }\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n }\r\n return { logoUrl: logoUrl || undefined, companyName: companyName || undefined, supportEmail: supportEmail || undefined, socialLinks: socialLinks.length ? socialLinks : undefined };\r\n}\r\n","/** Email-safe primary button (table-based). */\r\n\r\nexport function escapeHtml(s: string): string {\r\n return s\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"');\r\n}\r\n\r\n/** href for use inside double-quoted HTML attribute */\r\nexport function escapeAttr(s: string): string {\r\n return escapeHtml(s);\r\n}\r\n\r\nexport function primaryCtaButton(href: string, label: string): string {\r\n return `<table role=\"presentation\" cellpadding=\"0\" cellspacing=\"0\" style=\"margin:20px 0;\">\r\n<tr><td style=\"border-radius:6px;background:#1a1a1a;\">\r\n<a href=\"${escapeAttr(href)}\" style=\"display:inline-block;padding:12px 22px;font-size:14px;font-weight:600;color:#ffffff;text-decoration:none;\">${escapeHtml(label)}</a>\r\n</td></tr>\r\n</table>`;\r\n}\r\n","import type { TemplateContext } from './types';\r\nimport { renderLayout } from './layout';\r\nimport { escapeHtml, primaryCtaButton } from './inline-cta';\r\n\r\nexport function render(\r\n ctx: TemplateContext<{ name?: string; loginUrl?: string; verifyEmailUrl?: string }>\r\n) {\r\n const { name, loginUrl, verifyEmailUrl, companyDetails } = ctx;\r\n\r\n if (verifyEmailUrl) {\r\n const subject = 'Confirm your email';\r\n const greeting =\r\n name && name.trim() ? `Hi ${escapeHtml(name.trim())},` : 'Hi,';\r\n const bodyHtml = `<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">${greeting}</p>\r\n<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">Thanks for signing up. Please confirm your email address to activate your account. Until you confirm, you won’t be able to sign in.</p>\r\n${primaryCtaButton(verifyEmailUrl, 'Confirm email address')}\r\n<p style=\"margin:16px 0 0 0;font-size:12px;line-height:1.5;color:#888;\">This link expires in a few days. If you didn’t create an account, you can ignore this message.<br/><span style=\"word-break:break-all;\">${escapeHtml(verifyEmailUrl)}</span></p>`;\r\n const text = [\r\n greeting,\r\n '',\r\n 'Confirm your email to activate your account:',\r\n verifyEmailUrl,\r\n '',\r\n 'You cannot sign in until your email is confirmed.',\r\n ].join('\\n');\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return { subject, html, text };\r\n }\r\n\r\n const subject = 'Welcome';\r\n const bodyHtml = `<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">Welcome${name ? `, ${escapeHtml(name)}` : ''}.</p><p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">Your account has been created.</p>${\r\n loginUrl ? `${primaryCtaButton(loginUrl, 'Sign in')}` : ''\r\n }`;\r\n const text = `Welcome${name ? `, ${name}` : ''}. Your account has been created.${loginUrl ? ` Sign in: ${loginUrl}` : ''}`;\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return { subject, html, text };\r\n}\r\n","import type { TemplateContext } from './types';\r\nimport { renderLayout } from './layout';\r\nimport { escapeHtml, primaryCtaButton } from './inline-cta';\r\n\r\nexport function render(ctx: TemplateContext<{ resetLink: string }>) {\r\n const { resetLink, companyDetails } = ctx;\r\n const subject = 'Reset your password';\r\n const bodyHtml = `<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">Hello,</p>\r\n<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">We received a request to reset the password for your account. If you made this request, use the button below to choose a new password.</p>\r\n<p style=\"margin:0 0 8px 0;font-size:14px;line-height:1.5;color:#555;\">For your security, this link will stop working after a short time. If it expires, request a new reset from the sign-in page.</p>\r\n${primaryCtaButton(resetLink, 'Reset password')}\r\n<p style=\"margin:16px 0 0 0;font-size:12px;line-height:1.5;color:#888;\">If you did not request a password reset, you can safely ignore this email—your password will stay the same.</p>\r\n<p style=\"margin:12px 0 0 0;font-size:12px;line-height:1.5;color:#888;\">If the button does not work, copy and paste this URL into your browser:<br/><span style=\"word-break:break-all;\">${escapeHtml(resetLink)}</span></p>`;\r\n const text = [\r\n 'Hello,',\r\n '',\r\n 'We received a request to reset your password. Open the link below to set a new password:',\r\n resetLink,\r\n '',\r\n 'This link expires after a limited time.',\r\n '',\r\n 'If you did not request this, you can ignore this email.',\r\n ].join('\\n');\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return { subject, html, text };\r\n}\r\n","import type { TemplateContext } from './types';\r\nimport { renderLayout } from './layout';\r\n\r\nexport function render(ctx: TemplateContext<{ name?: string }>) {\r\n const { name, companyDetails } = ctx;\r\n const subject = 'Password changed';\r\n const bodyHtml = `<h2>Password changed</h2><p>Your password has been updated successfully${name ? `, ${escapeHtml(name)}` : ''}.</p>`;\r\n const text = `Your password has been updated successfully${name ? `, ${name}` : ''}.`;\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return { subject, html, text };\r\n}\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\r\n}\r\n","import type { TemplateContext, OrderPlacedLineItem } from './types';\r\nimport { renderLayout } from './layout';\r\nimport { escapeHtml } from './inline-cta';\r\n\r\nfunction formatMoney(amount: number | string, currency?: string): string {\r\n const v = typeof amount === 'string' ? parseFloat(amount) : amount;\r\n const num = Number.isFinite(v) ? Number(v).toFixed(2) : String(amount);\r\n return currency ? `${num} ${currency}` : num;\r\n}\r\n\r\nfunction renderLineItemsHtml(items: OrderPlacedLineItem[], currency?: string): string {\r\n if (!items.length) {\r\n return '<p style=\"margin:12px 0 0 0;font-size:14px;color:#666;\">No line items.</p>';\r\n }\r\n const rows = items\r\n .map((it) => {\r\n const name = escapeHtml(it.productName);\r\n const sku =\r\n it.sku && String(it.sku).trim()\r\n ? `<span style=\"font-size:12px;color:#888;\"> (${escapeHtml(String(it.sku).trim())})</span>`\r\n : '';\r\n const hsn =\r\n it.hsn && String(it.hsn).trim()\r\n ? `<br/><span style=\"font-size:11px;color:#888;\">HSN: ${escapeHtml(String(it.hsn).trim())}</span>`\r\n : '';\r\n const taxNote =\r\n it.tax != null && String(it.tax).trim() && Number(it.tax) !== 0\r\n ? `<br/><span style=\"font-size:11px;color:#888;\">Tax: ${escapeHtml(formatMoney(it.tax, currency))}</span>`\r\n : '';\r\n return `<tr>\r\n<td style=\"padding:10px 8px 10px 0;border-bottom:1px solid #eee;vertical-align:top;font-size:14px;color:#333;\">${name}${sku}${hsn}${taxNote}</td>\r\n<td align=\"right\" style=\"padding:10px 8px;border-bottom:1px solid #eee;vertical-align:top;font-size:14px;color:#333;white-space:nowrap;\">${escapeHtml(String(it.quantity))}</td>\r\n<td align=\"right\" style=\"padding:10px 8px;border-bottom:1px solid #eee;vertical-align:top;font-size:14px;color:#333;white-space:nowrap;\">${escapeHtml(formatMoney(it.unitPrice, currency))}</td>\r\n<td align=\"right\" style=\"padding:10px 0 10px 8px;border-bottom:1px solid #eee;vertical-align:top;font-size:14px;color:#333;white-space:nowrap;\">${escapeHtml(formatMoney(it.lineTotal, currency))}</td>\r\n</tr>`;\r\n })\r\n .join('');\r\n return `<p style=\"margin:16px 0 8px 0;font-size:14px;font-weight:600;color:#111;\">Order items</p>\r\n<table role=\"presentation\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"border-collapse:collapse;\">\r\n<tr>\r\n<td style=\"padding:0 8px 8px 0;font-size:12px;font-weight:600;color:#555;text-transform:uppercase;letter-spacing:0.02em;\">Item</td>\r\n<td align=\"right\" style=\"padding:0 8px 8px 8px;font-size:12px;font-weight:600;color:#555;text-transform:uppercase;\">Qty</td>\r\n<td align=\"right\" style=\"padding:0 8px 8px 8px;font-size:12px;font-weight:600;color:#555;text-transform:uppercase;\">Price</td>\r\n<td align=\"right\" style=\"padding:0 0 8px 8px;font-size:12px;font-weight:600;color:#555;text-transform:uppercase;\">Total</td>\r\n</tr>\r\n${rows}\r\n</table>`;\r\n}\r\n\r\nfunction renderLineItemsText(items: OrderPlacedLineItem[], currency?: string): string {\r\n if (!items.length) return '';\r\n const lines = items.map((it) => {\r\n let s = `- ${it.productName} × ${it.quantity} @ ${formatMoney(it.unitPrice, currency)} = ${formatMoney(it.lineTotal, currency)}`;\r\n if (it.sku) s += ` [${it.sku}]`;\r\n if (it.hsn && String(it.hsn).trim()) s += ` HSN:${it.hsn}`;\r\n if (it.tax != null && Number(it.tax) !== 0) s += ` tax:${formatMoney(it.tax, currency)}`;\r\n return s;\r\n });\r\n return ['Items:', ...lines].join('\\n');\r\n}\r\n\r\nfunction formatAddressLines(addr: Record<string, string> | undefined): string[] {\r\n if (!addr || typeof addr !== 'object') return [];\r\n const parts = [addr.line1, addr.line2, [addr.city, addr.state].filter(Boolean).join(', '), addr.postalCode, addr.country].filter(\r\n (x) => x != null && String(x).trim() !== ''\r\n ) as string[];\r\n return parts.map((p) => String(p).trim()).filter(Boolean);\r\n}\r\n\r\nfunction renderAddressesHtml(billing?: Record<string, string>, shipping?: Record<string, string>): string {\r\n const bLines = formatAddressLines(billing);\r\n const sLines = formatAddressLines(shipping);\r\n if (!bLines.length && !sLines.length) return '';\r\n let html = '<p style=\"margin:16px 0 8px 0;font-size:14px;font-weight:600;color:#111;\">Addresses</p>';\r\n if (bLines.length) {\r\n html += `<p style=\"margin:0 0 4px 0;font-size:12px;font-weight:600;color:#555;\">Billing</p><p style=\"margin:0 0 12px 0;font-size:14px;line-height:1.5;color:#333;\">${bLines.map((l) => escapeHtml(l)).join('<br/>')}</p>`;\r\n }\r\n if (sLines.length) {\r\n html += `<p style=\"margin:0 0 4px 0;font-size:12px;font-weight:600;color:#555;\">Shipping</p><p style=\"margin:0 0 0 0;font-size:14px;line-height:1.5;color:#333;\">${sLines.map((l) => escapeHtml(l)).join('<br/>')}</p>`;\r\n }\r\n return html;\r\n}\r\n\r\nfunction renderAddressesText(billing?: Record<string, string>, shipping?: Record<string, string>): string {\r\n const bLines = formatAddressLines(billing);\r\n const sLines = formatAddressLines(shipping);\r\n const out: string[] = [];\r\n if (bLines.length) out.push('Billing:', ...bLines.map((l) => ` ${l}`));\r\n if (sLines.length) out.push('Shipping:', ...sLines.map((l) => ` ${l}`));\r\n return out.length ? out.join('\\n') : '';\r\n}\r\n\r\nexport function render(\r\n ctx: TemplateContext<{\r\n orderNumber: string;\r\n total?: string;\r\n subtotal?: string;\r\n tax?: string;\r\n currency?: string;\r\n customerName?: string;\r\n audience?: 'customer' | 'sales';\r\n internalCustomerEmail?: string;\r\n lineItems?: OrderPlacedLineItem[];\r\n billingAddress?: Record<string, string>;\r\n shippingAddress?: Record<string, string>;\r\n }>\r\n) {\r\n const {\r\n orderNumber,\r\n total,\r\n subtotal,\r\n tax,\r\n currency,\r\n customerName,\r\n companyDetails,\r\n audience = 'customer',\r\n internalCustomerEmail,\r\n lineItems = [],\r\n billingAddress,\r\n shippingAddress,\r\n } = ctx;\r\n\r\n const itemsHtml = renderLineItemsHtml(lineItems, currency);\r\n const itemsText = renderLineItemsText(lineItems, currency);\r\n const addrHtml = renderAddressesHtml(billingAddress, shippingAddress);\r\n const addrText = renderAddressesText(billingAddress, shippingAddress);\r\n\r\n const subtotalLine =\r\n subtotal != null && String(subtotal).trim() !== ''\r\n ? `<p style=\"margin:8px 0 0 0;font-size:14px;line-height:1.5;color:#333;\"><strong>Subtotal:</strong> ${escapeHtml(String(subtotal))}${currency ? ` ${escapeHtml(currency)}` : ''}</p>`\r\n : '';\r\n const taxLine =\r\n tax != null && String(tax).trim() !== '' && Number(tax) !== 0\r\n ? `<p style=\"margin:4px 0 0 0;font-size:14px;line-height:1.5;color:#333;\"><strong>Tax:</strong> ${escapeHtml(String(tax))}${currency ? ` ${escapeHtml(currency)}` : ''}</p>`\r\n : '';\r\n const totalLine =\r\n total != null && String(total).trim() !== ''\r\n ? `<p style=\"margin:12px 0 0 0;font-size:15px;line-height:1.5;color:#333;\"><strong>Order total:</strong> ${escapeHtml(String(total))}${currency ? ` ${escapeHtml(currency)}` : ''}</p>`\r\n : '';\r\n\r\n let subject: string;\r\n let bodyHtml: string;\r\n let text: string;\r\n\r\n if (audience === 'sales') {\r\n subject = `New order #${orderNumber}`;\r\n const who =\r\n customerName || internalCustomerEmail\r\n ? `<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\"><strong>Customer:</strong> ${escapeHtml(customerName || '—')}${\r\n internalCustomerEmail\r\n ? ` <span style=\"color:#555;\">(${escapeHtml(internalCustomerEmail)})</span>`\r\n : ''\r\n }</p>`\r\n : '';\r\n bodyHtml = `<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">A new order has been placed and payment completed.</p>\r\n<p style=\"margin:0 0 8px 0;font-size:15px;line-height:1.5;color:#333;\"><strong>Order number:</strong> ${escapeHtml(orderNumber)}</p>\r\n${who}\r\n${addrHtml}\r\n${itemsHtml}\r\n${subtotalLine}${taxLine}${totalLine}`;\r\n text = [\r\n `New order #${orderNumber}`,\r\n customerName ? `Customer: ${customerName}` : '',\r\n internalCustomerEmail ? `Email: ${internalCustomerEmail}` : '',\r\n addrText,\r\n itemsText,\r\n subtotal != null ? `Subtotal: ${subtotal}${currency ? ` ${currency}` : ''}` : '',\r\n tax != null && Number(tax) !== 0 ? `Tax: ${tax}${currency ? ` ${currency}` : ''}` : '',\r\n total != null ? `Order total: ${total}${currency ? ` ${currency}` : ''}` : '',\r\n ]\r\n .filter(Boolean)\r\n .join('\\n\\n');\r\n } else {\r\n subject = `Order confirmed #${orderNumber}`;\r\n const thanksPlain =\r\n customerName && customerName.trim()\r\n ? `Thank you, ${customerName.trim()}.`\r\n : 'Thank you for your order.';\r\n const thanksHtml = `${escapeHtml(thanksPlain)} We’ve received your order and will process it shortly.`;\r\n bodyHtml = `<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">${thanksHtml}</p>\r\n<p style=\"margin:0 0 8px 0;font-size:15px;line-height:1.5;color:#333;\"><strong>Order number:</strong> ${escapeHtml(orderNumber)}</p>\r\n${addrHtml}\r\n${itemsHtml}\r\n${subtotalLine}${taxLine}${totalLine}\r\n<p style=\"margin:16px 0 0 0;font-size:13px;line-height:1.5;color:#666;\">If you have questions, reply to this email or contact us using the details below.</p>`;\r\n text = [\r\n `Order confirmed #${orderNumber}`,\r\n `${thanksPlain} We’ve received your order and will process it shortly.`,\r\n '',\r\n addrText,\r\n itemsText,\r\n subtotal != null ? `Subtotal: ${subtotal}${currency ? ` ${currency}` : ''}` : '',\r\n tax != null && Number(tax) !== 0 ? `Tax: ${tax}${currency ? ` ${currency}` : ''}` : '',\r\n total != null ? `Order total: ${total}${currency ? ` ${currency}` : ''}` : '',\r\n '',\r\n 'We will process your order shortly.',\r\n ]\r\n .filter((line, i, arr) => !(line === '' && arr[i - 1] === ''))\r\n .join('\\n');\r\n }\r\n\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return { subject, html, text };\r\n}\r\n","import type { TemplateContext } from './types';\r\nimport { renderLayout } from './layout';\r\n\r\nexport function render(\r\n ctx: TemplateContext<{ returnId?: string; orderNumber?: string }>\r\n) {\r\n const { returnId, orderNumber, companyDetails } = ctx;\r\n const subject = 'Return initiated';\r\n const bodyHtml = `<h2>Return initiated</h2><p>Your return request has been received.</p>${orderNumber ? `<p><strong>Order:</strong> ${escapeHtml(orderNumber)}</p>` : ''}${returnId ? `<p><strong>Return ID:</strong> ${escapeHtml(returnId)}</p>` : ''}`;\r\n const text = `Return initiated.${orderNumber ? ` Order: ${orderNumber}` : ''}${returnId ? ` Return ID: ${returnId}` : ''}`;\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return { subject, html, text };\r\n}\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\r\n}\r\n","import type { TemplateContext } from './types';\r\nimport { renderLayout } from './layout';\r\n\r\nexport function render(\r\n ctx: TemplateContext<{\r\n orderNumber?: string;\r\n status?: string;\r\n trackingUrl?: string;\r\n }>\r\n) {\r\n const { orderNumber, status, trackingUrl, companyDetails } = ctx;\r\n const subject = status ? `Shipping update: ${status}` : 'Shipping update';\r\n const bodyHtml = `<h2>Shipping update</h2>${status ? `<p><strong>Status:</strong> ${escapeHtml(status)}</p>` : ''}${orderNumber ? `<p><strong>Order:</strong> ${escapeHtml(orderNumber)}</p>` : ''}${trackingUrl ? `<p><a href=\"${escapeHtml(trackingUrl)}\">Track your order</a></p>` : ''}`;\r\n const text = `Shipping update.${status ? ` Status: ${status}` : ''}${orderNumber ? ` Order: ${orderNumber}` : ''}${trackingUrl ? ` Track: ${trackingUrl}` : ''}`;\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return { subject, html, text };\r\n}\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\r\n}\r\n","import type { TemplateContext } from './types';\r\nimport { renderLayout } from './layout';\r\nimport { escapeHtml, primaryCtaButton } from './inline-cta';\r\n\r\nexport function render(\r\n ctx: TemplateContext<{ inviteLink: string; email: string; inviteeName?: string }>\r\n) {\r\n const { inviteLink, email, inviteeName, companyDetails } = ctx;\r\n const subject = \"You're invited\";\r\n const greeting =\r\n inviteeName && inviteeName.trim()\r\n ? `Hello ${escapeHtml(inviteeName.trim())},`\r\n : 'Hello,';\r\n const bodyHtml = `<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">${greeting}</p>\r\n<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">You have been invited to create your account for <strong>${escapeHtml(email)}</strong>. Use the secure link below to choose your password and activate access.</p>\r\n<p style=\"margin:0 0 8px 0;font-size:14px;line-height:1.5;color:#555;\">This link is personal to you. If you did not expect this invitation, you can ignore this message.</p>\r\n${primaryCtaButton(inviteLink, 'Accept invitation & set password')}\r\n<p style=\"margin:16px 0 0 0;font-size:12px;line-height:1.5;color:#888;\">If the button does not work, copy and paste this URL into your browser:<br/><span style=\"word-break:break-all;\">${escapeHtml(inviteLink)}</span></p>`;\r\n const text = [\r\n inviteeName?.trim() ? `Hello ${inviteeName.trim()},` : 'Hello,',\r\n '',\r\n `You have been invited to create your account (${email}).`,\r\n 'Open this link to set your password:',\r\n inviteLink,\r\n '',\r\n 'If you did not expect this invitation, you can ignore this email.',\r\n ].join('\\n');\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return { subject, html, text };\r\n}\r\n","import type { TemplateContext } from './types';\r\nimport { renderLayout } from './layout';\r\n\r\nexport function render(\r\n ctx: TemplateContext<{\r\n formName: string;\r\n contactName: string;\r\n contactEmail: string;\r\n formData: unknown;\r\n formFieldRows?: { label: string; value: string }[];\r\n }>\r\n) {\r\n const { formName, contactName, contactEmail, formData, formFieldRows, companyDetails } = ctx;\r\n const subject = `New Form Submission: ${formName}`;\r\n\r\n const fieldsBlock =\r\n formFieldRows && formFieldRows.length > 0\r\n ? formFieldRows\r\n .map(\r\n (r) =>\r\n `<p style=\"margin:10px 0 0 0;line-height:1.5;\"><strong>${escapeHtml(r.label)}</strong><br/>${escapeHtml(r.value)}</p>`\r\n )\r\n .join('')\r\n : `<p style=\"margin:10px 0 0 0;font-size:13px;white-space:pre-wrap;\">${escapeHtml(JSON.stringify(formData, null, 2))}</p>`;\r\n\r\n const bodyHtml = `<p style=\"margin:0 0 6px 0;font-size:18px;font-weight:600;color:#111;\">New Form Submission</p>\r\n<p style=\"margin:0 0 4px 0;\"><strong>Form:</strong> ${escapeHtml(formName)}</p>\r\n<p style=\"margin:0 0 8px 0;\"><strong>Contact:</strong> ${escapeHtml(contactName)}${contactEmail ? ` (${escapeHtml(contactEmail)})` : ''}</p>\r\n${fieldsBlock}`;\r\n\r\n const textLines = [\r\n 'New Form Submission',\r\n `Form: ${formName}`,\r\n `Contact: ${contactName}${contactEmail ? ` (${contactEmail})` : ''}`,\r\n '',\r\n ...(formFieldRows?.length\r\n ? formFieldRows.map((r) => `${r.label}: ${r.value}`)\r\n : [JSON.stringify(formData, null, 2)]),\r\n ];\r\n const text = textLines.join('\\n');\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return { subject, html, text };\r\n}\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\r\n}\r\n","import type { TemplateContext } from './types';\r\nimport { renderLayout } from './layout';\r\n\r\nexport type OtpTemplateCtx = TemplateContext<{\r\n code: string;\r\n}>;\r\n\r\nexport function render(ctx: OtpTemplateCtx) {\r\n const { code, companyDetails } = ctx;\r\n const name = companyDetails.companyName?.trim() || 'Our store';\r\n const bodyHtml = `\r\n <p>Your verification code is:</p>\r\n <p style=\"font-size:24px;font-weight:bold;letter-spacing:4px;\">${escapeHtml(code)}</p>\r\n <p style=\"color:#666;font-size:14px;\">This code expires in 10 minutes. If you did not request it, you can ignore this email.</p>\r\n `;\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return {\r\n subject: `${name}: your sign-in code`,\r\n html,\r\n text: `Your code is ${code}. It expires in 10 minutes.`,\r\n };\r\n}\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\r\n}\r\n","import type { TemplateContext } from './types';\r\nimport { renderLayout } from './layout';\r\n\r\nexport interface ChatLeadTemplateCtx {\r\n contactName: string;\r\n contactEmail: string;\r\n contactPhone?: string | null;\r\n conversationId: number;\r\n latestMessage: string;\r\n intentCode?: string | null;\r\n intentReason: string;\r\n transcript?: string;\r\n}\r\n\r\nexport function render(ctx: TemplateContext<ChatLeadTemplateCtx>) {\r\n const {\r\n contactName,\r\n contactEmail,\r\n contactPhone,\r\n conversationId,\r\n latestMessage,\r\n intentCode,\r\n intentReason,\r\n transcript,\r\n companyDetails,\r\n } = ctx;\r\n\r\n const intentDisplay = intentCode?.trim()\r\n ? `${intentCode.trim()}${intentReason?.trim() ? ` — ${intentReason.trim()}` : ''}`\r\n : intentReason;\r\n const subject = `Chat lead${intentCode?.trim() ? ` [${intentCode.trim()}]` : ''}: ${contactName || contactEmail || 'Visitor'}`;\r\n\r\n const transcriptBlock = transcript?.trim()\r\n ? `<div style=\"margin-top:16px;padding:12px;background:#f9fafb;border-radius:6px;border:1px solid #e5e7eb;\">\r\n<p style=\"margin:0 0 8px 0;font-size:13px;font-weight:600;color:#374151;\">Recent conversation</p>\r\n<pre style=\"margin:0;font-size:12px;white-space:pre-wrap;font-family:inherit;color:#4b5563;\">${escapeHtml(transcript.trim())}</pre>\r\n</div>`\r\n : '';\r\n\r\n const bodyHtml = `<p style=\"margin:0 0 6px 0;font-size:18px;font-weight:600;color:#111;\">New chat lead</p>\r\n<p style=\"margin:0 0 12px 0;font-size:14px;color:#374151;\">A visitor showed interest based on your intent rules.</p>\r\n<table style=\"width:100%;border-collapse:collapse;font-size:14px;\">\r\n<tr><td style=\"padding:4px 8px 4px 0;color:#6b7280;vertical-align:top;\">Name</td><td>${escapeHtml(contactName || '—')}</td></tr>\r\n<tr><td style=\"padding:4px 8px 4px 0;color:#6b7280;vertical-align:top;\">Email</td><td><a href=\"mailto:${escapeHtml(contactEmail)}\">${escapeHtml(contactEmail)}</a></td></tr>\r\n<tr><td style=\"padding:4px 8px 4px 0;color:#6b7280;vertical-align:top;\">Phone</td><td>${escapeHtml(contactPhone?.trim() || '—')}</td></tr>\r\n<tr><td style=\"padding:4px 8px 4px 0;color:#6b7280;vertical-align:top;\">Conversation</td><td>#${conversationId}</td></tr>\r\n<tr><td style=\"padding:4px 8px 4px 0;color:#6b7280;vertical-align:top;\">Intent</td><td>${escapeHtml(intentReason)}</td></tr>\r\n</table>\r\n<p style=\"margin:16px 0 6px 0;font-size:13px;font-weight:600;color:#374151;\">Latest message</p>\r\n<p style=\"margin:0;font-size:14px;white-space:pre-wrap;\">${escapeHtml(latestMessage)}</p>\r\n${transcriptBlock}`;\r\n\r\n const text = [\r\n 'New chat lead',\r\n `Name: ${contactName || '—'}`,\r\n `Email: ${contactEmail}`,\r\n `Phone: ${contactPhone?.trim() || '—'}`,\r\n `Conversation: #${conversationId}`,\r\n `Intent: ${intentDisplay}`,\r\n '',\r\n 'Latest message:',\r\n latestMessage,\r\n transcript?.trim() ? `\\nRecent conversation:\\n${transcript.trim()}` : '',\r\n ].join('\\n');\r\n\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return { subject, html, text };\r\n}\r\n\r\nfunction escapeHtml(s: string): string {\r\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/\"/g, '"');\r\n}\r\n","import type { TemplateContext } from './types';\r\nimport { renderLayout } from './layout';\r\nimport { escapeHtml, primaryCtaButton } from './inline-cta';\r\n\r\nexport type VendorOnboardedAudience = 'owner' | 'internal';\r\nexport type VendorOnboardedActivation = 'invite' | 'password';\r\nexport type VendorOnboardedKind = 'vendor_onboard' | 'team_invite';\r\n\r\nexport interface VendorOnboardedContext {\r\n audience: VendorOnboardedAudience;\r\n activation: VendorOnboardedActivation;\r\n kind?: VendorOnboardedKind;\r\n vendorName: string;\r\n vendorSlug?: string;\r\n ownerName?: string;\r\n ownerEmail: string;\r\n inviteLink?: string;\r\n signInLink?: string;\r\n}\r\n\r\nexport function render(ctx: TemplateContext<VendorOnboardedContext>) {\r\n const {\r\n audience,\r\n activation,\r\n kind = 'vendor_onboard',\r\n vendorName,\r\n vendorSlug,\r\n ownerName,\r\n ownerEmail,\r\n inviteLink,\r\n signInLink,\r\n companyDetails,\r\n } = ctx;\r\n\r\n const storeLabel = vendorName.trim() || 'your store';\r\n const greeting =\r\n ownerName && ownerName.trim() ? `Hello ${escapeHtml(ownerName.trim())},` : 'Hello,';\r\n const slugNote =\r\n vendorSlug && vendorSlug.trim()\r\n ? `<p style=\"margin:0 0 8px 0;font-size:14px;line-height:1.5;color:#555;\"><strong>Store URL slug:</strong> ${escapeHtml(vendorSlug.trim())}</p>`\r\n : '';\r\n\r\n let subject: string;\r\n let bodyHtml: string;\r\n let text: string;\r\n\r\n if (audience === 'internal') {\r\n const action =\r\n kind === 'team_invite'\r\n ? 'A team member was invited to a vendor store.'\r\n : activation === 'invite'\r\n ? 'A new vendor store was created and the owner was invited.'\r\n : 'A new vendor store was created with an active owner account.';\r\n subject =\r\n kind === 'team_invite' ? `Team invite: ${storeLabel}` : `New vendor: ${storeLabel}`;\r\n bodyHtml = `<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">${action}</p>\r\n<p style=\"margin:0 0 8px 0;font-size:15px;line-height:1.5;color:#333;\"><strong>Store:</strong> ${escapeHtml(storeLabel)}</p>\r\n${slugNote}\r\n<p style=\"margin:0 0 8px 0;font-size:15px;line-height:1.5;color:#333;\"><strong>Owner / invitee:</strong> ${escapeHtml(ownerName?.trim() || '—')} <span style=\"color:#555;\">(${escapeHtml(ownerEmail)})</span></p>\r\n<p style=\"margin:0 0 0 0;font-size:14px;line-height:1.5;color:#555;\"><strong>Activation:</strong> ${escapeHtml(activation === 'invite' ? 'Invitation' : 'Password set')}</p>`;\r\n text = [\r\n subject,\r\n '',\r\n action,\r\n `Store: ${storeLabel}`,\r\n vendorSlug ? `Slug: ${vendorSlug}` : '',\r\n `Owner / invitee: ${ownerName?.trim() || '—'} (${ownerEmail})`,\r\n `Activation: ${activation === 'invite' ? 'Invitation' : 'Password set'}`,\r\n ]\r\n .filter(Boolean)\r\n .join('\\n');\r\n } else if (kind === 'team_invite' && activation === 'invite' && inviteLink) {\r\n subject = `You're invited to ${storeLabel}`;\r\n bodyHtml = `<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">${greeting}</p>\r\n<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">You have been invited to join the vendor team for <strong>${escapeHtml(storeLabel)}</strong>. Use the secure link below to set your password and activate your account.</p>\r\n${primaryCtaButton(inviteLink, 'Accept invitation & set password')}\r\n<p style=\"margin:16px 0 0 0;font-size:12px;line-height:1.5;color:#888;\">If the button does not work, copy and paste this URL into your browser:<br/><span style=\"word-break:break-all;\">${escapeHtml(inviteLink)}</span></p>`;\r\n text = [\r\n ownerName?.trim() ? `Hello ${ownerName.trim()},` : 'Hello,',\r\n '',\r\n `You have been invited to join ${storeLabel}.`,\r\n 'Open this link to set your password:',\r\n inviteLink,\r\n ].join('\\n');\r\n } else if (activation === 'invite' && inviteLink) {\r\n subject = `Your vendor store \"${storeLabel}\" is ready`;\r\n bodyHtml = `<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">${greeting}</p>\r\n<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">Your vendor store <strong>${escapeHtml(storeLabel)}</strong> has been created. Accept the invitation below to set your password and access the admin dashboard.</p>\r\n${slugNote}\r\n${primaryCtaButton(inviteLink, 'Accept invitation & set password')}\r\n<p style=\"margin:16px 0 0 0;font-size:12px;line-height:1.5;color:#888;\">If the button does not work, copy and paste this URL into your browser:<br/><span style=\"word-break:break-all;\">${escapeHtml(inviteLink)}</span></p>`;\r\n text = [\r\n ownerName?.trim() ? `Hello ${ownerName.trim()},` : 'Hello,',\r\n '',\r\n `Your vendor store \"${storeLabel}\" has been created.`,\r\n 'Open this link to set your password:',\r\n inviteLink,\r\n ].join('\\n');\r\n } else {\r\n subject = `Welcome to ${storeLabel}`;\r\n const loginUrl = signInLink?.trim() || inviteLink?.trim() || '';\r\n bodyHtml = `<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">${greeting}</p>\r\n<p style=\"margin:0 0 12px 0;font-size:15px;line-height:1.5;color:#333;\">Your vendor store <strong>${escapeHtml(storeLabel)}</strong> has been created and your owner account is ready. Sign in to the admin dashboard to manage your store.</p>\r\n${slugNote}\r\n${loginUrl ? primaryCtaButton(loginUrl, 'Sign in to admin') : ''}\r\n${loginUrl ? `<p style=\"margin:16px 0 0 0;font-size:12px;line-height:1.5;color:#888;\">Sign-in URL:<br/><span style=\"word-break:break-all;\">${escapeHtml(loginUrl)}</span></p>` : ''}`;\r\n text = [\r\n ownerName?.trim() ? `Hello ${ownerName.trim()},` : 'Hello,',\r\n '',\r\n `Your vendor store \"${storeLabel}\" has been created.`,\r\n loginUrl ? `Sign in: ${loginUrl}` : '',\r\n ]\r\n .filter(Boolean)\r\n .join('\\n');\r\n }\r\n\r\n const html = renderLayout({ bodyHtml, companyDetails });\r\n return { subject, html, text };\r\n}\r\n","export * from './types';\r\nexport { renderLayout } from './layout';\r\nimport type { EmailTemplateName, TemplateContext } from './types';\r\nimport { render as renderSignup } from './signup';\r\nimport { render as renderPasswordReset } from './passwordReset';\r\nimport { render as renderPasswordChange } from './passwordChange';\r\nimport { render as renderOrderPlaced } from './orderPlaced';\r\nimport { render as renderReturnInitiated } from './returnInitiated';\r\nimport { render as renderShippingUpdate } from './shippingUpdate';\r\nimport { render as renderInvite } from './invite';\r\nimport { render as renderFormSubmission } from './formSubmission';\r\nimport { render as renderOtp } from './otp';\r\nimport { render as renderChatLead } from './chatLead';\r\nimport { render as renderVendorOnboarded } from './vendorOnboarded';\r\n\r\nexport {\r\n renderSignup,\r\n renderPasswordReset,\r\n renderPasswordChange,\r\n renderOrderPlaced,\r\n renderReturnInitiated,\r\n renderShippingUpdate,\r\n renderInvite,\r\n renderFormSubmission,\r\n renderOtp,\r\n renderChatLead,\r\n renderVendorOnboarded,\r\n};\r\n\r\nexport type EmailRenderResult = { subject: string; html: string; text?: string };\r\n\r\nconst templateRenderMap: Record<\r\n EmailTemplateName,\r\n (ctx: TemplateContext<unknown>) => EmailRenderResult\r\n> = {\r\n signup: renderSignup as (ctx: TemplateContext<unknown>) => EmailRenderResult,\r\n passwordReset: renderPasswordReset as (ctx: TemplateContext<unknown>) => EmailRenderResult,\r\n passwordChange: renderPasswordChange as (ctx: TemplateContext<unknown>) => EmailRenderResult,\r\n orderPlaced: renderOrderPlaced as (ctx: TemplateContext<unknown>) => EmailRenderResult,\r\n returnInitiated: renderReturnInitiated as (ctx: TemplateContext<unknown>) => EmailRenderResult,\r\n shippingUpdate: renderShippingUpdate as (ctx: TemplateContext<unknown>) => EmailRenderResult,\r\n invite: renderInvite as (ctx: TemplateContext<unknown>) => EmailRenderResult,\r\n formSubmission: renderFormSubmission as (ctx: TemplateContext<unknown>) => EmailRenderResult,\r\n otp: renderOtp as (ctx: TemplateContext<unknown>) => EmailRenderResult,\r\n chatLead: renderChatLead as (ctx: TemplateContext<unknown>) => EmailRenderResult,\r\n vendorOnboarded: renderVendorOnboarded as (ctx: TemplateContext<unknown>) => EmailRenderResult,\r\n};\r\n\r\nexport function getTemplateRenderer(name: EmailTemplateName) {\r\n return templateRenderMap[name];\r\n}\r\n","import type {\r\n CompanyDetails,\r\n EmailTemplateName,\r\n EmailTemplateResult,\r\n TemplateContext,\r\n} from './templates/types';\r\nimport { renderLayout } from './templates/layout';\r\nimport { getTemplateRenderer } from './templates/index';\r\n\r\nexport interface RenderEmailOptions {\r\n renderLayout?: (opts: { bodyHtml: string; companyDetails: CompanyDetails }) => string;\r\n getBody?: (templateName: string, ctx: TemplateContext<unknown>) => EmailTemplateResult | null;\r\n}\r\n\r\nexport interface RenderedEmail {\r\n subject: string;\r\n html: string;\r\n text?: string;\r\n}\r\n\r\nexport function renderEmail(\r\n templateName: EmailTemplateName,\r\n ctx: TemplateContext<unknown>,\r\n options?: RenderEmailOptions\r\n): RenderedEmail {\r\n const layoutFn = options?.renderLayout ?? renderLayout;\r\n const getBody = options?.getBody;\r\n\r\n if (getBody) {\r\n const custom = getBody(templateName, ctx);\r\n if (custom != null) {\r\n const html = layoutFn({ bodyHtml: custom.bodyHtml, companyDetails: ctx.companyDetails });\r\n return { subject: custom.subject, html, text: custom.text };\r\n }\r\n }\r\n\r\n const render = getTemplateRenderer(templateName);\r\n if (!render) {\r\n throw new Error(`Unknown email template: ${templateName}`);\r\n }\r\n return render(ctx);\r\n}\r\n","import type { CmsPlugin } from '../types';\r\nimport {\r\n EmailService,\r\n sesRegionSupportsSmtp,\r\n sesSmtpHost,\r\n} from './email-service';\r\nimport type { RenderEmailOptions } from './renderer';\r\n\r\nconst EMAIL_TYPES = ['AWS', 'SMTP', 'GMAIL', 'SENDGRID'] as const;\r\ntype EmailType = (typeof EMAIL_TYPES)[number];\r\n\r\nfunction normalizeEmailType(raw: string | undefined, fallback: EmailType): EmailType {\r\n const v = String(raw ?? fallback).trim().toUpperCase();\r\n return (EMAIL_TYPES.includes(v as EmailType) ? v : fallback) as EmailType;\r\n}\r\n\r\n/** Dev mail catchers; must not override AWS SES SMTP host. */\r\nfunction isLocalSmtpHost(host: string | undefined): boolean {\r\n if (!host) return false;\r\n const h = host.trim().toLowerCase();\r\n return h === 'localhost' || h === '127.0.0.1' || h === '::1';\r\n}\r\n\r\nexport interface EmailPluginConfig {\r\n type: 'AWS' | 'SMTP' | 'GMAIL' | 'SENDGRID';\r\n user?: string;\r\n password?: string;\r\n from: string;\r\n to: string;\r\n host?: string;\r\n port?: number;\r\n secure?: boolean;\r\n region?: string;\r\n accessKeyId?: string;\r\n secretAccessKey?: string;\r\n templateOptions?: RenderEmailOptions;\r\n}\r\n\r\nexport function emailPlugin(config: EmailPluginConfig): CmsPlugin<EmailService> {\r\n return {\r\n name: 'email',\r\n version: '1.0.0',\r\n async init(context) {\r\n const from = config.from || context.config.SMTP_FROM || 'no-reply@example.com';\r\n const to = config.to || context.config.SMTP_TO || 'info@example.com';\r\n /** Env wins over plugin defaults (hosts often pass type: 'SMTP' while SMTP_TYPE=AWS in .env). */\r\n const type = normalizeEmailType(context.config.SMTP_TYPE ?? config.type, 'SMTP');\r\n const portEnv = context.config.SMTP_PORT;\r\n const portParsed = portEnv ? parseInt(portEnv, 10) : undefined;\r\n /** SES SMTP/API region; use AWS_SES_REGION when AWS_REGION has no SMTP (e.g. ap-south-2 → ap-south-1). */\r\n const region =\r\n config.region ?? context.config.AWS_SES_REGION ?? context.config.AWS_REGION;\r\n let host: string | undefined = config.host ?? context.config.SMTP_HOST;\r\n if (type === 'AWS' && isLocalSmtpHost(host)) {\r\n host = undefined;\r\n }\r\n const merged: EmailPluginConfig = {\r\n ...config,\r\n from,\r\n to,\r\n type,\r\n user: config.user ?? context.config.SMTP_USER,\r\n password:\r\n config.password ?? context.config.SMTP_PASSWORD ?? context.config.SMTP_PASS,\r\n host,\r\n port: config.port ?? (Number.isFinite(portParsed) ? portParsed : undefined),\r\n secure: config.secure ?? context.config.SMTP_SECURE === 'true',\r\n region,\r\n accessKeyId: config.accessKeyId ?? context.config.AWS_ACCESS_KEY_ID,\r\n secretAccessKey: config.secretAccessKey ?? context.config.AWS_SECRET_ACCESS_KEY,\r\n };\r\n if (type === 'AWS' && !merged.region) {\r\n context.logger.warn(\r\n 'Email plugin skipped: AWS SES requires AWS_SES_REGION or AWS_REGION'\r\n );\r\n return undefined;\r\n }\r\n if (\r\n type === 'AWS' &&\r\n merged.region &&\r\n merged.user &&\r\n merged.password &&\r\n !sesRegionSupportsSmtp(merged.region)\r\n ) {\r\n context.logger.warn(\r\n `Email plugin: region ${merged.region} has no SES SMTP endpoint (ENOTFOUND). Set AWS_SES_REGION=ap-south-1 and create SMTP credentials in that SES region.`\r\n );\r\n }\r\n if (\r\n type === 'AWS' &&\r\n !(\r\n (merged.user && merged.password) ||\r\n (merged.accessKeyId && merged.secretAccessKey)\r\n )\r\n ) {\r\n context.logger.warn(\r\n 'Email plugin skipped: AWS SES requires SMTP_USER and SMTP_PASSWORD (SES SMTP) or AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY (SES API)'\r\n );\r\n return undefined;\r\n }\r\n if ((type === 'SMTP' || type === 'GMAIL') && (!merged.user || !merged.password)) {\r\n context.logger.warn('Email plugin skipped: SMTP credentials not configured');\r\n return undefined;\r\n }\r\n if (type === 'SMTP' && !merged.host) {\r\n context.logger.warn(\r\n 'Email plugin skipped: SMTP_TYPE=SMTP requires SMTP_HOST (or use SMTP_TYPE=AWS with AWS_REGION and SES SMTP credentials)'\r\n );\r\n return undefined;\r\n }\r\n const resolvedHost =\r\n type === 'AWS' && merged.region\r\n ? merged.host || sesSmtpHost(merged.region)\r\n : merged.host;\r\n context.logger.info('Email plugin initialized', { type, host: resolvedHost, region: merged.region });\r\n return new EmailService(merged);\r\n },\r\n };\r\n}\r\n\r\nexport { EmailService, emailTemplates } from './email-service';\r\nexport type { EmailData, EmailPluginConfig as EmailConfig, EmailServiceInterface, RenderedEmail } from './email-service';\r\nexport { renderEmail } from './renderer';\r\nexport { getCompanyDetailsFromSettings, mergeEmailLayoutCompanyDetails } from './templates/types';\r\nexport { renderLayout } from './templates/layout';\r\nexport { registerEmailQueueProcessor, queueEmail, queueOrderPlacedEmails, queueVendorOnboardEmails } from './email-queue';\r\nexport { sendChatLeadEmail } from './chat-lead-email';\r\nexport type { SendChatLeadEmailInput } from './chat-lead-email';\r\nexport type { EmailJobPayload, OrderPlacedEmailPayload, VendorOnboardEmailPayload } from './email-queue';\r\nexport type {\r\n CompanyDetails,\r\n SocialLinkItem,\r\n EmailTemplateName,\r\n EmailTemplateResult,\r\n TemplateContext,\r\n OrderPlacedLineItem,\r\n} from './templates/types';\r\nexport type { RenderEmailOptions } from './renderer';\r\n","import type { CompanyDetails } from './templates/types';\r\nimport { mergeEmailLayoutCompanyDetails } from './templates/types';\r\nimport { queueEmail } from './email-queue';\r\nimport type { CmsAppLike } from './email-queue';\r\nimport type { EmailService } from './email-service';\r\nimport { parseEmailRecipientsFromConfig } from '../../lib/email-recipients';\r\nimport { CHAT_EMAIL_LOG } from '../llm/chat-email-intent';\r\n\r\nexport interface SendChatLeadEmailInput {\r\n contactName: string;\r\n contactEmail: string;\r\n contactPhone?: string | null;\r\n conversationId: number;\r\n latestMessage: string;\r\n /** e.g. SALES_LEAD */\r\n intentCode?: string | null;\r\n intentReason: string;\r\n transcript?: string;\r\n companyDetails: CompanyDetails;\r\n /** When set, overrides CRM / SMTP default recipients for this lead. */\r\n recipients?: string[];\r\n}\r\n\r\nfunction resolveLeadRecipients(\r\n emailPlugin: EmailService,\r\n emailSettings: Record<string, string>\r\n): string[] {\r\n const fromCrm = parseEmailRecipientsFromConfig(\r\n emailSettings.crmEmails ?? emailSettings.crmEmail ?? ''\r\n );\r\n if (fromCrm.length > 0) return fromCrm;\r\n const fallback = emailPlugin.getDefaultTo?.() ?? '';\r\n if (fallback.trim()) return [fallback.trim()];\r\n return [];\r\n}\r\n\r\n/**\r\n * Notify the team about a classified chat lead (intent-specific recipients, or CRM / SMTP fallback).\r\n */\r\nexport async function sendChatLeadEmail(\r\n cms: CmsAppLike,\r\n emailSettings: Record<string, string>,\r\n brandingSettings: Record<string, string>,\r\n input: SendChatLeadEmailInput\r\n): Promise<{ sent: boolean; recipients: string[]; error?: string }> {\r\n console.info(CHAT_EMAIL_LOG, 'send start', {\r\n conversationId: input.conversationId,\r\n intentCode: input.intentCode ?? null,\r\n contactEmail: input.contactEmail,\r\n contactName: input.contactName,\r\n explicitRecipients: input.recipients?.length ?? 0,\r\n });\r\n\r\n const email = cms.getPlugin('email') as EmailService | undefined;\r\n if (!email?.send || !email.renderTemplate) {\r\n console.warn(CHAT_EMAIL_LOG, 'send failed', {\r\n conversationId: input.conversationId,\r\n reason: 'email_plugin_disabled',\r\n });\r\n return { sent: false, recipients: [], error: 'Email plugin is not enabled' };\r\n }\r\n\r\n const recipients =\r\n input.recipients?.filter((r) => r.trim().includes('@')).map((r) => r.trim()) ??\r\n resolveLeadRecipients(email, emailSettings);\r\n if (recipients.length === 0) {\r\n console.warn(CHAT_EMAIL_LOG, 'send failed', {\r\n conversationId: input.conversationId,\r\n reason: 'no_recipients',\r\n });\r\n return {\r\n sent: false,\r\n recipients: [],\r\n error: 'No lead email recipients (configure intent Email To, CRM emails, or SMTP default To)',\r\n };\r\n }\r\n\r\n console.info(CHAT_EMAIL_LOG, 'send recipients resolved', {\r\n conversationId: input.conversationId,\r\n recipients,\r\n source: input.recipients?.length ? 'intent_email_to' : 'crm_or_smtp_fallback',\r\n });\r\n\r\n const companyDetails = mergeEmailLayoutCompanyDetails(brandingSettings, emailSettings);\r\n const ctx = {\r\n ...input,\r\n companyDetails: input.companyDetails ?? companyDetails,\r\n };\r\n\r\n let anySent = false;\r\n for (const to of recipients) {\r\n await queueEmail(cms, {\r\n to,\r\n templateName: 'chatLead',\r\n ctx,\r\n });\r\n console.info(CHAT_EMAIL_LOG, 'send queued', {\r\n conversationId: input.conversationId,\r\n to,\r\n template: 'chatLead',\r\n });\r\n anySent = true;\r\n }\r\n\r\n console.info(CHAT_EMAIL_LOG, 'send complete', {\r\n conversationId: input.conversationId,\r\n sent: anySent,\r\n recipientCount: recipients.length,\r\n });\r\n\r\n return { sent: anySent, recipients };\r\n}\r\n","/** Parse stored config value into a list of emails (JSON array, or comma/semicolon-separated string). */\r\nexport function parseEmailRecipientsFromConfig(raw: string | undefined | null): string[] {\r\n if (raw == null || raw === '') return [];\r\n const trimmed = raw.trim();\r\n if (trimmed.startsWith('[')) {\r\n try {\r\n const parsed = JSON.parse(trimmed) as unknown;\r\n if (Array.isArray(parsed)) {\r\n return parsed.map((e) => String(e).trim()).filter(Boolean);\r\n }\r\n } catch {\r\n // fall through\r\n }\r\n }\r\n return trimmed\r\n .split(/[,;]+/)\r\n .map((s) => s.trim())\r\n .filter(Boolean);\r\n}\r\n\r\n/** Serialize email list for config storage (JSON array in DB). */\r\nexport function serializeEmailRecipients(emails: string[]): string {\r\n return JSON.stringify(emails);\r\n}\r\n\r\n/** Join for SMTP `to` header (multiple recipients). */\r\nexport function joinRecipientsForSend(emails: string[]): string | null {\r\n if (!emails.length) return null;\r\n return emails.join(', ');\r\n}\r\n","import type { LlmAgentOptions, LlmMessage, LlmServiceInterface } from './llm-service';\r\n\r\n/** One routable lead intent (admin-configurable). */\r\nexport interface ChatLeadIntentDefinition {\r\n /** Stable key, e.g. SALES_LEAD, CAREERS */\r\n intent: string;\r\n description: string;\r\n emailTo: string;\r\n}\r\n\r\nexport interface ChatEmailToolSettings {\r\n /** When false, skip intent detection and lead emails. */\r\n enabled: boolean;\r\n /** Intent → description → recipient routing table. */\r\n intents: ChatLeadIntentDefinition[];\r\n /**\r\n * Extra rules for the intent classifier (when to use NONE, edge cases, priority).\r\n * Merged into the classifier system prompt together with the intent table.\r\n */\r\n classifierInstructions: string;\r\n /** Extra instructions merged into the chat agent system prompt when the tool is enabled. */\r\n toolPrompt?: string;\r\n}\r\n\r\nexport interface ChatEmailIntentResult {\r\n /** Matched intent key, or null if none / not interested. */\r\n intent: string | null;\r\n /** Human-readable label for emails (intent key + description snippet). */\r\n intentLabel: string;\r\n reason: string;\r\n /** Recipient for this intent; null when intent is null. */\r\n emailTo: string | null;\r\n}\r\n\r\nexport const DEFAULT_CHAT_LEAD_INTENTS: ChatLeadIntentDefinition[] = [\r\n { intent: 'SALES_LEAD', description: 'Wants to buy, price inquiry, quotation', emailTo: 'sales@company.com' },\r\n { intent: 'TEST_DRIVE', description: 'Wants test drive or demo', emailTo: 'sales@company.com' },\r\n { intent: 'FINANCE_LOAN', description: 'EMI, loan, or financing', emailTo: 'finance@company.com' },\r\n { intent: 'SERVICE_REQUEST', description: 'Service, repair, or maintenance', emailTo: 'service@company.com' },\r\n { intent: 'BOOKING', description: 'Booking request', emailTo: 'sales@company.com' },\r\n { intent: 'AVAILABILITY', description: 'Stock or product availability', emailTo: 'sales@company.com' },\r\n { intent: 'COMPLAINT', description: 'Complaint or escalation', emailTo: 'support@company.com' },\r\n { intent: 'SUPPORT', description: 'General support', emailTo: 'support@company.com' },\r\n { intent: 'PARTNERSHIP', description: 'Dealer, distributor, or business inquiry', emailTo: 'partnerships@company.com' },\r\n { intent: 'CAREERS', description: 'Job or career inquiry', emailTo: 'hr@company.com' },\r\n { intent: 'FOLLOW_UP', description: 'Existing customer follow-up', emailTo: 'crm@company.com' },\r\n];\r\n\r\nconst NONE_INTENT = 'NONE';\r\n\r\n/** Server log prefix for lead-email intent detection and delivery. */\r\nexport const CHAT_EMAIL_LOG = '[chat-email-tool]';\r\n\r\nfunction logChatEmail(step: string, data?: Record<string, unknown>): void {\r\n if (data && Object.keys(data).length > 0) {\r\n console.info(CHAT_EMAIL_LOG, step, data);\r\n } else {\r\n console.info(CHAT_EMAIL_LOG, step);\r\n }\r\n}\r\n\r\nfunction normalizeIntentKey(raw: string): string {\r\n return raw\r\n .trim()\r\n .toUpperCase()\r\n .replace(/[^A-Z0-9]+/g, '_')\r\n .replace(/^_+|_+$/g, '');\r\n}\r\n\r\nfunction parseIntentsJson(raw: string | undefined): ChatLeadIntentDefinition[] | null {\r\n if (!raw?.trim()) return null;\r\n try {\r\n const parsed = JSON.parse(raw) as unknown;\r\n if (!Array.isArray(parsed)) return null;\r\n const out: ChatLeadIntentDefinition[] = [];\r\n for (const row of parsed) {\r\n if (!row || typeof row !== 'object') continue;\r\n const o = row as Record<string, unknown>;\r\n const intent = normalizeIntentKey(String(o.intent ?? o.id ?? ''));\r\n const description = String(o.description ?? '').trim();\r\n const emailTo = String(o.emailTo ?? o.email ?? '').trim();\r\n if (!intent || !description || !emailTo) continue;\r\n out.push({ intent, description, emailTo });\r\n }\r\n return out.length > 0 ? out : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction dedupeIntents(intents: ChatLeadIntentDefinition[]): ChatLeadIntentDefinition[] {\r\n const seen = new Set<string>();\r\n const out: ChatLeadIntentDefinition[] = [];\r\n for (const row of intents) {\r\n const key = normalizeIntentKey(row.intent);\r\n if (!key || seen.has(key)) continue;\r\n seen.add(key);\r\n out.push({\r\n intent: key,\r\n description: row.description.trim(),\r\n emailTo: row.emailTo.trim(),\r\n });\r\n }\r\n return out;\r\n}\r\n\r\nexport function parseChatEmailToolSettings(map: Record<string, string>): ChatEmailToolSettings {\r\n const fromJson = parseIntentsJson(map.emailIntents);\r\n const intents = dedupeIntents(fromJson ?? []);\r\n\r\n const legacyPositive = map.emailIntentPrompt?.trim() ?? '';\r\n const legacyNegative = map.emailNegativeIntentPrompt?.trim() ?? '';\r\n let classifierInstructions = map.emailClassifierInstructions?.trim() ?? '';\r\n if (!classifierInstructions && (legacyPositive || legacyNegative)) {\r\n const parts: string[] = [];\r\n if (legacyPositive) parts.push(`Legacy positive signals:\\n${legacyPositive}`);\r\n if (legacyNegative) parts.push(`Do NOT assign an intent when:\\n${legacyNegative}`);\r\n classifierInstructions = parts.join('\\n\\n');\r\n }\r\n\r\n return {\r\n enabled: map.emailToolEnabled === 'true',\r\n intents,\r\n classifierInstructions,\r\n toolPrompt: map.emailToolPrompt ?? '',\r\n };\r\n}\r\n\r\n/** Parse `emailIntents` config value from DB (empty array when unset or invalid). */\r\nexport function parseEmailIntentsFromSettings(raw: string | undefined): ChatLeadIntentDefinition[] {\r\n return dedupeIntents(parseIntentsJson(raw) ?? []);\r\n}\r\n\r\nexport function serializeChatLeadIntents(intents: ChatLeadIntentDefinition[]): string {\r\n return JSON.stringify(\r\n dedupeIntents(intents).map((r) => ({\r\n intent: r.intent,\r\n description: r.description,\r\n emailTo: r.emailTo,\r\n }))\r\n );\r\n}\r\n\r\n/** Stored on the chatbot `llm_agents.validation_rules` JSON under `emailTool`. */\r\nexport type LlmAgentEmailToolJson = {\r\n enabled?: boolean;\r\n classifierInstructions?: string;\r\n toolPrompt?: string;\r\n intents?: ChatLeadIntentDefinition[];\r\n};\r\n\r\nconst EMAIL_TOOL_VALIDATION_KEY = 'emailTool';\r\n\r\nfunction parseEmailToolObject(raw: unknown): LlmAgentEmailToolJson | null {\r\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;\r\n const o = raw as Record<string, unknown>;\r\n const intentsRaw = o.intents;\r\n let intents: ChatLeadIntentDefinition[] | undefined;\r\n if (Array.isArray(intentsRaw)) {\r\n const parsed = parseIntentsJson(JSON.stringify(intentsRaw));\r\n if (parsed?.length) intents = parsed;\r\n }\r\n return {\r\n enabled: o.enabled === true,\r\n classifierInstructions:\r\n typeof o.classifierInstructions === 'string' ? o.classifierInstructions.trim() : undefined,\r\n toolPrompt: typeof o.toolPrompt === 'string' ? o.toolPrompt.trim() : undefined,\r\n intents,\r\n };\r\n}\r\n\r\n/** Read email tool config from chatbot agent `validation_rules` JSON. */\r\nexport function parseEmailToolFromAgentValidationRules(\r\n validationRulesText: string | null | undefined\r\n): LlmAgentEmailToolJson | null {\r\n const raw = validationRulesText?.trim();\r\n if (!raw) return null;\r\n try {\r\n const parsed = JSON.parse(raw) as unknown;\r\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return null;\r\n const emailTool = (parsed as Record<string, unknown>)[EMAIL_TOOL_VALIDATION_KEY];\r\n return parseEmailToolObject(emailTool);\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/** Split guardrails JSON (textarea) from embedded `emailTool` for the Plugins UI. */\r\nexport function splitValidationRulesForAdmin(\r\n validationRulesText: string | null | undefined\r\n): { guardrailsJson: string; emailTool: LlmAgentEmailToolJson | null } {\r\n const raw = validationRulesText?.trim() ?? '';\r\n if (!raw) return { guardrailsJson: '', emailTool: null };\r\n try {\r\n const parsed = JSON.parse(raw) as Record<string, unknown>;\r\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\r\n return { guardrailsJson: raw, emailTool: null };\r\n }\r\n const emailTool = parseEmailToolObject(parsed[EMAIL_TOOL_VALIDATION_KEY]);\r\n const rest = { ...parsed };\r\n delete rest[EMAIL_TOOL_VALIDATION_KEY];\r\n const guardrailsJson =\r\n Object.keys(rest).length > 0 ? JSON.stringify(rest, null, 2) : '';\r\n return { guardrailsJson, emailTool };\r\n } catch {\r\n return { guardrailsJson: raw, emailTool: null };\r\n }\r\n}\r\n\r\n/** Merge lead-email fields into chatbot `validation_rules` while preserving guardrails JSON. */\r\nexport function mergeEmailToolIntoValidationRules(\r\n guardrailsJson: string | null | undefined,\r\n emailTool: {\r\n classifierInstructions: string;\r\n toolPrompt: string;\r\n intents: ChatLeadIntentDefinition[];\r\n }\r\n): string | null {\r\n const intents = dedupeIntents(emailTool.intents);\r\n const hasEmail =\r\n intents.length > 0 ||\r\n emailTool.classifierInstructions.trim() !== '' ||\r\n emailTool.toolPrompt.trim() !== '';\r\n\r\n let base: Record<string, unknown> = {};\r\n const raw = guardrailsJson?.trim();\r\n if (raw) {\r\n try {\r\n const parsed = JSON.parse(raw) as unknown;\r\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\r\n base = { ...(parsed as Record<string, unknown>) };\r\n delete base[EMAIL_TOOL_VALIDATION_KEY];\r\n } else {\r\n return raw;\r\n }\r\n } catch {\r\n return raw;\r\n }\r\n }\r\n\r\n if (!hasEmail) {\r\n return Object.keys(base).length > 0 ? JSON.stringify(base, null, 2) : null;\r\n }\r\n\r\n base[EMAIL_TOOL_VALIDATION_KEY] = {\r\n enabled: true,\r\n classifierInstructions: emailTool.classifierInstructions.trim(),\r\n toolPrompt: emailTool.toolPrompt.trim(),\r\n intents: intents.map((r) => ({\r\n intent: r.intent,\r\n description: r.description,\r\n emailTo: r.emailTo,\r\n })),\r\n };\r\n\r\n return JSON.stringify(base, null, 2);\r\n}\r\n\r\nexport type LlmNotifyEmailAgentSource = {\r\n systemInstruction?: string | null;\r\n validationRules?: string | null;\r\n};\r\n\r\nexport type ResolveChatEmailToolSources = {\r\n /** Legacy: `emailTool` embedded on chatbot row (migrated to notify agent in admin). */\r\n chatbotValidationRules?: string | null;\r\n /** Notify agent (`scope = email_intent_chatbot`) — primary store for intents + routing instructions. */\r\n notifyAgent?: LlmNotifyEmailAgentSource | null;\r\n};\r\n\r\n/**\r\n * Lead email settings: notify agent first, then chatbot `validation_rules.emailTool`, then `configs`.\r\n * Classifier text = notify `system_instruction` + optional `emailTool.classifierInstructions`.\r\n */\r\nexport function resolveChatEmailToolSettings(\r\n configMap: Record<string, string>,\r\n sources?: ResolveChatEmailToolSources | string | null\r\n): ChatEmailToolSettings {\r\n const fromConfig = parseChatEmailToolSettings(configMap);\r\n const resolved: ResolveChatEmailToolSources =\r\n typeof sources === 'string' || sources == null\r\n ? { chatbotValidationRules: typeof sources === 'string' ? sources : null }\r\n : sources;\r\n\r\n const fromChatbot = parseEmailToolFromAgentValidationRules(resolved.chatbotValidationRules);\r\n const fromNotify = resolved.notifyAgent\r\n ? parseEmailToolFromAgentValidationRules(resolved.notifyAgent.validationRules)\r\n : null;\r\n const notifySystem = resolved.notifyAgent?.systemInstruction?.trim() ?? '';\r\n\r\n const intents =\r\n fromNotify?.intents?.length\r\n ? fromNotify.intents\r\n : fromChatbot?.intents?.length\r\n ? fromChatbot.intents\r\n : fromConfig.intents;\r\n\r\n const classifierParts = [\r\n notifySystem,\r\n fromNotify?.classifierInstructions?.trim(),\r\n fromChatbot?.classifierInstructions?.trim(),\r\n fromConfig.classifierInstructions.trim(),\r\n ].filter(Boolean);\r\n\r\n const toolPrompt =\r\n fromNotify?.toolPrompt?.trim() ||\r\n fromChatbot?.toolPrompt?.trim() ||\r\n fromConfig.toolPrompt?.trim() ||\r\n '';\r\n\r\n return {\r\n enabled: fromConfig.enabled,\r\n intents,\r\n classifierInstructions: classifierParts.join('\\n\\n'),\r\n toolPrompt,\r\n };\r\n}\r\n\r\nfunction intentByKey(\r\n intents: ChatLeadIntentDefinition[],\r\n key: string | null\r\n): ChatLeadIntentDefinition | null {\r\n if (!key) return null;\r\n const norm = normalizeIntentKey(key);\r\n return intents.find((i) => i.intent === norm) ?? null;\r\n}\r\n\r\nfunction buildIntentTableForPrompt(intents: ChatLeadIntentDefinition[]): string {\r\n return intents\r\n .map((i) => `- ${i.intent}: ${i.description} → notify ${i.emailTo}`)\r\n .join('\\n');\r\n}\r\n\r\nfunction buildIntentClassifierSystem(\r\n config: ChatEmailToolSettings,\r\n agentClassifierInstructions?: string | null\r\n): string {\r\n const table = buildIntentTableForPrompt(config.intents);\r\n const extra = [agentClassifierInstructions?.trim(), config.classifierInstructions.trim()]\r\n .filter(Boolean)\r\n .join('\\n\\n');\r\n const intentKeys = config.intents.map((i) => i.intent).join(', ');\r\n return `You classify a chat visitor into exactly one lead intent for email routing.\r\n\r\nAvailable intents (pick the best match):\r\n${table}\r\n\r\nIf the visitor is not ready for a lead email (general FAQ, greetings only, spam, off-topic, no clear business need), use intent \"${NONE_INTENT}\".\r\n\r\nAllowed intent values: ${intentKeys}, or ${NONE_INTENT}.\r\n\r\n${extra ? `Additional instructions:\\n${extra}\\n` : ''}\r\nReply with ONLY valid JSON, no markdown:\r\n{\"intent\":\"INTENT_KEY\",\"reason\":\"short explanation\"}\r\nUse \"${NONE_INTENT}\" when no intent applies.`;\r\n}\r\n\r\n/**\r\n * Merged into the chatbot system prompt: own instructions + classifier rules + intent catalog + extra chat notes.\r\n */\r\nexport function buildChatEmailAgentContext(settings: ChatEmailToolSettings): string {\r\n if (!settings.enabled) return '';\r\n const classifier = settings.classifierInstructions.trim();\r\n const extra = settings.toolPrompt?.trim() ?? '';\r\n const parts: string[] = [];\r\n\r\n if (settings.intents.length > 0) {\r\n parts.push(\r\n '## Lead email routing',\r\n 'When a visitor message clearly matches an intent below, the system sends one team notification email (per conversation). Continue the conversation normally in all cases.'\r\n );\r\n if (classifier) parts.push(`### Routing rules\\n${classifier}`);\r\n parts.push(`### Intent catalog\\n${buildIntentTableForPrompt(settings.intents)}`);\r\n } else if (classifier) {\r\n parts.push(`## Lead email routing\\n${classifier}`);\r\n }\r\n\r\n if (extra) parts.push(`### Assistant behavior\\n${extra}`);\r\n return parts.join('\\n\\n');\r\n}\r\n\r\n/** Chatbot system prompt: base instruction + guardrails + lead-email block. */\r\nexport function buildChatbotSystemPromptWithEmailTool(\r\n baseSystemInstruction: string | undefined,\r\n guardrailsForPrompt: string | null,\r\n emailSettings: ChatEmailToolSettings\r\n): string {\r\n let prompt = (baseSystemInstruction ?? '').trim();\r\n const guard = guardrailsForPrompt?.trim();\r\n if (guard) prompt = [prompt, guard].filter(Boolean).join('\\n\\n');\r\n if (emailSettings.enabled) {\r\n const emailCtx = buildChatEmailAgentContext(emailSettings);\r\n if (emailCtx) prompt = [prompt, emailCtx].filter(Boolean).join('\\n\\n');\r\n }\r\n return prompt;\r\n}\r\n\r\nfunction formatTranscript(history: LlmMessage[], latestMessage: string, maxChars = 4000): string {\r\n const lines: string[] = [];\r\n for (const m of history) {\r\n const role = m.role === 'assistant' ? 'Assistant' : m.role === 'user' ? 'Visitor' : 'System';\r\n lines.push(`${role}: ${m.content}`);\r\n }\r\n const last = history[history.length - 1];\r\n if (!last || last.role !== 'user' || last.content !== latestMessage) {\r\n lines.push(`Visitor: ${latestMessage}`);\r\n }\r\n let text = lines.join('\\n');\r\n if (text.length > maxChars) text = text.slice(-maxChars);\r\n return text;\r\n}\r\n\r\nfunction parseIntentJson(\r\n raw: string,\r\n intents: ChatLeadIntentDefinition[]\r\n): { intent: string; reason: string } | null {\r\n const trimmed = raw.trim();\r\n const fence = trimmed.match(/```(?:json)?\\s*([\\s\\S]*?)```/i);\r\n const candidate = (fence?.[1] ?? trimmed).trim();\r\n const tryParse = (s: string) => {\r\n const o = JSON.parse(s) as { intent?: unknown; interested?: unknown; reason?: unknown };\r\n let intentRaw: string | null = null;\r\n if (typeof o.intent === 'string') intentRaw = o.intent;\r\n else if (o.interested === false) intentRaw = NONE_INTENT;\r\n else if (o.interested === true && intents[0]) intentRaw = intents[0].intent;\r\n if (intentRaw == null) return null;\r\n const reason =\r\n typeof o.reason === 'string' && o.reason.trim() ? o.reason.trim() : 'Classified from conversation';\r\n return { intent: normalizeIntentKey(intentRaw), reason };\r\n };\r\n try {\r\n return tryParse(candidate);\r\n } catch {\r\n const m = candidate.match(/\\{[\\s\\S]*\\}/);\r\n if (!m) return null;\r\n try {\r\n return tryParse(m[0]);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Classify the latest visitor message (with conversation context) into a configured lead intent.\r\n */\r\nexport async function detectChatLeadIntent(\r\n llm: Pick<LlmServiceInterface, 'chatAgent'>,\r\n params: {\r\n settings: ChatEmailToolSettings;\r\n message: string;\r\n history: LlmMessage[];\r\n contact: { name?: string | null; email?: string | null; phone?: string | null };\r\n model?: string;\r\n /** From `llm_agents` scope `email_intent_chatbot` — merged into classifier instructions. */\r\n agentClassifierInstructions?: string | null;\r\n }\r\n): Promise<ChatEmailIntentResult> {\r\n if (!params.settings.intents.length) {\r\n logChatEmail('classify skipped', { reason: 'no_intents_configured' });\r\n return {\r\n intent: null,\r\n intentLabel: 'NONE',\r\n reason: 'No lead intents configured',\r\n emailTo: null,\r\n };\r\n }\r\n\r\n logChatEmail('classify start', {\r\n intentCount: params.settings.intents.length,\r\n intentKeys: params.settings.intents.map((i) => i.intent),\r\n model: params.model?.trim() || '(gateway default)',\r\n messageChars: params.message.length,\r\n historyTurns: params.history.length,\r\n hasClassifierInstructions: Boolean(\r\n params.agentClassifierInstructions?.trim() || params.settings.classifierInstructions.trim()\r\n ),\r\n });\r\n\r\n const transcript = formatTranscript(params.history, params.message);\r\n const contactLines = [\r\n params.contact.name?.trim() ? `Name: ${params.contact.name.trim()}` : null,\r\n params.contact.email?.trim() ? `Email: ${params.contact.email.trim()}` : null,\r\n params.contact.phone?.trim() ? `Phone: ${params.contact.phone.trim()}` : null,\r\n ]\r\n .filter(Boolean)\r\n .join('\\n');\r\n\r\n const userPrompt = `Customer:\\n${contactLines || '(unknown)'}\\n\\nConversation:\\n${transcript}\\n\\nPick the single best intent for the visitor's latest message.`;\r\n\r\n const res = await llm.chatAgent({\r\n systemPrompt: buildIntentClassifierSystem(params.settings, params.agentClassifierInstructions),\r\n userPrompt,\r\n temperature: 0.1,\r\n max_tokens: 256,\r\n ...(params.model?.trim() ? { model: params.model.trim() } : {}),\r\n });\r\n\r\n const rawContent = res.content ?? '';\r\n logChatEmail('classify llm response', {\r\n responseChars: rawContent.length,\r\n responsePreview: rawContent.slice(0, 280) + (rawContent.length > 280 ? '…' : ''),\r\n });\r\n\r\n const parsed = parseIntentJson(rawContent, params.settings.intents);\r\n if (!parsed) {\r\n logChatEmail('classify result', {\r\n matched: false,\r\n outcome: 'parse_failed',\r\n emailWillSend: false,\r\n });\r\n return {\r\n intent: null,\r\n intentLabel: 'Unclassified',\r\n reason: 'Could not parse intent classifier response',\r\n emailTo: null,\r\n };\r\n }\r\n\r\n if (parsed.intent === NONE_INTENT) {\r\n logChatEmail('classify result', {\r\n matched: false,\r\n outcome: NONE_INTENT,\r\n reason: parsed.reason,\r\n emailWillSend: false,\r\n });\r\n return {\r\n intent: null,\r\n intentLabel: NONE_INTENT,\r\n reason: parsed.reason,\r\n emailTo: null,\r\n };\r\n }\r\n\r\n const matched = intentByKey(params.settings.intents, parsed.intent);\r\n if (!matched) {\r\n logChatEmail('classify result', {\r\n matched: false,\r\n outcome: 'unknown_intent',\r\n parsedIntent: parsed.intent,\r\n reason: parsed.reason,\r\n emailWillSend: false,\r\n });\r\n return {\r\n intent: null,\r\n intentLabel: parsed.intent,\r\n reason: `Unknown intent \"${parsed.intent}\": ${parsed.reason}`,\r\n emailTo: null,\r\n };\r\n }\r\n\r\n logChatEmail('classify result', {\r\n matched: true,\r\n outcome: 'intent_found',\r\n intent: matched.intent,\r\n emailTo: matched.emailTo,\r\n reason: parsed.reason,\r\n emailWillSend: true,\r\n });\r\n\r\n return {\r\n intent: matched.intent,\r\n intentLabel: `${matched.intent} — ${matched.description}`,\r\n reason: parsed.reason,\r\n emailTo: matched.emailTo,\r\n };\r\n}\r\n\r\nexport function buildTranscriptForLeadEmail(history: LlmMessage[], latestMessage: string): string {\r\n return formatTranscript(history, latestMessage);\r\n}\r\n\r\n/** Parse comma/semicolon-separated emails for one intent row. */\r\nexport function parseIntentRecipientEmails(emailTo: string): string[] {\r\n return emailTo\r\n .split(/[,;]+/)\r\n .map((s) => s.trim())\r\n .filter((s) => s.length > 0 && s.includes('@'));\r\n}\r\n","import { google } from 'googleapis';\r\n\r\nexport interface AnalyticsData {\r\n visitors: number;\r\n pageViews: number;\r\n bounceRate: number;\r\n avgSessionDuration: number;\r\n topPages: Array<{ page: string; views: number }>;\r\n trafficSources: Array<{ source: string; sessions: number }>;\r\n geographicData: Array<{ country: string; sessions: number }>;\r\n dailyUsers: Array<{ date: string; users: number }>;\r\n}\r\n\r\nexport interface AnalyticsPluginConfig {\r\n privateKey: string;\r\n clientEmail: string;\r\n viewId: string;\r\n}\r\n\r\nexport class AnalyticsService {\r\n private analytics: ReturnType<typeof google.analyticsdata>;\r\n private viewId: string;\r\n\r\n constructor(config: AnalyticsPluginConfig) {\r\n const privateKey = config.privateKey.replace(/\\\\n/g, '\\n');\r\n const auth = new google.auth.JWT({\r\n email: config.clientEmail,\r\n key: privateKey,\r\n scopes: ['https://www.googleapis.com/auth/analytics.readonly'],\r\n });\r\n this.analytics = google.analyticsdata({ version: 'v1beta', auth });\r\n this.viewId = config.viewId;\r\n }\r\n\r\n async getAnalyticsData(days = 30): Promise<AnalyticsData> {\r\n const endDate = new Date();\r\n const startDate = new Date();\r\n startDate.setDate(startDate.getDate() - days);\r\n\r\n const [visitors, pageViews, bounceRate, sessionDuration, topPages, trafficSources, geographicData, dailyUsers] =\r\n await Promise.all([\r\n this.getVisitors(startDate, endDate),\r\n this.getPageViews(startDate, endDate),\r\n this.getBounceRate(startDate, endDate),\r\n this.getAvgSessionDuration(startDate, endDate),\r\n this.getTopPages(startDate, endDate),\r\n this.getTrafficSources(startDate, endDate),\r\n this.getGeographicData(startDate, endDate),\r\n this.getDailyUsers(startDate, endDate),\r\n ]);\r\n\r\n return {\r\n visitors,\r\n pageViews,\r\n bounceRate,\r\n avgSessionDuration: sessionDuration,\r\n topPages,\r\n trafficSources,\r\n geographicData,\r\n dailyUsers,\r\n };\r\n }\r\n\r\n private async runReport(requestBody: Record<string, unknown>) {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const response = await (this.analytics.properties.runReport as any)({\r\n property: `properties/${this.viewId}`,\r\n requestBody,\r\n });\r\n return response?.data as { rows?: Array<{ dimensionValues: { value: string }[]; metricValues: { value: string }[] }> };\r\n }\r\n\r\n private async getVisitors(startDate: Date, endDate: Date): Promise<number> {\r\n const data = await this.runReport({\r\n dateRanges: [{ startDate: startDate.toISOString().split('T')[0], endDate: endDate.toISOString().split('T')[0] }],\r\n metrics: [{ name: 'totalUsers' }],\r\n });\r\n return parseInt(data.rows?.[0]?.metricValues?.[0]?.value || '0');\r\n }\r\n\r\n private async getPageViews(startDate: Date, endDate: Date): Promise<number> {\r\n const data = await this.runReport({\r\n dateRanges: [{ startDate: startDate.toISOString().split('T')[0], endDate: endDate.toISOString().split('T')[0] }],\r\n metrics: [{ name: 'screenPageViews' }],\r\n });\r\n return parseInt(data.rows?.[0]?.metricValues?.[0]?.value || '0');\r\n }\r\n\r\n private async getBounceRate(startDate: Date, endDate: Date): Promise<number> {\r\n const data = await this.runReport({\r\n dateRanges: [{ startDate: startDate.toISOString().split('T')[0], endDate: endDate.toISOString().split('T')[0] }],\r\n metrics: [{ name: 'bounceRate' }],\r\n });\r\n return parseFloat(data.rows?.[0]?.metricValues?.[0]?.value || '0');\r\n }\r\n\r\n private async getAvgSessionDuration(startDate: Date, endDate: Date): Promise<number> {\r\n const data = await this.runReport({\r\n dateRanges: [{ startDate: startDate.toISOString().split('T')[0], endDate: endDate.toISOString().split('T')[0] }],\r\n metrics: [{ name: 'averageSessionDuration' }],\r\n });\r\n return parseFloat(data.rows?.[0]?.metricValues?.[0]?.value || '0');\r\n }\r\n\r\n private async getTopPages(startDate: Date, endDate: Date): Promise<Array<{ page: string; views: number }>> {\r\n const data = await this.runReport({\r\n dateRanges: [{ startDate: startDate.toISOString().split('T')[0], endDate: endDate.toISOString().split('T')[0] }],\r\n dimensions: [{ name: 'pagePath' }],\r\n metrics: [{ name: 'screenPageViews' }],\r\n limit: 10,\r\n });\r\n return data.rows?.map((row) => ({ page: row.dimensionValues[0].value, views: parseInt(row.metricValues[0].value) })) || [];\r\n }\r\n\r\n private async getTrafficSources(\r\n startDate: Date,\r\n endDate: Date\r\n ): Promise<Array<{ source: string; sessions: number }>> {\r\n const data = await this.runReport({\r\n dateRanges: [{ startDate: startDate.toISOString().split('T')[0], endDate: endDate.toISOString().split('T')[0] }],\r\n dimensions: [{ name: 'sessionSource' }],\r\n metrics: [{ name: 'sessions' }],\r\n limit: 10,\r\n });\r\n return data.rows?.map((row) => ({ source: row.dimensionValues[0].value, sessions: parseInt(row.metricValues[0].value) })) || [];\r\n }\r\n\r\n private async getGeographicData(\r\n startDate: Date,\r\n endDate: Date\r\n ): Promise<Array<{ country: string; sessions: number }>> {\r\n const data = await this.runReport({\r\n dateRanges: [{ startDate: startDate.toISOString().split('T')[0], endDate: endDate.toISOString().split('T')[0] }],\r\n dimensions: [{ name: 'country' }],\r\n metrics: [{ name: 'sessions' }],\r\n limit: 10,\r\n });\r\n return data.rows?.map((row) => ({ country: row.dimensionValues[0].value, sessions: parseInt(row.metricValues[0].value) })) || [];\r\n }\r\n\r\n private async getDailyUsers(startDate: Date, endDate: Date): Promise<Array<{ date: string; users: number }>> {\r\n const data = await this.runReport({\r\n dateRanges: [{ startDate: startDate.toISOString().split('T')[0], endDate: endDate.toISOString().split('T')[0] }],\r\n dimensions: [{ name: 'date' }],\r\n metrics: [{ name: 'totalUsers' }],\r\n orderBys: [{ dimension: { dimensionName: 'date' } }],\r\n });\r\n return (\r\n data.rows?.map((row) => {\r\n const dateStr = row.dimensionValues[0].value;\r\n return { date: `${dateStr.substring(4, 6)}/${dateStr.substring(6, 8)}`, users: parseInt(row.metricValues[0].value) };\r\n }) || []\r\n );\r\n }\r\n}\r\n","import type { CmsPlugin } from '../types';\r\nimport { AnalyticsService } from './analytics-service';\r\n\r\nexport interface AnalyticsPluginConfig {\r\n privateKey?: string;\r\n clientEmail?: string;\r\n viewId?: string;\r\n}\r\n\r\nexport function analyticsPlugin(config: AnalyticsPluginConfig = {}): CmsPlugin<AnalyticsService> {\r\n return {\r\n name: 'analytics',\r\n version: '1.0.0',\r\n async init(context) {\r\n const privateKey = config.privateKey ?? context.config.GOOGLE_ANALYTICS_PRIVATE_KEY;\r\n const clientEmail = config.clientEmail ?? context.config.GOOGLE_ANALYTICS_CLIENT_EMAIL;\r\n const viewId = config.viewId ?? context.config.GOOGLE_ANALYTICS_VIEW_ID ?? '';\r\n if (!privateKey || !clientEmail || !viewId) {\r\n throw new Error('Google Analytics credentials not configured');\r\n }\r\n return new AnalyticsService({ privateKey, clientEmail, viewId });\r\n },\r\n };\r\n}\r\n\r\nexport { AnalyticsService } from './analytics-service';\r\nexport type { AnalyticsData } from './analytics-service';\r\n","/**\r\n * India (TRAI / DLT): promotional and service SMS must use templates registered on operator DLT\r\n * (e.g. Jio, Airtel, BSNL/VIL portals) and linked to your Principal Entity ID and Header (sender).\r\n * MSG91 maps your DLT-approved template to a Flow / template_id used by their API. Arbitrary free-text\r\n * SMS APIs are often rejected (e.g. “template id missing”). Prefer Flow with `template_id` from the\r\n * `message_templates` row (`externalTemplateRef`) or optional env `MSG91_TEMPLATE_ID`, and variables that\r\n * match your DLT template placeholders (commonly var1…).\r\n *\r\n * References: TRAI TCCCPR-2018; MSG91 DLT / Flow docs; operator DLT portals for template approval.\r\n */\r\n\r\nexport interface SmsSendOptions {\r\n to: string;\r\n /** Plain body (Twilio/webhook/sendhttp). With `templateKey`, filled after resolving the template. */\r\n body?: string;\r\n /** Resolve copy + Flow ref from DB `message_templates` (channel sms) with code defaults. */\r\n templateKey?: string;\r\n /** For MSG91 Flow: value injected into the OTP variable (see template `providerMeta.otpVarKey`). */\r\n otpCode?: string;\r\n /** Template variables (e.g. `code`) and extra Flow recipient fields. */\r\n variables?: Record<string, string>;\r\n}\r\n\r\nexport type MessageTemplateRowLoader = (\r\n channel: string,\r\n templateKey: string\r\n) => Promise<{\r\n body: string;\r\n externalTemplateRef: string | null;\r\n providerMeta: Record<string, unknown> | null;\r\n enabled: boolean;\r\n} | null>;\r\n\r\n/** Which transport to use for outbound SMS. */\r\nexport type SmsProviderId = 'msg91' | 'twilio' | 'webhook';\r\n\r\n/** Stored in admin `smsProvider` or env `SMS_PROVIDER`. `auto` picks first with credentials: msg91 → twilio → webhook. */\r\nexport type SmsProviderChoice = SmsProviderId | 'auto';\r\n\r\n/** MSG91: use DLT Flow API vs legacy sendhttp (non‑India / legacy only). */\r\nexport type Msg91ApiMode = 'flow' | 'sendhttp' | 'auto';\r\n\r\nexport interface SmsServiceConfig {\r\n provider?: SmsProviderChoice;\r\n /** Admin settings key `smsProvider` (msg91 | twilio | webhook | auto). */\r\n smsProvider?: string;\r\n /** MSG91: auth key */\r\n msg91AuthKey?: string;\r\n /** DLT-approved sender ID (required for sendhttp; Flow uses template/header mapped in MSG91 panel). */\r\n msg91SenderId?: string;\r\n /** Transactional route; default 4 (sendhttp only). */\r\n msg91Route?: string;\r\n /**\r\n * MSG91 Flow ID / template_id shown in panel after mapping DLT template (India).\r\n * Required for `flow` mode.\r\n */\r\n msg91TemplateId?: string;\r\n /** `flow` = POST control.msg91.com/api/v5/flow/ (DLT). `sendhttp` = legacy GET API. `auto` = flow if template id set, else sendhttp. */\r\n msg91ApiMode?: Msg91ApiMode;\r\n /** Recipient JSON key for OTP value in Flow API (must match MSG91 template variables). Default var1. */\r\n msg91OtpVarKey?: string;\r\n /** Flow API short_url flag; default 0. */\r\n msg91FlowShortUrl?: string;\r\n accountSid?: string;\r\n authToken?: string;\r\n from?: string;\r\n webhookUrl?: string;\r\n webhookSecret?: string;\r\n}\r\n\r\nfunction norm(v: string | undefined): string | undefined {\r\n const t = v?.trim();\r\n return t || undefined;\r\n}\r\n\r\nfunction pick(\r\n plugin: Partial<SmsServiceConfig>,\r\n db: Record<string, string>,\r\n env: Record<string, string>,\r\n ...keys: string[]\r\n): string | undefined {\r\n for (const key of keys) {\r\n const pk = key as keyof SmsServiceConfig;\r\n if (pk in plugin && plugin[pk] !== undefined && String(plugin[pk]).trim() !== '') {\r\n const v = norm(String(plugin[pk]));\r\n if (v) return v;\r\n }\r\n if (norm(db[key])) return norm(db[key]);\r\n if (norm(env[key])) return norm(env[key]);\r\n }\r\n return undefined;\r\n}\r\n\r\nfunction parseMsg91ApiMode(raw: string | undefined): Msg91ApiMode {\r\n const x = (raw || 'auto').toLowerCase().trim();\r\n if (x === 'flow' || x === 'sendhttp' || x === 'auto') return x;\r\n return 'auto';\r\n}\r\n\r\nexport function mergeSmsConfigLayers(\r\n env: Record<string, string>,\r\n db: Record<string, string>,\r\n plugin: Partial<SmsServiceConfig>\r\n): SmsServiceConfig {\r\n const pRaw = pick(plugin, db, env, 'smsProvider', 'SMS_PROVIDER', 'provider')?.toLowerCase();\r\n const provider: SmsProviderChoice | undefined =\r\n pRaw === 'msg91' || pRaw === 'twilio' || pRaw === 'webhook' || pRaw === 'auto' ? (pRaw as SmsProviderChoice) : undefined;\r\n\r\n return {\r\n provider: provider ?? 'auto',\r\n msg91AuthKey: pick(plugin, db, env, 'msg91AuthKey', 'MSG91_AUTH_KEY'),\r\n msg91SenderId: pick(plugin, db, env, 'msg91SenderId', 'MSG91_SENDER_ID'),\r\n msg91Route: pick(plugin, db, env, 'msg91Route', 'MSG91_ROUTE') ?? '4',\r\n msg91TemplateId: pick(plugin, db, env, 'msg91TemplateId', 'MSG91_TEMPLATE_ID'),\r\n msg91ApiMode: parseMsg91ApiMode(pick(plugin, db, env, 'msg91ApiMode', 'MSG91_API_MODE')),\r\n msg91OtpVarKey: pick(plugin, db, env, 'msg91OtpVarKey', 'MSG91_OTP_VAR_KEY') ?? 'var1',\r\n msg91FlowShortUrl: pick(plugin, db, env, 'msg91FlowShortUrl', 'MSG91_FLOW_SHORT_URL') ?? '0',\r\n accountSid: pick(plugin, db, env, 'accountSid', 'TWILIO_ACCOUNT_SID'),\r\n authToken: pick(plugin, db, env, 'authToken', 'TWILIO_AUTH_TOKEN'),\r\n from: pick(plugin, db, env, 'from', 'TWILIO_FROM_NUMBER', 'TWILIO_MESSAGING_SERVICE_SID'),\r\n webhookUrl: pick(plugin, db, env, 'webhookUrl', 'SMS_WEBHOOK_URL'),\r\n webhookSecret: pick(plugin, db, env, 'webhookSecret', 'SMS_WEBHOOK_SECRET'),\r\n };\r\n}\r\n\r\n/** True when Flow can run: auth key and a template id (per-send or global/env). */\r\nexport function msg91FlowConfigured(cfg: SmsServiceConfig, flowTemplateIdForSend?: string): boolean {\r\n const tid = (flowTemplateIdForSend || cfg.msg91TemplateId || '').trim();\r\n return Boolean(cfg.msg91AuthKey && tid);\r\n}\r\n\r\nexport function msg91SendhttpConfigured(cfg: SmsServiceConfig): boolean {\r\n return Boolean(cfg.msg91AuthKey && cfg.msg91SenderId);\r\n}\r\n\r\n/** MSG91 is usable with auth key (Flow id may come per message from `message_templates`). */\r\nexport function msg91Configured(cfg: SmsServiceConfig): boolean {\r\n return Boolean(cfg.msg91AuthKey);\r\n}\r\n\r\nexport function resolveMsg91SendMode(cfg: SmsServiceConfig, flowTemplateIdForSend?: string): 'flow' | 'sendhttp' | null {\r\n const tid = (flowTemplateIdForSend || cfg.msg91TemplateId || '').trim();\r\n const mode = cfg.msg91ApiMode ?? 'auto';\r\n if (mode === 'flow') {\r\n if (!cfg.msg91AuthKey || !tid) return null;\r\n return 'flow';\r\n }\r\n if (mode === 'sendhttp') return msg91SendhttpConfigured(cfg) ? 'sendhttp' : null;\r\n if (cfg.msg91AuthKey && tid) return 'flow';\r\n if (msg91SendhttpConfigured(cfg)) return 'sendhttp';\r\n return null;\r\n}\r\n\r\nexport function twilioConfigured(cfg: SmsServiceConfig): boolean {\r\n return Boolean(cfg.accountSid && cfg.authToken && cfg.from);\r\n}\r\n\r\nexport function webhookConfigured(cfg: SmsServiceConfig): boolean {\r\n return Boolean(cfg.webhookUrl);\r\n}\r\n\r\nexport function resolveSmsProvider(cfg: SmsServiceConfig): SmsProviderId | null {\r\n const want = cfg.provider ?? 'auto';\r\n if (want === 'msg91' && msg91Configured(cfg)) return 'msg91';\r\n if (want === 'twilio' && twilioConfigured(cfg)) return 'twilio';\r\n if (want === 'webhook' && webhookConfigured(cfg)) return 'webhook';\r\n if (want !== 'auto') return null;\r\n\r\n if (msg91Configured(cfg)) return 'msg91';\r\n if (twilioConfigured(cfg)) return 'twilio';\r\n if (webhookConfigured(cfg)) return 'webhook';\r\n return null;\r\n}\r\n\r\nexport function anySmsProviderConfigured(cfg: SmsServiceConfig): boolean {\r\n return resolveSmsProvider(cfg) !== null;\r\n}\r\n\r\nconst MSG91_FLOW_URL = 'https://control.msg91.com/api/v5/flow/';\r\n\r\nasync function sendViaMsg91Flow(\r\n cfg: SmsServiceConfig,\r\n to: string,\r\n body: string,\r\n opts: Pick<SmsSendOptions, 'otpCode' | 'variables'>,\r\n overrides?: { templateId?: string; otpVarKey?: string }\r\n): Promise<boolean> {\r\n const authkey = cfg.msg91AuthKey!;\r\n const templateId = (overrides?.templateId || cfg.msg91TemplateId || '').trim();\r\n if (!templateId) return false;\r\n const mobile = to.replace(/^\\+/, '').replace(/\\s/g, '');\r\n if (!mobile) return false;\r\n\r\n const varKey = (overrides?.otpVarKey || cfg.msg91OtpVarKey || 'var1').trim() || 'var1';\r\n const recipient: Record<string, string> = { mobiles: mobile };\r\n const vars: Record<string, string> = { ...(opts.variables ?? {}) };\r\n if (opts.otpCode) vars[varKey] = opts.otpCode;\r\n else if (!(varKey in vars)) {\r\n const m = body.match(/\\d{4,8}/);\r\n if (m) vars[varKey] = m[0];\r\n }\r\n if (Object.keys(vars).length === 0) return false;\r\n\r\n for (const [k, v] of Object.entries(vars)) {\r\n recipient[k] = v;\r\n }\r\n\r\n const payload = {\r\n template_id: templateId,\r\n short_url: cfg.msg91FlowShortUrl ?? '0',\r\n recipients: [recipient],\r\n };\r\n\r\n try {\r\n const res = await fetch(MSG91_FLOW_URL, {\r\n method: 'POST',\r\n headers: {\r\n accept: 'application/json',\r\n 'content-type': 'application/json',\r\n authkey,\r\n },\r\n body: JSON.stringify(payload),\r\n });\r\n const text = await res.text();\r\n if (!res.ok) return false;\r\n try {\r\n const j = JSON.parse(text) as { type?: string; message?: string };\r\n if (j.type === 'error' || (typeof j.message === 'string' && /error|fail/i.test(j.message))) return false;\r\n } catch {\r\n const lower = text.toLowerCase();\r\n if (lower.includes('error') || lower.includes('invalid') || lower.includes('fail')) return false;\r\n }\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nasync function sendViaMsg91Sendhttp(cfg: SmsServiceConfig, to: string, body: string): Promise<boolean> {\r\n const authkey = cfg.msg91AuthKey;\r\n const sender = cfg.msg91SenderId;\r\n if (!authkey || !sender) return false;\r\n const route = cfg.msg91Route?.trim() || '4';\r\n const mobile = to.replace(/^\\+/, '').replace(/\\s/g, '');\r\n if (!mobile) return false;\r\n const params = new URLSearchParams({\r\n authkey,\r\n mobiles: mobile,\r\n message: body,\r\n sender,\r\n route,\r\n country: '0',\r\n });\r\n const url = `https://api.msg91.com/api/sendhttp.php?${params.toString()}`;\r\n try {\r\n const res = await fetch(url, { method: 'GET' });\r\n const text = (await res.text()).trim();\r\n if (!res.ok) return false;\r\n const lower = text.toLowerCase();\r\n if (lower.includes('error') || lower.includes('invalid') || lower.includes('failed')) return false;\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nasync function sendViaMsg91(\r\n cfg: SmsServiceConfig,\r\n to: string,\r\n body: string,\r\n opts: SmsSendOptions,\r\n flowOverrides?: { templateId?: string; otpVarKey?: string }\r\n): Promise<boolean> {\r\n const flowTid = (flowOverrides?.templateId || cfg.msg91TemplateId || '').trim();\r\n const mode = resolveMsg91SendMode(cfg, flowTid);\r\n if (mode === 'flow') {\r\n return sendViaMsg91Flow(cfg, to, body, { otpCode: opts.otpCode, variables: opts.variables }, flowOverrides);\r\n }\r\n if (mode === 'sendhttp') {\r\n return sendViaMsg91Sendhttp(cfg, to, body);\r\n }\r\n return false;\r\n}\r\n\r\nasync function sendViaTwilio(cfg: SmsServiceConfig, to: string, body: string): Promise<boolean> {\r\n const { accountSid, authToken, from } = cfg;\r\n if (!accountSid || !authToken || !from) return false;\r\n const url = `https://api.twilio.com/2010-04-01/Accounts/${accountSid}/Messages.json`;\r\n const auth = Buffer.from(`${accountSid}:${authToken}`).toString('base64');\r\n const params = new URLSearchParams({ To: to, From: from, Body: body });\r\n const res = await fetch(url, {\r\n method: 'POST',\r\n headers: { Authorization: `Basic ${auth}`, 'Content-Type': 'application/x-www-form-urlencoded' },\r\n body: params.toString(),\r\n });\r\n return res.ok;\r\n}\r\n\r\nasync function sendViaWebhook(cfg: SmsServiceConfig, to: string, body: string): Promise<boolean> {\r\n const { webhookUrl, webhookSecret } = cfg;\r\n if (!webhookUrl) return false;\r\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\r\n if (webhookSecret) headers.Authorization = `Bearer ${webhookSecret}`;\r\n const res = await fetch(webhookUrl, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify({ to, message: body }),\r\n });\r\n return res.ok;\r\n}\r\n\r\nexport type SmsSettingsLoader = () => Promise<Record<string, string>>;\r\n\r\nexport class SmsService {\r\n private env: Record<string, string>;\r\n private plugin: Partial<SmsServiceConfig>;\r\n private getSmsSettings?: SmsSettingsLoader;\r\n private getMessageTemplateRow?: MessageTemplateRowLoader;\r\n\r\n constructor(\r\n env: Record<string, string>,\r\n plugin: Partial<SmsServiceConfig> = {},\r\n getSmsSettings?: SmsSettingsLoader,\r\n getMessageTemplateRow?: MessageTemplateRowLoader\r\n ) {\r\n this.env = env;\r\n this.plugin = plugin;\r\n this.getSmsSettings = getSmsSettings;\r\n this.getMessageTemplateRow = getMessageTemplateRow;\r\n }\r\n\r\n private async merged(): Promise<SmsServiceConfig> {\r\n const db = (await this.getSmsSettings?.()) ?? {};\r\n return mergeSmsConfigLayers(this.env, db, this.plugin);\r\n }\r\n\r\n async send(opts: SmsSendOptions): Promise<boolean> {\r\n try {\r\n const dbEarly = (await this.getSmsSettings?.()) ?? {};\r\n if (dbEarly.enabled === 'false') return false;\r\n let effective: SmsSendOptions = { ...opts };\r\n let flowOverrides: { templateId?: string; otpVarKey?: string } | undefined;\r\n\r\n if (opts.templateKey?.trim()) {\r\n if (!this.getMessageTemplateRow) return false;\r\n const { resolveSmsTemplateForSend } = await import('../../message-templates/sms-defaults');\r\n const { applyTemplateVars } = await import('../../message-templates/interpolate');\r\n const resolved = await resolveSmsTemplateForSend(opts.templateKey.trim(), this.getMessageTemplateRow);\r\n if (!resolved) return false;\r\n const vars = { ...(opts.variables ?? {}) };\r\n const code = vars.code ?? vars.otp ?? opts.otpCode ?? '';\r\n if (code) {\r\n vars.code = code;\r\n delete vars.otp;\r\n }\r\n effective.body = applyTemplateVars(resolved.body, vars);\r\n effective.otpCode = code || effective.otpCode;\r\n effective.variables = vars;\r\n flowOverrides = {\r\n templateId: resolved.externalTemplateRef,\r\n otpVarKey: resolved.otpVarKey,\r\n };\r\n }\r\n\r\n const body = (effective.body ?? '').trim();\r\n if (!body) return false;\r\n\r\n const cfg = await this.merged();\r\n const p = resolveSmsProvider(cfg);\r\n if (!p) return false;\r\n if (p === 'msg91') return sendViaMsg91(cfg, opts.to, body, effective, flowOverrides);\r\n if (p === 'twilio') return sendViaTwilio(cfg, opts.to, body);\r\n return sendViaWebhook(cfg, opts.to, body);\r\n } catch {\r\n return false;\r\n }\r\n }\r\n}\r\n","const SMS_QUEUE_NAME = 'sms';\r\n\r\nexport interface CmsAppLike {\r\n getPlugin(name: string): unknown;\r\n}\r\n\r\nexport interface SmsJobPayload {\r\n to: string;\r\n /** Legacy / Twilio / sendhttp plain text. */\r\n body?: string;\r\n templateKey?: string;\r\n variables?: Record<string, string>;\r\n otpCode?: string;\r\n}\r\n\r\nexport function registerSmsQueueProcessor(cms: CmsAppLike): void {\r\n const queue = cms.getPlugin('queue') as\r\n | { add: (name: string, data: object) => Promise<void>; registerProcessor: (name: string, fn: (data: object) => Promise<void>) => void }\r\n | undefined;\r\n const sms = cms.getPlugin('sms') as\r\n | {\r\n send: (opts: {\r\n to: string;\r\n body?: string;\r\n templateKey?: string;\r\n variables?: Record<string, string>;\r\n otpCode?: string;\r\n }) => Promise<boolean>;\r\n }\r\n | undefined;\r\n if (!queue || !sms || typeof sms.send !== 'function') return;\r\n queue.registerProcessor(SMS_QUEUE_NAME, async (data: object) => {\r\n const payload = data as SmsJobPayload;\r\n if (!payload.to) return;\r\n if (payload.templateKey?.trim()) {\r\n await sms.send({\r\n to: payload.to,\r\n templateKey: payload.templateKey.trim(),\r\n variables: payload.variables,\r\n otpCode: payload.otpCode,\r\n });\r\n return;\r\n }\r\n if (!payload.body?.trim()) return;\r\n await sms.send({\r\n to: payload.to,\r\n body: payload.body,\r\n otpCode: payload.otpCode,\r\n variables: payload.variables,\r\n });\r\n });\r\n}\r\n\r\nexport async function queueSms(cms: CmsAppLike, payload: SmsJobPayload): Promise<void> {\r\n const queue = cms.getPlugin('queue') as { add: (name: string, data: object) => Promise<void> } | undefined;\r\n const sms = cms.getPlugin('sms') as\r\n | {\r\n send: (opts: {\r\n to: string;\r\n body?: string;\r\n templateKey?: string;\r\n variables?: Record<string, string>;\r\n otpCode?: string;\r\n }) => Promise<boolean>;\r\n }\r\n | undefined;\r\n if (queue) {\r\n await queue.add(SMS_QUEUE_NAME, payload);\r\n return;\r\n }\r\n if (sms && typeof sms.send === 'function') {\r\n if (payload.templateKey?.trim()) {\r\n await sms.send({\r\n to: payload.to,\r\n templateKey: payload.templateKey.trim(),\r\n variables: payload.variables,\r\n otpCode: payload.otpCode,\r\n });\r\n return;\r\n }\r\n if (payload.body?.trim()) {\r\n await sms.send({\r\n to: payload.to,\r\n body: payload.body,\r\n otpCode: payload.otpCode,\r\n variables: payload.variables,\r\n });\r\n }\r\n }\r\n}\r\n","import type { CmsPlugin, PluginContext } from '../types';\r\nimport {\r\n SmsService,\r\n type SmsServiceConfig,\r\n type MessageTemplateRowLoader,\r\n mergeSmsConfigLayers,\r\n anySmsProviderConfigured,\r\n} from './sms-service';\r\n\r\nexport interface SmsPluginConfig extends Partial<SmsServiceConfig> {\r\n /** Load admin settings group `sms` (enabled, smsProvider). Secrets typically stay in env. */\r\n getSmsSettings?: () => Promise<Record<string, string>>;\r\n /** Resolve `message_templates` rows for SMS (required for `templateKey` sends). */\r\n getMessageTemplateRow?: MessageTemplateRowLoader;\r\n}\r\n\r\nexport interface SmsServiceInterface {\r\n send(opts: {\r\n to: string;\r\n body?: string;\r\n templateKey?: string;\r\n otpCode?: string;\r\n variables?: Record<string, string>;\r\n }): Promise<boolean>;\r\n}\r\n\r\nexport function smsPlugin(config: SmsPluginConfig = {}): CmsPlugin<SmsServiceInterface | null> {\r\n return {\r\n name: 'sms',\r\n version: '1.0.0',\r\n async init(context: PluginContext) {\r\n const env = context.config as Record<string, string>;\r\n const { getSmsSettings, getMessageTemplateRow, ...staticRest } = config;\r\n let db: Record<string, string> = {};\r\n try {\r\n db = (await getSmsSettings?.()) ?? {};\r\n } catch {\r\n /* ignore */\r\n }\r\n const merged = mergeSmsConfigLayers(env, db, staticRest);\r\n if (!anySmsProviderConfigured(merged)) {\r\n context.logger.warn(\r\n 'SMS plugin skipped: set MSG91_AUTH_KEY (Flow template id per Plugins → SMS templates or MSG91_TEMPLATE_ID; or sendhttp: MSG91_SENDER_ID), or TWILIO_*, or SMS_WEBHOOK_URL'\r\n );\r\n return null;\r\n }\r\n const svc = new SmsService(env, staticRest, getSmsSettings, getMessageTemplateRow);\r\n return {\r\n send: (opts) => svc.send(opts),\r\n };\r\n },\r\n };\r\n}\r\n\r\nexport {\r\n mergeSmsConfigLayers,\r\n resolveSmsProvider,\r\n anySmsProviderConfigured,\r\n msg91Configured,\r\n msg91FlowConfigured,\r\n msg91SendhttpConfigured,\r\n resolveMsg91SendMode,\r\n twilioConfigured,\r\n webhookConfigured,\r\n} from './sms-service';\r\nexport type {\r\n SmsProviderId,\r\n SmsProviderChoice,\r\n SmsServiceConfig,\r\n SmsSendOptions,\r\n SmsSettingsLoader,\r\n Msg91ApiMode,\r\n MessageTemplateRowLoader,\r\n} from './sms-service';\r\n\r\nexport { registerSmsQueueProcessor, queueSms } from './sms-queue';\r\nexport type { SmsJobPayload } from './sms-queue';\r\n","import type { CmsPlugin, PluginContext } from '../types';\r\n\r\nexport interface PaymentIntent {\r\n id: string;\r\n clientSecret: string;\r\n amount: number;\r\n currency: string;\r\n status: string;\r\n}\r\n\r\nexport interface PaymentServiceInterface {\r\n createPaymentIntent(amount: number, currency: string, metadata?: Record<string, string>): Promise<PaymentIntent>;\r\n capturePayment(paymentId: string, amount?: number): Promise<boolean>;\r\n verifyWebhookSignature(payload: string | Buffer, signature: string): boolean;\r\n}\r\n\r\nexport interface StripeConfig {\r\n provider: 'stripe';\r\n secretKey: string;\r\n webhookSecret?: string;\r\n}\r\n\r\nexport interface RazorpayConfig {\r\n provider: 'razorpay';\r\n keyId: string;\r\n keySecret: string;\r\n webhookSecret?: string;\r\n}\r\n\r\nexport type PaymentPluginConfig = StripeConfig | RazorpayConfig;\r\n\r\nexport function paymentPlugin(config: PaymentPluginConfig): CmsPlugin<PaymentServiceInterface | undefined> {\r\n return {\r\n name: 'payment',\r\n version: '1.0.0',\r\n async init(context: PluginContext) {\r\n if (config.provider === 'stripe') {\r\n const { StripePaymentService } = await import('./stripe');\r\n const secretKey = config.secretKey || context.config.STRIPE_SECRET_KEY;\r\n if (!secretKey) {\r\n context.logger.warn('Payment plugin skipped: Stripe secret key not configured');\r\n return undefined;\r\n }\r\n return new StripePaymentService({\r\n secretKey,\r\n webhookSecret: config.webhookSecret || context.config.STRIPE_WEBHOOK_SECRET,\r\n });\r\n }\r\n\r\n if (config.provider === 'razorpay') {\r\n const { RazorpayPaymentService } = await import('./razorpay');\r\n const keyId = config.keyId || context.config.RAZORPAY_KEY_ID;\r\n const keySecret = config.keySecret || context.config.RAZORPAY_KEY_SECRET;\r\n if (!keyId || !keySecret) {\r\n context.logger.warn('Payment plugin skipped: Razorpay credentials not configured');\r\n return undefined;\r\n }\r\n return new RazorpayPaymentService({\r\n keyId,\r\n keySecret,\r\n webhookSecret: config.webhookSecret || context.config.RAZORPAY_WEBHOOK_SECRET,\r\n });\r\n }\r\n\r\n context.logger.warn(`Payment plugin skipped: unknown provider \"${(config as { provider: string }).provider}\"`);\r\n return undefined;\r\n },\r\n };\r\n}\r\n","import type { CmsPlugin } from '../types';\r\nimport type { StorageService } from './types';\r\n\r\nexport interface S3StoragePluginConfig {\r\n region: string;\r\n accessKeyId: string;\r\n secretAccessKey: string;\r\n bucket: string;\r\n baseUrl?: string;\r\n prefix?: string;\r\n}\r\n\r\nfunction getS3Storage(config: S3StoragePluginConfig): StorageService {\r\n const prefix = (config.prefix ?? 'uploads').replace(/\\/$/, '');\r\n const keyPrefix = prefix ? `${prefix}/` : '';\r\n\r\n return {\r\n async upload(buffer: Buffer, key: string, contentType: string): Promise<string> {\r\n const { S3Client, PutObjectCommand } = await import('@aws-sdk/client-s3');\r\n const client = new S3Client({\r\n region: config.region,\r\n credentials: {\r\n accessKeyId: config.accessKeyId,\r\n secretAccessKey: config.secretAccessKey,\r\n },\r\n });\r\n const fullKey = keyPrefix + key.replace(/^\\/+/, '');\r\n await client.send(\r\n new PutObjectCommand({\r\n Bucket: config.bucket,\r\n Key: fullKey,\r\n Body: buffer,\r\n ContentType: contentType,\r\n })\r\n );\r\n if (config.baseUrl) {\r\n return `${config.baseUrl.replace(/\\/$/, '')}/${fullKey}`;\r\n }\r\n return `https://s3.${config.region}.amazonaws.com/${config.bucket}/${fullKey}`;\r\n },\r\n };\r\n}\r\n\r\nexport function s3StoragePlugin(\r\n config: Partial<S3StoragePluginConfig> & { bucket: string }\r\n): CmsPlugin<StorageService> {\r\n return {\r\n name: 'storage',\r\n version: '1.0.0',\r\n async init(context) {\r\n const region = config.region ?? context.config.AWS_REGION ?? '';\r\n const accessKeyId = config.accessKeyId ?? context.config.AWS_ACCESS_KEY_ID ?? '';\r\n const secretAccessKey = config.secretAccessKey ?? context.config.AWS_SECRET_ACCESS_KEY ?? '';\r\n const bucket = config.bucket ?? context.config.AWS_BUCKET_NAME ?? '';\r\n const baseUrl = config.baseUrl ?? context.config.S3_MEDIA_URL ?? context.config.S3_CUSTOM_DOMAIN;\r\n const resolvedBaseUrl =\r\n typeof baseUrl === 'string' && baseUrl\r\n ? baseUrl.startsWith('http')\r\n ? baseUrl\r\n : `https://${baseUrl}`\r\n : undefined;\r\n if (!region || !accessKeyId || !secretAccessKey || !bucket) {\r\n throw new Error('S3 storage plugin: missing region, accessKeyId, secretAccessKey or bucket');\r\n }\r\n return getS3Storage({\r\n region,\r\n accessKeyId,\r\n secretAccessKey,\r\n bucket,\r\n baseUrl: resolvedBaseUrl,\r\n prefix: config.prefix ?? 'uploads',\r\n });\r\n },\r\n };\r\n}\r\n","import type { CmsPlugin } from '../types';\r\nimport type { StorageService } from './types';\r\n\r\nexport interface LocalStoragePluginConfig {\r\n /** Directory relative to process.cwd() (e.g. \"public/uploads\"). */\r\n dir?: string;\r\n /** Public URL prefix for returned URLs (e.g. \"\" for \"/uploads/...\"). */\r\n publicPath?: string;\r\n}\r\n\r\nfunction getLocalStorage(config: LocalStoragePluginConfig): StorageService {\r\n const dir = (config.dir ?? 'public/uploads').replace(/\\/$/, '');\r\n const publicPath =\r\n config.publicPath ??\r\n (dir === 'public/uploads' ? '/uploads' : `/${dir.replace(/^\\/+/, '').replace(/\\\\/g, '/')}`);\r\n\r\n return {\r\n async upload(buffer: Buffer, key: string, _contentType: string): Promise<string> {\r\n const fs = await import('fs/promises');\r\n const path = await import('path');\r\n const normalizedKey = key.replace(/^\\/+/, '').replace(/\\.\\./g, '');\r\n const fileName = normalizedKey.replace(/^uploads\\//, '');\r\n const fullDir = path.join(process.cwd(), dir);\r\n await fs.mkdir(fullDir, { recursive: true });\r\n const filePath = path.join(fullDir, fileName);\r\n const fileDir = path.dirname(filePath);\r\n await fs.mkdir(fileDir, { recursive: true });\r\n await fs.writeFile(filePath, buffer);\r\n return `${publicPath.replace(/\\/$/, '')}/${fileName}`;\r\n },\r\n };\r\n}\r\n\r\nexport function localStoragePlugin(config: LocalStoragePluginConfig = {}): CmsPlugin<StorageService> {\r\n return {\r\n name: 'storage',\r\n version: '1.0.0',\r\n async init(context) {\r\n const dir = config.dir ?? context.config.UPLOAD_DIR ?? 'public/uploads';\r\n return getLocalStorage({ ...config, dir });\r\n },\r\n };\r\n}\r\n","export interface LlmMessage {\n role: 'user' | 'assistant' | 'system';\n content: string;\n}\n\n/** Passed to {@link LlmService.chat} / {@link LlmService.streamChat}; only `model`, `temperature`, and `max_tokens` are sent to the gateway. */\nexport interface LlmChatOptions {\n systemPrompt?: string;\n userPrompt?: string;\n history?: LlmMessage[];\n context?: string;\n model?: string;\n temperature?: number;\n max_tokens?: number;\n}\n\n/** Options for {@link LlmService.chatAgent} / {@link LlmService.streamChatAgent}: composes system + context + history + user into chat messages. */\nexport interface LlmAgentOptions {\n systemPrompt?: string;\n userPrompt: string;\n history?: LlmMessage[];\n /** RAG or other material; merged into the system message when set. */\n context?: string;\n model?: string;\n temperature?: number;\n max_tokens?: number;\n}\n\nexport interface LlmServiceInterface {\n chat(messages: LlmMessage[], options?: LlmChatOptions): Promise<{ content: string }>;\n streamChat(messages: LlmMessage[], options?: LlmChatOptions): AsyncIterable<string>;\n chatAgent(options: LlmAgentOptions): Promise<{ content: string }>;\n streamChatAgent(options: LlmAgentOptions): AsyncIterable<string>;\n /**\n * Embeddings for RAG / knowledge base. Wire format depends on {@link LlmServiceEmbedOptions}:\n * OpenAI `{base}/v1/embeddings`, or Hugging Face via `@huggingface/inference` (Hub-routed feature extraction) with legacy HTTP fallback.\n */\n embed?(text: string, options?: { model?: string }): Promise<number[]>;\n}\n\n/**\n * Normalize Hugging Face Inference feature-extraction response to a single `number[]`.\n */\nfunction parseOpenAiEmbeddingJson(data: Record<string, unknown>): number[] | null {\n let embedding = (data?.data as Array<{ embedding?: number[] }>)?.[0]?.embedding;\n if (!Array.isArray(embedding) && Array.isArray(data?.embedding)) {\n embedding = data.embedding as number[];\n }\n if (!Array.isArray(embedding) && Array.isArray((data?.data as unknown[])?.[0])) {\n const first = (data.data as unknown[])[0];\n embedding = Array.isArray(first) ? first : (first as { embedding?: number[] })?.embedding;\n }\n return Array.isArray(embedding) ? embedding : null;\n}\n\nexport function parseHfInferenceEmbeddingBody(data: unknown): number[] | null {\n if (data === null || data === undefined) return null;\n if (Array.isArray(data)) {\n if (data.length === 0) return null;\n const first = data[0];\n if (typeof first === 'number') return data as number[];\n if (Array.isArray(first) && first.length > 0 && typeof first[0] === 'number') {\n return first as number[];\n }\n if (Array.isArray(first) && Array.isArray(first[0]) && typeof (first[0] as number[])[0] === 'number') {\n return first[0] as number[];\n }\n return null;\n }\n if (typeof data === 'object' && data !== null && !Array.isArray(data)) {\n const o = data as Record<string, unknown>;\n if (typeof o.error === 'string') return null;\n if ('embeddings' in o) return parseHfInferenceEmbeddingBody(o.embeddings);\n }\n return null;\n}\n\nexport type LlmEmbeddingProvider = 'openai' | 'huggingface';\n\nexport interface LlmServiceEmbedOptions {\n embeddingProvider?: LlmEmbeddingProvider;\n /** Legacy manual HTTP base when the Inference SDK path fails; default `https://router.huggingface.co/v1` (router host is normalized to `…/hf-inference`). */\n hfInferenceBaseUrl?: string;\n /** Token for embedding calls; defaults to chat `apiKey`. */\n embeddingApiKey?: string;\n /**\n * Default `model` for `POST …/v1/chat/completions` when the caller omits `model`.\n * Set via plugin / CMS `LLM_CHAT_MODEL` or env `LLM_CHAT_MODEL`.\n * If unset, the library picks a fallback from `LLM_GATEWAY_URL` (HF router vs OpenRouter-style).\n */\n defaultChatModel?: string;\n}\n\n/** OpenRouter and similar OpenAI-compatible gateways (not HF router). */\nconst FALLBACK_CHAT_MODEL_OPENAI_SHAPE = 'openai/gpt-4o-mini';\n/** Default when `LLM_GATEWAY_URL` points at Hugging Face Inference (Hub-style id). */\nconst FALLBACK_CHAT_MODEL_HUGGINGFACE = 'meta-llama/Meta-Llama-3.1-8B-Instruct';\n\nfunction defaultChatModelForGateway(baseURL: string): string {\n const u = baseURL.toLowerCase();\n if (u.includes('huggingface.co') || u.includes('hf.co') || u.includes('hf-inference')) {\n return FALLBACK_CHAT_MODEL_HUGGINGFACE;\n }\n return FALLBACK_CHAT_MODEL_OPENAI_SHAPE;\n}\n\nfunction formatLlmGatewayError(status: number, bodyText: string, defaultChatModel: string): string {\n let hint = '';\n try {\n const j = JSON.parse(bodyText) as { error?: { code?: string; message?: string } };\n const code = j?.error?.code;\n if (\n code === 'model_not_supported' ||\n code === 'model_not_found' ||\n /not supported by any provider|does not exist/i.test(j?.error?.message ?? '')\n ) {\n hint = ` Hint: set LLM_CHAT_MODEL (or CMS) to a model your gateway lists. HF router: Hub ids (e.g. \"${FALLBACK_CHAT_MODEL_HUGGINGFACE}\"); OpenRouter: e.g. \"${FALLBACK_CHAT_MODEL_OPENAI_SHAPE}\".`;\n }\n } catch {\n /* ignore */\n }\n return `LLM gateway error: ${status} ${bodyText}${hint}`;\n}\n\n/**\n * Set `LLM_DEBUG=1` (or `true` / `yes`) to log composed chat payloads.\n * Set `LLM_EMBED_DEBUG=1` for per-request embedding logs (verbose with many chunks).\n * Set `LLM_CHAT_MODEL` for the default chat model when agents/requests omit `model` (gateway-specific id).\n * If unset, fallback is chosen from `LLM_GATEWAY_URL` (HF vs other).\n */\nexport class LlmService implements LlmServiceInterface {\n private static embedHttpErrorLogged = false;\n private static embedShapeErrorLogged = false;\n private static embedSuccessLogged = false;\n private static hfDimensionMismatchWarned = false;\n private static hfInferenceSdkErrorLogged = false;\n\n private readonly baseURL: string;\n private readonly apiKey: string;\n private readonly defaultEmbeddingModel?: string;\n private readonly embeddingProvider: LlmEmbeddingProvider;\n private readonly hfInferenceBaseURL: string;\n private readonly embeddingApiKey: string;\n private readonly defaultChatModel: string;\n\n constructor(baseURL: string, apiKey: string, defaultEmbeddingModel?: string, embedOpts?: LlmServiceEmbedOptions) {\n this.baseURL = baseURL.replace(/\\/$/, '');\n this.apiKey = apiKey;\n this.defaultEmbeddingModel = defaultEmbeddingModel;\n const p = (embedOpts?.embeddingProvider ?? 'openai').toLowerCase();\n this.embeddingProvider = p === 'huggingface' ? 'huggingface' : 'openai';\n this.hfInferenceBaseURL = (embedOpts?.hfInferenceBaseUrl ?? 'https://router.huggingface.co/v1').replace(\n /\\/$/,\n ''\n );\n this.embeddingApiKey = (embedOpts?.embeddingApiKey ?? apiKey).trim();\n const fromOpts = embedOpts?.defaultChatModel?.trim();\n const fromEnv = typeof process !== 'undefined' ? process.env.LLM_CHAT_MODEL?.trim() : '';\n const auto = defaultChatModelForGateway(this.baseURL);\n this.defaultChatModel = (fromOpts || fromEnv || auto).trim() || auto;\n }\n\n private resolveChatModel(explicit?: string): string {\n const m = (explicit?.trim() || this.defaultChatModel).trim();\n return m || defaultChatModelForGateway(this.baseURL);\n }\n\n private get base(): string {\n return this.baseURL.replace(/\\/$/, '');\n }\n\n private get url(): string {\n return `${this.base}/v1/chat/completions`;\n }\n\n private llmDebugEnabled(): boolean {\n const v = process.env.LLM_DEBUG?.toLowerCase();\n return v === '1' || v === 'true' || v === 'yes';\n }\n\n /** Per-request embedding logs (noisy with many chunks). Set `LLM_EMBED_DEBUG=1`. */\n private embedDebugEnabled(): boolean {\n const v = process.env.LLM_EMBED_DEBUG?.toLowerCase();\n return v === '1' || v === 'true' || v === 'yes';\n }\n\n private logAgentComposition(options: LlmAgentOptions): void {\n if (!this.llmDebugEnabled()) return;\n const { systemPrompt, context, history = [], userPrompt, model, temperature, max_tokens } = options;\n console.log('\\n[LLM chatAgent] composing request');\n if (systemPrompt?.trim()) {\n console.log('[System instruction]\\n', systemPrompt.trim());\n }\n if (context?.trim()) {\n console.log('[Context — merged into system message by chatAgent]\\n', context.trim());\n }\n if (history.length > 0) {\n console.log('[Conversation so far]');\n for (const m of history) {\n console.log(` ${m.role}: ${m.content}`);\n }\n }\n console.log('[Current user message]\\n', userPrompt);\n if (model !== undefined || temperature !== undefined || max_tokens !== undefined) {\n console.log('[Agent options]', { model, temperature, max_tokens });\n }\n }\n\n private logChatCompletionsRequest(\n kind: 'chat' | 'streamChat',\n messages: LlmMessage[],\n options: LlmChatOptions,\n stream: boolean\n ): void {\n if (!this.llmDebugEnabled()) return;\n const model = this.resolveChatModel(options.model);\n console.log(`\\n[LLM ${kind}] POST`, this.url);\n console.log('[Request options]', {\n model,\n temperature: options.temperature,\n max_tokens: options.max_tokens,\n stream,\n });\n console.log('[Messages — wire payload]\\n', JSON.stringify(messages, null, 2));\n }\n\n async embed(text: string, options: { model?: string } = {}): Promise<number[]> {\n const input = text.slice(0, 8000);\n if (this.embeddingProvider === 'huggingface') {\n const model =\n options.model ?? this.defaultEmbeddingModel ?? 'sentence-transformers/all-MiniLM-L6-v2';\n return this.embedHuggingFaceInference(input, model);\n }\n\n const model = options.model ?? this.defaultEmbeddingModel ?? 'text-embedding-3-small';\n return this.fetchOpenAiShapeEmbeddings(`${this.base}/v1/embeddings`, model, input, this.apiKey);\n }\n\n /**\n * POST `{ url }` with OpenAI-style `{ model, input }` and Bearer token; parses `{ data:[{embedding}] }`.\n */\n private async fetchOpenAiShapeEmbeddings(\n embedUrl: string,\n model: string,\n input: string,\n bearerToken: string\n ): Promise<number[]> {\n if (this.embedDebugEnabled()) {\n console.info('[LLM embed] request', { url: embedUrl, model, inputChars: input.length });\n }\n const res = await fetch(embedUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${bearerToken}`,\n },\n body: JSON.stringify({\n model,\n input,\n }),\n });\n if (!res.ok) {\n const body = await res.text();\n const hint404 =\n res.status === 404\n ? 'This base URL does not expose OpenAI-compatible POST /v1/embeddings. For Hugging Face embeddings, set EMBEDDING_PROVIDER=huggingface and an HF token (EMBEDDING_API_KEY); the server uses @huggingface/inference (router /v1/embeddings is chat-only and is not used).'\n : 'Embeddings HTTP error — knowledge_base_chunks.embedding will stay NULL for failed calls.';\n if (!LlmService.embedHttpErrorLogged) {\n LlmService.embedHttpErrorLogged = true;\n console.error('[LLM embed]', hint404, {\n url: embedUrl,\n status: res.status,\n statusText: res.statusText,\n bodyPreview: body.slice(0, 800),\n });\n } else if (this.embedDebugEnabled()) {\n console.warn('[LLM embed] repeat HTTP error', { status: res.status, bodyPreview: body.slice(0, 200) });\n }\n return [];\n }\n let data: Record<string, unknown>;\n try {\n data = (await res.json()) as Record<string, unknown>;\n } catch {\n if (!LlmService.embedShapeErrorLogged) {\n LlmService.embedShapeErrorLogged = true;\n console.error('[LLM embed] Response body is not JSON — treating as no embedding.');\n }\n return [];\n }\n const embedding = parseOpenAiEmbeddingJson(data);\n if (!embedding) {\n if (!LlmService.embedShapeErrorLogged) {\n LlmService.embedShapeErrorLogged = true;\n console.error(\n '[LLM embed] Response OK but no parseable embedding array (OpenAI shape expected). knowledge_base_chunks will not update.',\n {\n url: embedUrl,\n topKeys: Object.keys(data),\n data0Type: Array.isArray(data?.data) ? typeof (data.data as unknown[])[0] : 'n/a',\n }\n );\n }\n return [];\n }\n if (!LlmService.embedSuccessLogged) {\n LlmService.embedSuccessLogged = true;\n console.info('[LLM embed] first success', { dimension: embedding.length, model });\n } else if (this.embedDebugEnabled()) {\n console.info('[LLM embed] ok', { dimension: embedding.length });\n }\n return embedding;\n }\n\n /**\n * Hugging Face–recommended path: Hub resolves a provider that supports `feature-extraction` for the model.\n */\n private async embedViaHuggingfaceInferenceSdk(input: string, model: string): Promise<number[] | null> {\n const token = this.embeddingApiKey.trim();\n if (!token) return null;\n try {\n const { InferenceClient } = await import('@huggingface/inference');\n const hf = new InferenceClient(token);\n const raw = await hf.featureExtraction({\n model,\n inputs: input,\n });\n const embedding = parseHfInferenceEmbeddingBody(raw as unknown);\n if (!embedding?.length) {\n if (this.embedDebugEnabled()) {\n console.warn('[LLM embed HF] Inference SDK returned no parseable vector', {\n model,\n shape: Array.isArray(raw) ? `array(len=${raw.length})` : typeof raw,\n });\n }\n return null;\n }\n return embedding;\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n if (!LlmService.hfInferenceSdkErrorLogged) {\n LlmService.hfInferenceSdkErrorLogged = true;\n console.warn(\n '[LLM embed HF] @huggingface/inference featureExtraction failed — trying legacy HTTP URLs.',\n { model, message: message.slice(0, 500) }\n );\n } else if (this.embedDebugEnabled()) {\n console.warn('[LLM embed HF] repeat Inference SDK failure', { message: message.slice(0, 200) });\n }\n return null;\n }\n }\n\n /** Base URL for legacy `…/pipeline/…` and `…/models/{model}` tries (HF router only). */\n private hfLegacyInferenceBase(normalizedBase: string): string {\n if (/router\\.huggingface\\.co|api-inference\\.huggingface\\.co/i.test(normalizedBase)) {\n return 'https://router.huggingface.co/hf-inference';\n }\n return normalizedBase;\n }\n\n /**\n * Hugging Face embeddings: `@huggingface/inference` (Hub-routed feature extraction), then\n * legacy direct `hf-inference` HTTP tries. Note: `https://router.huggingface.co/v1/embeddings` is not\n * offered for embeddings (OpenAI-compatible `/v1` on HF is chat-only).\n */\n private async embedHuggingFaceInference(input: string, model: string): Promise<number[]> {\n const normalizedBase = this.hfInferenceBaseURL.replace(/\\/$/, '');\n\n const fromSdk = await this.embedViaHuggingfaceInferenceSdk(input, model);\n if (fromSdk?.length) {\n if (!LlmService.embedSuccessLogged) {\n LlmService.embedSuccessLogged = true;\n console.info('[LLM embed HF] first success', { dimension: fromSdk.length, model, via: '@huggingface/inference' });\n if (!LlmService.hfDimensionMismatchWarned && fromSdk.length !== 1536) {\n LlmService.hfDimensionMismatchWarned = true;\n console.warn(\n `[LLM embed HF] Embedding dimensions=${fromSdk.length}; ensure knowledge_base_chunks.embedding uses vector(${fromSdk.length}) (see migrations).`\n );\n }\n } else if (this.embedDebugEnabled()) {\n console.info('[LLM embed HF] ok', { dimension: fromSdk.length, via: '@huggingface/inference' });\n }\n return fromSdk;\n }\n\n const legacyBase = this.hfLegacyInferenceBase(normalizedBase);\n const baseWithProvider =\n /\\/hf-inference$/i.test(legacyBase) || !/router\\.huggingface\\.co/i.test(legacyBase)\n ? legacyBase\n : `${legacyBase.replace(/\\/$/, '')}/hf-inference`;\n\n const bodyVariants: Array<{ label: string; body: string }> = [\n {\n label: 'inputs_parameters_mean_normalize',\n body: JSON.stringify({\n inputs: input,\n parameters: { pooling: 'mean', normalize: true },\n options: { wait_for_model: true },\n }),\n },\n {\n label: 'inputs_string',\n body: JSON.stringify({ inputs: input, options: { wait_for_model: true } }),\n },\n {\n label: 'inputs_string_array',\n body: JSON.stringify({ inputs: [input], options: { wait_for_model: true } }),\n },\n {\n label: 'inputs_wrapped_sentences',\n body: JSON.stringify({ inputs: { sentences: [input] }, options: { wait_for_model: true } }),\n },\n {\n label: 'top_level_sentences',\n body: JSON.stringify({ sentences: [input], options: { wait_for_model: true } }),\n },\n ];\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.embeddingApiKey}`,\n };\n\n const candidateUrls: string[] = [];\n const pushUrl = (u: string) => {\n if (!candidateUrls.includes(u)) candidateUrls.push(u);\n };\n pushUrl(`${baseWithProvider}/pipeline/feature-extraction/${model}`);\n pushUrl(`${baseWithProvider}/models/${model}`);\n\n let lastUrl = '';\n let lastStatus = 0;\n let lastBodyPreview = '';\n let lastAttempt = '';\n\n for (const embedUrl of candidateUrls) {\n for (const { label, body } of bodyVariants) {\n if (this.embedDebugEnabled()) {\n console.info('[LLM embed HF] attempt', { url: embedUrl, model, inputChars: input.length, body: label });\n }\n const res = await fetch(embedUrl, {\n method: 'POST',\n headers,\n body,\n });\n const bodyText = await res.text();\n lastUrl = embedUrl;\n lastStatus = res.status;\n lastBodyPreview = bodyText.slice(0, 800);\n lastAttempt = `${embedUrl} (${label})`;\n\n if (!res.ok) {\n if (this.embedDebugEnabled()) {\n console.warn('[LLM embed HF] attempt failed, trying next if any', {\n url: embedUrl,\n body: label,\n status: res.status,\n bodyPreview: bodyText.slice(0, 200),\n });\n }\n continue;\n }\n\n let data: unknown;\n try {\n data = JSON.parse(bodyText) as unknown;\n } catch {\n if (this.embedDebugEnabled()) {\n console.warn('[LLM embed HF] response not JSON, trying next if any', { url: embedUrl, body: label });\n }\n continue;\n }\n\n const embedding = parseHfInferenceEmbeddingBody(data);\n if (!embedding?.length) {\n if (this.embedDebugEnabled()) {\n const preview =\n typeof data === 'object' && data !== null && !Array.isArray(data)\n ? Object.keys(data as object)\n : typeof data;\n console.warn('[LLM embed HF] no parseable embedding, trying next if any', {\n url: embedUrl,\n body: label,\n preview,\n });\n }\n continue;\n }\n\n if (!LlmService.embedSuccessLogged) {\n LlmService.embedSuccessLogged = true;\n console.info('[LLM embed HF] first success', { dimension: embedding.length, model, url: embedUrl, body: label });\n if (!LlmService.hfDimensionMismatchWarned && embedding.length !== 1536) {\n LlmService.hfDimensionMismatchWarned = true;\n console.warn(\n `[LLM embed HF] Embedding dimensions=${embedding.length}; ensure knowledge_base_chunks.embedding uses vector(${embedding.length}) (see migrations).`\n );\n }\n } else if (this.embedDebugEnabled()) {\n console.info('[LLM embed HF] ok', { dimension: embedding.length, url: embedUrl, body: label });\n }\n return embedding;\n }\n }\n\n if (!LlmService.embedHttpErrorLogged) {\n LlmService.embedHttpErrorLogged = true;\n console.error(\n '[LLM embed HF] All Hugging Face embedding attempts failed — knowledge chunks stay without vectors.',\n {\n triedInferenceSdk: true,\n triedLegacyHttp: candidateUrls,\n lastAttempt,\n lastUrl,\n lastStatus,\n lastBodyPreview,\n hint: 'Use an HF token with permission to call Inference Providers / Hub API mapping. Install ships @huggingface/inference; EMBEDDING_MODEL defaults to sentence-transformers/all-MiniLM-L6-v2. Router OpenAI /v1/embeddings is not used (chat-only).',\n }\n );\n } else if (this.embedDebugEnabled()) {\n console.warn('[LLM embed HF] repeat failure (all attempts)', {\n lastAttempt,\n lastUrl,\n lastStatus,\n bodyPreview: lastBodyPreview.slice(0, 200),\n });\n }\n return [];\n }\n\n private buildAgentMessages(options: LlmAgentOptions): LlmMessage[] {\n const { systemPrompt, userPrompt, history = [], context } = options;\n const messages: LlmMessage[] = [];\n let systemContent = systemPrompt?.trim();\n if (context) {\n systemContent = systemContent\n ? `${systemContent}\\n\\nContext:\\n${context}`\n : `Use the following context to answer:\\n\\n${context}`;\n }\n if (systemContent) {\n messages.push({ role: 'system', content: systemContent });\n }\n if (history.length > 0) {\n messages.push(...history);\n }\n messages.push({ role: 'user', content: userPrompt });\n return messages;\n }\n\n async chatAgent(options: LlmAgentOptions): Promise<{ content: string }> {\n this.logAgentComposition(options);\n const messages = this.buildAgentMessages(options);\n const { model, temperature, max_tokens } = options;\n return this.chat(messages, { model, temperature, max_tokens });\n }\n\n async *streamChatAgent(options: LlmAgentOptions): AsyncIterable<string> {\n this.logAgentComposition(options);\n const messages = this.buildAgentMessages(options);\n const { model, temperature, max_tokens } = options;\n yield* this.streamChat(messages, { model, temperature, max_tokens });\n }\n\n async chat(messages: LlmMessage[], options: LlmChatOptions = {}): Promise<{ content: string }> {\n this.logChatCompletionsRequest('chat', messages, options, false);\n const res = await fetch(this.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n model: this.resolveChatModel(options.model),\n messages,\n stream: false,\n temperature: options.temperature,\n max_tokens: options.max_tokens,\n }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(formatLlmGatewayError(res.status, text, this.defaultChatModel));\n }\n const data = (await res.json()) as { choices?: Array<{ message?: { content?: string } }> };\n const content = data.choices?.[0]?.message?.content ?? '';\n if (this.llmDebugEnabled()) {\n console.log('\\n[LLM chat] assistant reply\\n', content);\n }\n return { content };\n }\n\n async *streamChat(messages: LlmMessage[], options: LlmChatOptions = {}): AsyncIterable<string> {\n this.logChatCompletionsRequest('streamChat', messages, options, true);\n const res = await fetch(this.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n model: this.resolveChatModel(options.model),\n messages,\n stream: true,\n temperature: options.temperature,\n max_tokens: options.max_tokens,\n }),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(formatLlmGatewayError(res.status, text, this.defaultChatModel));\n }\n const reader = res.body?.getReader();\n if (!reader) return;\n const decoder = new TextDecoder();\n let buffer = '';\n const debug = this.llmDebugEnabled();\n let streamedReply = '';\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n for (const line of lines) {\n if (line.startsWith('data: ') && line !== 'data: [DONE]') {\n try {\n const json = JSON.parse(line.slice(6)) as { choices?: Array<{ delta?: { content?: string } }> };\n const content = json.choices?.[0]?.delta?.content;\n if (content) {\n if (debug) streamedReply += content;\n yield content;\n }\n } catch {\n // skip malformed chunk\n }\n }\n }\n }\n if (debug) {\n console.log('\\n[LLM streamChat] assistant reply (full)\\n', streamedReply);\n }\n }\n}\n","/** Stable `llm_agents.scope` values — one active row per scope. */\r\nexport const LLM_AGENT_SCOPE_CHATBOT = 'chatbot';\r\nexport const LLM_AGENT_SCOPE_BLOG_CREATION = 'blog_creation';\r\nexport const LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST = 'social_media_post';\r\nexport const LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT = 'email_intent_chatbot';\r\n/** Blog metadata enrichment step (categories/tags/SEO hints). */\r\nexport const LLM_AGENT_SCOPE_BLOG_METADATA = 'blog_metadata';\r\n\r\nexport const LLM_AGENT_SCOPES = [\r\n LLM_AGENT_SCOPE_CHATBOT,\r\n LLM_AGENT_SCOPE_BLOG_CREATION,\r\n LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST,\r\n LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT,\r\n LLM_AGENT_SCOPE_BLOG_METADATA,\r\n] as const;\r\n\r\nexport type LlmAgentScope = (typeof LLM_AGENT_SCOPES)[number];\r\n\r\n/** Default slugs used when seeding or bootstrapping rows per scope. */\r\nexport const LLM_AGENT_DEFAULT_SLUG_BY_SCOPE: Record<LlmAgentScope, string> = {\r\n [LLM_AGENT_SCOPE_CHATBOT]: 'site-chat-assistant',\r\n [LLM_AGENT_SCOPE_BLOG_CREATION]: 'blog-generator',\r\n [LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST]: 'blog-generator-social',\r\n [LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]: 'email-intent-chatbot',\r\n [LLM_AGENT_SCOPE_BLOG_METADATA]: 'blog-generator-metadata',\r\n};\r\n\r\nexport const LLM_AGENT_DEFAULT_NAME_BY_SCOPE: Record<LlmAgentScope, string> = {\r\n [LLM_AGENT_SCOPE_CHATBOT]: 'Site Chat Assistant',\r\n [LLM_AGENT_SCOPE_BLOG_CREATION]: 'Blog Generator',\r\n [LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST]: 'Blog Generator (Social)',\r\n [LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT]: 'Chat Lead Intent Classifier',\r\n [LLM_AGENT_SCOPE_BLOG_METADATA]: 'Blog Generator (Metadata)',\r\n};\r\n\r\n/** @deprecated Use {@link LLM_AGENT_SCOPE_CHATBOT} and scope-based lookup. */\r\nexport const SITE_CHAT_ASSISTANT_SLUG = LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];\r\n\r\n/** @deprecated Use {@link LLM_AGENT_DEFAULT_NAME_BY_SCOPE}. */\r\nexport const SITE_CHAT_ASSISTANT_NAME = LLM_AGENT_DEFAULT_NAME_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];\r\n\r\nconst LEGACY_SLUG_TO_SCOPE: Record<string, LlmAgentScope> = {\r\n 'site-chat-assistant': LLM_AGENT_SCOPE_CHATBOT,\r\n 'blog-generator': LLM_AGENT_SCOPE_BLOG_CREATION,\r\n 'blog-generator-social': LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST,\r\n 'blog-generator-metadata': LLM_AGENT_SCOPE_BLOG_METADATA,\r\n 'email-intent-chatbot': LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT,\r\n};\r\n\r\nexport function isLlmAgentScope(value: string | null | undefined): value is LlmAgentScope {\r\n if (!value?.trim()) return false;\r\n return (LLM_AGENT_SCOPES as readonly string[]).includes(value.trim());\r\n}\r\n\r\nexport function scopeFromLegacySlug(slug: string | null | undefined): LlmAgentScope | null {\r\n if (!slug?.trim()) return null;\r\n return LEGACY_SLUG_TO_SCOPE[slug.trim()] ?? null;\r\n}\r\n\r\n/** @deprecated Resolve agents by `scope` instead of slug blocklists. */\r\nexport const BLOG_LLM_AGENT_SLUGS = [\r\n LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_BLOG_CREATION],\r\n LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_BLOG_METADATA],\r\n LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST],\r\n] as const;\r\n\r\n/** @deprecated Resolve agents by `scope` instead of slug blocklists. */\r\nexport function isBlogLlmAgentSlug(slug: string | null | undefined): boolean {\r\n const scope = scopeFromLegacySlug(slug);\r\n if (!scope) return false;\r\n return (\r\n scope === LLM_AGENT_SCOPE_BLOG_CREATION ||\r\n scope === LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST ||\r\n scope === LLM_AGENT_SCOPE_BLOG_METADATA\r\n );\r\n}\r\n","import type { DataSource, EntityTarget } from 'typeorm';\r\nimport type { EntityMap } from '../../api/crud';\r\nimport type { LlmAgent } from '../../entities/llm-agent.entity';\r\nimport type { LlmAgentScope } from './llm-agent-scope';\r\n\r\nexport type FindLlmAgentByScopeOptions = {\r\n /** When true (default), only returns rows with `enabled: true`. */\r\n enabledOnly?: boolean;\r\n};\r\n\r\n/**\r\n * Load the active `llm_agents` row for a given scope.\r\n * At most one non-deleted row per scope is expected (enforced by DB index + CRUD).\r\n */\r\nexport async function findLlmAgentByScope(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n scope: LlmAgentScope,\r\n options: FindLlmAgentByScopeOptions = {}\r\n): Promise<LlmAgent | null> {\r\n const { enabledOnly = true } = options;\r\n const entity = entityMap.llm_agents;\r\n if (!entity) return null;\r\n\r\n const repo = dataSource.getRepository(entity as EntityTarget<LlmAgent>);\r\n const where: Record<string, unknown> = { scope, deleted: false };\r\n if (enabledOnly) where.enabled = true;\r\n\r\n return repo.findOne({ where: where as object });\r\n}\r\n","import type { CmsPlugin } from '../types';\r\nimport { LlmService, type LlmEmbeddingProvider } from './llm-service';\r\n\r\nexport interface LlmPluginConfig {\r\n baseURL?: string;\r\n apiKey?: string;\r\n /** Default chat model when agents omit `model` (`POST /v1/chat/completions`). Env: `LLM_CHAT_MODEL`. If unset, inferred from `LLM_GATEWAY_URL` (HF vs OpenRouter-style default). */\r\n defaultChatModel?: string;\r\n /** Default model for embed(); also from env EMBEDDING_MODEL. */\r\n embeddingModel?: string;\r\n /**\r\n * `openai` (default): `POST {LLM_GATEWAY_URL}/v1/embeddings`.\r\n * `huggingface`: `@huggingface/inference` feature extraction (Hub-routed), with legacy `…/hf-inference/…` HTTP fallback. Env: `EMBEDDING_PROVIDER=huggingface`.\r\n */\r\n embeddingProvider?: LlmEmbeddingProvider;\r\n /** Legacy HTTP base if the SDK path fails; default `https://router.huggingface.co/v1` (router hosts map to `…/hf-inference`). Env: `HF_INFERENCE_URL`. */\r\n hfInferenceBaseUrl?: string;\r\n /** Optional; defaults to `apiKey`. Env: `EMBEDDING_API_KEY`. */\r\n embeddingApiKey?: string;\r\n}\r\n\r\nfunction normalizeEmbeddingProvider(raw: string | undefined): LlmEmbeddingProvider {\r\n if (!raw) return 'openai';\r\n const s = raw.toLowerCase().trim();\r\n if (s === 'huggingface' || s === 'hf' || s === 'hf_inference' || s === 'inference') return 'huggingface';\r\n return 'openai';\r\n}\r\n\r\nexport function llmPlugin(config: LlmPluginConfig = {}): CmsPlugin<LlmService | undefined> {\r\n return {\r\n name: 'llm',\r\n version: '1.0.0',\r\n async init(context) {\r\n const baseURL = config.baseURL ?? context.config.LLM_GATEWAY_URL;\r\n const apiKey = config.apiKey ?? context.config.LLM_API_KEY;\r\n if (!baseURL || !apiKey) {\r\n context.logger.warn('LLM plugin skipped: LLM_GATEWAY_URL or LLM_API_KEY not set');\r\n return undefined;\r\n }\r\n const embeddingModel = config.embeddingModel ?? context.config.EMBEDDING_MODEL;\r\n const defaultChatModel =\r\n config.defaultChatModel?.trim() ||\r\n (typeof context.config.LLM_CHAT_MODEL === 'string' ? context.config.LLM_CHAT_MODEL.trim() : '') ||\r\n undefined;\r\n const embeddingProvider = normalizeEmbeddingProvider(\r\n config.embeddingProvider ?? (context.config.EMBEDDING_PROVIDER as string | undefined)\r\n );\r\n const hfInferenceBaseUrl =\r\n config.hfInferenceBaseUrl ?? (context.config.HF_INFERENCE_URL as string | undefined);\r\n const embeddingApiKey = config.embeddingApiKey ?? (context.config.EMBEDDING_API_KEY as string | undefined);\r\n return new LlmService(baseURL.replace(/\\/$/, ''), apiKey, embeddingModel, {\r\n embeddingProvider,\r\n hfInferenceBaseUrl,\r\n embeddingApiKey,\r\n defaultChatModel,\r\n });\r\n },\r\n };\r\n}\r\n\r\nexport { LlmService, parseHfInferenceEmbeddingBody } from './llm-service';\r\nexport type {\r\n LlmServiceInterface,\r\n LlmServiceEmbedOptions,\r\n LlmMessage,\r\n LlmChatOptions,\r\n LlmAgentOptions,\r\n LlmEmbeddingProvider,\r\n} from './llm-service';\r\nexport {\r\n LLM_AGENT_SCOPES,\r\n LLM_AGENT_SCOPE_CHATBOT,\r\n LLM_AGENT_SCOPE_BLOG_CREATION,\r\n LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST,\r\n LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT,\r\n LLM_AGENT_SCOPE_BLOG_METADATA,\r\n LLM_AGENT_DEFAULT_SLUG_BY_SCOPE,\r\n LLM_AGENT_DEFAULT_NAME_BY_SCOPE,\r\n SITE_CHAT_ASSISTANT_SLUG,\r\n SITE_CHAT_ASSISTANT_NAME,\r\n BLOG_LLM_AGENT_SLUGS,\r\n isBlogLlmAgentSlug,\r\n isLlmAgentScope,\r\n scopeFromLegacySlug,\r\n type LlmAgentScope,\r\n} from './llm-agent-scope';\r\nexport { findLlmAgentByScope } from './find-llm-agent-by-scope';\r\nexport type { FindLlmAgentByScopeOptions } from './find-llm-agent-by-scope';\r\nexport {\r\n detectChatLeadIntent,\r\n parseChatEmailToolSettings,\r\n parseEmailIntentsFromSettings,\r\n serializeChatLeadIntents,\r\n buildTranscriptForLeadEmail,\r\n buildChatEmailAgentContext,\r\n buildChatbotSystemPromptWithEmailTool,\r\n CHAT_EMAIL_LOG,\r\n resolveChatEmailToolSettings,\r\n type LlmNotifyEmailAgentSource,\r\n type ResolveChatEmailToolSources,\r\n mergeEmailToolIntoValidationRules,\r\n splitValidationRulesForAdmin,\r\n parseEmailToolFromAgentValidationRules,\r\n parseIntentRecipientEmails,\r\n DEFAULT_CHAT_LEAD_INTENTS,\r\n} from './chat-email-intent';\r\nexport type {\r\n ChatEmailToolSettings,\r\n ChatEmailIntentResult,\r\n ChatLeadIntentDefinition,\r\n} from './chat-email-intent';\r\n","import Redis from 'ioredis';\r\nimport type { CmsPlugin } from '../types';\r\nimport type { CacheService } from './types';\r\nimport { MemoryCache } from './memory-cache';\r\nimport { RedisCache } from './redis-cache';\r\n\r\nexport type { CacheService } from './types';\r\nexport { MemoryCache } from './memory-cache';\r\nexport { RedisCache } from './redis-cache';\r\n\r\nexport interface CachePluginConfig {\r\n redisUrl?: string;\r\n}\r\n\r\nexport function cachePlugin(config?: CachePluginConfig): CmsPlugin<CacheService> {\r\n return {\r\n name: 'cache',\r\n version: '1.0.0',\r\n async init(context) {\r\n const redisUrl = config?.redisUrl ?? context.config.REDIS_URL ?? '';\r\n const url = typeof redisUrl === 'string' ? redisUrl.trim() : '';\r\n if (url) {\r\n const client = new Redis(url);\r\n return new RedisCache(client);\r\n }\r\n return new MemoryCache();\r\n },\r\n };\r\n}\r\n","import { LRUCache } from 'lru-cache';\r\nimport type { CacheService } from './types';\r\n\r\nconst DEFAULT_MAX = 500;\r\nconst DEFAULT_TTL_MS = 60 * 1000;\r\n\r\nexport class MemoryCache implements CacheService {\r\n private readonly cache: LRUCache<string, string>;\r\n\r\n constructor(options?: { max?: number; ttlMs?: number }) {\r\n const max = options?.max ?? DEFAULT_MAX;\r\n const ttlMs = options?.ttlMs ?? DEFAULT_TTL_MS;\r\n this.cache = new LRUCache<string, string>({ max, ttl: ttlMs });\r\n }\r\n\r\n async get(key: string): Promise<string | null> {\r\n const value = this.cache.get(key);\r\n return value ?? null;\r\n }\r\n\r\n async set(key: string, value: string, ttlSeconds?: number): Promise<void> {\r\n const ttlMs = ttlSeconds != null && ttlSeconds > 0 ? ttlSeconds * 1000 : undefined;\r\n this.cache.set(key, value, { ttl: ttlMs });\r\n }\r\n\r\n async del(key: string): Promise<void> {\r\n this.cache.delete(key);\r\n }\r\n}\r\n","import type Redis from 'ioredis';\r\nimport type { CacheService } from './types';\r\n\r\nexport class RedisCache implements CacheService {\r\n constructor(private readonly client: Redis) {}\r\n\r\n async get(key: string): Promise<string | null> {\r\n return this.client.get(key);\r\n }\r\n\r\n async set(key: string, value: string, ttlSeconds?: number): Promise<void> {\r\n if (ttlSeconds != null && ttlSeconds > 0) {\r\n await this.client.set(key, value, 'EX', ttlSeconds);\r\n } else {\r\n await this.client.set(key, value);\r\n }\r\n }\r\n\r\n async del(key: string): Promise<void> {\r\n await this.client.del(key);\r\n }\r\n}\r\n","import { Queue, Worker } from 'bullmq';\r\nimport type { Job } from 'bullmq';\r\nimport type { QueueService } from './types';\r\n\r\nfunction connectionFromUrl(redisUrl: string): { host: string; port: number; username?: string; password?: string; maxRetriesPerRequest: number | null } {\r\n const u = new URL(redisUrl);\r\n return {\r\n host: u.hostname,\r\n port: u.port ? parseInt(u.port, 10) : 6379,\r\n ...(u.username && { username: u.username }),\r\n ...(u.password && { password: u.password }),\r\n maxRetriesPerRequest: null,\r\n };\r\n}\r\n\r\nexport class BullMQQueue implements QueueService {\r\n private readonly connectionOptions: ReturnType<typeof connectionFromUrl>;\r\n private readonly queues = new Map<string, Queue>();\r\n private readonly workers = new Map<string, Worker>();\r\n\r\n constructor(redisUrl: string) {\r\n this.connectionOptions = connectionFromUrl(redisUrl);\r\n }\r\n\r\n async add(queueName: string, data: object): Promise<void> {\r\n const queue = this.getOrCreateQueue(queueName);\r\n await queue.add(queueName, data);\r\n }\r\n\r\n registerProcessor(queueName: string, processor: (data: object) => Promise<void>): void {\r\n if (this.workers.has(queueName)) return;\r\n const worker = new Worker(\r\n queueName,\r\n async (job: Job) => {\r\n await processor(job.data as object);\r\n },\r\n { connection: this.connectionOptions }\r\n );\r\n this.workers.set(queueName, worker);\r\n }\r\n\r\n private getOrCreateQueue(queueName: string): Queue {\r\n let queue = this.queues.get(queueName);\r\n if (!queue) {\r\n queue = new Queue(queueName, { connection: this.connectionOptions });\r\n this.queues.set(queueName, queue);\r\n }\r\n return queue;\r\n }\r\n\r\n async destroy(): Promise<void> {\r\n for (const w of this.workers.values()) await w.close();\r\n this.workers.clear();\r\n for (const q of this.queues.values()) await q.close();\r\n this.queues.clear();\r\n }\r\n}\r\n","import fastq from 'fastq';\r\nimport type { QueueService } from './types';\r\n\r\ntype Task = object;\r\n\r\nexport class MemoryQueue implements QueueService {\r\n private readonly queues = new Map<string, fastq.queueAsPromised<Task>>();\r\n\r\n async add(queueName: string, data: object): Promise<void> {\r\n const q = this.queues.get(queueName);\r\n if (!q) throw new Error(`No processor registered for queue: ${queueName}`);\r\n // fastq.promise push resolves when the task finishes — do not await or HTTP handlers block on SMTP etc.\r\n void Promise.resolve(q.push(data as Task)).catch(() => undefined);\r\n }\r\n\r\n registerProcessor(queueName: string, processor: (data: object) => Promise<void>): void {\r\n if (this.queues.has(queueName)) return;\r\n const worker = async (task: Task) => processor(task);\r\n const q = fastq.promise(worker, 1);\r\n this.queues.set(queueName, q);\r\n }\r\n}\r\n","import type { CmsPlugin } from '../types';\r\nimport type { QueueService } from './types';\r\nimport { BullMQQueue } from './bullmq-queue';\r\nimport { MemoryQueue } from './memory-queue';\r\n\r\nexport type { QueueService } from './types';\r\nexport { BullMQQueue } from './bullmq-queue';\r\nexport { MemoryQueue } from './memory-queue';\r\n\r\nexport interface QueuePluginConfig {\r\n redisUrl?: string;\r\n}\r\n\r\nexport function queuePlugin(config?: QueuePluginConfig): CmsPlugin<QueueService> {\r\n let instance: BullMQQueue | MemoryQueue | undefined;\r\n return {\r\n name: 'queue',\r\n version: '1.0.0',\r\n async init(context) {\r\n const redisUrl = config?.redisUrl ?? context.config.REDIS_URL ?? '';\r\n const url = typeof redisUrl === 'string' ? redisUrl.trim() : '';\r\n if (url) {\r\n instance = new BullMQQueue(url);\r\n return instance;\r\n }\r\n instance = new MemoryQueue();\r\n return instance;\r\n },\r\n async destroy() {\r\n if (instance && 'destroy' in instance && typeof instance.destroy === 'function') {\r\n await instance.destroy();\r\n }\r\n },\r\n };\r\n}\r\n","import type { CmsPlugin, PluginContext } from '../types';\r\nimport { PgBossService } from './pg-boss-service';\r\n\r\nexport type { PgBossService, JobRunnerPayload } from './pg-boss-service';\r\nexport { JOB_RUNNER_QUEUE } from './pg-boss-service';\r\n\r\nexport interface PgBossPluginConfig {\r\n /** Postgres connection string; defaults to context.config.DATABASE_URL */\r\n connectionString?: string;\r\n schema?: string;\r\n}\r\n\r\nexport function pgBossPlugin(config: PgBossPluginConfig = {}): CmsPlugin<PgBossService | undefined> {\r\n let instance: PgBossService | undefined;\r\n return {\r\n name: 'pg_boss',\r\n version: '1.0.0',\r\n async init(context: PluginContext) {\r\n const url =\r\n config.connectionString?.trim() ||\r\n context.config.DATABASE_URL?.trim() ||\r\n '';\r\n if (!url) {\r\n context.logger.warn('pg-boss plugin skipped: DATABASE_URL missing');\r\n return undefined;\r\n }\r\n const schema = config.schema ?? context.config.PG_BOSS_SCHEMA ?? '';\r\n instance = new PgBossService(url, typeof schema === 'string' ? schema : undefined);\r\n await instance.start();\r\n context.logger.info('pg-boss started');\r\n return instance;\r\n },\r\n async destroy() {\r\n await instance?.stop();\r\n instance = undefined;\r\n },\r\n };\r\n}\r\n","import {\r\n Entity,\r\n PrimaryGeneratedColumn,\r\n Column,\r\n CreateDateColumn,\r\n UpdateDateColumn,\r\n OneToMany,\r\n} from 'typeorm';\r\nimport { JobScheduleRun } from './job-schedule-run.entity';\r\n\r\nexport type JobScheduleMode = 'interval' | 'daily' | 'weekly' | 'cron';\r\nexport type JobScheduleType = 'blog_generate';\r\n\r\n@Entity('job_schedules')\r\nexport class JobSchedule {\r\n @PrimaryGeneratedColumn('uuid')\r\n id: string;\r\n\r\n @Column({ type: 'text' })\r\n name: string;\r\n\r\n @Column({ type: 'varchar', length: 64, default: 'blog_generate' })\r\n jobType: JobScheduleType;\r\n\r\n @Column({ type: 'boolean', default: false })\r\n enabled: boolean;\r\n\r\n @Column({ type: 'varchar', length: 32, default: 'daily' })\r\n scheduleMode: JobScheduleMode;\r\n\r\n @Column({ type: 'int', nullable: true })\r\n intervalMinutes: number | null;\r\n\r\n @Column({ type: 'varchar', length: 8, nullable: true })\r\n runAtTime: string | null;\r\n\r\n @Column({ type: 'jsonb', nullable: true })\r\n runOnDays: number[] | null;\r\n\r\n @Column({ type: 'varchar', length: 64, default: 'UTC' })\r\n timezone: string;\r\n\r\n @Column({ type: 'text', nullable: true })\r\n cronExpression: string | null;\r\n\r\n @Column({ type: 'jsonb', default: {} })\r\n payload: Record<string, unknown>;\r\n\r\n @Column({ type: 'int', nullable: true })\r\n authorId: number | null;\r\n\r\n @Column({ type: 'varchar', length: 128, unique: true })\r\n pgBossScheduleName: string;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n lastRunAt: Date | null;\r\n\r\n @Column({ type: 'varchar', length: 32, nullable: true })\r\n lastRunStatus: string | null;\r\n\r\n @Column({ type: 'text', nullable: true })\r\n lastRunError: string | null;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n nextRunAt: Date | null;\r\n\r\n @OneToMany(() => JobScheduleRun, (r) => r.schedule)\r\n runs: JobScheduleRun[];\r\n\r\n @CreateDateColumn()\r\n createdAt: Date;\r\n\r\n @UpdateDateColumn()\r\n updatedAt: Date;\r\n}\r\n","import {\r\n Entity,\r\n PrimaryGeneratedColumn,\r\n Column,\r\n CreateDateColumn,\r\n ManyToOne,\r\n JoinColumn,\r\n} from 'typeorm';\r\nimport { JobSchedule } from './job-schedule.entity';\r\n\r\n@Entity('job_schedule_runs')\r\nexport class JobScheduleRun {\r\n @PrimaryGeneratedColumn('uuid')\r\n id: string;\r\n\r\n @Column({ type: 'uuid' })\r\n scheduleId: string;\r\n\r\n @ManyToOne(() => JobSchedule, (s) => s.runs, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'scheduleId' })\r\n schedule: JobSchedule;\r\n\r\n @Column({ type: 'timestamp' })\r\n startedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n finishedAt: Date | null;\r\n\r\n @Column({ type: 'varchar', length: 32 })\r\n status: string;\r\n\r\n @Column({ type: 'text', nullable: true })\r\n error: string | null;\r\n\r\n @Column({ type: 'jsonb', nullable: true })\r\n result: Record<string, unknown> | null;\r\n\r\n @Column({ type: 'varchar', length: 16, default: 'schedule' })\r\n triggeredBy: string;\r\n\r\n @CreateDateColumn()\r\n createdAt: Date;\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport type { EntityMap } from '../../api/crud';\r\nimport { JobSchedule } from '../../entities/job-schedule.entity';\r\nimport { JobScheduleRun } from '../../entities/job-schedule-run.entity';\r\nimport type { PgBossService, JobRunnerPayload } from '../pg-boss/pg-boss-service';\r\nimport { JOB_RUNNER_QUEUE } from '../pg-boss/pg-boss-service';\r\nimport { runBlogGenerateFromSchedule, loadJobSchedule } from './blog-generate-job';\r\nimport { syncJobScheduleToPgBoss } from './schedule-sync';\r\nimport { computeNextRunAt } from './schedule-next-run';\r\n\r\nexport interface CmsAppLike {\r\n getPlugin(name: string): unknown;\r\n}\r\n\r\nexport interface JobRunnerDeps {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n config?: Record<string, string>;\r\n}\r\n\r\nlet executeJobRef: ((payload: JobRunnerPayload) => Promise<void>) | null = null;\r\n\r\nexport function registerJobRunnerWorker(cms: CmsAppLike, deps: JobRunnerDeps): void {\r\n const boss = cms.getPlugin('pg_boss') as PgBossService | undefined;\r\n if (!boss) return;\r\n\r\n const config = deps.config ?? {};\r\n\r\n const execute = async (payload: JobRunnerPayload) => {\r\n const schedule = await loadJobSchedule(deps.dataSource, deps.entityMap, payload.scheduleId);\r\n if (!schedule) {\r\n console.warn('[job-runner] schedule not found:', payload.scheduleId);\r\n return;\r\n }\r\n if (payload.triggeredBy === 'schedule' && !schedule.enabled) {\r\n return;\r\n }\r\n\r\n const runRepo = deps.dataSource.getRepository(JobScheduleRun);\r\n const startedAt = new Date();\r\n const runRow = runRepo.create({\r\n scheduleId: schedule.id,\r\n startedAt,\r\n finishedAt: null,\r\n status: 'running',\r\n error: null,\r\n result: null,\r\n triggeredBy: payload.triggeredBy ?? 'schedule',\r\n });\r\n await runRepo.save(runRow);\r\n\r\n const scheduleRepo = deps.dataSource.getRepository(JobSchedule);\r\n schedule.lastRunAt = startedAt;\r\n schedule.lastRunStatus = 'running';\r\n schedule.lastRunError = null;\r\n await scheduleRepo.save(schedule);\r\n\r\n try {\r\n let result: Record<string, unknown> = {};\r\n if (schedule.jobType === 'blog_generate') {\r\n const out = await runBlogGenerateFromSchedule(\r\n deps.dataSource,\r\n deps.entityMap,\r\n schedule,\r\n cms,\r\n config\r\n );\r\n result = { blogIds: out.blogIds, slugs: out.slugs };\r\n } else {\r\n throw new Error(`Unsupported jobType: ${schedule.jobType}`);\r\n }\r\n\r\n const finishedAt = new Date();\r\n runRow.status = 'success';\r\n runRow.finishedAt = finishedAt;\r\n runRow.result = result;\r\n await runRepo.save(runRow);\r\n\r\n schedule.lastRunAt = finishedAt;\r\n schedule.lastRunStatus = 'success';\r\n schedule.lastRunError = null;\r\n schedule.nextRunAt = computeNextRunAt(schedule, finishedAt);\r\n await scheduleRepo.save(schedule);\r\n } catch (e) {\r\n const message = e instanceof Error ? e.message : String(e);\r\n const finishedAt = new Date();\r\n runRow.status = 'failed';\r\n runRow.finishedAt = finishedAt;\r\n runRow.error = message.slice(0, 4000);\r\n await runRepo.save(runRow);\r\n\r\n schedule.lastRunAt = finishedAt;\r\n schedule.lastRunStatus = 'failed';\r\n schedule.lastRunError = message.slice(0, 4000);\r\n await scheduleRepo.save(schedule);\r\n\r\n throw e;\r\n }\r\n };\r\n\r\n executeJobRef = execute;\r\n\r\n const registerQueue = async (queueName: string) => {\r\n await boss.registerWork<JobRunnerPayload>(queueName, execute);\r\n };\r\n\r\n void boss.registerWork<JobRunnerPayload>(JOB_RUNNER_QUEUE, execute);\r\n\r\n void (async () => {\r\n try {\r\n const repo = deps.dataSource.getRepository(JobSchedule);\r\n const enabled = await repo.find({ where: { enabled: true } });\r\n for (const row of enabled) {\r\n await registerQueue(row.pgBossScheduleName);\r\n await syncJobScheduleToPgBoss(cms, row, registerQueue);\r\n }\r\n } catch (err) {\r\n console.error('[job-runner] failed to sync enabled schedules:', err);\r\n }\r\n })();\r\n}\r\n\r\n/** Re-register work for a queue after API updates a schedule. */\r\nexport async function ensureScheduleQueueWorker(\r\n cms: CmsAppLike,\r\n queueName: string\r\n): Promise<void> {\r\n const boss = cms.getPlugin('pg_boss') as PgBossService | undefined;\r\n if (!boss || !executeJobRef) return;\r\n await boss.registerWork<JobRunnerPayload>(queueName, executeJobRef);\r\n}\r\n","import type { DataSource, EntityTarget } from 'typeorm';\r\nimport { In } from 'typeorm';\r\nimport type { EntityMap } from '../../api/crud';\r\nimport type { JobSchedule } from '../../entities/job-schedule.entity';\r\nimport { JobSchedule as JobScheduleEntity } from '../../entities/job-schedule.entity';\r\nimport type { RssFeed } from '../../entities/rss-feed.entity';\r\nimport type { LlmAgent } from '../../entities/llm-agent.entity';\r\nimport { llmAgentToChatAgentOptions } from '../../entities/llm-agent.entity';\r\nimport type { Category } from '../../entities/category.entity';\r\nimport type { Tag } from '../../entities/tag.entity';\r\nimport { BlogGeneratorService } from '../blog-generator/blog-generator-service';\r\nimport { persistAllGeneratedBlogDrafts } from '../blog-generator/blog-generator-persist';\r\nimport { findLlmAgentByScope } from '../llm/find-llm-agent-by-scope';\r\nimport {\r\n LLM_AGENT_SCOPE_BLOG_CREATION,\r\n LLM_AGENT_SCOPE_BLOG_METADATA,\r\n LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST,\r\n} from '../llm/llm-agent-scope';\r\nimport type { LlmService } from '../llm/llm-service';\r\nimport { recordRssFetchSuccess } from '../../api/rss-feed-blog-api';\r\n\r\nexport interface BlogGenerateJobResult {\r\n blogIds: number[];\r\n slugs: string[];\r\n}\r\n\r\nexport type BlogGeneratePayload = {\r\n rssFeedIds?: string[];\r\n persistToCms?: boolean;\r\n};\r\n\r\nexport async function resolveScheduleAuthorId(\r\n schedule: JobSchedule,\r\n config: Record<string, string>\r\n): Promise<number> {\r\n if (schedule.authorId != null && Number.isFinite(schedule.authorId)) {\r\n return schedule.authorId;\r\n }\r\n const fromEnv = config.BLOG_GENERATOR_SCHEDULE_AUTHOR_ID?.trim();\r\n if (fromEnv) {\r\n const n = Number(fromEnv);\r\n if (Number.isFinite(n) && n > 0) return n;\r\n }\r\n throw new Error(\r\n 'No authorId on schedule and BLOG_GENERATOR_SCHEDULE_AUTHOR_ID is not set'\r\n );\r\n}\r\n\r\nexport async function runBlogGenerateFromSchedule(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n schedule: JobSchedule,\r\n cms: { getPlugin: (name: string) => unknown },\r\n config: Record<string, string>\r\n): Promise<BlogGenerateJobResult> {\r\n const svc = cms.getPlugin('blog_generator') as BlogGeneratorService | undefined;\r\n if (!svc) throw new Error('Blog Generator plugin is not enabled');\r\n\r\n const llm = cms.getPlugin('llm') as LlmService | undefined;\r\n if (!llm) throw new Error('LLM plugin is not enabled');\r\n\r\n if (!entityMap.blogs || !entityMap.tags || !entityMap.categories || !entityMap.seos) {\r\n throw new Error('blogs, tags, categories, and seos are required in entity map');\r\n }\r\n\r\n const payload = (schedule.payload ?? {}) as BlogGeneratePayload;\r\n const rssUrls = await resolveRssUrls(dataSource, entityMap, payload);\r\n\r\n if (rssUrls.length === 0) {\r\n throw new Error('No RSS feeds configured for this schedule');\r\n }\r\n\r\n let llmAgentChatOptions: { model?: string; temperature?: number; max_tokens?: number } | undefined;\r\n let metadataLlmAgentChatOptions: { model?: string; temperature?: number; max_tokens?: number } | undefined;\r\n let socialLlmAgentChatOptions: { model?: string; temperature?: number; max_tokens?: number } | undefined;\r\n let metadataRow: LlmAgent | null = null;\r\n let socialRow: LlmAgent | null = null;\r\n\r\n let blogCreationRow: LlmAgent | null = null;\r\n if (entityMap.llm_agents) {\r\n blogCreationRow = await findLlmAgentByScope(dataSource, entityMap, LLM_AGENT_SCOPE_BLOG_CREATION);\r\n if (blogCreationRow) {\r\n const o = llmAgentToChatAgentOptions(blogCreationRow);\r\n llmAgentChatOptions = { model: o.model, temperature: o.temperature, max_tokens: o.max_tokens };\r\n }\r\n metadataRow = await findLlmAgentByScope(dataSource, entityMap, LLM_AGENT_SCOPE_BLOG_METADATA);\r\n if (metadataRow) {\r\n const mo = llmAgentToChatAgentOptions(metadataRow);\r\n metadataLlmAgentChatOptions = {\r\n model: mo.model,\r\n temperature: mo.temperature,\r\n max_tokens: mo.max_tokens,\r\n };\r\n }\r\n socialRow = await findLlmAgentByScope(dataSource, entityMap, LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST);\r\n if (socialRow) {\r\n const so = llmAgentToChatAgentOptions(socialRow);\r\n socialLlmAgentChatOptions = {\r\n model: so.model,\r\n temperature: so.temperature,\r\n max_tokens: so.max_tokens,\r\n };\r\n }\r\n }\r\n\r\n const categoryEntities = entityMap.categories\r\n ? await dataSource.getRepository(entityMap.categories as EntityTarget<Category>).find({\r\n where: { deleted: false } as object,\r\n select: ['id', 'name'],\r\n })\r\n : [];\r\n const categoryRows = categoryEntities\r\n .map((r) => ({\r\n id: Number((r as Category).id),\r\n name: String((r as Category).name ?? '').trim(),\r\n }))\r\n .filter((r) => Number.isFinite(r.id) && r.name !== '');\r\n\r\n const tagEntities = entityMap.tags\r\n ? await dataSource.getRepository(entityMap.tags as EntityTarget<Tag>).find({\r\n where: { deleted: false } as object,\r\n select: ['name'],\r\n })\r\n : [];\r\n const tagNames = tagEntities\r\n .map((r) => String((r as Tag).name ?? '').trim())\r\n .filter((n) => n !== '');\r\n\r\n for (const rssUrl of rssUrls) {\r\n if (entityMap.rss_feeds) {\r\n const latest = await svc.getLatestArticleFromFeed(rssUrl);\r\n await recordRssFetchSuccess(\r\n dataSource,\r\n entityMap.rss_feeds as EntityTarget<RssFeed>,\r\n entityMap.rss_articles as EntityTarget<import('../../entities/rss-article.entity').RssArticle> | undefined,\r\n rssUrl,\r\n latest == null\r\n ? null\r\n : {\r\n title: latest.title,\r\n link: latest.link,\r\n summary: latest.summary,\r\n content: latest.content,\r\n creator: latest.creator,\r\n date: latest.date,\r\n }\r\n );\r\n }\r\n }\r\n\r\n const out = await svc.generateBlogMarkdownFromRss({\r\n llm,\r\n rssUrls,\r\n systemInstruction: blogCreationRow?.systemInstruction?.trim() || undefined,\r\n validationRules: blogCreationRow?.validationRules?.trim() || undefined,\r\n categoryNamesHint: categoryRows.map((c) => c.name),\r\n tagNamesHint: tagNames,\r\n llmAgentChatOptions,\r\n metadataSystemInstruction: metadataRow?.systemInstruction,\r\n metadataValidationRules: metadataRow?.validationRules ?? undefined,\r\n metadataLlmAgentChatOptions,\r\n socialSystemInstruction: socialRow?.systemInstruction,\r\n socialValidationRules: socialRow?.validationRules ?? undefined,\r\n socialLlmAgentChatOptions,\r\n });\r\n\r\n const authorId = await resolveScheduleAuthorId(schedule, config);\r\n const saved = await persistAllGeneratedBlogDrafts(\r\n dataSource,\r\n {\r\n blogs: entityMap.blogs,\r\n tags: entityMap.tags,\r\n categories: entityMap.categories,\r\n seos: entityMap.seos,\r\n },\r\n { drafts: out.blogDrafts, authorId }\r\n );\r\n\r\n return {\r\n blogIds: saved.map((s) => s.blogId),\r\n slugs: saved.map((s) => s.slug),\r\n };\r\n}\r\n\r\nasync function resolveRssUrls(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n payload: BlogGeneratePayload\r\n): Promise<string[]> {\r\n const ids = Array.isArray(payload.rssFeedIds)\r\n ? payload.rssFeedIds.filter((id) => typeof id === 'string' && id.trim())\r\n : [];\r\n\r\n if (!entityMap.rss_feeds) {\r\n throw new Error('rss_feeds entity is not configured');\r\n }\r\n\r\n const repo = dataSource.getRepository(entityMap.rss_feeds as EntityTarget<RssFeed>);\r\n const feeds =\r\n ids.length > 0\r\n ? await repo.find({ where: { id: In(ids), isActive: true } as object })\r\n : await repo.find({ where: { isActive: true } as object });\r\n\r\n if (ids.length > 0 && feeds.length === 0) {\r\n throw new Error('No active RSS feeds found for the given feed ids');\r\n }\r\n\r\n return [...new Set(feeds.map((f) => String((f as RssFeed).rssUrl).trim()).filter(Boolean))];\r\n}\r\n\r\nexport async function loadJobSchedule(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n scheduleId: string\r\n): Promise<JobSchedule | null> {\r\n const repo = dataSource.getRepository(\r\n (entityMap.job_schedules ?? JobScheduleEntity) as EntityTarget<JobSchedule>\r\n );\r\n return repo.findOne({ where: { id: scheduleId } });\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';\r\nimport type { LlmAgentOptions } from '../plugins/llm/llm-service';\r\n\r\n@Entity('llm_agents')\r\nexport class LlmAgent {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n /** Stable key for API / widgets (e.g. `support`, `sales`). */\r\n @Column('varchar')\r\n slug: string;\r\n\r\n /**\r\n * Logical role for this agent (`chatbot`, `blog_creation`, `social_media_post`, `email_intent_chatbot`, …).\r\n * At most one active row per scope; resolve agents by scope in application code.\r\n */\r\n @Column('varchar', { nullable: true })\r\n scope: string | null;\r\n\r\n /** Passed as `systemPrompt` to `LlmService.chatAgent`. */\r\n @Column('text', { name: 'system_instruction', default: '' })\r\n systemInstruction: string;\r\n\r\n @Column('varchar', { nullable: true })\r\n model: string | null;\r\n\r\n @Column('double precision', { name: 'temperature', nullable: true })\r\n temperature: number | null;\r\n\r\n @Column('int', { name: 'max_tokens', nullable: true })\r\n maxTokens: number | null;\r\n\r\n /**\r\n * Rules string: plain prose → appended to system prompt as output guardrails; JSON → see `parseLlmAgentValidationRules` in cms-handlers\r\n * (structural checks + optional `guardrails` / `outputRules` / `outputInstructions` for the model).\r\n */\r\n @Column('text', { name: 'validation_rules', nullable: true })\r\n validationRules: string | null;\r\n\r\n @Column('boolean', { default: true })\r\n enabled: boolean;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n}\r\n\r\n/** Partial {@link LlmAgentOptions} for merging with `userPrompt` / `history` / `context`. */\r\nexport function llmAgentToChatAgentOptions(\r\n agent: LlmAgent\r\n): Pick<LlmAgentOptions, 'systemPrompt' | 'model' | 'temperature' | 'max_tokens'> {\r\n return {\r\n systemPrompt: agent.systemInstruction?.trim() || undefined,\r\n model: agent.model?.trim() || undefined,\r\n temperature: agent.temperature ?? undefined,\r\n max_tokens: agent.maxTokens ?? undefined,\r\n };\r\n}\r\n","import type { DataSource, EntityManager, EntityTarget, ObjectLiteral, Repository } from 'typeorm';\r\nimport type { BlogGeneratorBlogDraft } from './blog-generator-service';\r\n\r\nexport interface BlogGeneratorPersistEntityMap {\r\n blogs: EntityTarget<ObjectLiteral>;\r\n tags: EntityTarget<ObjectLiteral>;\r\n categories: EntityTarget<ObjectLiteral>;\r\n seos: EntityTarget<ObjectLiteral>;\r\n}\r\n\r\nfunction slugBase(draft: BlogGeneratorBlogDraft): string {\r\n const raw = (draft.slug?.trim() || draft.title || 'post')\r\n .toLowerCase()\r\n .replace(/[^a-z0-9]+/g, '-')\r\n .replace(/^-+|-+$/g, '')\r\n .slice(0, 100);\r\n return raw || 'post';\r\n}\r\n\r\nfunction normalizeSlugSegment(input: string): string {\r\n const t = input.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 100);\r\n return t || 'post';\r\n}\r\n\r\n/** Unique among all rows (including soft-deleted) so DB unique constraints never collide. */\r\nasync function allocateUniqueSlug(repo: Repository<ObjectLiteral>, base: string): Promise<string> {\r\n let b = normalizeSlugSegment(base);\r\n for (let i = 0; i < 120; i++) {\r\n const s = i === 0 ? b : `${b}-${i + 1}`.slice(0, 160);\r\n const exists = await repo.findOne({ where: { slug: s } as object });\r\n if (!exists) return s;\r\n }\r\n throw new Error('Could not allocate a unique slug');\r\n}\r\n\r\nasync function findOrCreateTag(repo: Repository<ObjectLiteral>, name: string): Promise<ObjectLiteral> {\r\n const trimmed = name.trim().slice(0, 500);\r\n if (!trimmed) throw new Error('Empty tag name');\r\n let row = await repo.findOne({ where: { name: trimmed } as object });\r\n if (row && (row as { deleted?: boolean }).deleted) {\r\n await repo.update(\r\n { id: (row as { id: number }).id } as object,\r\n { deleted: false, updatedAt: new Date() } as object\r\n );\r\n row = await repo.findOne({ where: { id: (row as { id: number }).id } as object });\r\n return row!;\r\n }\r\n if (row) return row;\r\n const now = new Date();\r\n return repo.save(\r\n repo.create({\r\n name: trimmed,\r\n deleted: false,\r\n createdAt: now,\r\n updatedAt: now,\r\n } as object)\r\n );\r\n}\r\n\r\nasync function findOrCreateCategory(\r\n repo: Repository<ObjectLiteral>,\r\n displayName: string\r\n): Promise<ObjectLiteral | null> {\r\n const n = displayName.trim().slice(0, 500);\r\n if (!n) return null;\r\n let row = await repo\r\n .createQueryBuilder('c')\r\n .where('LOWER(TRIM(c.name)) = LOWER(TRIM(:n))', { n })\r\n .getOne();\r\n if (row && (row as { deleted?: boolean }).deleted) {\r\n await repo.update(\r\n { id: (row as { id: number }).id } as object,\r\n { deleted: false, updatedAt: new Date() } as object\r\n );\r\n row = await repo.findOne({ where: { id: (row as { id: number }).id } as object });\r\n return row!;\r\n }\r\n if (row) return row;\r\n const now = new Date();\r\n return repo.save(\r\n repo.create({\r\n name: n,\r\n deleted: false,\r\n createdAt: now,\r\n updatedAt: now,\r\n } as object)\r\n );\r\n}\r\n\r\n/**\r\n * Inserts SEO row, blog row, resolves/creates tags and optional category, links `blog_tags`.\r\n * Run inside a transaction (`manager`) for atomicity.\r\n */\r\nexport async function persistGeneratedBlogDraft(\r\n manager: EntityManager,\r\n maps: BlogGeneratorPersistEntityMap,\r\n params: { draft: BlogGeneratorBlogDraft; authorId: number }\r\n): Promise<{\r\n blogId: number;\r\n slug: string;\r\n categoryId: number | null;\r\n seoId: number;\r\n tagIds: number[];\r\n}> {\r\n const { draft, authorId } = params;\r\n const blogRepo = manager.getRepository(maps.blogs);\r\n const tagRepo = manager.getRepository(maps.tags);\r\n const catRepo = manager.getRepository(maps.categories);\r\n const seoRepo = manager.getRepository(maps.seos);\r\n\r\n const uniqueBlogSlug = await allocateUniqueSlug(blogRepo, slugBase(draft));\r\n const uniqueSeoSlug = await allocateUniqueSlug(seoRepo, uniqueBlogSlug);\r\n\r\n const seoRow = await seoRepo.save(\r\n seoRepo.create({\r\n slug: uniqueSeoSlug,\r\n title: draft.seo.title,\r\n description: draft.seo.description,\r\n keywords: draft.seo.keywords,\r\n ogTitle: draft.seo.ogTitle ?? draft.seo.title,\r\n ogDescription: draft.seo.ogDescription ?? draft.seo.description,\r\n ogImage: null,\r\n deleted: false,\r\n createdAt: new Date(),\r\n updatedAt: new Date(),\r\n } as object)\r\n );\r\n const seoId = Number((seoRow as { id: number }).id);\r\n\r\n let categoryId: number | null = null;\r\n if (draft.categoryName?.trim()) {\r\n const cat = await findOrCreateCategory(catRepo, draft.categoryName);\r\n if (cat) categoryId = Number((cat as { id: number }).id);\r\n }\r\n\r\n const tagEntities: ObjectLiteral[] = [];\r\n const seen = new Set<string>();\r\n for (const t of draft.tags ?? []) {\r\n const key = t.trim().toLowerCase();\r\n if (!key || seen.has(key)) continue;\r\n seen.add(key);\r\n tagEntities.push(await findOrCreateTag(tagRepo, t));\r\n }\r\n\r\n const socialTrim =\r\n typeof draft.socialMediaContent === 'string' && draft.socialMediaContent.trim()\r\n ? draft.socialMediaContent.trim().slice(0, 2900)\r\n : null;\r\n\r\n const now = new Date();\r\n const blogRow = await blogRepo.save(\r\n blogRepo.create({\r\n title: draft.title.trim().slice(0, 500) || 'Untitled',\r\n content: draft.markdown,\r\n socialMediaContent: socialTrim,\r\n slug: uniqueBlogSlug,\r\n authorId,\r\n categoryId,\r\n seoId,\r\n published: false,\r\n deleted: false,\r\n coverImage: null,\r\n createdBy: authorId,\r\n updatedBy: authorId,\r\n createdAt: now,\r\n updatedAt: now,\r\n } as object)\r\n );\r\n const blogId = Number((blogRow as { id: number }).id);\r\n\r\n if (tagEntities.length > 0) {\r\n const blog = await blogRepo.findOne({\r\n where: { id: blogId } as object,\r\n relations: ['tags'],\r\n });\r\n if (blog) {\r\n (blog as { tags: ObjectLiteral[] }).tags = tagEntities;\r\n await blogRepo.save(blog);\r\n }\r\n }\r\n\r\n const tagIds = tagEntities.map((e) => Number((e as { id: number }).id)).filter((id) => Number.isFinite(id));\r\n\r\n return { blogId, slug: uniqueBlogSlug, categoryId, seoId, tagIds };\r\n}\r\n\r\n/** Persist every draft; each draft runs in its own transaction. */\r\nexport async function persistAllGeneratedBlogDrafts(\r\n dataSource: DataSource,\r\n maps: BlogGeneratorPersistEntityMap,\r\n params: { drafts: BlogGeneratorBlogDraft[]; authorId: number }\r\n): Promise<\r\n Array<{\r\n blogId: number;\r\n slug: string;\r\n categoryId: number | null;\r\n seoId: number;\r\n tagIds: number[];\r\n }>\r\n> {\r\n const out: Array<{ blogId: number; slug: string; categoryId: number | null; seoId: number; tagIds: number[] }> = [];\r\n for (const draft of params.drafts) {\r\n const row = await dataSource.transaction((manager) =>\r\n persistGeneratedBlogDraft(manager, maps, { draft, authorId: params.authorId })\r\n );\r\n out.push(row);\r\n }\r\n return out;\r\n}\r\n","import type { DataSource, EntityTarget } from 'typeorm';\r\nimport type { RssFeed } from '../entities/rss-feed.entity';\r\nimport type { RssArticle } from '../entities/rss-article.entity';\r\n\r\nexport function deriveRssFeedDisplayName(rssUrl: string): string {\r\n try {\r\n const u = new URL(rssUrl);\r\n const h = u.hostname.replace(/^www\\./i, '');\r\n return (h || rssUrl).slice(0, 500);\r\n } catch {\r\n return rssUrl.slice(0, 500);\r\n }\r\n}\r\n\r\nexport async function upsertRssFeedRow(\r\n dataSource: DataSource,\r\n feedEntity: EntityTarget<RssFeed>,\r\n rssUrl: string,\r\n opts?: { name?: string; websiteUrl?: string | null }\r\n): Promise<RssFeed> {\r\n const repo = dataSource.getRepository(feedEntity);\r\n const trimmed = rssUrl.trim();\r\n const name = (opts?.name?.trim() || deriveRssFeedDisplayName(trimmed)).slice(0, 500);\r\n let row = await repo.findOne({ where: { rssUrl: trimmed } });\r\n if (!row) {\r\n row = repo.create({\r\n name,\r\n rssUrl: trimmed,\r\n websiteUrl: opts?.websiteUrl?.trim() || null,\r\n isActive: true,\r\n fetchFrequencyMinutes: 60,\r\n });\r\n } else {\r\n row.name = name;\r\n if (opts?.websiteUrl !== undefined) {\r\n row.websiteUrl = opts.websiteUrl?.trim() || null;\r\n }\r\n row.updatedAt = new Date();\r\n }\r\n return repo.save(row);\r\n}\r\n\r\nexport async function recordRssFetchSuccess(\r\n dataSource: DataSource,\r\n feedEntity: EntityTarget<RssFeed>,\r\n articleEntity: EntityTarget<RssArticle> | undefined,\r\n rssUrl: string,\r\n latest: {\r\n title?: string;\r\n link?: string;\r\n summary?: string;\r\n content?: string;\r\n creator?: string;\r\n date: Date;\r\n } | null\r\n): Promise<void> {\r\n const feedRepo = dataSource.getRepository(feedEntity);\r\n const row = await feedRepo.findOne({ where: { rssUrl: rssUrl.trim() } });\r\n if (!row) return;\r\n row.lastFetchedAt = new Date();\r\n if (latest?.date) {\r\n row.lastArticleDate = latest.date;\r\n }\r\n row.updatedAt = new Date();\r\n await feedRepo.save(row);\r\n\r\n const articleUrl = latest?.link?.trim();\r\n if (!latest || !articleUrl || !articleEntity) return;\r\n\r\n const artRepo = dataSource.getRepository(articleEntity);\r\n await artRepo.upsert(\r\n {\r\n rssFeedId: row.id,\r\n externalId: articleUrl.slice(0, 2000),\r\n title: (latest.title?.trim() || 'Untitled').slice(0, 2000),\r\n articleUrl: articleUrl.slice(0, 2000),\r\n summary: latest.summary?.trim() ? latest.summary.trim().slice(0, 100000) : null,\r\n content: latest.content?.trim() ? latest.content.trim().slice(0, 500000) : null,\r\n author: latest.creator?.trim() ? latest.creator.trim().slice(0, 500) : null,\r\n publishedAt: latest.date,\r\n imageUrl: null,\r\n rawData: { source: 'blog-generator-latest', rssUrl: rssUrl.trim() },\r\n contentHash: null,\r\n isProcessed: false,\r\n },\r\n { conflictPaths: ['rssFeedId', 'articleUrl'], skipUpdateIfNoValuesChanged: false }\r\n );\r\n}\r\n\r\nexport function serializeRssFeed(f: RssFeed) {\r\n return {\r\n id: f.id,\r\n name: f.name,\r\n rssUrl: f.rssUrl,\r\n websiteUrl: f.websiteUrl,\r\n isActive: f.isActive,\r\n fetchFrequencyMinutes: f.fetchFrequencyMinutes,\r\n lastFetchedAt: f.lastFetchedAt?.toISOString() ?? null,\r\n lastArticleDate: f.lastArticleDate?.toISOString() ?? null,\r\n createdAt: f.createdAt.toISOString(),\r\n updatedAt: f.updatedAt.toISOString(),\r\n };\r\n}\r\n","import type { JobSchedule } from '../../entities/job-schedule.entity';\r\n\r\nexport function pgBossScheduleNameForId(scheduleId: string): string {\r\n return `schedule:${scheduleId}`;\r\n}\r\n\r\nexport function buildCronFromSchedule(schedule: Pick<\r\n JobSchedule,\r\n 'scheduleMode' | 'intervalMinutes' | 'runAtTime' | 'runOnDays' | 'cronExpression'\r\n>): string {\r\n if (schedule.scheduleMode === 'cron' && schedule.cronExpression?.trim()) {\r\n return schedule.cronExpression.trim();\r\n }\r\n\r\n const time = parseRunAtTime(schedule.runAtTime);\r\n const minute = time?.minute ?? 0;\r\n const hour = time?.hour ?? 9;\r\n\r\n if (schedule.scheduleMode === 'interval') {\r\n const mins = schedule.intervalMinutes ?? 60;\r\n if (mins >= 60 && mins % 60 === 0) {\r\n const h = Math.max(1, Math.min(23, Math.floor(mins / 60)));\r\n if (h === 1) return `${minute} * * * *`;\r\n return `${minute} */${h} * * *`;\r\n }\r\n if (mins <= 59) {\r\n return `*/${Math.max(1, mins)} * * * *`;\r\n }\r\n return `${minute} * * * *`;\r\n }\r\n\r\n if (schedule.scheduleMode === 'weekly') {\r\n const days = Array.isArray(schedule.runOnDays) && schedule.runOnDays.length > 0\r\n ? schedule.runOnDays.filter((d) => d >= 0 && d <= 6).join(',')\r\n : '1';\r\n return `${minute} ${hour} * * ${days}`;\r\n }\r\n\r\n // daily (default)\r\n return `${minute} ${hour} * * *`;\r\n}\r\n\r\nfunction parseRunAtTime(runAtTime: string | null): { hour: number; minute: number } | null {\r\n if (!runAtTime?.trim()) return null;\r\n const m = runAtTime.trim().match(/^(\\d{1,2}):(\\d{2})$/);\r\n if (!m) return null;\r\n const hour = parseInt(m[1]!, 10);\r\n const minute = parseInt(m[2]!, 10);\r\n if (hour < 0 || hour > 23 || minute < 0 || minute > 59) return null;\r\n return { hour, minute };\r\n}\r\n\r\nexport function validateScheduleInput(schedule: Pick<\r\n JobSchedule,\r\n 'scheduleMode' | 'intervalMinutes' | 'runAtTime' | 'cronExpression'\r\n>): string | null {\r\n if (schedule.scheduleMode === 'cron') {\r\n if (!schedule.cronExpression?.trim()) return 'cronExpression is required for cron mode';\r\n return null;\r\n }\r\n if (schedule.scheduleMode === 'interval') {\r\n const mins = schedule.intervalMinutes;\r\n if (mins == null || !Number.isFinite(mins) || mins < 1 || mins > 10080) {\r\n return 'intervalMinutes must be between 1 and 10080';\r\n }\r\n return null;\r\n }\r\n if (schedule.runAtTime?.trim()) {\r\n if (!parseRunAtTime(schedule.runAtTime)) return 'runAtTime must be HH:mm (24h)';\r\n }\r\n return null;\r\n}\r\n","import type { JobSchedule } from '../../entities/job-schedule.entity';\r\nimport type { PgBossService } from '../pg-boss/pg-boss-service';\r\nimport type { JobRunnerPayload } from '../pg-boss/pg-boss-service';\r\nimport { buildCronFromSchedule } from './schedule-cron';\r\n\r\nexport interface CmsPgBossLike {\r\n getPlugin(name: string): unknown;\r\n}\r\n\r\nexport async function syncJobScheduleToPgBoss(\r\n cms: CmsPgBossLike,\r\n schedule: JobSchedule,\r\n onRegisterQueue?: (queueName: string) => Promise<void>\r\n): Promise<void> {\r\n const boss = cms.getPlugin('pg_boss') as PgBossService | undefined;\r\n if (!boss) return;\r\n\r\n const name = schedule.pgBossScheduleName;\r\n await boss.unschedule(name);\r\n\r\n if (!schedule.enabled) return;\r\n\r\n const cron = buildCronFromSchedule(schedule);\r\n const data: JobRunnerPayload = {\r\n scheduleId: schedule.id,\r\n triggeredBy: 'schedule',\r\n };\r\n await boss.schedule(name, cron, data, { tz: schedule.timezone || 'UTC' });\r\n\r\n if (onRegisterQueue) {\r\n await onRegisterQueue(name);\r\n }\r\n}\r\n\r\nexport async function queueJobScheduleNow(cms: CmsPgBossLike, scheduleId: string): Promise<void> {\r\n const boss = cms.getPlugin('pg_boss') as PgBossService | undefined;\r\n if (!boss) {\r\n throw new Error('pg-boss is not configured (DATABASE_URL required)');\r\n }\r\n const { JOB_RUNNER_QUEUE } = await import('../pg-boss/pg-boss-service');\r\n await boss.send(JOB_RUNNER_QUEUE, {\r\n scheduleId,\r\n triggeredBy: 'manual',\r\n } satisfies JobRunnerPayload);\r\n}\r\n","import { parseExpression } from 'cron-parser';\r\nimport type { JobSchedule } from '../../entities/job-schedule.entity';\r\nimport { buildCronFromSchedule } from './schedule-cron';\r\n\r\nexport type ScheduleNextRunInput = Pick<\r\n JobSchedule,\r\n | 'enabled'\r\n | 'scheduleMode'\r\n | 'intervalMinutes'\r\n | 'runAtTime'\r\n | 'runOnDays'\r\n | 'cronExpression'\r\n | 'timezone'\r\n>;\r\n\r\n/** Next fire time from resolved cron + timezone (pg-boss does not expose this on schedules). */\r\nexport function computeNextRunAt(schedule: ScheduleNextRunInput, from = new Date()): Date | null {\r\n if (!schedule.enabled) return null;\r\n try {\r\n const cron = buildCronFromSchedule(schedule);\r\n const tz = schedule.timezone?.trim() || 'UTC';\r\n const interval = parseExpression(cron, {\r\n currentDate: from,\r\n tz,\r\n });\r\n return interval.next().toDate();\r\n } catch (err) {\r\n console.warn('[job-schedules] could not compute next run:', err);\r\n return null;\r\n }\r\n}\r\n","import { randomUUID } from 'crypto';\r\nimport type { DataSource, EntityTarget } from 'typeorm';\r\nimport type { EntityMap } from './crud';\r\nimport type { CmsGetter } from './cms-api-handler';\r\nimport { JobSchedule } from '../entities/job-schedule.entity';\r\nimport { JobScheduleRun } from '../entities/job-schedule-run.entity';\r\nimport {\r\n buildCronFromSchedule,\r\n pgBossScheduleNameForId,\r\n validateScheduleInput,\r\n} from '../plugins/jobs/schedule-cron';\r\nimport { syncJobScheduleToPgBoss, queueJobScheduleNow } from '../plugins/jobs/schedule-sync';\r\nimport { ensureScheduleQueueWorker } from '../plugins/jobs/job-runner';\r\nimport { computeNextRunAt } from '../plugins/jobs/schedule-next-run';\r\n\r\nexport interface JobScheduleApiConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n json: (body: unknown, init?: ResponseInit) => Response;\r\n requireAuth: (req: Request) => Promise<Response | null>;\r\n requireEntityPermission?: (\r\n req: Request,\r\n entity: string,\r\n action: 'read' | 'create' | 'update' | 'delete'\r\n ) => Promise<Response | null>;\r\n getCms?: CmsGetter;\r\n config?: Record<string, string>;\r\n}\r\n\r\nfunction serializeSchedule(s: JobSchedule) {\r\n return {\r\n id: s.id,\r\n name: s.name,\r\n jobType: s.jobType,\r\n enabled: s.enabled,\r\n scheduleMode: s.scheduleMode,\r\n intervalMinutes: s.intervalMinutes,\r\n runAtTime: s.runAtTime,\r\n runOnDays: s.runOnDays,\r\n timezone: s.timezone,\r\n cronExpression: s.cronExpression,\r\n cronResolved: buildCronFromSchedule(s),\r\n payload: s.payload ?? {},\r\n authorId: s.authorId,\r\n pgBossScheduleName: s.pgBossScheduleName,\r\n lastRunAt: s.lastRunAt?.toISOString() ?? null,\r\n lastRunStatus: s.lastRunStatus,\r\n lastRunError: s.lastRunError,\r\n nextRunAt: (computeNextRunAt(s) ?? s.nextRunAt)?.toISOString() ?? null,\r\n createdAt: s.createdAt.toISOString(),\r\n updatedAt: s.updatedAt.toISOString(),\r\n };\r\n}\r\n\r\nfunction serializeRun(r: JobScheduleRun) {\r\n return {\r\n id: r.id,\r\n scheduleId: r.scheduleId,\r\n startedAt: r.startedAt.toISOString(),\r\n finishedAt: r.finishedAt?.toISOString() ?? null,\r\n status: r.status,\r\n error: r.error,\r\n result: r.result,\r\n triggeredBy: r.triggeredBy,\r\n createdAt: r.createdAt.toISOString(),\r\n };\r\n}\r\n\r\ntype ScheduleBody = {\r\n name?: unknown;\r\n jobType?: unknown;\r\n enabled?: unknown;\r\n scheduleMode?: unknown;\r\n intervalMinutes?: unknown;\r\n runAtTime?: unknown;\r\n runOnDays?: unknown;\r\n timezone?: unknown;\r\n cronExpression?: unknown;\r\n payload?: unknown;\r\n authorId?: unknown;\r\n};\r\n\r\nfunction parseScheduleBody(body: ScheduleBody, existing?: JobSchedule): Partial<JobSchedule> {\r\n const scheduleMode =\r\n typeof body.scheduleMode === 'string'\r\n ? (body.scheduleMode as JobSchedule['scheduleMode'])\r\n : existing?.scheduleMode ?? 'daily';\r\n\r\n const patch: Partial<JobSchedule> = {\r\n name: typeof body.name === 'string' ? body.name.trim().slice(0, 500) : existing?.name,\r\n jobType:\r\n body.jobType === 'blog_generate'\r\n ? 'blog_generate'\r\n : (existing?.jobType ?? 'blog_generate'),\r\n enabled: typeof body.enabled === 'boolean' ? body.enabled : existing?.enabled ?? false,\r\n scheduleMode,\r\n intervalMinutes:\r\n typeof body.intervalMinutes === 'number'\r\n ? body.intervalMinutes\r\n : body.intervalMinutes != null\r\n ? Number(body.intervalMinutes)\r\n : existing?.intervalMinutes ?? null,\r\n runAtTime:\r\n typeof body.runAtTime === 'string'\r\n ? body.runAtTime.trim() || null\r\n : body.runAtTime === null\r\n ? null\r\n : existing?.runAtTime ?? null,\r\n runOnDays: Array.isArray(body.runOnDays)\r\n ? body.runOnDays.map((d) => Number(d)).filter((d) => Number.isFinite(d))\r\n : existing?.runOnDays ?? null,\r\n timezone:\r\n typeof body.timezone === 'string' && body.timezone.trim()\r\n ? body.timezone.trim().slice(0, 64)\r\n : existing?.timezone ?? 'UTC',\r\n cronExpression:\r\n typeof body.cronExpression === 'string'\r\n ? body.cronExpression.trim() || null\r\n : existing?.cronExpression ?? null,\r\n payload:\r\n body.payload != null && typeof body.payload === 'object' && !Array.isArray(body.payload)\r\n ? (body.payload as Record<string, unknown>)\r\n : existing?.payload ?? {},\r\n authorId:\r\n typeof body.authorId === 'number'\r\n ? body.authorId\r\n : body.authorId != null\r\n ? Number(body.authorId)\r\n : existing?.authorId ?? null,\r\n };\r\n\r\n return patch;\r\n}\r\n\r\nexport function createJobScheduleHandlers(apiConfig: JobScheduleApiConfig) {\r\n const { dataSource, entityMap, json, requireAuth, requireEntityPermission, getCms } = apiConfig;\r\n\r\n const ScheduleEntity = (entityMap.job_schedules ?? JobSchedule) as EntityTarget<JobSchedule>;\r\n const RunEntity = (entityMap.job_schedule_runs ?? JobScheduleRun) as EntityTarget<JobScheduleRun>;\r\n\r\n async function perm(req: Request, action: 'read' | 'create' | 'update' | 'delete') {\r\n if (!requireEntityPermission) return null;\r\n return requireEntityPermission(req, 'blogs', action);\r\n }\r\n\r\n async function syncAfterSave(cms: Awaited<ReturnType<CmsGetter>>, schedule: JobSchedule) {\r\n await syncJobScheduleToPgBoss(cms, schedule, async (queueName) => {\r\n await ensureScheduleQueueWorker(cms, queueName);\r\n });\r\n const repo = dataSource.getRepository(ScheduleEntity);\r\n schedule.nextRunAt = computeNextRunAt(schedule);\r\n await repo.save(schedule);\r\n }\r\n\r\n return {\r\n async list(req: Request): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await perm(req, 'read');\r\n if (pe) return pe;\r\n const list = await dataSource.getRepository(ScheduleEntity).find({\r\n order: { updatedAt: 'DESC' },\r\n });\r\n return json({ schedules: list.map(serializeSchedule) });\r\n },\r\n\r\n async getById(req: Request, id: string): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await perm(req, 'read');\r\n if (pe) return pe;\r\n const row = await dataSource.getRepository(ScheduleEntity).findOne({ where: { id } as object });\r\n if (!row) return json({ error: 'Schedule not found' }, { status: 404 });\r\n const runs = await dataSource.getRepository(RunEntity).find({\r\n where: { scheduleId: id } as object,\r\n order: { startedAt: 'DESC' },\r\n take: 20,\r\n });\r\n return json({ schedule: serializeSchedule(row), runs: runs.map(serializeRun) });\r\n },\r\n\r\n async create(req: Request): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await perm(req, 'create');\r\n if (pe) return pe;\r\n if (!getCms) return json({ error: 'CMS not configured' }, { status: 503 });\r\n\r\n let body: ScheduleBody;\r\n try {\r\n body = (await req.json()) as ScheduleBody;\r\n } catch {\r\n return json({ error: 'Invalid JSON body' }, { status: 400 });\r\n }\r\n\r\n const patch = parseScheduleBody(body);\r\n if (!patch.name) return json({ error: 'name is required' }, { status: 400 });\r\n\r\n const draft = Object.assign(new JobSchedule(), patch);\r\n const validationError = validateScheduleInput(draft);\r\n if (validationError) return json({ error: validationError }, { status: 400 });\r\n\r\n const repo = dataSource.getRepository(ScheduleEntity);\r\n let row = repo.create({\r\n ...(patch as JobSchedule),\r\n pgBossScheduleName: `pending-${randomUUID()}`,\r\n });\r\n row = await repo.save(row);\r\n row.pgBossScheduleName = pgBossScheduleNameForId(row.id);\r\n row = await repo.save(row);\r\n\r\n const cms = await getCms();\r\n await syncAfterSave(cms, row);\r\n\r\n return json({ schedule: serializeSchedule(row) }, { status: 201 });\r\n },\r\n\r\n async update(req: Request, id: string): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await perm(req, 'update');\r\n if (pe) return pe;\r\n if (!getCms) return json({ error: 'CMS not configured' }, { status: 503 });\r\n\r\n const repo = dataSource.getRepository(ScheduleEntity);\r\n const existing = await repo.findOne({ where: { id } as object });\r\n if (!existing) return json({ error: 'Schedule not found' }, { status: 404 });\r\n\r\n let body: ScheduleBody;\r\n try {\r\n body = (await req.json()) as ScheduleBody;\r\n } catch {\r\n return json({ error: 'Invalid JSON body' }, { status: 400 });\r\n }\r\n\r\n const patch = parseScheduleBody(body, existing);\r\n Object.assign(existing, patch);\r\n const validationError = validateScheduleInput(existing);\r\n if (validationError) return json({ error: validationError }, { status: 400 });\r\n\r\n const row = await repo.save(existing);\r\n const cms = await getCms();\r\n await syncAfterSave(cms, row);\r\n\r\n return json({ schedule: serializeSchedule(row) });\r\n },\r\n\r\n async remove(req: Request, id: string): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await perm(req, 'delete');\r\n if (pe) return pe;\r\n if (!getCms) return json({ error: 'CMS not configured' }, { status: 503 });\r\n\r\n const repo = dataSource.getRepository(ScheduleEntity);\r\n const existing = await repo.findOne({ where: { id } as object });\r\n if (!existing) return json({ error: 'Schedule not found' }, { status: 404 });\r\n\r\n const cms = await getCms();\r\n existing.enabled = false;\r\n await syncJobScheduleToPgBoss(cms, existing);\r\n await repo.delete({ id });\r\n\r\n return json({ ok: true });\r\n },\r\n\r\n async runNow(req: Request, id: string): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await perm(req, 'create');\r\n if (pe) return pe;\r\n if (!getCms) return json({ error: 'CMS not configured' }, { status: 503 });\r\n\r\n const repo = dataSource.getRepository(ScheduleEntity);\r\n const existing = await repo.findOne({ where: { id } as object });\r\n if (!existing) return json({ error: 'Schedule not found' }, { status: 404 });\r\n\r\n try {\r\n const cms = await getCms();\r\n await queueJobScheduleNow(cms, id);\r\n return json({ ok: true, message: 'Job queued' });\r\n } catch (e) {\r\n const message = e instanceof Error ? e.message : 'Failed to queue job';\r\n return json({ error: message }, { status: 503 });\r\n }\r\n },\r\n\r\n async listRuns(req: Request, id: string): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await perm(req, 'read');\r\n if (pe) return pe;\r\n const runs = await dataSource.getRepository(RunEntity).find({\r\n where: { scheduleId: id } as object,\r\n order: { startedAt: 'DESC' },\r\n take: 50,\r\n });\r\n return json({ runs: runs.map(serializeRun) });\r\n },\r\n };\r\n}\r\n","export type CaptchaProviderId = 'turnstile' | 'recaptcha_v3';\r\n\r\nexport interface CaptchaPublicConfig {\r\n enabled: boolean;\r\n activeProvider: CaptchaProviderId | null;\r\n siteKey: string | null;\r\n availableProviders: Array<{ id: CaptchaProviderId; siteKey: string }>;\r\n multipleProviders: boolean;\r\n}\r\n\r\nexport type CaptchaVerifyResult =\r\n | { ok: true }\r\n | { ok: false; status: number; message: string };\r\n\r\ninterface ResolvedKeys {\r\n turnstile: { site: string; secret: string } | null;\r\n recaptcha: { site: string; secret: string } | null;\r\n /** When both providers configured, set only if CAPTCHA_PROVIDER env is set */\r\n envDefaultProvider: CaptchaProviderId | null;\r\n minScore: number;\r\n}\r\n\r\nfunction resolveKeys(config: Record<string, string>): ResolvedKeys {\r\n const turnstile =\r\n config.TURNSTILE_SITE_KEY?.trim() && config.TURNSTILE_SECRET_KEY?.trim()\r\n ? { site: config.TURNSTILE_SITE_KEY.trim(), secret: config.TURNSTILE_SECRET_KEY.trim() }\r\n : null;\r\n const recaptcha =\r\n config.RECAPTCHA_SITE_KEY?.trim() && config.RECAPTCHA_SECRET_KEY?.trim()\r\n ? { site: config.RECAPTCHA_SITE_KEY.trim(), secret: config.RECAPTCHA_SECRET_KEY.trim() }\r\n : null;\r\n const raw = config.CAPTCHA_PROVIDER?.trim().toLowerCase();\r\n let envDefaultProvider: CaptchaProviderId | null = null;\r\n if (raw === 'turnstile') envDefaultProvider = 'turnstile';\r\n else if (raw === 'recaptcha_v3' || raw === 'recaptcha') envDefaultProvider = 'recaptcha_v3';\r\n\r\n const minScore = parseFloat(config.RECAPTCHA_MIN_SCORE ?? '0.5');\r\n return {\r\n turnstile,\r\n recaptcha,\r\n envDefaultProvider,\r\n minScore: Number.isFinite(minScore) ? minScore : 0.5,\r\n };\r\n}\r\n\r\nexport function buildCaptchaPublicConfig(config: Record<string, string>): CaptchaPublicConfig {\r\n const r = resolveKeys(config);\r\n const available: Array<{ id: CaptchaProviderId; siteKey: string }> = [];\r\n if (r.turnstile) available.push({ id: 'turnstile', siteKey: r.turnstile.site });\r\n if (r.recaptcha) available.push({ id: 'recaptcha_v3', siteKey: r.recaptcha.site });\r\n const enabled = available.length > 0;\r\n const multipleProviders = available.length > 1;\r\n let activeProvider: CaptchaProviderId | null = null;\r\n if (r.turnstile && !r.recaptcha) activeProvider = 'turnstile';\r\n else if (r.recaptcha && !r.turnstile) activeProvider = 'recaptcha_v3';\r\n else if (multipleProviders) {\r\n activeProvider = r.envDefaultProvider ?? available[0]!.id;\r\n }\r\n let siteKey: string | null = null;\r\n if (activeProvider === 'turnstile' && r.turnstile) siteKey = r.turnstile.site;\r\n else if (activeProvider === 'recaptcha_v3' && r.recaptcha) siteKey = r.recaptcha.site;\r\n if (!siteKey && available.length === 1) siteKey = available[0]!.siteKey;\r\n return {\r\n enabled,\r\n activeProvider,\r\n siteKey,\r\n availableProviders: available,\r\n multipleProviders,\r\n };\r\n}\r\n\r\nfunction clientIp(req: Request): string | undefined {\r\n const cf = req.headers.get('cf-connecting-ip')?.trim();\r\n if (cf) return cf;\r\n const xff = req.headers.get('x-forwarded-for')?.trim();\r\n if (xff) return xff.split(',')[0]!.trim();\r\n const real = req.headers.get('x-real-ip')?.trim();\r\n if (real) return real;\r\n return undefined;\r\n}\r\n\r\nfunction normalizeBodyProvider(v: unknown): CaptchaProviderId | null {\r\n if (v === 'turnstile') return 'turnstile';\r\n if (v === 'recaptcha_v3' || v === 'recaptcha') return 'recaptcha_v3';\r\n return null;\r\n}\r\n\r\nfunction pickVerifyProvider(\r\n body: Record<string, unknown>,\r\n r: ResolvedKeys\r\n): { provider: CaptchaProviderId; secret: string } | { error: string } {\r\n const bodyP = normalizeBodyProvider(body.captchaProvider);\r\n const hasT = !!r.turnstile;\r\n const hasR = !!r.recaptcha;\r\n\r\n if (hasT && !hasR) {\r\n if (bodyP && bodyP !== 'turnstile') return { error: 'Invalid captchaProvider' };\r\n return { provider: 'turnstile', secret: r.turnstile!.secret };\r\n }\r\n if (hasR && !hasT) {\r\n if (bodyP && bodyP !== 'recaptcha_v3') return { error: 'Invalid captchaProvider' };\r\n return { provider: 'recaptcha_v3', secret: r.recaptcha!.secret };\r\n }\r\n if (!hasT && !hasR) return { error: 'Captcha not configured' };\r\n\r\n if (bodyP === 'turnstile' && hasT) return { provider: 'turnstile', secret: r.turnstile!.secret };\r\n if (bodyP === 'recaptcha_v3' && hasR) return { provider: 'recaptcha_v3', secret: r.recaptcha!.secret };\r\n if (r.envDefaultProvider === 'turnstile' && hasT) return { provider: 'turnstile', secret: r.turnstile!.secret };\r\n if (r.envDefaultProvider === 'recaptcha_v3' && hasR) return { provider: 'recaptcha_v3', secret: r.recaptcha!.secret };\r\n return { error: 'captchaProvider required (turnstile or recaptcha_v3)' };\r\n}\r\n\r\nasync function verifyTurnstile(secret: string, token: string, remoteip?: string): Promise<boolean> {\r\n const body = new URLSearchParams({ secret, response: token });\r\n if (remoteip) body.set('remoteip', remoteip);\r\n const res = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\r\n body: body.toString(),\r\n });\r\n if (!res.ok) return false;\r\n const data = (await res.json()) as { success?: boolean };\r\n return data.success === true;\r\n}\r\n\r\nasync function verifyRecaptcha(\r\n secret: string,\r\n token: string,\r\n remoteip: string | undefined,\r\n minScore: number\r\n): Promise<{ ok: boolean; score?: number }> {\r\n const body = new URLSearchParams({ secret, response: token });\r\n if (remoteip) body.set('remoteip', remoteip);\r\n const res = await fetch('https://www.google.com/recaptcha/api/siteverify', {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\r\n body: body.toString(),\r\n });\r\n if (!res.ok) return { ok: false };\r\n const data = (await res.json()) as { success?: boolean; score?: number };\r\n if (data.success !== true) return { ok: false };\r\n const score = typeof data.score === 'number' ? data.score : 0;\r\n return { ok: score >= minScore, score };\r\n}\r\n\r\nexport class CaptchaService {\r\n constructor(private readonly env: Record<string, string>) {}\r\n\r\n isEnforced(): boolean {\r\n return buildCaptchaPublicConfig(this.env).enabled;\r\n }\r\n\r\n getPublicConfig(): CaptchaPublicConfig {\r\n return buildCaptchaPublicConfig(this.env);\r\n }\r\n\r\n async verify(body: Record<string, unknown>, req: Request): Promise<CaptchaVerifyResult> {\r\n if (!this.isEnforced()) return { ok: true };\r\n const token = typeof body.captchaToken === 'string' ? body.captchaToken.trim() : '';\r\n if (!token) return { ok: false, status: 400, message: 'captchaToken required' };\r\n\r\n const r = resolveKeys(this.env);\r\n const picked = pickVerifyProvider(body, r);\r\n if ('error' in picked) return { ok: false, status: 400, message: picked.error };\r\n\r\n const ip = clientIp(req);\r\n if (picked.provider === 'turnstile') {\r\n const ok = await verifyTurnstile(picked.secret, token, ip);\r\n if (!ok) return { ok: false, status: 400, message: 'Captcha verification failed' };\r\n return { ok: true };\r\n }\r\n const vr = await verifyRecaptcha(picked.secret, token, ip, r.minScore);\r\n if (!vr.ok) return { ok: false, status: 400, message: 'Captcha verification failed or score too low' };\r\n return { ok: true };\r\n }\r\n}\r\n","import type { CmsPlugin, PluginContext } from '../types';\r\nimport { CaptchaService } from './captcha-service';\r\n\r\nexport function captchaPlugin(): CmsPlugin<CaptchaService | void> {\r\n return {\r\n name: 'captcha',\r\n version: '1.0.0',\r\n async init(ctx: PluginContext) {\r\n const s = new CaptchaService(ctx.config);\r\n return s.isEnforced() ? s : undefined;\r\n },\r\n };\r\n}\r\n","import type { CaptchaService } from './captcha-service';\r\n\r\ntype JsonResponse = (body: unknown, init?: { status?: number; headers?: HeadersInit }) => Response;\r\n\r\nexport async function assertCaptchaOk(\r\n getCms: (() => Promise<{ getPlugin: (name: string) => unknown }>) | undefined,\r\n body: Record<string, unknown>,\r\n req: Request,\r\n json: JsonResponse\r\n): Promise<Response | null> {\r\n if (!getCms) return null;\r\n let cms: { getPlugin: (name: string) => unknown };\r\n try {\r\n cms = await getCms();\r\n } catch {\r\n return null;\r\n }\r\n const svc = cms.getPlugin('captcha') as CaptchaService | undefined;\r\n if (!svc || typeof (svc as CaptchaService).verify !== 'function') return null;\r\n const result = await svc.verify(body, req);\r\n if (result.ok) return null;\r\n return json({ error: result.message }, { status: result.status });\r\n}\r\n","/// <reference path=\"./rss-parser.d.ts\" />\r\n\r\nimport Parser from 'rss-parser';\r\nimport type { LlmServiceInterface, LlmAgentOptions } from '../llm/llm-service';\r\nimport {\r\n mergeGuardrailsIntoSystemPrompt,\r\n parseLlmAgentValidationRules,\r\n validateUserMessageAgainstStructuredRules,\r\n} from '../../api/cms-handlers';\r\nimport {\r\n BLOG_GENERATOR_AGENT_NAME,\r\n BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION,\r\n BLOG_GENERATOR_DEFAULT_VALIDATION_RULES,\r\n BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR,\r\n} from './blog-generator-agent-defaults';\r\nimport {\r\n BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION,\r\n BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES,\r\n} from './blog-generator-metadata-defaults';\r\nimport {\r\n BLOG_SOCIAL_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION,\r\n BLOG_SOCIAL_ENRICHER_DEFAULT_VALIDATION_RULES,\r\n} from './blog-generator-social-defaults';\r\n\r\n/**\r\n * Keep parser configuration SIMPLE initially.\r\n * The default parser behavior works best for most feeds.\r\n */\r\nconst parser = new Parser({\r\n defaultRSS: 2,\r\n});\r\n\r\nexport interface LatestArticleFromFeed {\r\n title?: string;\r\n link?: string;\r\n\r\n /** Short excerpt */\r\n summary?: string;\r\n\r\n /** Full content if available */\r\n content?: string;\r\n\r\n date: Date;\r\n\r\n creator?: string;\r\n\r\n categories?: string[];\r\n}\r\n\r\ntype RssItem = {\r\n title?: string;\r\n link?: string;\r\n\r\n pubDate?: string;\r\n isoDate?: string;\r\n\r\n contentSnippet?: string;\r\n summary?: string;\r\n description?: string;\r\n\r\n content?: string;\r\n\r\n creator?: string;\r\n 'dc:creator'?: string;\r\n\r\n 'content:encoded'?: string;\r\n\r\n categories?: string[];\r\n\r\n guid?: string | { _: string };\r\n};\r\n\r\nfunction asString(v: unknown): string {\r\n return typeof v === 'string' ? v : '';\r\n}\r\n\r\nfunction trimOrUndefined(\r\n s: string\r\n): string | undefined {\r\n\r\n const t = s.trim();\r\n\r\n return t === ''\r\n ? undefined\r\n : t;\r\n}\r\n\r\nfunction normalizeLink(\r\n item: RssItem\r\n): string | undefined {\r\n\r\n const l = item.link;\r\n\r\n return typeof l === 'string' &&\r\n l.trim() !== ''\r\n ? l\r\n : undefined;\r\n}\r\n\r\nfunction stripLeadingBom(\r\n body: string\r\n): string {\r\n\r\n if (body.charCodeAt(0) === 0xfeff) {\r\n return body.slice(1);\r\n }\r\n\r\n return body;\r\n}\r\n\r\nfunction looksLikeHtmlNotFeed(\r\n body: string\r\n): boolean {\r\n\r\n const head =\r\n body\r\n .slice(0, 800)\r\n .trimStart()\r\n .toLowerCase();\r\n\r\n return (\r\n head.startsWith('<!doctype html') ||\r\n head.startsWith('<html') ||\r\n\r\n (\r\n head.startsWith('<') &&\r\n /<head[\\s>]|<body[\\s>]/.test(head) &&\r\n !/<rss[\\s>]|<feed[\\s>]/.test(head)\r\n )\r\n );\r\n}\r\n\r\nexport function getRssArticleSummaryFromItem(\r\n item: RssItem\r\n): {\r\n summary: string;\r\n fullContent: string;\r\n} {\r\n\r\n const encoded =\r\n item['content:encoded'];\r\n\r\n const encodedStr =\r\n asString(encoded);\r\n\r\n const summary =\r\n\r\n asString(item.contentSnippet) ||\r\n\r\n asString(item.summary) ||\r\n\r\n asString(item.description) ||\r\n\r\n '';\r\n\r\n /** Prefer `content:encoded` — `rss-parser` maps `<description>` onto `content`, which is often only the teaser. */\r\n const fullContent =\r\n encodedStr ||\r\n asString(item.content) ||\r\n asString(item.description) ||\r\n '';\r\n\r\n return {\r\n summary,\r\n fullContent,\r\n };\r\n}\r\n\r\nexport type BlogGeneratorDraftParseMode = 'json' | 'plaintext';\r\n\r\nexport interface BlogGeneratorSeoDraft {\r\n title: string | null;\r\n description: string | null;\r\n keywords: string | null;\r\n ogTitle: string | null;\r\n ogDescription: string | null;\r\n}\r\n\r\nexport interface BlogGeneratorBlogDraft {\r\n title: string;\r\n slug?: string;\r\n markdown: string;\r\n /** Short plain-text copy for social (e.g. LinkedIn); optional until social LLM step runs. */\r\n socialMediaContent?: string | null;\r\n categoryName: string | null;\r\n seo: BlogGeneratorSeoDraft;\r\n /** Suggested tag labels (may not exist in CMS yet). */\r\n tags: string[];\r\n parseMode: BlogGeneratorDraftParseMode;\r\n}\r\n\r\nfunction emptySeoDraft(): BlogGeneratorSeoDraft {\r\n return {\r\n title: null,\r\n description: null,\r\n keywords: null,\r\n ogTitle: null,\r\n ogDescription: null,\r\n };\r\n}\r\n\r\nfunction parseTagsField(v: unknown): string[] {\r\n if (!Array.isArray(v)) return [];\r\n const out = v\r\n .map((x) => String(x).trim())\r\n .filter(Boolean)\r\n .map((s) => s.slice(0, 80));\r\n return [...new Set(out)].slice(0, 16);\r\n}\r\n\r\nfunction mergeSeoDraft(base: BlogGeneratorSeoDraft, patch: BlogGeneratorSeoDraft): BlogGeneratorSeoDraft {\r\n return {\r\n title: patch.title ?? base.title,\r\n description: patch.description ?? base.description,\r\n keywords: patch.keywords ?? base.keywords,\r\n ogTitle: patch.ogTitle ?? base.ogTitle,\r\n ogDescription: patch.ogDescription ?? base.ogDescription,\r\n };\r\n}\r\n\r\nfunction normSeoString(v: unknown): string | null {\r\n if (v == null) return null;\r\n if (Array.isArray(v)) {\r\n const s = v\r\n .map((x) => String(x).trim())\r\n .filter(Boolean)\r\n .join(', ');\r\n return s || null;\r\n }\r\n const s = String(v).trim();\r\n return s || null;\r\n}\r\n\r\nfunction stripInnerHtmlToText(html: string): string {\r\n return html.replace(/<[^>]+>/g, '').replace(/\\s+/g, ' ').trim();\r\n}\r\n\r\nfunction extractTitleFromHtml(html: string): string | null {\r\n const s = html.trim();\r\n const h1 = /<h1\\b[^>]*>([\\s\\S]*?)<\\/h1>/i.exec(s);\r\n if (h1) {\r\n const t = stripInnerHtmlToText(h1[1] ?? '');\r\n if (t) return t;\r\n }\r\n const h2 = /<h2\\b[^>]*>([\\s\\S]*?)<\\/h2>/i.exec(s);\r\n if (h2) {\r\n const t = stripInnerHtmlToText(h2[1] ?? '');\r\n if (t) return t;\r\n }\r\n return null;\r\n}\r\n\r\nfunction extractTitleFromMarkdown(md: string): string | null {\r\n for (const line of md.split(/\\r?\\n/)) {\r\n const t = line.trim();\r\n const m = /^(#{1,6})\\s+(.+)$/.exec(t);\r\n if (!m) continue;\r\n let title = m[2]!.trim();\r\n title = title.replace(/\\s+#+\\s*$/, '').trim();\r\n if (title) return title;\r\n }\r\n return null;\r\n}\r\n\r\n/** Prefer HTML headings; fall back to ATX markdown for legacy drafts. */\r\nfunction extractTitleFromBlogBody(body: string): string | null {\r\n return extractTitleFromHtml(body) ?? extractTitleFromMarkdown(body);\r\n}\r\n\r\nfunction stripLeadingCodeFence(text: string): string {\r\n let t = text.trim();\r\n if (!t.startsWith('```')) return t;\r\n const firstNl = t.indexOf('\\n');\r\n if (firstNl === -1) return t;\r\n t = t.slice(firstNl + 1);\r\n if (t.endsWith('```')) t = t.slice(0, -3);\r\n return t.trim();\r\n}\r\n\r\n/**\r\n * Parses the LLM reply: prefers a single JSON object with blogTitle, blogHtml/blogMarkdown/content, categoryName, seo, …\r\n * Falls back to treating the entire string as HTML (or legacy markdown) if JSON parsing fails.\r\n */\r\nexport function parseBlogGeneratorAgentContent(raw: string): BlogGeneratorBlogDraft {\r\n const trimmed = raw.trim();\r\n if (!trimmed) {\r\n return {\r\n title: 'Untitled draft',\r\n markdown: '',\r\n categoryName: null,\r\n seo: emptySeoDraft(),\r\n tags: [],\r\n parseMode: 'plaintext',\r\n };\r\n }\r\n\r\n const jsonCandidate = stripLeadingCodeFence(trimmed);\r\n\r\n try {\r\n const data = JSON.parse(jsonCandidate) as Record<string, unknown>;\r\n if (data && typeof data === 'object' && !Array.isArray(data)) {\r\n const markdown = String(\r\n data.blogHtml ?? data.blogMarkdown ?? data.markdown ?? data.content ?? ''\r\n ).trim();\r\n const titleRaw = String(data.blogTitle ?? data.title ?? '').trim();\r\n const title = titleRaw || extractTitleFromBlogBody(markdown) || 'Untitled draft';\r\n const slugRaw =\r\n typeof data.blogSlug === 'string'\r\n ? data.blogSlug.trim()\r\n : typeof data.slug === 'string'\r\n ? data.slug.trim()\r\n : '';\r\n const slug = slugRaw === '' ? undefined : slugRaw;\r\n const categoryName = typeof data.categoryName === 'string' ? data.categoryName.trim() || null : null;\r\n\r\n const seoRaw = data.seo;\r\n const seoObj =\r\n seoRaw && typeof seoRaw === 'object' && !Array.isArray(seoRaw) ? (seoRaw as Record<string, unknown>) : {};\r\n const seo: BlogGeneratorSeoDraft = {\r\n title: normSeoString(seoObj.title),\r\n description: normSeoString(seoObj.description),\r\n keywords: normSeoString(seoObj.keywords),\r\n ogTitle: normSeoString(seoObj.ogTitle ?? seoObj.og_title),\r\n ogDescription: normSeoString(seoObj.ogDescription ?? seoObj.og_description),\r\n };\r\n\r\n if (markdown) {\r\n return {\r\n title,\r\n slug,\r\n markdown,\r\n categoryName,\r\n seo,\r\n tags: parseTagsField(data.tags),\r\n parseMode: 'json',\r\n };\r\n }\r\n }\r\n } catch {\r\n /* plaintext fallback below */\r\n }\r\n\r\n const title = extractTitleFromBlogBody(trimmed) ?? 'Untitled draft';\r\n return {\r\n title,\r\n markdown: trimmed,\r\n categoryName: null,\r\n seo: emptySeoDraft(),\r\n tags: [],\r\n parseMode: 'plaintext',\r\n };\r\n}\r\n\r\nexport function resolveBlogCategoryIdByName(\r\n needle: string | null | undefined,\r\n rows: readonly { id: number; name: string }[]\r\n): { categoryId: number | null; matched: boolean } {\r\n if (!needle?.trim()) return { categoryId: null, matched: false };\r\n const n = needle.trim().toLowerCase();\r\n const hit = rows.find((r) => r.name.trim().toLowerCase() === n);\r\n return hit ? { categoryId: hit.id, matched: true } : { categoryId: null, matched: false };\r\n}\r\n\r\nfunction formatOneFeedBlock(rssUrl: string, article: LatestArticleFromFeed): string {\r\n const title = article.title ?? '';\r\n const link = article.link ?? '';\r\n const dateIso =\r\n article.date instanceof Date && !Number.isNaN(article.date.getTime()) ? article.date.toISOString() : '';\r\n const summary = article.summary ?? '';\r\n const body = article.content ?? '';\r\n return `FEED_URL:\r\n${rssUrl}\r\n\r\nTITLE:\r\n${title}\r\n\r\nLINK:\r\n${link}\r\n\r\nPUBLISHED (ISO):\r\n${dateIso}\r\n\r\nEXCERPT / SUMMARY:\r\n${summary}\r\n\r\nFULL SOURCE (may contain HTML):\r\n${body}`;\r\n}\r\n\r\n/**\r\n * Minimal user payload: latest item per feed only (system prompt carries writing rules).\r\n */\r\nexport function buildRssUserPromptFromFeeds(feeds: ReadonlyArray<{ rssUrl: string; article: LatestArticleFromFeed }>): string {\r\n const blocks = feeds.map((f) => formatOneFeedBlock(f.rssUrl, f.article));\r\n return `Latest item from each feed (factual source only):\r\n\r\n${blocks.join('\\n\\n------------------------------\\n\\n')}`;\r\n}\r\n\r\n/**\r\n * User message for the metadata-only LLM step (one blog at a time).\r\n */\r\nexport function buildBlogMetadataUserPrompt(opts: {\r\n title: string;\r\n markdown: string;\r\n categoryNames: readonly string[];\r\n tagNames: readonly string[];\r\n}): string {\r\n const catBlock =\r\n opts.categoryNames.length === 0\r\n ? 'AVAILABLE_BLOG_CATEGORIES: (none — use empty string for categoryName).'\r\n : `AVAILABLE_BLOG_CATEGORIES (categoryName must be exactly one of these strings, or \"\"):\\n${opts.categoryNames.map((n) => `- ${n}`).join('\\n')}`;\r\n const tagBlock =\r\n opts.tagNames.length === 0\r\n ? 'EXISTING_TAG_NAMES: (none — propose new short tag strings).'\r\n : `EXISTING_TAG_NAMES (prefer reusing these exact strings when they fit):\\n${opts.tagNames.map((n) => `- ${n}`).join('\\n')}`;\r\n return `${catBlock}\r\n\r\n${tagBlock}\r\n\r\nBLOG_TITLE:\r\n${opts.title}\r\n\r\nBLOG_HTML:\r\n${opts.markdown}`;\r\n}\r\n\r\n/** Parses JSON from the metadata-enrichment LLM (category, slug, seo, tags). */\r\nexport function parseBlogMetadataEnrichmentJson(raw: string): {\r\n categoryName: string | null;\r\n blogSlug: string | null;\r\n seo: BlogGeneratorSeoDraft;\r\n tags: string[];\r\n} {\r\n const trimmed = raw.trim();\r\n if (!trimmed) {\r\n throw new Error('Metadata LLM returned empty content.');\r\n }\r\n const candidate = stripLeadingCodeFence(trimmed);\r\n let data: Record<string, unknown>;\r\n try {\r\n data = JSON.parse(candidate) as Record<string, unknown>;\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n throw new Error(`Metadata LLM JSON parse failed: ${msg}`);\r\n }\r\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\r\n throw new Error('Metadata LLM returned invalid JSON root.');\r\n }\r\n const categoryName =\r\n typeof data.categoryName === 'string' ? data.categoryName.trim() || null : null;\r\n const blogSlugRaw = typeof data.blogSlug === 'string' ? data.blogSlug.trim() : '';\r\n const blogSlug = blogSlugRaw === '' ? null : blogSlugRaw;\r\n const seoRaw = data.seo;\r\n const seoObj =\r\n seoRaw && typeof seoRaw === 'object' && !Array.isArray(seoRaw) ? (seoRaw as Record<string, unknown>) : {};\r\n const seo: BlogGeneratorSeoDraft = {\r\n title: normSeoString(seoObj.title),\r\n description: normSeoString(seoObj.description),\r\n keywords: normSeoString(seoObj.keywords),\r\n ogTitle: normSeoString(seoObj.ogTitle ?? seoObj.og_title),\r\n ogDescription: normSeoString(seoObj.ogDescription ?? seoObj.og_description),\r\n };\r\n const tags = parseTagsField(data.tags);\r\n return { categoryName, blogSlug, seo, tags };\r\n}\r\n\r\n/** User message for the social-summary LLM step (one blog at a time). */\r\nexport function buildBlogSocialUserPrompt(opts: { title: string; markdown: string }): string {\r\n const md =\r\n opts.markdown.length > 120000 ? `${opts.markdown.slice(0, 120000)}\\n…(truncated)` : opts.markdown;\r\n return `BLOG_TITLE:\\n${opts.title}\\n\\nBODY_HTML_OR_MARKDOWN:\\n${md}`;\r\n}\r\n\r\n/** Parses JSON from the social LLM: `{ \"socialMediaContent\": \"...\" }`. */\r\nexport function parseBlogSocialEnrichmentJson(raw: string): { socialMediaContent: string } {\r\n const trimmed = raw.trim();\r\n if (!trimmed) {\r\n throw new Error('Social LLM returned empty content.');\r\n }\r\n const candidate = stripLeadingCodeFence(trimmed);\r\n let data: Record<string, unknown>;\r\n try {\r\n data = JSON.parse(candidate) as Record<string, unknown>;\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n throw new Error(`Social LLM JSON parse failed: ${msg}`);\r\n }\r\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\r\n throw new Error('Social LLM returned invalid JSON root.');\r\n }\r\n const s = typeof data.socialMediaContent === 'string' ? data.socialMediaContent.trim() : '';\r\n if (!s) {\r\n throw new Error('Social LLM JSON missing socialMediaContent string.');\r\n }\r\n return { socialMediaContent: s.slice(0, 2900) };\r\n}\r\n\r\nfunction splitMarkdownArticles(raw: string): string[] {\r\n const sep = BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR;\r\n const lines = raw.split(/\\r?\\n/);\r\n const chunks: string[] = [];\r\n let buf: string[] = [];\r\n for (const line of lines) {\r\n if (line.trim() === sep) {\r\n const piece = buf.join('\\n').trim();\r\n if (piece) chunks.push(piece);\r\n buf = [];\r\n } else {\r\n buf.push(line);\r\n }\r\n }\r\n const last = buf.join('\\n').trim();\r\n if (last) chunks.push(last);\r\n return chunks.length > 0 ? chunks : [raw.trim()].filter(Boolean);\r\n}\r\n\r\n/**\r\n * Parses LLM output: prefers HTML + {@link BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR} for multiple articles.\r\n * If the model still returns legacy JSON with `blogHtml` / `blogMarkdown`, returns a single draft from that object.\r\n */\r\nexport function parseBlogGeneratorModelOutput(raw: string): BlogGeneratorBlogDraft[] {\r\n const trimmed = raw.trim();\r\n if (!trimmed) {\r\n return [\r\n {\r\n title: 'Untitled draft',\r\n markdown: '',\r\n categoryName: null,\r\n seo: emptySeoDraft(),\r\n tags: [],\r\n parseMode: 'plaintext',\r\n },\r\n ];\r\n }\r\n\r\n const jsonTry = parseBlogGeneratorAgentContent(trimmed);\r\n if (jsonTry.parseMode === 'json' && jsonTry.markdown.trim()) {\r\n return [jsonTry];\r\n }\r\n\r\n const parts = splitMarkdownArticles(trimmed);\r\n return parts.map((part) => {\r\n const t = part.trim();\r\n const title = extractTitleFromBlogBody(t) ?? 'Untitled draft';\r\n return {\r\n title,\r\n markdown: t,\r\n categoryName: null,\r\n seo: emptySeoDraft(),\r\n tags: [],\r\n parseMode: 'plaintext' as const,\r\n };\r\n });\r\n}\r\n\r\nexport class BlogGeneratorService {\r\n\r\n readonly version = '1.0.0' as const;\r\n\r\n async getLatestArticleFromFeed(\r\n rssUrl: string\r\n ): Promise<LatestArticleFromFeed | null> {\r\n\r\n const url = rssUrl.trim();\r\n\r\n if (!url) {\r\n return null;\r\n }\r\n\r\n const response = await fetch(url, {\r\n cache: 'no-store',\r\n\r\n headers: {\r\n 'User-Agent':\r\n 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',\r\n\r\n Accept:\r\n 'application/rss+xml, application/atom+xml, application/xml, text/xml, */*;q=0.8',\r\n },\r\n });\r\n\r\n if (!response.ok) {\r\n\r\n throw new Error(\r\n `Feed request failed: HTTP ${response.status}`\r\n );\r\n }\r\n\r\n const xml =\r\n stripLeadingBom(\r\n await response.text()\r\n ).trim();\r\n\r\n if (looksLikeHtmlNotFeed(xml)) {\r\n\r\n throw new Error(\r\n 'Feed URL returned HTML instead of RSS/Atom'\r\n );\r\n }\r\n\r\n let feed:\r\n Awaited<\r\n ReturnType<\r\n typeof parser.parseString\r\n >\r\n >;\r\n\r\n try {\r\n\r\n feed =\r\n await parser.parseString(xml);\r\n\r\n } catch (e) {\r\n\r\n const msg =\r\n e instanceof Error\r\n ? e.message\r\n : String(e);\r\n\r\n throw new Error(\r\n `RSS parsing failed: ${msg}`\r\n );\r\n }\r\n\r\n if (!feed.items?.length) {\r\n return null;\r\n }\r\n\r\n const articles:\r\n LatestArticleFromFeed[] =\r\n\r\n feed.items.map(raw => {\r\n\r\n const item =\r\n raw as RssItem;\r\n\r\n const {\r\n summary,\r\n fullContent,\r\n } =\r\n getRssArticleSummaryFromItem(item);\r\n\r\n const summaryTrim =\r\n trimOrUndefined(summary);\r\n\r\n const fullTrim =\r\n trimOrUndefined(fullContent);\r\n\r\n return {\r\n\r\n title:\r\n trimOrUndefined(\r\n asString(item.title)\r\n ),\r\n\r\n link:\r\n normalizeLink(item),\r\n\r\n summary:\r\n summaryTrim,\r\n\r\n content:\r\n fullTrim ??\r\n summaryTrim,\r\n\r\n creator:\r\n\r\n trimOrUndefined(\r\n\r\n asString(item.creator) ||\r\n\r\n asString(\r\n item['dc:creator']\r\n )\r\n ),\r\n\r\n categories:\r\n item.categories || [],\r\n\r\n date:\r\n new Date(\r\n item.isoDate ??\r\n item.pubDate ??\r\n 0\r\n ),\r\n };\r\n });\r\n\r\n // SORT NEWEST FIRST\r\n articles.sort(\r\n (a, b) =>\r\n b.date.getTime() -\r\n a.date.getTime()\r\n );\r\n\r\n // RETURN ONLY LATEST ARTICLE\r\n return articles[0] ?? null;\r\n }\r\n\r\n /** Defaults for the Blog Generator Agent (admin can override per request). */\r\n getAgentDefaults(): {\r\n agentName: string;\r\n systemInstruction: string;\r\n validationRules: string;\r\n } {\r\n return {\r\n agentName: BLOG_GENERATOR_AGENT_NAME,\r\n systemInstruction: BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION,\r\n validationRules: BLOG_GENERATOR_DEFAULT_VALIDATION_RULES,\r\n };\r\n }\r\n\r\n /**\r\n * Second LLM call: one draft at a time — category, URL slug, SEO fields, tags (JSON).\r\n */\r\n private async enrichBlogDraftWithLlmMetadata(\r\n llm: LlmServiceInterface,\r\n draft: BlogGeneratorBlogDraft,\r\n opts: {\r\n categoryNamesHint: readonly string[];\r\n tagNamesHint: readonly string[];\r\n systemInstruction?: string;\r\n validationRules?: string;\r\n llmAgentChatOptions?: Pick<LlmAgentOptions, 'model' | 'temperature' | 'max_tokens'>;\r\n }\r\n ): Promise<BlogGeneratorBlogDraft> {\r\n const systemBase = (opts.systemInstruction?.trim() || BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION).trim();\r\n const validationRaw = opts.validationRules?.trim()\r\n ? opts.validationRules.trim()\r\n : BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES;\r\n const parsedRules = parseLlmAgentValidationRules(validationRaw);\r\n const userPayload = buildBlogMetadataUserPrompt({\r\n title: draft.title,\r\n markdown: draft.markdown,\r\n categoryNames: opts.categoryNamesHint,\r\n tagNames: opts.tagNamesHint,\r\n });\r\n const check = validateUserMessageAgainstStructuredRules(userPayload, parsedRules.structured);\r\n if (!check.ok) {\r\n throw new Error(check.error);\r\n }\r\n const systemContent = mergeGuardrailsIntoSystemPrompt(systemBase, parsedRules.guardrailsForPrompt);\r\n const opt = opts.llmAgentChatOptions;\r\n const temperature = opt?.temperature !== undefined && opt.temperature !== null ? opt.temperature : 0.35;\r\n const max_tokens = opt?.max_tokens !== undefined && opt.max_tokens !== null ? opt.max_tokens : 8192;\r\n const modelTrim = opt?.model?.trim();\r\n const res = await llm.chatAgent({\r\n systemPrompt: systemContent,\r\n userPrompt: userPayload,\r\n temperature,\r\n max_tokens,\r\n ...(modelTrim ? { model: modelTrim } : {}),\r\n });\r\n const raw = (res.content ?? '').trim();\r\n let meta: ReturnType<typeof parseBlogMetadataEnrichmentJson>;\r\n try {\r\n meta = parseBlogMetadataEnrichmentJson(raw);\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n throw new Error(`Blog metadata step failed for \"${draft.title.slice(0, 120)}\": ${msg}`);\r\n }\r\n const categoryName =\r\n meta.categoryName != null && meta.categoryName !== '' ? meta.categoryName : draft.categoryName;\r\n const slug = meta.blogSlug != null && meta.blogSlug !== '' ? meta.blogSlug : draft.slug;\r\n const seo = mergeSeoDraft(draft.seo, meta.seo);\r\n const tags = meta.tags.length > 0 ? meta.tags : draft.tags;\r\n return {\r\n ...draft,\r\n categoryName,\r\n slug,\r\n seo,\r\n tags,\r\n };\r\n }\r\n\r\n /**\r\n * Third LLM call: one draft at a time — short social copy (JSON `{ socialMediaContent }`).\r\n */\r\n private async enrichBlogDraftWithLlmSocial(\r\n llm: LlmServiceInterface,\r\n draft: BlogGeneratorBlogDraft,\r\n opts: {\r\n systemInstruction?: string;\r\n validationRules?: string;\r\n llmAgentChatOptions?: Pick<LlmAgentOptions, 'model' | 'temperature' | 'max_tokens'>;\r\n }\r\n ): Promise<BlogGeneratorBlogDraft> {\r\n const systemBase = (opts.systemInstruction?.trim() || BLOG_SOCIAL_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION).trim();\r\n const validationRaw = opts.validationRules?.trim()\r\n ? opts.validationRules.trim()\r\n : BLOG_SOCIAL_ENRICHER_DEFAULT_VALIDATION_RULES;\r\n const parsedRules = parseLlmAgentValidationRules(validationRaw);\r\n const userPayload = buildBlogSocialUserPrompt({ title: draft.title, markdown: draft.markdown });\r\n const check = validateUserMessageAgainstStructuredRules(userPayload, parsedRules.structured);\r\n if (!check.ok) {\r\n throw new Error(check.error);\r\n }\r\n const systemContent = mergeGuardrailsIntoSystemPrompt(systemBase, parsedRules.guardrailsForPrompt);\r\n const opt = opts.llmAgentChatOptions;\r\n const temperature = opt?.temperature !== undefined && opt.temperature !== null ? opt.temperature : 0.4;\r\n const max_tokens = opt?.max_tokens !== undefined && opt.max_tokens !== null ? opt.max_tokens : 2048;\r\n const modelTrim = opt?.model?.trim();\r\n const res = await llm.chatAgent({\r\n systemPrompt: systemContent,\r\n userPrompt: userPayload,\r\n temperature,\r\n max_tokens,\r\n ...(modelTrim ? { model: modelTrim } : {}),\r\n });\r\n const raw = (res.content ?? '').trim();\r\n let parsed: ReturnType<typeof parseBlogSocialEnrichmentJson>;\r\n try {\r\n parsed = parseBlogSocialEnrichmentJson(raw);\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n throw new Error(`Blog social step failed for \"${draft.title.slice(0, 120)}\": ${msg}`);\r\n }\r\n return { ...draft, socialMediaContent: parsed.socialMediaContent };\r\n }\r\n\r\n /**\r\n * Fetches the latest item for each RSS URL, then calls {@link LlmServiceInterface.chatAgent}.\r\n * `userPrompt` is only per-feed source material; rules live in the system prompt.\r\n * Expects HTML article fragment(s), optionally separated by {@link BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR}.\r\n */\r\n async generateBlogMarkdownFromRss(params: {\r\n llm: LlmServiceInterface;\r\n /** Single feed (legacy). */\r\n rssUrl?: string;\r\n /** One or more feeds; latest item per URL is sent together. Prefer this when multiple URLs. */\r\n rssUrls?: readonly string[];\r\n systemInstruction?: string;\r\n validationRules?: string;\r\n /** Reserved for future structured output; writer does not inject categories into the user prompt. */\r\n categoryNamesHint?: readonly string[];\r\n /** Names of non-deleted tags in CMS (hint for reuse). */\r\n tagNamesHint?: readonly string[];\r\n /** From optional `llm_agents` row (slug `blog-generator`): model / sampling for the writer step. */\r\n llmAgentChatOptions?: Pick<LlmAgentOptions, 'model' | 'temperature' | 'max_tokens'>;\r\n /** Optional overrides for the metadata step; defaults live in `blog-generator-metadata-defaults.ts`. */\r\n metadataSystemInstruction?: string;\r\n metadataValidationRules?: string;\r\n /** From optional `llm_agents` row (slug `blog-generator-metadata`): model / sampling for metadata only. */\r\n metadataLlmAgentChatOptions?: Pick<LlmAgentOptions, 'model' | 'temperature' | 'max_tokens'>;\r\n /** Optional overrides for the social-summary step; defaults in `blog-generator-social-defaults.ts`. */\r\n socialSystemInstruction?: string;\r\n socialValidationRules?: string;\r\n /** From optional `llm_agents` row (slug `blog-generator-social`): model / sampling for social copy only. */\r\n socialLlmAgentChatOptions?: Pick<LlmAgentOptions, 'model' | 'temperature' | 'max_tokens'>;\r\n }): Promise<{\r\n agentName: string;\r\n feedArticles: Array<{ rssUrl: string; article: LatestArticleFromFeed }>;\r\n /** First feed's article (backward compatibility). */\r\n article: LatestArticleFromFeed;\r\n /** Raw model reply (HTML body per defaults; legacy markdown or JSON still parsed when present). */\r\n blogMarkdown: string;\r\n blogDrafts: BlogGeneratorBlogDraft[];\r\n /** Same as first draft; backward compatibility. */\r\n blogDraft: BlogGeneratorBlogDraft;\r\n }> {\r\n const rawUrls = (() => {\r\n if (params.rssUrls?.length) {\r\n return [...new Set(params.rssUrls.map((u) => u.trim()).filter(Boolean))];\r\n }\r\n const one = params.rssUrl?.trim();\r\n return one ? [one] : [];\r\n })();\r\n if (rawUrls.length === 0) {\r\n throw new Error('Provide rssUrl or rssUrls with at least one feed URL.');\r\n }\r\n\r\n const feedArticles: Array<{ rssUrl: string; article: LatestArticleFromFeed }> = [];\r\n for (const rssUrl of rawUrls) {\r\n const article = await this.getLatestArticleFromFeed(rssUrl);\r\n if (!article) {\r\n throw new Error(`No items found in this feed: ${rssUrl}`);\r\n }\r\n feedArticles.push({ rssUrl, article });\r\n }\r\n\r\n const systemBase = (params.systemInstruction?.trim() || BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION).trim();\r\n const validationRaw = params.validationRules?.trim()\r\n ? params.validationRules.trim()\r\n : BLOG_GENERATOR_DEFAULT_VALIDATION_RULES;\r\n\r\n const parsed = parseLlmAgentValidationRules(validationRaw);\r\n const userPayload = buildRssUserPromptFromFeeds(feedArticles);\r\n const check = validateUserMessageAgainstStructuredRules(userPayload, parsed.structured);\r\n if (!check.ok) {\r\n throw new Error(check.error);\r\n }\r\n\r\n const systemContent = mergeGuardrailsIntoSystemPrompt(systemBase, parsed.guardrailsForPrompt);\r\n\r\n const opt = params.llmAgentChatOptions;\r\n const temperature = opt?.temperature !== undefined && opt.temperature !== null ? opt.temperature : 0.55;\r\n const max_tokens = opt?.max_tokens !== undefined && opt.max_tokens !== null ? opt.max_tokens : 20000;\r\n const modelTrim = opt?.model?.trim();\r\n\r\n const res = await params.llm.chatAgent({\r\n systemPrompt: systemContent,\r\n userPrompt: userPayload,\r\n temperature,\r\n max_tokens,\r\n ...(modelTrim ? { model: modelTrim } : {}),\r\n });\r\n\r\n const raw = (res.content ?? '').trim();\r\n if (!raw) {\r\n throw new Error('LLM returned empty content.');\r\n }\r\n\r\n const blogDrafts = parseBlogGeneratorModelOutput(raw);\r\n const nonEmpty = blogDrafts.filter((d) => d.markdown.trim());\r\n if (nonEmpty.length === 0) {\r\n throw new Error('LLM returned empty blog body.');\r\n }\r\n const normalizedDrafts = nonEmpty.map((d) => ({ ...d, tags: d.tags ?? [] }));\r\n const enrichedDrafts: BlogGeneratorBlogDraft[] = [];\r\n for (const d of normalizedDrafts) {\r\n enrichedDrafts.push(\r\n await this.enrichBlogDraftWithLlmMetadata(params.llm, d, {\r\n categoryNamesHint: params.categoryNamesHint ?? [],\r\n tagNamesHint: params.tagNamesHint ?? [],\r\n systemInstruction: params.metadataSystemInstruction,\r\n validationRules: params.metadataValidationRules,\r\n llmAgentChatOptions: params.metadataLlmAgentChatOptions,\r\n })\r\n );\r\n }\r\n const withSocial: BlogGeneratorBlogDraft[] = [];\r\n for (const d of enrichedDrafts) {\r\n withSocial.push(\r\n await this.enrichBlogDraftWithLlmSocial(params.llm, d, {\r\n systemInstruction: params.socialSystemInstruction,\r\n validationRules: params.socialValidationRules,\r\n llmAgentChatOptions: params.socialLlmAgentChatOptions,\r\n })\r\n );\r\n }\r\n const blogDraft = withSocial[0]!;\r\n\r\n return {\r\n agentName: BLOG_GENERATOR_AGENT_NAME,\r\n feedArticles,\r\n article: feedArticles[0]!.article,\r\n blogMarkdown: raw,\r\n blogDrafts: withSocial,\r\n blogDraft,\r\n };\r\n }\r\n}","import type { DataSource, EntityTarget, ObjectLiteral } from 'typeorm';\r\nimport { IsNull } from 'typeorm';\r\n\r\n/** Links an unclaimed contact (same email, no userId) to the new user after signup or invite. */\r\nexport async function linkUnclaimedContactToUser(\r\n dataSource: DataSource,\r\n contactsEntity: EntityTarget<ObjectLiteral>,\r\n userId: number,\r\n email: string\r\n): Promise<void> {\r\n const repo = dataSource.getRepository(contactsEntity);\r\n const found = await repo.findOne({\r\n where: { email, userId: IsNull(), deleted: false } as ObjectLiteral,\r\n });\r\n if (found) await repo.update((found as { id: number }).id, { userId });\r\n}\r\n","/**\r\n * CMS API handlers: dashboard, analytics, upload, blog/form by slug, users (list/create/get/update/delete/regenerate-invite/avatar/profile).\r\n * All accept injectable deps; upload supports S3 or local.\r\n */\r\nimport type { DataSource, EntityTarget } from 'typeorm';\r\nimport { linkUnclaimedContactToUser } from '../lib/link-contact-to-user';\r\nimport { MoreThanOrEqual, ILike, In } from 'typeorm';\r\nimport type { EntityMap } from './crud';\r\nimport type { EntityCrudAction } from '../auth/permission-entities';\r\nimport type { SessionUser } from '../auth/helpers';\r\nimport { queueEmail } from '../plugins/email/email-queue';\r\nimport type { CompanyDetails } from '../plugins/email/templates/types';\r\nimport { queueErp } from '../plugins/erp/erp-queue';\r\nimport type { ERPSubmissionService } from '../plugins/erp/erp-submission';\r\nimport { assertCaptchaOk } from '../plugins/captcha/assert';\r\nimport { llmAgentToChatAgentOptions, type LlmAgent } from '../entities/llm-agent.entity';\r\nimport type { LlmAgentOptions, LlmMessage } from '../plugins/llm/llm-service';\r\nimport {\r\n buildChatbotSystemPromptWithEmailTool,\r\n buildTranscriptForLeadEmail,\r\n CHAT_EMAIL_LOG,\r\n detectChatLeadIntent,\r\n parseIntentRecipientEmails,\r\n resolveChatEmailToolSettings,\r\n} from '../plugins/llm/chat-email-intent';\r\nimport { findLlmAgentByScope } from '../plugins/llm/find-llm-agent-by-scope';\r\nimport {\r\n LLM_AGENT_DEFAULT_SLUG_BY_SCOPE,\r\n LLM_AGENT_SCOPE_CHATBOT,\r\n LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT,\r\n} from '../plugins/llm/llm-agent-scope';\r\nimport { sendChatLeadEmail } from '../plugins/email/chat-lead-email';\r\nimport { mergeEmailLayoutCompanyDetails } from '../plugins/email/templates/types';\r\n\r\nexport type RequireEntityPermissionFn = (req: Request, entity: string, action: EntityCrudAction) => Promise<Response | null>;\r\n\r\n/** Avoid duplicating the current user turn when the DB already includes it (see postMessage flow). */\r\nfunction historyBeforeCurrentUser(history: LlmMessage[], currentUserContent: string): LlmMessage[] {\r\n const last = history[history.length - 1];\r\n if (last?.role === 'user' && last.content === currentUserContent) {\r\n return history.slice(0, -1);\r\n }\r\n return [...history];\r\n}\r\n\r\n/**\r\n * Optional JSON in `LlmAgent.validationRules`. Used for programmatic checks before the LLM call.\r\n * For natural-language output rules, use `guardrails` / `outputRules` / `outputInstructions` (merged into system prompt).\r\n */\r\nexport type LlmAgentValidationRulesJson = {\r\n maxUserChars?: number;\r\n maxMessageLength?: number;\r\n minUserChars?: number;\r\n minMessageLength?: number;\r\n blockedSubstrings?: string[];\r\n /** Shown to the model as output guardrails (first non-empty of guardrails | outputRules | outputInstructions wins). */\r\n guardrails?: string;\r\n outputRules?: string;\r\n outputInstructions?: string;\r\n};\r\n\r\nexport type ParsedLlmAgentValidation = {\r\n /** Subset used for length / substring checks only. */\r\n structured: Pick<\r\n LlmAgentValidationRulesJson,\r\n 'maxUserChars' | 'maxMessageLength' | 'minUserChars' | 'minMessageLength' | 'blockedSubstrings'\r\n >;\r\n /** Appended to system prompt so the model follows output guardrails. */\r\n guardrailsForPrompt: string | null;\r\n};\r\n\r\nfunction pickStructuredRules(rules: LlmAgentValidationRulesJson): ParsedLlmAgentValidation['structured'] {\r\n return {\r\n maxUserChars: rules.maxUserChars,\r\n maxMessageLength: rules.maxMessageLength,\r\n minUserChars: rules.minUserChars,\r\n minMessageLength: rules.minMessageLength,\r\n blockedSubstrings: rules.blockedSubstrings,\r\n };\r\n}\r\n\r\nfunction guardrailsTextFromJsonObject(rules: LlmAgentValidationRulesJson): string | null {\r\n const g =\r\n (typeof rules.guardrails === 'string' && rules.guardrails.trim()) ||\r\n (typeof rules.outputRules === 'string' && rules.outputRules.trim()) ||\r\n (typeof rules.outputInstructions === 'string' && rules.outputInstructions.trim()) ||\r\n '';\r\n return g || null;\r\n}\r\n\r\n/**\r\n * - Valid JSON object: structural keys → validation; `guardrails` / `outputRules` / `outputInstructions` → prompt suffix.\r\n * - Not JSON: entire string is treated as prose guardrails for the prompt (no programmatic rules unless you use JSON).\r\n */\r\nexport function parseLlmAgentValidationRules(\r\n validationRulesText: string | null | undefined\r\n): ParsedLlmAgentValidation {\r\n const raw = validationRulesText?.trim();\r\n if (!raw) return { structured: {}, guardrailsForPrompt: null };\r\n try {\r\n const parsed = JSON.parse(raw) as unknown;\r\n if (typeof parsed === 'string') {\r\n const s = parsed.trim();\r\n return { structured: {}, guardrailsForPrompt: s || null };\r\n }\r\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\r\n return { structured: {}, guardrailsForPrompt: raw };\r\n }\r\n const rules = parsed as LlmAgentValidationRulesJson;\r\n return {\r\n structured: pickStructuredRules(rules),\r\n guardrailsForPrompt: guardrailsTextFromJsonObject(rules),\r\n };\r\n } catch {\r\n return { structured: {}, guardrailsForPrompt: raw };\r\n }\r\n}\r\n\r\nexport function validateUserMessageAgainstStructuredRules(\r\n message: string,\r\n structured: ParsedLlmAgentValidation['structured']\r\n): { ok: true } | { ok: false; error: string } {\r\n const maxLen = structured.maxUserChars ?? structured.maxMessageLength;\r\n if (typeof maxLen === 'number' && Number.isFinite(maxLen) && maxLen >= 0 && message.length > maxLen) {\r\n return { ok: false, error: `Message exceeds maximum length (${maxLen} characters)` };\r\n }\r\n\r\n const minLen = structured.minUserChars ?? structured.minMessageLength;\r\n if (typeof minLen === 'number' && Number.isFinite(minLen) && minLen > 0 && message.length < minLen) {\r\n return { ok: false, error: `Message is shorter than minimum length (${minLen} characters)` };\r\n }\r\n\r\n const blocked = structured.blockedSubstrings;\r\n if (Array.isArray(blocked) && blocked.length > 0) {\r\n const lower = message.toLowerCase();\r\n for (const s of blocked) {\r\n if (typeof s !== 'string' || !s.trim()) continue;\r\n if (lower.includes(s.toLowerCase())) {\r\n return { ok: false, error: 'Message contains disallowed content' };\r\n }\r\n }\r\n }\r\n\r\n return { ok: true };\r\n}\r\n\r\n/** Parses `validationRules` then runs programmatic checks only. */\r\nexport function validateUserMessageAgainstAgentRules(\r\n message: string,\r\n validationRulesText: string | null | undefined\r\n): { ok: true } | { ok: false; error: string } {\r\n const { structured } = parseLlmAgentValidationRules(validationRulesText);\r\n return validateUserMessageAgainstStructuredRules(message, structured);\r\n}\r\n\r\n/** Merges guardrails prose into the system instruction sent to the model. */\r\nexport function mergeGuardrailsIntoSystemPrompt(\r\n baseSystem: string | undefined,\r\n guardrailsForPrompt: string | null\r\n): string {\r\n const g = guardrailsForPrompt?.trim();\r\n const b = (baseSystem ?? '').trim();\r\n if (!g) return b;\r\n const block = `### Output guardrails (follow in every reply)\\n${g}`;\r\n return b ? `${b}\\n\\n${block}` : block;\r\n}\r\n\r\nexport interface CmsHandlersBase {\r\n json: (body: unknown, init?: { status?: number }) => Response;\r\n requireAuth: (req: Request) => Promise<Response | null>;\r\n requireEntityPermission?: RequireEntityPermissionFn;\r\n}\r\n\r\nexport interface DashboardStatsConfig extends CmsHandlersBase {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n requirePermission?: (req: Request, permission: string) => Promise<Response | null>;\r\n}\r\n\r\nexport function createDashboardStatsHandler(config: DashboardStatsConfig) {\r\n const { dataSource, entityMap, json, requireAuth, requirePermission, requireEntityPermission } = config;\r\n return async function GET(req: Request): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'dashboard', 'read');\r\n if (pe) return pe;\r\n }\r\n if (requirePermission) {\r\n const permErr = await requirePermission(req, 'view_dashboard');\r\n if (permErr) return permErr;\r\n }\r\n try {\r\n const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);\r\n const repo = (name: string) => entityMap[name] ? dataSource.getRepository(entityMap[name]) : undefined;\r\n const [contactsCount, formsCount, formSubmissionsCount, usersCount, blogsCount, recentContacts, recentSubmissions, contactTypeRows] = await Promise.all([\r\n repo('contacts')?.count({ where: { deleted: false } }) ?? 0,\r\n repo('forms')?.count({ where: { deleted: false } }) ?? 0,\r\n repo('form_submissions')?.count() ?? 0,\r\n repo('users')?.count({ where: { deleted: false } }) ?? 0,\r\n repo('blogs')?.count({ where: { deleted: false } }) ?? 0,\r\n repo('contacts')?.count({\r\n where: { deleted: false, createdAt: MoreThanOrEqual(sevenDaysAgo) },\r\n }) ?? 0,\r\n repo('form_submissions')?.count({ where: { createdAt: MoreThanOrEqual(sevenDaysAgo) } }) ?? 0,\r\n repo('contacts')\r\n ?.createQueryBuilder('c')\r\n .select(\"COALESCE(NULLIF(TRIM(c.type), ''), 'unknown')\", 'type')\r\n .addSelect('COUNT(*)', 'count')\r\n .where('c.deleted = :deleted', { deleted: false })\r\n .groupBy(\"COALESCE(NULLIF(TRIM(c.type), ''), 'unknown')\")\r\n .getRawMany<{ type: string; count: string }>() ?? [],\r\n ]);\r\n return json({\r\n contacts: { total: contactsCount, recent: recentContacts },\r\n forms: { total: formsCount, submissions: formSubmissionsCount, recentSubmissions },\r\n users: usersCount,\r\n blogs: blogsCount,\r\n contactTypes: (contactTypeRows ?? []).map((row) => ({\r\n type: row.type || 'unknown',\r\n count: Number(row.count || 0),\r\n })),\r\n });\r\n } catch (err) {\r\n return json({ error: 'Failed to fetch dashboard stats' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nexport interface EcommerceAnalyticsConfig extends CmsHandlersBase {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n}\r\n\r\ntype SalesTrendPoint = { date: string; value: number; orders: number };\r\ntype ReturnsTrendPoint = { date: string; value: number; count: number };\r\n\r\nfunction toNum(v: unknown): number {\r\n const n = typeof v === 'number' ? v : Number(v ?? 0);\r\n return Number.isFinite(n) ? n : 0;\r\n}\r\n\r\nfunction toIsoDate(d: Date): string {\r\n return d.toISOString().slice(0, 10);\r\n}\r\n\r\nexport function createEcommerceAnalyticsHandler(config: EcommerceAnalyticsConfig) {\r\n const { dataSource, entityMap, json, requireAuth, requireEntityPermission } = config;\r\n return async function GET(req: Request): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'analytics', 'read');\r\n if (pe) return pe;\r\n }\r\n if (!entityMap.orders || !entityMap.order_items || !entityMap.payments || !entityMap.products) {\r\n return json({ error: 'Store analytics unavailable' }, { status: 404 });\r\n }\r\n try {\r\n const url = new URL(req.url);\r\n const rawDays = parseInt(url.searchParams.get('days') || '30', 10);\r\n const days = Number.isFinite(rawDays) ? Math.min(365, Math.max(7, rawDays)) : 30;\r\n const end = new Date();\r\n const start = new Date(end.getTime() - days * 24 * 60 * 60 * 1000);\r\n\r\n const orderRepo = dataSource.getRepository(entityMap.orders);\r\n const paymentRepo = dataSource.getRepository(entityMap.payments);\r\n const itemRepo = dataSource.getRepository(entityMap.order_items);\r\n const productRepo = dataSource.getRepository(entityMap.products);\r\n\r\n const [salesOrders, returnOrders, replacementOrders, payments, products] = await Promise.all([\r\n orderRepo.find({\r\n where: { deleted: false, createdAt: MoreThanOrEqual(start), orderKind: 'sale', status: In(['confirmed', 'processing', 'completed']) } as object,\r\n select: ['id', 'contactId', 'createdAt', 'subtotal', 'discount', 'tax', 'total', 'status'],\r\n }),\r\n orderRepo.find({\r\n where: { deleted: false, createdAt: MoreThanOrEqual(start), orderKind: 'return' } as object,\r\n select: ['id', 'createdAt', 'total'],\r\n }),\r\n orderRepo.find({\r\n where: { deleted: false, createdAt: MoreThanOrEqual(start), orderKind: 'replacement' } as object,\r\n select: ['id', 'createdAt', 'total'],\r\n }),\r\n paymentRepo.find({\r\n where: { deleted: false, createdAt: MoreThanOrEqual(start) } as object,\r\n select: ['id', 'status', 'method', 'amount', 'createdAt'],\r\n }),\r\n productRepo.find({\r\n where: { deleted: false } as object,\r\n select: ['id', 'name', 'quantity'],\r\n }),\r\n ]);\r\n\r\n const saleOrderIds = salesOrders.map((o) => o.id);\r\n const orderItems = saleOrderIds.length\r\n ? await itemRepo.find({\r\n where: { orderId: In(saleOrderIds) } as object,\r\n select: ['id', 'orderId', 'productId', 'quantity', 'total'],\r\n })\r\n : [];\r\n\r\n const grossSales = salesOrders.reduce((sum, o) => sum + toNum(o.subtotal), 0);\r\n const discounts = salesOrders.reduce((sum, o) => sum + toNum(o.discount), 0);\r\n const taxes = salesOrders.reduce((sum, o) => sum + toNum(o.tax), 0);\r\n const returnsValue = returnOrders.reduce((sum, o) => sum + toNum(o.total), 0);\r\n const replacementsValue = replacementOrders.reduce((sum, o) => sum + toNum(o.total), 0);\r\n const netSales = grossSales - discounts - returnsValue;\r\n const ordersCount = salesOrders.length;\r\n const aov = ordersCount > 0 ? netSales / ordersCount : 0;\r\n const returnRate = ordersCount > 0 ? (returnOrders.length / ordersCount) * 100 : 0;\r\n\r\n const salesByDate = new Map<string, { value: number; orders: number }>();\r\n const returnsByDate = new Map<string, { value: number; count: number }>();\r\n for (const o of salesOrders) {\r\n const key = toIsoDate(new Date(o.createdAt));\r\n const row = salesByDate.get(key) ?? { value: 0, orders: 0 };\r\n row.value += toNum(o.total);\r\n row.orders += 1;\r\n salesByDate.set(key, row);\r\n }\r\n for (const o of returnOrders) {\r\n const key = toIsoDate(new Date(o.createdAt));\r\n const row = returnsByDate.get(key) ?? { value: 0, count: 0 };\r\n row.value += toNum(o.total);\r\n row.count += 1;\r\n returnsByDate.set(key, row);\r\n }\r\n\r\n const salesOverTime: SalesTrendPoint[] = [];\r\n const returnsTrend: ReturnsTrendPoint[] = [];\r\n for (let i = days - 1; i >= 0; i--) {\r\n const d = new Date(end.getTime() - i * 24 * 60 * 60 * 1000);\r\n const key = toIsoDate(d);\r\n const sales = salesByDate.get(key) ?? { value: 0, orders: 0 };\r\n const returns = returnsByDate.get(key) ?? { value: 0, count: 0 };\r\n salesOverTime.push({ date: key, value: Number(sales.value.toFixed(2)), orders: sales.orders });\r\n returnsTrend.push({ date: key, value: Number(returns.value.toFixed(2)), count: returns.count });\r\n }\r\n\r\n const productNameMap = new Map<number, string>();\r\n for (const p of products) productNameMap.set(Number(p.id), (p.name || `Product #${p.id}`).trim());\r\n const productAgg = new Map<number, { name: string; units: number; sales: number }>();\r\n for (const item of orderItems) {\r\n const productId = Number(item.productId);\r\n const productName = productNameMap.get(productId) || `Product #${productId}`;\r\n const row = productAgg.get(productId) ?? { name: productName, units: 0, sales: 0 };\r\n row.units += toNum(item.quantity);\r\n row.sales += toNum(item.total);\r\n productAgg.set(productId, row);\r\n }\r\n const topProducts = Array.from(productAgg.values())\r\n .sort((a, b) => b.sales - a.sales)\r\n .slice(0, 5)\r\n .map((p) => ({ ...p, sales: Number(p.sales.toFixed(2)) }));\r\n\r\n const allSaleOrderContactIds = Array.from(new Set(salesOrders.map((o) => Number(o.contactId)).filter((n) => Number.isInteger(n) && n > 0)));\r\n const allTimeCounts = allSaleOrderContactIds.length\r\n ? await orderRepo\r\n .createQueryBuilder('o')\r\n .select('o.contactId', 'contactId')\r\n .addSelect('COUNT(*)', 'total')\r\n .where('o.deleted = :deleted', { deleted: false })\r\n .andWhere('o.orderKind = :orderKind', { orderKind: 'sale' })\r\n .andWhere('o.contactId IN (:...contactIds)', { contactIds: allSaleOrderContactIds })\r\n .groupBy('o.contactId')\r\n .getRawMany<{ contactId: string; total: string }>()\r\n : [];\r\n const countMap = new Map<number, number>();\r\n for (const c of allTimeCounts) countMap.set(Number(c.contactId), Number(c.total));\r\n const purchasingCustomers = allSaleOrderContactIds.length;\r\n const returningCustomers = allSaleOrderContactIds.filter((id) => (countMap.get(id) ?? 0) > 1).length;\r\n const newCustomers = Math.max(0, purchasingCustomers - returningCustomers);\r\n const returningCustomerRate = purchasingCustomers > 0 ? (returningCustomers / purchasingCustomers) * 100 : 0;\r\n\r\n const totalPayments = payments.length;\r\n const completedPayments = payments.filter((p) => p.status === 'completed').length;\r\n const failedPayments = payments.filter((p) => p.status === 'failed').length;\r\n const paymentSuccessRate = totalPayments > 0 ? (completedPayments / totalPayments) * 100 : 0;\r\n const paymentMethodMap = new Map<string, { method: string; count: number; amount: number }>();\r\n for (const p of payments) {\r\n const method = (p.method || 'unknown').toLowerCase();\r\n const row = paymentMethodMap.get(method) ?? { method, count: 0, amount: 0 };\r\n row.count += 1;\r\n row.amount += toNum(p.amount);\r\n paymentMethodMap.set(method, row);\r\n }\r\n const paymentMethods = Array.from(paymentMethodMap.values())\r\n .sort((a, b) => b.count - a.count)\r\n .map((p) => ({ ...p, amount: Number(p.amount.toFixed(2)) }));\r\n\r\n const totalInventory = products.reduce((sum, p) => sum + toNum(p.quantity), 0);\r\n const outOfStockCount = products.filter((p) => toNum(p.quantity) <= 0).length;\r\n const lowStockCount = products.filter((p) => toNum(p.quantity) > 0 && toNum(p.quantity) <= 5).length;\r\n const inventoryRisk = {\r\n outOfStockCount,\r\n lowStockCount,\r\n totalInventory,\r\n };\r\n\r\n return json({\r\n rangeDays: days,\r\n kpis: {\r\n netSales: Number(netSales.toFixed(2)),\r\n grossSales: Number(grossSales.toFixed(2)),\r\n ordersPlaced: ordersCount,\r\n averageOrderValue: Number(aov.toFixed(2)),\r\n returningCustomerRate: Number(returningCustomerRate.toFixed(2)),\r\n returnRate: Number(returnRate.toFixed(2)),\r\n returnValue: Number(returnsValue.toFixed(2)),\r\n discounts: Number(discounts.toFixed(2)),\r\n taxes: Number(taxes.toFixed(2)),\r\n paymentSuccessRate: Number(paymentSuccessRate.toFixed(2)),\r\n },\r\n salesOverTime,\r\n topProducts,\r\n customerMix: {\r\n newCustomers,\r\n returningCustomers,\r\n repeatPurchaseRate: Number(returningCustomerRate.toFixed(2)),\r\n },\r\n returnsTrend,\r\n paymentPerformance: {\r\n successCount: completedPayments,\r\n failedCount: failedPayments,\r\n successRate: Number(paymentSuccessRate.toFixed(2)),\r\n methods: paymentMethods,\r\n },\r\n conversionProxy: {\r\n sessions: 0,\r\n checkoutStarted: 0,\r\n ordersPlaced: ordersCount,\r\n },\r\n salesBreakdown: {\r\n sales: { count: ordersCount, value: Number(grossSales.toFixed(2)) },\r\n returns: { count: returnOrders.length, value: Number(returnsValue.toFixed(2)) },\r\n replacements: { count: replacementOrders.length, value: Number(replacementsValue.toFixed(2)) },\r\n },\r\n geoPerformance: [],\r\n inventoryRisk,\r\n });\r\n } catch {\r\n return json({ error: 'Failed to fetch ecommerce analytics' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nexport interface AnalyticsHandlerConfig extends CmsHandlersBase {\r\n getAnalyticsData?: (days: number) => Promise<unknown>;\r\n getPropertyId?: () => ({ currentViewId?: string; [k: string]: unknown });\r\n getPermissions?: () => ({ serviceAccountEmail?: string; currentViewId?: string; [k: string]: unknown });\r\n}\r\n\r\nexport function createAnalyticsHandlers(config: AnalyticsHandlerConfig) {\r\n const { json, getAnalyticsData, getPropertyId, getPermissions } = config;\r\n return {\r\n async GET(req: Request): Promise<Response> {\r\n if (!getAnalyticsData) return json({ error: 'Analytics not configured' }, { status: 404 });\r\n try {\r\n const url = new URL(req.url);\r\n const days = parseInt(url.searchParams.get('days') || '30', 10);\r\n const data = await getAnalyticsData(days);\r\n return json(data);\r\n } catch (err: unknown) {\r\n const msg = err instanceof Error ? err.message : '';\r\n if (msg.includes('authentication credential')) return json({ error: 'Google Analytics authentication failed.' }, { status: 401 });\r\n if (msg.includes('sufficient permissions')) return json({ error: 'Service account does not have access.' }, { status: 403 });\r\n return json({ error: 'Failed to fetch analytics data' }, { status: 500 });\r\n }\r\n },\r\n propertyId: async (): Promise<Response> => {\r\n const payload = getPropertyId ? getPropertyId() : { currentViewId: process.env.GOOGLE_ANALYTICS_VIEW_ID };\r\n return json({ message: 'Property ID Information', ...payload });\r\n },\r\n permissions: async (): Promise<Response> => {\r\n const payload = getPermissions ? getPermissions() : {\r\n serviceAccountEmail: process.env.GOOGLE_ANALYTICS_CLIENT_EMAIL,\r\n currentViewId: process.env.GOOGLE_ANALYTICS_VIEW_ID,\r\n };\r\n return json({ message: 'Permission Troubleshooting Guide', ...payload });\r\n },\r\n };\r\n}\r\n\r\nimport type { StorageService } from '../plugins/storage';\r\nimport { sanitizeMediaFolderPath } from '../lib/media-folder-path';\r\nimport { relativePathFromMediaParentId } from '../lib/media-parent-path';\r\nimport { extractZipMediaIntoParentTree } from '../lib/media-zip-extract';\r\n\r\nexport type { StorageService };\r\n\r\nexport interface UploadHandlerConfig extends CmsHandlersBase {\r\n /** Storage plugin instance or getter (e.g. () => getCms().then(c => c.getPlugin('storage'))). If not set, uses local fallback. */\r\n storage?: StorageService | (() => StorageService | undefined) | (() => Promise<StorageService | undefined>);\r\n /** Fallback when storage not set: dir relative to cwd (e.g. \"public/uploads\") */\r\n localUploadDir?: string;\r\n allowedTypes?: string[];\r\n maxSizeBytes?: number;\r\n /** Resolve folder chain for `parentId` (merged from createCmsApiHandler when omitted). */\r\n dataSource?: DataSource;\r\n entityMap?: EntityMap;\r\n}\r\n\r\nexport function createUploadHandler(config: UploadHandlerConfig) {\r\n const {\r\n json,\r\n requireAuth,\r\n requireEntityPermission,\r\n storage,\r\n localUploadDir = 'public/uploads',\r\n allowedTypes,\r\n maxSizeBytes = 10 * 1024 * 1024,\r\n dataSource,\r\n entityMap,\r\n } = config;\r\n const allowed = allowedTypes ?? [\r\n 'image/jpeg',\r\n 'image/png',\r\n 'image/gif',\r\n 'image/webp',\r\n 'application/pdf',\r\n 'text/plain',\r\n 'application/zip',\r\n 'application/x-zip-compressed',\r\n ];\r\n return async function POST(req: Request): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'upload', 'create');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const formData = await req.formData();\r\n const file = formData.get('file') as File | null;\r\n if (!file) return json({ error: 'No file uploaded' }, { status: 400 });\r\n if (!allowed.includes(file.type)) return json({ error: 'File type not allowed' }, { status: 400 });\r\n const defaultMax = 10 * 1024 * 1024;\r\n const maxZipBytes = 80 * 1024 * 1024;\r\n const baseMax = maxSizeBytes ?? defaultMax;\r\n const effectiveMax =\r\n file.type === 'application/zip' || file.type === 'application/x-zip-compressed'\r\n ? Math.max(baseMax, maxZipBytes)\r\n : baseMax;\r\n if (file.size > effectiveMax) return json({ error: 'File size exceeds limit' }, { status: 400 });\r\n const parentRaw = formData.get('parentId');\r\n let parentId: number | null = null;\r\n if (parentRaw != null && String(parentRaw).trim() !== '') {\r\n const n = Number(parentRaw);\r\n if (!Number.isFinite(n)) return json({ error: 'Invalid parentId' }, { status: 400 });\r\n parentId = n;\r\n }\r\n let folder = '';\r\n if (parentId != null) {\r\n if (!dataSource || !entityMap?.media) {\r\n return json({ error: 'Upload handler needs dataSource and entityMap for folder uploads' }, { status: 400 });\r\n }\r\n const repo = dataSource.getRepository(entityMap.media);\r\n const p = await repo.findOne({ where: { id: parentId } });\r\n if (!p || (p as { kind: string }).kind !== 'folder') {\r\n return json({ error: 'parent must be a folder' }, { status: 400 });\r\n }\r\n folder = await relativePathFromMediaParentId(dataSource, entityMap, parentId);\r\n } else {\r\n const folderRawLegacy = formData.get('folder') ?? formData.get('folderPath');\r\n if (folderRawLegacy && typeof folderRawLegacy === 'string' && folderRawLegacy.trim()) {\r\n folder = sanitizeMediaFolderPath(folderRawLegacy);\r\n }\r\n }\r\n const buffer = Buffer.from(await file.arrayBuffer());\r\n const fileName = `${Date.now()}-${file.name}`;\r\n const contentType = file.type || 'application/octet-stream';\r\n const relativeUnderUploads = folder ? `${folder}/${fileName}` : fileName;\r\n const raw = typeof storage === 'function' ? storage() : storage;\r\n const storageService = raw instanceof Promise ? await raw : raw;\r\n if (storageService) {\r\n const fileUrl = await storageService.upload(buffer, `uploads/${relativeUnderUploads}`, contentType);\r\n return json({ filePath: fileUrl, parentId });\r\n }\r\n const fs = await import('fs/promises');\r\n const path = await import('path');\r\n const dir = path.join(process.cwd(), localUploadDir);\r\n const filePath = path.join(dir, relativeUnderUploads);\r\n await fs.mkdir(path.dirname(filePath), { recursive: true });\r\n await fs.writeFile(filePath, buffer);\r\n const urlRel = `${localUploadDir.replace(/^\\/+/, '').replace(/\\\\/g, '/')}/${relativeUnderUploads.replace(/\\\\/g, '/')}`;\r\n return json({ filePath: `/${urlRel}`, parentId });\r\n } catch (err) {\r\n return json({ error: 'File upload failed' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\n/** POST /api/media/extract/:id — expand a zip media row into folders/files under the zip’s parent folder. */\r\nexport function createMediaZipExtractHandler(config: UploadHandlerConfig) {\r\n const { json, requireAuth, requireEntityPermission, storage, localUploadDir = 'public/uploads', dataSource, entityMap } =\r\n config;\r\n return async function POST(_req: Request, zipMediaId: string): Promise<Response> {\r\n const authErr = await requireAuth(_req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(_req, 'media', 'create');\r\n if (pe) return pe;\r\n }\r\n if (!dataSource || !entityMap?.media) {\r\n return json({ error: 'Media extract requires dataSource and entityMap' }, { status: 500 });\r\n }\r\n const id = Number(zipMediaId);\r\n if (!Number.isFinite(id)) return json({ error: 'Invalid id' }, { status: 400 });\r\n const repo = dataSource.getRepository(entityMap.media);\r\n const row = await repo.findOne({ where: { id } });\r\n if (!row) return json({ error: 'Not found' }, { status: 404 });\r\n try {\r\n const raw = typeof storage === 'function' ? storage() : storage;\r\n const storageService = raw instanceof Promise ? await raw : raw;\r\n const result = await extractZipMediaIntoParentTree({\r\n dataSource,\r\n entityMap,\r\n zipMediaRow: row,\r\n storage: storageService,\r\n localUploadDir,\r\n });\r\n return json({ ok: true, ...result });\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : 'Extract failed';\r\n return json({ error: msg }, { status: 400 });\r\n }\r\n };\r\n}\r\n\r\nexport interface BlogBySlugConfig extends CmsHandlersBase {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n}\r\n\r\nexport function createBlogBySlugHandler(config: BlogBySlugConfig) {\r\n const { dataSource, entityMap, json } = config;\r\n return async function GET(_req: Request, slug: string): Promise<Response> {\r\n try {\r\n const blogRepo = dataSource.getRepository(entityMap.blogs);\r\n const blog = await blogRepo.findOne({\r\n where: { slug, published: true },\r\n relations: ['author', 'category', 'tags', 'seo'],\r\n });\r\n if (!blog) return json({ error: 'Blog not found' }, { status: 404 });\r\n return json(blog);\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nexport interface FormBySlugConfig extends CmsHandlersBase {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n}\r\n\r\nexport function createFormBySlugHandler(config: FormBySlugConfig) {\r\n const { dataSource, entityMap, json } = config;\r\n return async function GET(_req: Request, slug: string): Promise<Response> {\r\n try {\r\n const formRepo = dataSource.getRepository(entityMap.forms);\r\n const form = await formRepo.findOne({\r\n where: { slug, published: true, deleted: false },\r\n relations: ['fields'],\r\n order: { fields: { order: 'ASC' } },\r\n });\r\n if (!form) return json({ error: 'Form not found' }, { status: 404 });\r\n const out = form as { fields?: unknown[] };\r\n if (Array.isArray(out.fields)) out.fields = out.fields.filter((f) => !(f as { deleted?: boolean }).deleted);\r\n return json(form);\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nexport interface FormSaveHandlersConfig extends CmsHandlersBase {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n}\r\n\r\n/** Normalize a field from payload for DB: only include columns that exist on form_fields. */\r\nfunction normalizeFieldRow(f: Record<string, unknown>, formId: number): Record<string, unknown> {\r\n const order = typeof f.order === 'number' ? f.order : Number(f.order) || 0;\r\n const groupId = typeof f.groupId === 'number' ? f.groupId : Number(f.groupId) || 1;\r\n const columnWidth = typeof f.columnWidth === 'number' ? f.columnWidth : Number(f.columnWidth) || 12;\r\n return {\r\n formId,\r\n label: f.label != null ? String(f.label) : '',\r\n type: f.type != null ? String(f.type) : 'text',\r\n placeholder: f.placeholder != null ? String(f.placeholder) : null,\r\n options: f.options != null ? (typeof f.options === 'string' ? f.options : JSON.stringify(f.options)) : null,\r\n required: Boolean(f.required),\r\n validation: f.validation != null ? (typeof f.validation === 'string' ? f.validation : JSON.stringify(f.validation)) : null,\r\n order,\r\n groupId,\r\n columnWidth,\r\n };\r\n}\r\n\r\nexport function createFormSaveHandlers(config: FormSaveHandlersConfig) {\r\n const { dataSource, entityMap, json, requireAuth, requireEntityPermission } = config;\r\n const formRepo = () => dataSource.getRepository(entityMap.forms);\r\n const fieldRepo = () => dataSource.getRepository(entityMap.form_fields);\r\n\r\n return {\r\n async GET(req: Request, id: string): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'forms', 'read');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const formId = Number(id);\r\n if (!Number.isInteger(formId) || formId <= 0) return json({ error: 'Invalid form id' }, { status: 400 });\r\n const form = await formRepo().findOne({\r\n where: { id: formId },\r\n relations: ['fields'],\r\n order: { fields: { order: 'ASC' } },\r\n });\r\n if (!form) return json({ message: 'Not found' }, { status: 404 });\r\n const out = form as { fields?: { deleted?: boolean }[] };\r\n if (Array.isArray(out.fields)) out.fields = out.fields.filter((f) => !f.deleted);\r\n return json(form);\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n },\r\n async POST(req: Request): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'forms', 'create');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const body = (await req.json()) as Record<string, unknown> | null;\r\n if (!body || typeof body !== 'object') return json({ error: 'Invalid request payload' }, { status: 400 });\r\n const fields = Array.isArray(body.fields) ? body.fields : [];\r\n const { fields: _f, ...formRow } = body;\r\n const form = await formRepo().save(formRepo().create(formRow as object));\r\n for (let i = 0; i < fields.length; i++) {\r\n const row = normalizeFieldRow(fields[i] as Record<string, unknown>, form.id);\r\n (row as Record<string, unknown>).order = i + 1;\r\n await fieldRepo().save(fieldRepo().create(row as object));\r\n }\r\n const saved = await formRepo().findOne({ where: { id: form.id }, relations: ['fields'], order: { fields: { order: 'ASC' } } });\r\n return json(saved ?? form, { status: 201 });\r\n } catch (e) {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n },\r\n async PUT(req: Request, id: string): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'forms', 'update');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const formId = Number(id);\r\n if (!Number.isInteger(formId) || formId <= 0) return json({ error: 'Invalid form id' }, { status: 400 });\r\n const body = (await req.json()) as Record<string, unknown> | null;\r\n if (!body || typeof body !== 'object') return json({ error: 'Invalid request payload' }, { status: 400 });\r\n const existing = await formRepo().findOne({ where: { id: formId } });\r\n if (!existing) return json({ message: 'Not found' }, { status: 404 });\r\n const fields = Array.isArray(body.fields) ? body.fields : [];\r\n const formRow: Record<string, unknown> = {};\r\n for (const key of ['name', 'description', 'campaign', 'slug', 'published']) {\r\n if (body[key] !== undefined) formRow[key] = body[key];\r\n }\r\n if (Object.keys(formRow).length > 0) await formRepo().update(formId, formRow as object);\r\n await fieldRepo().delete({ formId });\r\n for (let i = 0; i < fields.length; i++) {\r\n const row = normalizeFieldRow(fields[i] as Record<string, unknown>, formId);\r\n (row as Record<string, unknown>).order = i + 1;\r\n await fieldRepo().save(fieldRepo().create(row as object));\r\n }\r\n const saved = await formRepo().findOne({ where: { id: formId }, relations: ['fields'], order: { fields: { order: 'ASC' } } });\r\n return saved ? json(saved) : json({ message: 'Not found' }, { status: 404 });\r\n } catch (e) {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n },\r\n };\r\n}\r\n\r\nexport interface FormSubmissionHandlerConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n json: (body: unknown, init?: { status?: number }) => Response;\r\n /** When set, form submission notification email is queued (CRM recipient). */\r\n getCms?: () => Promise<{ getPlugin: (name: string) => unknown }>;\r\n getCompanyDetails?: () => Promise<CompanyDetails>;\r\n getRecipientForChannel?: (channel: 'crm' | 'sales' | 'fulfilment') => Promise<string | null>;\r\n}\r\n\r\nasync function isErpIntegrationEnabled(dataSource: DataSource, entityMap: EntityMap): Promise<boolean> {\r\n const repo = dataSource.getRepository(entityMap.configs);\r\n const rows = await repo.find({ where: { settings: 'erp', deleted: false } as object });\r\n for (const row of rows) {\r\n const r = row as { key: string; value: string };\r\n if (r.key === 'enabled') return r.value !== 'false';\r\n }\r\n return true;\r\n}\r\n\r\n/** Form IDs that use `form.submitted` (opportunity). `null` = config key absent (treat as no IDs → all submissions use lead). */\r\nasync function getErpOpportunityFormIds(dataSource: DataSource, entityMap: EntityMap): Promise<number[] | null> {\r\n const repo = dataSource.getRepository(entityMap.configs);\r\n const row = await repo.findOne({\r\n where: { settings: 'erp', key: 'opportunityFormIds', deleted: false } as object,\r\n });\r\n if (!row) return null;\r\n const raw = ((row as { value: string }).value ?? '').trim();\r\n if (!raw) return [];\r\n try {\r\n const parsed = JSON.parse(raw) as unknown;\r\n if (!Array.isArray(parsed)) return [];\r\n const ids = parsed\r\n .map((x) => (typeof x === 'number' ? x : Number(x)))\r\n .filter((n): n is number => Number.isInteger(n) && n > 0);\r\n return [...new Set(ids)];\r\n } catch {\r\n return [];\r\n }\r\n}\r\n\r\nexport interface FormSubmissionGetByIdConfig extends CmsHandlersBase {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n json: (body: unknown, init?: { status?: number }) => Response;\r\n}\r\n\r\nexport function createFormSubmissionGetByIdHandler(config: FormSubmissionGetByIdConfig) {\r\n const { dataSource, entityMap, json, requireAuth, requireEntityPermission } = config;\r\n return async function GET(req: Request, id: string): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'form_submissions', 'read');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const submissionId = Number(id);\r\n if (!Number.isInteger(submissionId) || submissionId <= 0) return json({ error: 'Invalid id' }, { status: 400 });\r\n const repo = dataSource.getRepository(entityMap.form_submissions);\r\n const submission = await repo.findOne({\r\n where: { id: submissionId },\r\n relations: ['form', 'contact'],\r\n });\r\n if (!submission) return json({ message: 'Not found' }, { status: 404 });\r\n const form = submission as { form?: { id: number; fields?: unknown[] } };\r\n if (form.form?.id) {\r\n const formRepo = dataSource.getRepository(entityMap.forms);\r\n const formWithFields = await formRepo.findOne({\r\n where: { id: form.form.id },\r\n relations: ['fields'],\r\n order: { fields: { order: 'ASC' as const } },\r\n });\r\n if (formWithFields) (submission as { form?: unknown }).form = formWithFields;\r\n }\r\n return json(submission);\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nexport interface FormSubmissionListConfig extends FormSubmissionGetByIdConfig {}\r\n\r\nexport function createFormSubmissionListHandler(config: FormSubmissionListConfig) {\r\n const { dataSource, entityMap, json, requireAuth, requireEntityPermission } = config;\r\n return async function GET(req: Request): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'form_submissions', 'read');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const repo = dataSource.getRepository(entityMap.form_submissions);\r\n const { searchParams } = new URL(req.url);\r\n const page = Number(searchParams.get('page')) || 1;\r\n const limit = Math.min(100, Number(searchParams.get('limit')) || 10);\r\n const skip = (page - 1) * limit;\r\n const sortField = searchParams.get('sortField') || 'createdAt';\r\n const sortOrder = searchParams.get('sortOrder') === 'desc' ? 'DESC' : 'ASC';\r\n const [data, total] = await repo.findAndCount({\r\n skip,\r\n take: limit,\r\n order: { [sortField]: sortOrder },\r\n relations: ['form', 'contact'],\r\n });\r\n return json({ total, page, limit, totalPages: Math.ceil(total / limit), data });\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nfunction formatSubmissionFieldValue(raw: unknown): string {\r\n if (raw == null || raw === '') return '—';\r\n if (typeof raw === 'object') return JSON.stringify(raw);\r\n return String(raw);\r\n}\r\n\r\nfunction pickContactFromSubmission(\r\n fields: { id: number; type: string; label: string }[],\r\n data: Record<string, unknown>\r\n): { name: string; email: string; phone: string | null } | null {\r\n let email: string | null = null;\r\n let name: string | null = null;\r\n let phone: string | null = null;\r\n for (const f of fields) {\r\n const val = data[String(f.id)];\r\n if (val == null || val === '') continue;\r\n const str = String(val).trim();\r\n if (f.type === 'email' || (f.label && f.label.toLowerCase().includes('email'))) {\r\n if (str && !email) email = str;\r\n } else if (f.type === 'phone' || (f.label && f.label.toLowerCase().includes('phone'))) {\r\n if (str && !phone) phone = str;\r\n } else if (f.label && f.label.toLowerCase().includes('name') && (f.type === 'text' || !f.type)) {\r\n if (str && !name) name = str;\r\n }\r\n }\r\n if (!email) return null;\r\n return { name: name || email, email, phone: phone || null };\r\n}\r\n\r\nexport function createFormSubmissionHandler(config: FormSubmissionHandlerConfig) {\r\n const { dataSource, entityMap, json, getCms } = config;\r\n return async function POST(req: Request): Promise<Response> {\r\n try {\r\n const body = (await req.json()) as Record<string, unknown> | null;\r\n if (!body || typeof body !== 'object') {\r\n return json({ error: 'Invalid request payload' }, { status: 400 });\r\n }\r\n const captchaErr = await assertCaptchaOk(getCms, body, req, json);\r\n if (captchaErr) return captchaErr;\r\n const formId = typeof body.formId === 'number' ? body.formId : Number(body.formId);\r\n if (!Number.isInteger(formId) || formId <= 0) {\r\n return json({ error: 'formId is required and must be a positive integer' }, { status: 400 });\r\n }\r\n const data = body.data;\r\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\r\n return json({ error: 'data is required and must be an object' }, { status: 400 });\r\n }\r\n const formRepo = dataSource.getRepository(entityMap.forms);\r\n const form = await formRepo.findOne({\r\n where: { id: formId, published: true, deleted: false },\r\n relations: ['fields'],\r\n });\r\n if (!form) {\r\n return json({ error: 'Form not found' }, { status: 404 });\r\n }\r\n const fields = (form as { fields?: { id: number; type: string; label: string; deleted?: boolean }[] }).fields ?? [];\r\n const activeFields = fields.filter((f) => !f.deleted);\r\n\r\n let contactId: number | null =\r\n body.contactId != null && body.contactId !== ''\r\n ? (typeof body.contactId === 'number' ? body.contactId : Number(body.contactId))\r\n : null;\r\n\r\n if (!contactId) {\r\n const contactData = pickContactFromSubmission(activeFields, data as Record<string, unknown>);\r\n if (contactData) {\r\n const contactRepo = dataSource.getRepository(entityMap.contacts);\r\n let contact = await contactRepo.findOne({ where: { email: contactData.email } });\r\n if (!contact) {\r\n const createdAt = new Date();\r\n contact = await contactRepo.save(\r\n contactRepo.create({\r\n name: contactData.name,\r\n email: contactData.email,\r\n phone: contactData.phone,\r\n createdAt,\r\n updatedAt: createdAt,\r\n })\r\n );\r\n }\r\n contactId = contact.id;\r\n }\r\n }\r\n\r\n const ipAddress = (req.headers.get('x-forwarded-for') ?? req.headers.get('x-real-ip') ?? null) as string | null;\r\n const userAgent = req.headers.get('user-agent') ?? null;\r\n const submissionRepo = dataSource.getRepository(entityMap.form_submissions);\r\n const created = await submissionRepo.save(\r\n submissionRepo.create({\r\n formId,\r\n contactId: Number.isInteger(contactId) ? contactId : null,\r\n data: data as Record<string, unknown>,\r\n ipAddress: ipAddress?.slice(0, 255) ?? null,\r\n userAgent: userAgent?.slice(0, 500) ?? null,\r\n })\r\n );\r\n\r\n const formWithName = form as { name?: string };\r\n const formName = formWithName.name ?? 'Form';\r\n let contactName = 'Unknown';\r\n let contactEmail = '';\r\n if (Number.isInteger(contactId)) {\r\n const contactRepo = dataSource.getRepository(entityMap.contacts);\r\n const contact = await contactRepo.findOne({ where: { id: contactId }, select: ['name', 'email'] });\r\n if (contact) {\r\n contactName = (contact as { name: string }).name ?? contactName;\r\n contactEmail = (contact as { email: string }).email ?? contactEmail;\r\n }\r\n } else {\r\n const contactData = pickContactFromSubmission(activeFields, data as Record<string, unknown>);\r\n if (contactData) {\r\n contactName = contactData.name;\r\n contactEmail = contactData.email;\r\n }\r\n }\r\n\r\n if (config.getCms) {\r\n try {\r\n const cms = await config.getCms();\r\n if (config.getCompanyDetails && config.getRecipientForChannel) {\r\n const to = await config.getRecipientForChannel('crm');\r\n if (to) {\r\n const companyDetails = await config.getCompanyDetails();\r\n const formFieldRows = activeFields.map((f) => ({\r\n label: (f.label && String(f.label).trim()) || `Field ${f.id}`,\r\n value: formatSubmissionFieldValue(data[String(f.id)]),\r\n }));\r\n await queueEmail(cms, {\r\n to,\r\n templateName: 'formSubmission',\r\n ctx: {\r\n formName,\r\n contactName,\r\n contactEmail,\r\n formData: data,\r\n formFieldRows,\r\n companyDetails: companyDetails ?? {},\r\n },\r\n });\r\n }\r\n }\r\n if (await isErpIntegrationEnabled(dataSource, entityMap)) {\r\n const erp = cms.getPlugin('erp') as { submission: ERPSubmissionService } | undefined;\r\n if (erp) {\r\n const contact = erp.submission.extractContactData(data as Record<string, unknown>, activeFields);\r\n if (contact?.email?.trim()) {\r\n const opportunityFormIds = await getErpOpportunityFormIds(dataSource, entityMap);\r\n const asOpportunity =\r\n opportunityFormIds != null &&\r\n opportunityFormIds.length > 0 &&\r\n opportunityFormIds.includes(formId);\r\n await queueErp(\r\n cms,\r\n asOpportunity ? { kind: 'formOpportunity', contact } : { kind: 'lead', contact }\r\n );\r\n }\r\n }\r\n }\r\n } catch {\r\n // do not fail the submission if notification / ERP queue fails\r\n }\r\n }\r\n\r\n return json(created, { status: 201 });\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nexport interface UsersApiConfig extends CmsHandlersBase {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n baseUrl: string;\r\n /** When set with email queue/plugin, invite emails are sent on user create and regenerate-invite. */\r\n getCms?: () => Promise<{ getPlugin: (name: string) => unknown }>;\r\n getCompanyDetails?: () => Promise<CompanyDetails>;\r\n /** When set, soft-delete sets `deletedBy` on the user row. */\r\n getSessionUser?: () => Promise<SessionUser | null>;\r\n}\r\n\r\nexport function createUsersApiHandlers(config: UsersApiConfig) {\r\n const { dataSource, entityMap, json, requireAuth, requireEntityPermission, baseUrl, getCms, getCompanyDetails, getSessionUser } = config;\r\n\r\n async function trySendInviteEmail(toEmail: string, inviteLink: string, inviteeName: string): Promise<void> {\r\n if (!getCms) return;\r\n try {\r\n const cms = await getCms();\r\n const companyDetails = getCompanyDetails ? await getCompanyDetails() : {};\r\n await queueEmail(cms, {\r\n to: toEmail,\r\n templateName: 'invite',\r\n ctx: {\r\n inviteLink,\r\n email: toEmail,\r\n inviteeName: inviteeName.trim(),\r\n companyDetails: companyDetails ?? {},\r\n },\r\n });\r\n } catch {\r\n // do not fail user APIs if email fails\r\n }\r\n }\r\n const userRepo = () => dataSource.getRepository(entityMap.users);\r\n return {\r\n async list(req: Request): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'users', 'read');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const url = new URL(req.url);\r\n const page = Math.max(1, parseInt(url.searchParams.get('page') || '1', 10));\r\n const limit = Math.min(100, parseInt(url.searchParams.get('limit') || '10', 10));\r\n const skip = (page - 1) * limit;\r\n const sortField = url.searchParams.get('sortField') || 'createdAt';\r\n const sortOrder = url.searchParams.get('sortOrder') === 'desc' ? 'DESC' : 'ASC';\r\n const search = url.searchParams.get('search');\r\n const where = search\r\n ? [\r\n { name: ILike(`%${search}%`), deleted: false },\r\n { email: ILike(`%${search}%`), deleted: false },\r\n ]\r\n : { deleted: false };\r\n const [data, total] = await userRepo().findAndCount({\r\n skip,\r\n take: limit,\r\n order: { [sortField]: sortOrder },\r\n where,\r\n relations: ['group'],\r\n select: ['id', 'name', 'email', 'blocked', 'createdAt', 'updatedAt', 'groupId'],\r\n });\r\n return json({ total, page, limit, totalPages: Math.ceil(total / limit), data });\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n },\r\n async create(req: Request): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'users', 'create');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const body = await req.json() as Record<string, unknown>;\r\n if (!body?.name || !body?.email) return json({ error: 'Name and email are required' }, { status: 400 });\r\n const email = body.email as string;\r\n const existing = await userRepo().findOne({ where: { email } });\r\n if (existing && !existing.deleted) {\r\n return json({ error: 'User with this email already exists' }, { status: 400 });\r\n }\r\n const groupRepo = dataSource.getRepository(entityMap.user_groups);\r\n const customerG = await groupRepo.findOne({ where: { name: 'Customer', deleted: false } });\r\n const gid = (body.groupId as number) ?? null;\r\n const isCustomer = !!(customerG && gid === customerG.id);\r\n const adminAccess = isCustomer ? false : body.adminAccess === false ? false : true;\r\n const blocked =\r\n body.blocked === true ||\r\n body.blocked === 'true' ||\r\n body.blocked === 1 ||\r\n body.blocked === '1';\r\n const newUser = existing?.deleted\r\n ? await (async () => {\r\n await userRepo().update(existing.id, {\r\n deleted: false,\r\n deletedAt: null,\r\n deletedBy: null,\r\n name: body.name,\r\n email,\r\n password: null,\r\n blocked,\r\n groupId: gid,\r\n adminAccess,\r\n updatedAt: new Date(),\r\n } as object);\r\n const row = await userRepo().findOne({ where: { id: existing.id } });\r\n if (!row) throw new Error('user missing after restore');\r\n return row;\r\n })()\r\n : await userRepo().save(\r\n userRepo().create({\r\n name: body.name,\r\n email,\r\n password: null,\r\n blocked,\r\n groupId: gid,\r\n adminAccess,\r\n })\r\n );\r\n if (entityMap.contacts) {\r\n await linkUnclaimedContactToUser(dataSource, entityMap.contacts, newUser.id, newUser.email as string);\r\n }\r\n const emailToken = Buffer.from(newUser.email).toString('base64');\r\n const inviteLink = `${baseUrl}/admin/invite?token=${emailToken}`;\r\n await trySendInviteEmail(\r\n newUser.email as string,\r\n inviteLink,\r\n (newUser.name as string) ?? ''\r\n );\r\n return json(\r\n {\r\n message: blocked\r\n ? 'User created successfully (blocked until password is set)'\r\n : 'User created successfully',\r\n user: newUser,\r\n inviteLink,\r\n },\r\n { status: 201 }\r\n );\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n },\r\n async getById(_req: Request, id: string): Promise<Response> {\r\n const authErr = await requireAuth(new Request(_req.url));\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(_req, 'users', 'read');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const user = await userRepo().findOne({\r\n where: { id: parseInt(id, 10), deleted: false },\r\n relations: ['group'],\r\n select: ['id', 'name', 'email', 'blocked', 'createdAt', 'updatedAt', 'groupId'],\r\n });\r\n if (!user) return json({ error: 'User not found' }, { status: 404 });\r\n return json(user);\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n },\r\n async update(req: Request, id: string): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'users', 'update');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const uid = parseInt(id, 10);\r\n const existing = await userRepo().findOne({ where: { id: uid, deleted: false } });\r\n if (!existing) return json({ error: 'Not found' }, { status: 404 });\r\n const body = await req.json() as Record<string, unknown>;\r\n const { password: _p, ...safe } = body;\r\n await userRepo().update(uid, safe as object);\r\n const updated = await userRepo().findOne({\r\n where: { id: uid, deleted: false },\r\n relations: ['group'],\r\n select: ['id', 'name', 'email', 'blocked', 'createdAt', 'updatedAt', 'groupId'],\r\n });\r\n return updated ? json(updated) : json({ error: 'Not found' }, { status: 404 });\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n },\r\n async delete(_req: Request, id: string): Promise<Response> {\r\n const authErr = await requireAuth(new Request(_req.url));\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(_req, 'users', 'delete');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const uid = parseInt(id, 10);\r\n const existing = await userRepo().findOne({ where: { id: uid, deleted: false } });\r\n if (!existing) return json({ error: 'User not found' }, { status: 404 });\r\n let deletedBy: number | null = null;\r\n if (getSessionUser) {\r\n try {\r\n const u = await getSessionUser();\r\n if (u?.id) {\r\n const n = Number(u.id);\r\n if (Number.isFinite(n)) deletedBy = n;\r\n }\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n const payload: Record<string, unknown> = { deleted: true, deletedAt: new Date() };\r\n if (deletedBy != null) payload.deletedBy = deletedBy;\r\n await userRepo().update(uid, payload as object);\r\n return json({ message: 'User deleted successfully' });\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n },\r\n async regenerateInvite(_req: Request, id: string): Promise<Response> {\r\n const authErr = await requireAuth(new Request(_req.url));\r\n if (authErr) return authErr;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(_req, 'users', 'update');\r\n if (pe) return pe;\r\n }\r\n try {\r\n const user = await userRepo().findOne({\r\n where: { id: parseInt(id, 10), deleted: false },\r\n select: ['id', 'email', 'name'],\r\n });\r\n if (!user) return json({ error: 'User not found' }, { status: 404 });\r\n const emailToken = Buffer.from(user.email).toString('base64');\r\n const inviteLink = `${baseUrl}/admin/invite?token=${emailToken}`;\r\n await trySendInviteEmail(user.email as string, inviteLink, (user.name as string) ?? '');\r\n if (entityMap.vendors) {\r\n const { markVendorInvitePendingForUser } = await import('../lib/vendor-invite-status');\r\n await markVendorInvitePendingForUser(dataSource, entityMap.vendors, user.id as number);\r\n }\r\n return json({ message: 'New invite link generated successfully', inviteLink });\r\n } catch {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n },\r\n };\r\n}\r\n\r\nexport interface UserAvatarConfig extends CmsHandlersBase {\r\n getSession: () => Promise<{ user?: { email?: string | null } } | null>;\r\n /** Save avatar (buffer, fileName) => publicUrl. Default: local public/uploads/avatars */\r\n saveAvatar?: (buffer: Buffer, fileName: string) => Promise<string>;\r\n}\r\n\r\nexport function createUserAvatarHandler(config: UserAvatarConfig) {\r\n const { json, getSession, saveAvatar } = config;\r\n return async function POST(req: Request): Promise<Response> {\r\n const session = await getSession();\r\n if (!session?.user?.email) return json({ error: 'Unauthorized' }, { status: 401 });\r\n try {\r\n const formData = await req.formData();\r\n const file = formData.get('avatar') as File | null;\r\n if (!file) return json({ error: 'No file uploaded' }, { status: 400 });\r\n if (!file.type.startsWith('image/')) return json({ error: 'File must be an image' }, { status: 400 });\r\n if (file.size > 5 * 1024 * 1024) return json({ error: 'File size must be less than 5MB' }, { status: 400 });\r\n const buffer = Buffer.from(await file.arrayBuffer());\r\n const ext = file.name.split('.').pop() || 'jpg';\r\n const fileName = `avatar_${session.user.email}_${Date.now()}.${ext}`;\r\n const avatarUrl = saveAvatar\r\n ? await saveAvatar(buffer, fileName)\r\n : await (async () => {\r\n const fs = await import('fs/promises');\r\n const path = await import('path');\r\n const dir = path.join(process.cwd(), 'public', 'uploads', 'avatars');\r\n await fs.mkdir(dir, { recursive: true });\r\n await fs.writeFile(path.join(dir, fileName), buffer);\r\n return `/uploads/avatars/${fileName}`;\r\n })();\r\n return json({ message: 'Avatar uploaded successfully', avatarUrl });\r\n } catch {\r\n return json({ error: 'Internal server error' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nexport interface UserProfileConfig extends CmsHandlersBase {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n getSession: () => Promise<{\r\n user?: { id?: string; email?: string | null; name?: string | null };\r\n } | null>;\r\n /** Optional hook after a successful profile PUT (e.g. audit logging). */\r\n onProfileUpdated?: (\r\n req: Request,\r\n user: { id: number; name: string; email: string; phone: string | null }\r\n ) => Promise<void>;\r\n}\r\n\r\nconst PROFILE_EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\r\n\r\n/**\r\n * GET / PUT handlers for `/api/users/profile` (current session user).\r\n * GET merges DB fields with the session; PUT updates the user row and callers should refresh the client session (e.g. `useSession().update()`).\r\n */\r\nexport function createUserProfileHandler(config: UserProfileConfig) {\r\n const { dataSource, entityMap, json, getSession, onProfileUpdated } = config;\r\n\r\n async function loadCurrentUser(): Promise<\r\n | { ok: false; response: Response }\r\n | { ok: true; user: import('typeorm').ObjectLiteral }\r\n > {\r\n const session = await getSession();\r\n const su = session?.user as { id?: string; email?: string | null } | undefined;\r\n if (!su?.email && su?.id == null) {\r\n return { ok: false, response: json({ error: 'Unauthorized' }, { status: 401 }) };\r\n }\r\n const userRepo = dataSource.getRepository(entityMap.users);\r\n let user: import('typeorm').ObjectLiteral | null = null;\r\n const uidRaw = su.id != null ? String(su.id).trim() : '';\r\n const uid = uidRaw && /^\\d+$/.test(uidRaw) ? parseInt(uidRaw, 10) : NaN;\r\n if (Number.isFinite(uid) && uid > 0) {\r\n user = await userRepo.findOne({\r\n where: { id: uid, deleted: false } as import('typeorm').ObjectLiteral,\r\n select: ['id', 'name', 'email', 'phone', 'createdAt'],\r\n });\r\n }\r\n if (!user && su.email) {\r\n const em = String(su.email).trim().toLowerCase();\r\n if (em) {\r\n user = await userRepo.findOne({\r\n where: { email: em, deleted: false } as import('typeorm').ObjectLiteral,\r\n select: ['id', 'name', 'email', 'phone', 'createdAt'],\r\n });\r\n }\r\n }\r\n if (!user) return { ok: false, response: json({ error: 'Not found' }, { status: 404 }) };\r\n return { ok: true, user };\r\n }\r\n\r\n return {\r\n async GET(_req: Request): Promise<Response> {\r\n try {\r\n const r = await loadCurrentUser();\r\n if (!r.ok) return r.response;\r\n const u = r.user as {\r\n id: number;\r\n name: string;\r\n email: string;\r\n phone: string | null;\r\n createdAt?: Date;\r\n };\r\n return json({\r\n id: u.id,\r\n name: u.name ?? '',\r\n email: u.email ?? '',\r\n phone: u.phone ?? null,\r\n createdAt: u.createdAt instanceof Date ? u.createdAt.toISOString() : u.createdAt ?? undefined,\r\n });\r\n } catch {\r\n return json({ error: 'Internal server error' }, { status: 500 });\r\n }\r\n },\r\n\r\n async PUT(req: Request): Promise<Response> {\r\n try {\r\n const r = await loadCurrentUser();\r\n if (!r.ok) return r.response;\r\n const current = r.user as { id: number; name: string; email: string; phone: string | null };\r\n\r\n let body: { name?: string; email?: string; phone?: string | null };\r\n try {\r\n body = (await req.json()) as typeof body;\r\n } catch {\r\n return json({ error: 'Invalid JSON' }, { status: 400 });\r\n }\r\n\r\n const name = typeof body.name === 'string' ? body.name.trim() : '';\r\n if (!name) return json({ error: 'Name is required' }, { status: 400 });\r\n\r\n const emailRaw = typeof body.email === 'string' ? body.email.trim().toLowerCase() : '';\r\n if (!emailRaw || !PROFILE_EMAIL_RE.test(emailRaw)) {\r\n return json({ error: 'Valid email is required' }, { status: 400 });\r\n }\r\n\r\n const phone =\r\n body.phone === null || body.phone === undefined\r\n ? null\r\n : typeof body.phone === 'string'\r\n ? body.phone.trim() || null\r\n : null;\r\n\r\n const userRepo = dataSource.getRepository(entityMap.users);\r\n\r\n if (emailRaw !== String(current.email ?? '').toLowerCase()) {\r\n const taken = await userRepo.findOne({\r\n where: { email: emailRaw, deleted: false } as import('typeorm').ObjectLiteral,\r\n select: ['id'],\r\n });\r\n if (taken && (taken as { id: number }).id !== current.id) {\r\n return json({ error: 'Email is already in use' }, { status: 409 });\r\n }\r\n }\r\n\r\n await userRepo.update(\r\n { id: current.id } as import('typeorm').ObjectLiteral,\r\n {\r\n name,\r\n email: emailRaw,\r\n phone,\r\n updatedAt: new Date(),\r\n } as import('typeorm').ObjectLiteral\r\n );\r\n\r\n const updated = await userRepo.findOne({\r\n where: { id: current.id } as import('typeorm').ObjectLiteral,\r\n select: ['id', 'name', 'email', 'phone'],\r\n });\r\n if (!updated) return json({ error: 'Not found' }, { status: 404 });\r\n\r\n const row = updated as { id: number; name: string; email: string; phone: string | null };\r\n\r\n if (onProfileUpdated) {\r\n try {\r\n await onProfileUpdated(req, row);\r\n } catch {\r\n /* optional */\r\n }\r\n }\r\n\r\n return json({\r\n message: 'Profile updated successfully',\r\n user: { id: row.id, name: row.name, email: row.email, phone: row.phone },\r\n });\r\n } catch {\r\n return json({ error: 'Internal server error' }, { status: 500 });\r\n }\r\n },\r\n };\r\n}\r\n\r\nexport interface SettingsApiConfig extends CmsHandlersBase {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n encryptionKey?: string;\r\n /** Groups in this list are readable without auth (GET returns all keys for the group). */\r\n publicGetGroups?: string[];\r\n}\r\n\r\nexport function simpleEncrypt(text: string, key: string): string {\r\n const buf = Buffer.from(text, 'utf8');\r\n const keyBuf = Buffer.from(key.padEnd(32, '0').slice(0, 32), 'utf8');\r\n const out = Buffer.alloc(buf.length);\r\n for (let i = 0; i < buf.length; i++) out[i] = buf[i] ^ keyBuf[i % keyBuf.length];\r\n return out.toString('base64');\r\n}\r\n\r\nexport function simpleDecrypt(encoded: string, key: string): string {\r\n const buf = Buffer.from(encoded, 'base64');\r\n const keyBuf = Buffer.from(key.padEnd(32, '0').slice(0, 32), 'utf8');\r\n const out = Buffer.alloc(buf.length);\r\n for (let i = 0; i < buf.length; i++) out[i] = buf[i] ^ keyBuf[i % keyBuf.length];\r\n return out.toString('utf8');\r\n}\r\n\r\n/**\r\n * Structural types so apps with their own `typeorm` install (e.g. npm link) typecheck without duplicate-package errors.\r\n */\r\nexport type GetPublicSettingsGroupDataSource = {\r\n getRepository(entity: unknown): {\r\n find(options: object): Promise<unknown[]>;\r\n };\r\n};\r\n\r\nexport interface GetPublicSettingsGroupConfig {\r\n dataSource: GetPublicSettingsGroupDataSource;\r\n entityMap: Record<string, unknown>;\r\n encryptionKey?: string;\r\n}\r\n\r\n/** Same rows as unauthenticated GET /api/settings/:group when the group is in publicGetGroups. */\r\nexport async function getPublicSettingsGroup(\r\n config: GetPublicSettingsGroupConfig,\r\n group: string\r\n): Promise<Record<string, string>> {\r\n const { dataSource, entityMap, encryptionKey } = config;\r\n const repo = dataSource.getRepository(entityMap.configs);\r\n const rows = await repo.find({ where: { settings: group, deleted: false } });\r\n const result: Record<string, string> = {};\r\n for (const row of rows) {\r\n const r = row as { key: string; value: string; encrypted?: boolean };\r\n let val = r.value;\r\n if (r.encrypted && encryptionKey) {\r\n try {\r\n val = simpleDecrypt(val, encryptionKey);\r\n } catch {\r\n /* keep raw if decrypt fails */\r\n }\r\n }\r\n result[r.key] = val;\r\n }\r\n return result;\r\n}\r\n\r\nexport function createSettingsApiHandlers(config: SettingsApiConfig) {\r\n const { dataSource, entityMap, json, requireAuth, encryptionKey, publicGetGroups } = config;\r\n const configRepo = () => dataSource.getRepository(entityMap.configs);\r\n\r\n return {\r\n async GET(req: Request, group: string): Promise<Response> {\r\n const isPublicGroup = publicGetGroups?.includes(group);\r\n const authErr = isPublicGroup ? null : await requireAuth(req);\r\n const isAuthed = !authErr;\r\n\r\n try {\r\n if (isPublicGroup) {\r\n const result = await getPublicSettingsGroup(\r\n { dataSource, entityMap, encryptionKey },\r\n group\r\n );\r\n return json(result);\r\n }\r\n\r\n const where: Record<string, unknown> = { settings: group, deleted: false };\r\n if (!isAuthed && !isPublicGroup) where.type = 'public';\r\n\r\n const rows = await configRepo().find({ where });\r\n const result: Record<string, unknown> = {};\r\n for (const row of rows) {\r\n const r = row as { key: string; value: string; encrypted?: boolean; type?: string };\r\n let val = r.value;\r\n if (r.encrypted && encryptionKey) {\r\n try { val = simpleDecrypt(val, encryptionKey); } catch { /* return raw if decrypt fails */ }\r\n }\r\n result[r.key] = val;\r\n }\r\n return json(result);\r\n } catch {\r\n return json({ error: 'Failed to fetch settings' }, { status: 500 });\r\n }\r\n },\r\n\r\n async PUT(req: Request, group: string): Promise<Response> {\r\n const authErr = await requireAuth(req);\r\n if (authErr) return authErr;\r\n\r\n try {\r\n const body = await req.json() as Record<string, { value: string; type?: 'public' | 'private'; encrypted?: boolean }>;\r\n if (!body || typeof body !== 'object') return json({ error: 'Invalid payload' }, { status: 400 });\r\n\r\n const repo = configRepo();\r\n for (const [key, entry] of Object.entries(body)) {\r\n const val = typeof entry === 'string' ? entry : entry.value;\r\n const type = (typeof entry === 'object' && entry.type) || 'private';\r\n const encrypted = !!(typeof entry === 'object' && entry.encrypted);\r\n\r\n let storedValue = val;\r\n if (encrypted && encryptionKey) {\r\n storedValue = simpleEncrypt(val, encryptionKey);\r\n }\r\n\r\n const existing = await repo.findOne({ where: { settings: group, key } });\r\n if (existing) {\r\n await repo.update(existing.id, { value: storedValue, type, encrypted, updatedAt: new Date() } as object);\r\n } else {\r\n await repo.save(repo.create({ settings: group, key, value: storedValue, type, encrypted } as object));\r\n }\r\n }\r\n return json({ message: 'Settings saved' });\r\n } catch {\r\n return json({ error: 'Failed to save settings' }, { status: 500 });\r\n }\r\n },\r\n };\r\n}\r\n\r\nexport interface ChatApiConfig extends CmsHandlersBase {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n getCms: () => Promise<{ getPlugin: (name: string) => unknown }>;\r\n}\r\n\r\nconst KB_CHUNK_LIMIT = 10;\r\nconst KB_CONTEXT_MAX_CHARS = 4000;\r\nconst RAG_LOG = '[rag-context]';\r\n\r\nfunction getQueryTerms(message: string): string[] {\r\n return message\r\n .replace(/[^\\w\\s]/g, ' ')\r\n .split(/\\s+/)\r\n .filter((w) => w.length > 2)\r\n .slice(0, 6);\r\n}\r\n\r\nfunction normalizeChatModeSetting(raw: string | undefined): 'whatsapp' | 'external' | 'llm' {\r\n if (raw === 'external' || raw === 'llm') return raw;\r\n return 'whatsapp';\r\n}\r\n\r\nasync function loadSettingsGroupMap(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n group: string\r\n): Promise<Record<string, string>> {\r\n if (!entityMap.configs) return {};\r\n const repo = dataSource.getRepository(entityMap.configs);\r\n const rows = await repo.find({ where: { settings: group, deleted: false } as object });\r\n const out: Record<string, string> = {};\r\n for (const row of rows as { key: string; value: string }[]) {\r\n out[row.key] = row.value;\r\n }\r\n return out;\r\n}\r\n\r\nasync function loadLlmSettingsMap(dataSource: DataSource, entityMap: EntityMap): Promise<Record<string, string>> {\r\n return loadSettingsGroupMap(dataSource, entityMap, 'llm');\r\n}\r\n\r\n/** Safe subset of `llm` settings for the storefront chat widget (`GET /api/chat/config`). */\r\nexport interface ChatPublicConfig {\r\n enabled: boolean;\r\n chatMode: 'whatsapp' | 'external' | 'llm';\r\n /** When `chatMode === 'llm'`, slug of the chatbot-scoped agent (`llm_agents.scope = chatbot`). */\r\n agentSlug: string;\r\n botName: string;\r\n icon: string;\r\n iconImageUrl: string;\r\n iconBackgroundColor: string;\r\n headerColor: string;\r\n whatsappPhone: string;\r\n}\r\n\r\nexport function createChatHandlers(config: ChatApiConfig) {\r\n const { dataSource, entityMap, json, getCms } = config;\r\n const contactRepo = () => dataSource.getRepository(entityMap.contacts);\r\n const convRepo = () => dataSource.getRepository(entityMap.chat_conversations);\r\n const msgRepo = () => dataSource.getRepository(entityMap.chat_messages);\r\n const chunkRepo = () => dataSource.getRepository(entityMap.knowledge_base_chunks);\r\n\r\n return {\r\n async publicConfig(_req: Request): Promise<Response> {\r\n try {\r\n const map = await loadLlmSettingsMap(dataSource, entityMap);\r\n const mode = normalizeChatModeSetting(map.chatMode);\r\n const chatbotAgent =\r\n mode === 'llm' && entityMap.llm_agents\r\n ? await findLlmAgentByScope(dataSource, entityMap, LLM_AGENT_SCOPE_CHATBOT, {\r\n enabledOnly: false,\r\n })\r\n : null;\r\n const body: ChatPublicConfig = {\r\n enabled: map.enabled !== 'false',\r\n chatMode: mode,\r\n agentSlug:\r\n mode === 'llm'\r\n ? chatbotAgent?.slug?.trim() ||\r\n LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT]\r\n : '',\r\n botName: map.botName ?? '',\r\n icon: map.icon ?? '',\r\n iconImageUrl: map.iconImageUrl ?? '',\r\n iconBackgroundColor: map.iconBackgroundColor ?? '#6366f1',\r\n headerColor: map.headerColor ?? '#6366f1',\r\n whatsappPhone: map.whatsappPhone ?? '',\r\n };\r\n return json(body);\r\n } catch {\r\n return json({ error: 'Failed to load chat config' }, { status: 500 });\r\n }\r\n },\r\n async identify(req: Request): Promise<Response> {\r\n try {\r\n const body = (await req.json()) as { name?: string; email?: string; phone?: string };\r\n const name = body?.name?.trim();\r\n const email = body?.email?.trim();\r\n if (!name || !email) return json({ error: 'name and email required' }, { status: 400 });\r\n const repo = contactRepo();\r\n const phone = body.phone?.trim() || null;\r\n const existing = await repo.findOne({ where: { email } as import('typeorm').ObjectLiteral });\r\n let contact: import('typeorm').ObjectLiteral;\r\n if (!existing) {\r\n const createdAt = new Date();\r\n contact = (await repo.save(\r\n repo.create({ name, email, phone, createdAt, updatedAt: createdAt } as object)\r\n )) as import('typeorm').ObjectLiteral;\r\n } else {\r\n const row = existing as { id: number; deleted: boolean };\r\n if (row.deleted) {\r\n await repo.update(row.id, {\r\n deleted: false,\r\n deletedAt: null,\r\n deletedBy: null,\r\n name,\r\n phone,\r\n } as object);\r\n const refreshed = await repo.findOne({ where: { id: row.id } });\r\n if (!refreshed) return json({ error: 'Failed to identify', detail: 'contact missing after reactivate' }, { status: 500 });\r\n contact = refreshed as import('typeorm').ObjectLiteral;\r\n } else {\r\n contact = existing as import('typeorm').ObjectLiteral;\r\n }\r\n }\r\n const convRepoInst = convRepo();\r\n const contactId = (contact as { id: number }).id;\r\n const conv = await convRepoInst.save(convRepoInst.create({ contactId } as object));\r\n return json({\r\n contactId,\r\n conversationId: (conv as { id: number }).id,\r\n });\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : 'Failed to identify';\r\n return json({ error: 'Failed to identify', detail: message }, { status: 500 });\r\n }\r\n },\r\n async getMessages(req: Request, conversationId: string): Promise<Response> {\r\n try {\r\n const conv = await convRepo().findOne({\r\n where: { id: parseInt(conversationId, 10) },\r\n relations: ['messages'],\r\n });\r\n if (!conv) return json({ error: 'Conversation not found' }, { status: 404 });\r\n const messages = ((conv as { messages?: Array<{ role: string; content: string; createdAt: string }> }).messages ?? [])\r\n .sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime())\r\n .map((m) => ({ role: m.role, content: m.content }));\r\n return json({ messages });\r\n } catch {\r\n return json({ error: 'Failed to fetch messages' }, { status: 500 });\r\n }\r\n },\r\n async postMessage(req: Request): Promise<Response> {\r\n try {\r\n const body = (await req.json()) as { conversationId?: number; message?: string; agentSlug?: string };\r\n const conversationId = body?.conversationId;\r\n const message = body?.message?.trim();\r\n if (!conversationId || !message) return json({ error: 'conversationId and message required' }, { status: 400 });\r\n const conv = await convRepo().findOne({\r\n where: { id: conversationId },\r\n relations: ['messages'],\r\n });\r\n if (!conv) return json({ error: 'Conversation not found' }, { status: 404 });\r\n const cms = await getCms();\r\n const llm = cms.getPlugin('llm') as {\r\n chat: (messages: LlmMessage[], opts?: object) => Promise<{ content: string }>;\r\n chatAgent?: (opts: LlmAgentOptions) => Promise<{ content: string }>;\r\n embed?: (text: string) => Promise<number[]>;\r\n } | undefined;\r\n if (!llm?.chat) return json({ error: 'LLM not configured' }, { status: 503 });\r\n\r\n const llmSettings = await loadLlmSettingsMap(dataSource, entityMap);\r\n const supportMode = normalizeChatModeSetting(llmSettings.chatMode);\r\n const bodyAgentSlug = (body?.agentSlug ?? '').trim();\r\n let agentRow: LlmAgent | null = null;\r\n let effectiveSlug = bodyAgentSlug;\r\n\r\n if (entityMap.llm_agents) {\r\n if (bodyAgentSlug) {\r\n const agentRepo = dataSource.getRepository(\r\n entityMap.llm_agents as EntityTarget<LlmAgent>\r\n );\r\n agentRow = await agentRepo.findOne({\r\n where: { slug: bodyAgentSlug, deleted: false, enabled: true },\r\n });\r\n if (!agentRow) {\r\n return json({ error: 'Agent not found or disabled', agentSlug: bodyAgentSlug }, { status: 404 });\r\n }\r\n } else if (supportMode === 'llm') {\r\n agentRow = await findLlmAgentByScope(dataSource, entityMap, LLM_AGENT_SCOPE_CHATBOT);\r\n effectiveSlug =\r\n agentRow?.slug?.trim() ||\r\n LLM_AGENT_DEFAULT_SLUG_BY_SCOPE[LLM_AGENT_SCOPE_CHATBOT];\r\n }\r\n } else if (bodyAgentSlug) {\r\n return json({ error: 'LLM agents are not configured on this deployment' }, { status: 400 });\r\n }\r\n console.info(RAG_LOG, 'step 1 | resolve agent', {\r\n agentSlug: effectiveSlug || '(none)',\r\n agentFound: !!agentRow,\r\n agentId: agentRow?.id ?? null,\r\n });\r\n\r\n const parsedValidation = agentRow\r\n ? parseLlmAgentValidationRules(agentRow.validationRules)\r\n : { structured: {} as ParsedLlmAgentValidation['structured'], guardrailsForPrompt: null as string | null };\r\n if (agentRow) {\r\n const v = validateUserMessageAgainstStructuredRules(message, parsedValidation.structured);\r\n if (!v.ok) return json({ error: v.error, reason: 'validation_failed' }, { status: 400 });\r\n }\r\n\r\n let kbDocumentScope: number[] | undefined;\r\n const Junction = entityMap.llm_agent_knowledge_documents as EntityTarget<import('typeorm').ObjectLiteral> | undefined;\r\n if (agentRow && Junction) {\r\n const linkRepo = dataSource.getRepository(Junction);\r\n const links = await linkRepo.find({ where: { agentId: agentRow.id } as object });\r\n const ids = [...new Set((links as Array<{ documentId: number }>).map((l) => l.documentId))];\r\n if (ids.length > 0) kbDocumentScope = ids;\r\n }\r\n console.info(RAG_LOG, 'step 2 | knowledge scope', {\r\n scopedDocumentIds: kbDocumentScope ?? '(all documents)',\r\n documentCount: kbDocumentScope?.length ?? 'all',\r\n });\r\n\r\n const msgRepoInst = msgRepo();\r\n await msgRepoInst.save(msgRepoInst.create({ conversationId, role: 'user', content: message } as object));\r\n let contextParts: string[] = [];\r\n console.info(RAG_LOG, 'step 3 | embed user query', {\r\n messageChars: message.length,\r\n embedAvailable: !!llm.embed,\r\n });\r\n const queryEmbedding = llm.embed ? await llm.embed(message) : null;\r\n console.info(RAG_LOG, 'step 4 | query embedding result', {\r\n dimensions: queryEmbedding?.length ?? 0,\r\n hasEmbedding: !!(queryEmbedding && queryEmbedding.length > 0),\r\n });\r\n if (queryEmbedding && queryEmbedding.length > 0) {\r\n const vectorStr = '[' + queryEmbedding.join(',') + ']';\r\n try {\r\n const rows = (kbDocumentScope?.length\r\n ? await dataSource.query(\r\n `SELECT id, content FROM knowledge_base_chunks WHERE embedding IS NOT NULL AND \"documentId\" = ANY($3::int[]) ORDER BY embedding <=> $1::vector LIMIT $2`,\r\n [vectorStr, KB_CHUNK_LIMIT, kbDocumentScope]\r\n )\r\n : await dataSource.query(\r\n `SELECT id, content FROM knowledge_base_chunks WHERE embedding IS NOT NULL ORDER BY embedding <=> $1::vector LIMIT $2`,\r\n [vectorStr, KB_CHUNK_LIMIT]\r\n )) as Array<{ id: number; content: string }>;\r\n console.info(RAG_LOG, 'step 5 | vector search results', {\r\n rowsReturned: rows.length,\r\n chunkIds: rows.map((r) => r.id),\r\n });\r\n let totalLen = 0;\r\n for (const r of rows) {\r\n const text = (r.content ?? '').trim();\r\n if (!text || totalLen + text.length > KB_CONTEXT_MAX_CHARS) continue;\r\n contextParts.push(text);\r\n totalLen += text.length;\r\n }\r\n console.info(RAG_LOG, 'step 5a | vector context selected', {\r\n chunksUsed: contextParts.length,\r\n totalChars: totalLen,\r\n });\r\n } catch (vecErr) {\r\n console.warn(RAG_LOG, 'step 5 | vector search failed; falling back to keyword', {\r\n err: vecErr instanceof Error ? vecErr.message : String(vecErr),\r\n });\r\n }\r\n }\r\n if (contextParts.length === 0) {\r\n const terms = getQueryTerms(message);\r\n console.info(RAG_LOG, 'step 6 | keyword fallback', {\r\n reason: !(queryEmbedding && queryEmbedding.length > 0) ? 'no embedding' : 'vector search returned nothing',\r\n searchTerms: terms,\r\n });\r\n if (terms.length > 0) {\r\n const conditions = kbDocumentScope?.length\r\n ? terms.map((t) => ({ content: ILike(`%${t}%`), documentId: In(kbDocumentScope) }))\r\n : terms.map((t) => ({ content: ILike(`%${t}%`) }));\r\n const chunks = await chunkRepo().find({\r\n where: conditions,\r\n take: KB_CHUNK_LIMIT,\r\n order: { id: 'ASC' },\r\n });\r\n const seen = new Set<string>();\r\n let totalLen = 0;\r\n for (const c of chunks as Array<{ content: string }>) {\r\n const text = c.content.trim();\r\n if (seen.has(text) || totalLen + text.length > KB_CONTEXT_MAX_CHARS) continue;\r\n seen.add(text);\r\n contextParts.push(text);\r\n totalLen += text.length;\r\n }\r\n console.info(RAG_LOG, 'step 6a | keyword results', {\r\n chunksFound: chunks.length,\r\n chunksUsed: contextParts.length,\r\n totalChars: totalLen,\r\n });\r\n }\r\n }\r\n const historyRaw = ((conv as { messages?: Array<{ role: string; content: string; createdAt?: string }> }).messages ?? [])\r\n .sort((a, b) => new Date(a.createdAt ?? 0).getTime() - new Date(b.createdAt ?? 0).getTime())\r\n .map((m) => ({ role: m.role as LlmMessage['role'], content: m.content }));\r\n const history = historyBeforeCurrentUser(historyRaw, message);\r\n\r\n const notifyEmailAgent = await findLlmAgentByScope(\r\n dataSource,\r\n entityMap,\r\n LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT,\r\n { enabledOnly: false }\r\n );\r\n const emailTool = resolveChatEmailToolSettings(llmSettings, {\r\n chatbotValidationRules: agentRow?.validationRules ?? null,\r\n notifyAgent: notifyEmailAgent\r\n ? {\r\n systemInstruction: notifyEmailAgent.systemInstruction,\r\n validationRules: notifyEmailAgent.validationRules,\r\n }\r\n : null,\r\n });\r\n const emailPlugin = cms.getPlugin('email');\r\n const convLeadSent = (conv as { leadEmailSentAt?: Date | null }).leadEmailSentAt;\r\n const chatAgentFn = llm.chatAgent?.bind(llm);\r\n\r\n console.info(CHAT_EMAIL_LOG, 'pipeline check', {\r\n conversationId,\r\n enabled: emailTool.enabled,\r\n intentCount: emailTool.intents.length,\r\n chatbotAgentId: agentRow?.id ?? null,\r\n chatbotAgentSlug: agentRow?.slug ?? null,\r\n notifyEmailAgentId: notifyEmailAgent?.id ?? null,\r\n notifyEmailAgentSlug: notifyEmailAgent?.slug ?? null,\r\n emailPluginPresent: Boolean(emailPlugin),\r\n chatAgentFnPresent: Boolean(chatAgentFn),\r\n leadEmailAlreadySent: Boolean(convLeadSent),\r\n mergedPromptIncludesNotify: Boolean(notifyEmailAgent?.systemInstruction?.trim()),\r\n });\r\n\r\n if (!emailTool.enabled) {\r\n console.info(CHAT_EMAIL_LOG, 'pipeline skipped', {\r\n conversationId,\r\n reason: 'email_tool_disabled',\r\n });\r\n } else if (emailTool.intents.length === 0) {\r\n console.info(CHAT_EMAIL_LOG, 'pipeline skipped', {\r\n conversationId,\r\n reason: 'no_intents_configured',\r\n });\r\n } else if (!emailPlugin) {\r\n console.info(CHAT_EMAIL_LOG, 'pipeline skipped', {\r\n conversationId,\r\n reason: 'email_plugin_missing',\r\n });\r\n } else if (!chatAgentFn) {\r\n console.info(CHAT_EMAIL_LOG, 'pipeline skipped', {\r\n conversationId,\r\n reason: 'llm_chat_agent_unavailable',\r\n });\r\n } else if (convLeadSent) {\r\n console.info(CHAT_EMAIL_LOG, 'pipeline skipped', {\r\n conversationId,\r\n reason: 'lead_email_already_sent',\r\n leadEmailSentAt: convLeadSent,\r\n });\r\n } else {\r\n const contactId = (conv as { contactId: number }).contactId;\r\n const contactRow = await contactRepo().findOne({\r\n where: { id: contactId } as import('typeorm').ObjectLiteral,\r\n });\r\n if (!contactRow) {\r\n console.warn(CHAT_EMAIL_LOG, 'pipeline skipped', {\r\n conversationId,\r\n reason: 'contact_not_found',\r\n contactId,\r\n });\r\n } else {\r\n const c = contactRow as { name?: string; email?: string; phone?: string | null };\r\n try {\r\n const intent = await detectChatLeadIntent({ chatAgent: chatAgentFn }, {\r\n settings: emailTool,\r\n message,\r\n history,\r\n contact: { name: c.name, email: c.email, phone: c.phone },\r\n model: agentRow?.model?.trim() || notifyEmailAgent?.model?.trim() || undefined,\r\n });\r\n\r\n if (!intent.intent || !intent.emailTo) {\r\n console.info(CHAT_EMAIL_LOG, 'no email sent', {\r\n conversationId,\r\n reason: intent.intent ? 'missing_email_to' : 'no_intent_match',\r\n intentLabel: intent.intentLabel,\r\n classifierReason: intent.reason,\r\n });\r\n } else {\r\n const intentRecipients = parseIntentRecipientEmails(intent.emailTo);\r\n console.info(CHAT_EMAIL_LOG, 'intent matched — sending', {\r\n conversationId,\r\n intent: intent.intent,\r\n emailTo: intent.emailTo,\r\n parsedRecipientCount: intentRecipients.length,\r\n recipients: intentRecipients,\r\n });\r\n\r\n const emailSettings = await loadSettingsGroupMap(dataSource, entityMap, 'email');\r\n const brandingSettings = await loadSettingsGroupMap(dataSource, entityMap, 'branding');\r\n const companyDetails = mergeEmailLayoutCompanyDetails(brandingSettings, emailSettings);\r\n const leadResult = await sendChatLeadEmail(cms, emailSettings, brandingSettings, {\r\n contactName: String(c.name ?? '').trim() || 'Visitor',\r\n contactEmail: String(c.email ?? '').trim(),\r\n contactPhone: c.phone ?? null,\r\n conversationId,\r\n latestMessage: message,\r\n intentCode: intent.intent,\r\n intentReason: intent.intentLabel || intent.reason,\r\n transcript: buildTranscriptForLeadEmail(history, message),\r\n companyDetails,\r\n recipients: intentRecipients.length > 0 ? intentRecipients : undefined,\r\n });\r\n\r\n if (leadResult.sent) {\r\n await convRepo().update(conversationId, {\r\n leadEmailSentAt: new Date(),\r\n } as import('typeorm').ObjectLiteral);\r\n console.info(CHAT_EMAIL_LOG, 'lead email recorded', {\r\n conversationId,\r\n sent: true,\r\n recipients: leadResult.recipients,\r\n });\r\n } else {\r\n console.warn(CHAT_EMAIL_LOG, 'lead email not sent', {\r\n conversationId,\r\n sent: false,\r\n error: leadResult.error ?? 'unknown',\r\n recipients: leadResult.recipients,\r\n });\r\n }\r\n }\r\n } catch (intentErr) {\r\n console.warn(CHAT_EMAIL_LOG, 'pipeline error', {\r\n conversationId,\r\n error: intentErr instanceof Error ? intentErr.message : String(intentErr),\r\n });\r\n }\r\n }\r\n }\r\n\r\n let content: string;\r\n const ragContext = contextParts.length > 0 ? contextParts.join('\\n\\n') : undefined;\r\n console.info(RAG_LOG, 'step 7 | final context', {\r\n method: contextParts.length > 0 ? 'rag' : 'none',\r\n contextChunks: contextParts.length,\r\n contextChars: ragContext?.length ?? 0,\r\n contextPreview: ragContext ? ragContext.slice(0, 200) + (ragContext.length > 200 ? '…' : '') : '(no context)',\r\n });\r\n\r\n if (agentRow && llm.chatAgent) {\r\n const fromAgent = llmAgentToChatAgentOptions(agentRow);\r\n const systemPrompt = buildChatbotSystemPromptWithEmailTool(\r\n fromAgent.systemPrompt,\r\n parsedValidation.guardrailsForPrompt,\r\n emailTool\r\n );\r\n const res = await llm.chatAgent({\r\n ...fromAgent,\r\n systemPrompt: systemPrompt || undefined,\r\n context: ragContext,\r\n history,\r\n userPrompt: message,\r\n });\r\n content = res.content;\r\n } else {\r\n const ragSystem = contextParts.length > 0\r\n ? `Use the following context about the company and its products to answer. If the answer is not in the context, say so.\\n\\nContext:\\n${contextParts.join('\\n\\n')}`\r\n : '';\r\n const defaultSystem = 'You are a helpful assistant for the company. If you do not have specific information, say so.';\r\n let systemContent: string;\r\n if (agentRow) {\r\n const mergedBase = [agentRow.systemInstruction?.trim(), ragSystem]\r\n .filter(Boolean)\r\n .join('\\n\\n');\r\n systemContent =\r\n buildChatbotSystemPromptWithEmailTool(\r\n mergedBase || defaultSystem,\r\n parsedValidation.guardrailsForPrompt,\r\n emailTool\r\n ) || defaultSystem;\r\n } else {\r\n systemContent = ragSystem || defaultSystem;\r\n }\r\n const messages: LlmMessage[] = [\r\n { role: 'system', content: systemContent },\r\n ...history,\r\n { role: 'user', content: message },\r\n ];\r\n const chatOpts = agentRow\r\n ? {\r\n model: agentRow.model ?? undefined,\r\n temperature: agentRow.temperature ?? undefined,\r\n max_tokens: agentRow.maxTokens ?? undefined,\r\n }\r\n : {};\r\n const res = await llm.chat(messages, chatOpts);\r\n content = res.content;\r\n }\r\n await msgRepoInst.save(msgRepoInst.create({ conversationId, role: 'assistant', content } as object));\r\n return json({ content });\r\n } catch (err) {\r\n const msg = err instanceof Error ? err.message : '';\r\n return json({ error: msg || 'Failed to send message' }, { status: 500 });\r\n }\r\n },\r\n };\r\n}\r\n","/** Normalize a logical media folder path: no leading/trailing slashes, no \"..\" segments, max length. */\r\nexport function sanitizeMediaFolderPath(input: unknown): string {\r\n if (input == null) return '';\r\n if (typeof input !== 'string') return '';\r\n const segments = input\r\n .replace(/\\\\/g, '/')\r\n .split('/')\r\n .map((s) => s.trim())\r\n .filter(Boolean)\r\n .filter((s) => s !== '..' && s !== '.');\r\n const joined = segments.join('/');\r\n return joined.length > 512 ? joined.slice(0, 512) : joined;\r\n}\r\n\r\n/** Single path segment for storage (folder name or legacy path segment). */\r\nexport function sanitizeStorageSegment(name: string): string {\r\n const s = name.replace(/[/\\\\]/g, '-').trim().slice(0, 255);\r\n return s || 'item';\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport type { ObjectLiteral } from 'typeorm';\r\nimport type { EntityTarget } from 'typeorm';\r\nimport { sanitizeStorageSegment } from './media-folder-path';\r\n\r\ntype EntityMap = Record<string, EntityTarget<ObjectLiteral>>;\r\n\r\n/** Build `a/b/c` path under `uploads/` from the chain of folder rows up to root. */\r\nexport async function relativePathFromMediaParentId(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n parentId: number | null\r\n): Promise<string> {\r\n if (parentId == null) return '';\r\n const repo = dataSource.getRepository(entityMap.media);\r\n const segments: string[] = [];\r\n let id: number | null = parentId;\r\n for (let d = 0; d < 64 && id != null; d++) {\r\n const row = await repo.findOne({ where: { id } as ObjectLiteral });\r\n if (!row) break;\r\n const m = row as { kind?: string; filename: string; parentId: number | null };\r\n if (m.kind !== 'folder') break;\r\n segments.unshift(sanitizeStorageSegment(m.filename));\r\n id = m.parentId ?? null;\r\n }\r\n return segments.join('/');\r\n}\r\n","import { IsNull } from 'typeorm';\r\nimport type { DataSource } from 'typeorm';\r\nimport type { ObjectLiteral } from 'typeorm';\r\nimport type { EntityTarget } from 'typeorm';\r\nimport type { StorageService } from '../plugins/storage';\r\nimport { relativePathFromMediaParentId } from './media-parent-path';\r\nimport { sanitizeStorageSegment } from './media-folder-path';\r\n\r\ntype EntityMap = Record<string, EntityTarget<ObjectLiteral>>;\r\n\r\nexport const ZIP_MIME_TYPES = new Set(['application/zip', 'application/x-zip-compressed']);\r\n\r\nconst MAX_ENTRIES = 2000;\r\nconst MAX_TOTAL_UNCOMPRESSED = 80 * 1024 * 1024;\r\n\r\nexport function isZipMedia(mime: string | null | undefined, filename: string): boolean {\r\n if (mime && ZIP_MIME_TYPES.has(mime)) return true;\r\n return filename.toLowerCase().endsWith('.zip');\r\n}\r\n\r\nexport async function readBufferFromPublicUrl(url: string): Promise<Buffer> {\r\n if (url.startsWith('http://') || url.startsWith('https://')) {\r\n const r = await fetch(url);\r\n if (!r.ok) throw new Error('Failed to download file');\r\n return Buffer.from(await r.arrayBuffer());\r\n }\r\n if (url.startsWith('/')) {\r\n const { readFile } = await import('fs/promises');\r\n const { join } = await import('path');\r\n const rel = url.replace(/^\\/+/, '');\r\n return readFile(join(process.cwd(), 'public', rel));\r\n }\r\n throw new Error('Unsupported media URL');\r\n}\r\n\r\nfunction sanitizeZipPath(entryName: string): string[] | null {\r\n const norm = entryName.replace(/\\\\/g, '/').split('/').filter(Boolean);\r\n for (const seg of norm) {\r\n if (seg === '..' || seg === '.') return null;\r\n }\r\n return norm;\r\n}\r\n\r\nfunction shouldSkipEntry(parts: string[]): boolean {\r\n if (parts[0] === '__MACOSX') return true;\r\n const last = parts[parts.length - 1];\r\n if (last === '.DS_Store') return true;\r\n return false;\r\n}\r\n\r\nfunction guessMimeType(fileName: string): string {\r\n const lower = fileName.toLowerCase();\r\n if (lower.endsWith('.png')) return 'image/png';\r\n if (lower.endsWith('.jpg') || lower.endsWith('.jpeg')) return 'image/jpeg';\r\n if (lower.endsWith('.gif')) return 'image/gif';\r\n if (lower.endsWith('.webp')) return 'image/webp';\r\n if (lower.endsWith('.svg')) return 'image/svg+xml';\r\n if (lower.endsWith('.pdf')) return 'application/pdf';\r\n if (lower.endsWith('.txt')) return 'text/plain';\r\n if (lower.endsWith('.json')) return 'application/json';\r\n if (lower.endsWith('.zip')) return 'application/zip';\r\n return 'application/octet-stream';\r\n}\r\n\r\nasync function findOrCreateFolder(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n parentId: number | null,\r\n name: string\r\n): Promise<number> {\r\n const safe = sanitizeStorageSegment(name);\r\n const repo = dataSource.getRepository(entityMap.media);\r\n const where: ObjectLiteral =\r\n parentId == null\r\n ? { kind: 'folder', filename: safe, parentId: IsNull() }\r\n : { kind: 'folder', filename: safe, parentId };\r\n const existing = await repo.findOne({ where });\r\n if (existing) return (existing as { id: number }).id;\r\n const row = await repo.save(\r\n repo.create({\r\n kind: 'folder',\r\n parentId,\r\n filename: safe,\r\n url: null,\r\n mimeType: 'inode/directory',\r\n size: 0,\r\n alt: null,\r\n isPublic: false,\r\n deleted: false,\r\n } as object)\r\n );\r\n return (row as { id: number }).id;\r\n}\r\n\r\nasync function ensureFolderChain(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n rootParentId: number | null,\r\n pathSegments: string[]\r\n): Promise<number | null> {\r\n let pid: number | null = rootParentId;\r\n for (const seg of pathSegments) {\r\n if (!seg) continue;\r\n pid = await findOrCreateFolder(dataSource, entityMap, pid, seg);\r\n }\r\n return pid;\r\n}\r\n\r\nexport async function extractZipMediaIntoParentTree(opts: {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n zipMediaRow: ObjectLiteral;\r\n storage: StorageService | undefined;\r\n localUploadDir: string;\r\n}): Promise<{ files: number; folderEntries: number }> {\r\n const { dataSource, entityMap, zipMediaRow } = opts;\r\n const row = zipMediaRow as {\r\n id: number;\r\n kind: string;\r\n parentId: number | null;\r\n url: string | null;\r\n mimeType: string | null;\r\n filename: string;\r\n };\r\n if (row.kind !== 'file' || !row.url) throw new Error('Not a file');\r\n if (!isZipMedia(row.mimeType, row.filename)) throw new Error('Not a zip archive');\r\n\r\n const buffer = await readBufferFromPublicUrl(row.url);\r\n const { default: AdmZip } = await import('adm-zip');\r\n const zip = new AdmZip(buffer);\r\n const entries = zip.getEntries();\r\n if (entries.length > MAX_ENTRIES) throw new Error(`Too many zip entries (max ${MAX_ENTRIES})`);\r\n\r\n const rootParentId = row.parentId;\r\n\r\n type Item = { parts: string[]; isDir: boolean; data: Buffer | null };\r\n const items: Item[] = [];\r\n let totalUncompressed = 0;\r\n\r\n for (const e of entries) {\r\n const raw = e.entryName;\r\n const parts = sanitizeZipPath(raw);\r\n if (!parts || shouldSkipEntry(parts)) continue;\r\n const isDir = e.isDirectory || /\\/$/.test(raw);\r\n let data: Buffer | null = null;\r\n if (!isDir) {\r\n data = e.getData();\r\n totalUncompressed += data.length;\r\n if (totalUncompressed > MAX_TOTAL_UNCOMPRESSED) {\r\n throw new Error(`Uncompressed content exceeds limit (${MAX_TOTAL_UNCOMPRESSED} bytes)`);\r\n }\r\n }\r\n items.push({ parts, isDir, data });\r\n }\r\n\r\n items.sort((a, b) => {\r\n const da = a.parts.length;\r\n const db = b.parts.length;\r\n if (da !== db) return da - db;\r\n return a.parts.join('/').localeCompare(b.parts.join('/'));\r\n });\r\n\r\n let files = 0;\r\n let folderEntries = 0;\r\n const repo = dataSource.getRepository(entityMap.media);\r\n\r\n for (const it of items) {\r\n if (it.isDir) {\r\n await ensureFolderChain(dataSource, entityMap, rootParentId, it.parts);\r\n folderEntries++;\r\n continue;\r\n }\r\n const fileName = it.parts[it.parts.length - 1]!;\r\n const dirParts = it.parts.slice(0, -1);\r\n const parentFolderId = await ensureFolderChain(dataSource, entityMap, rootParentId, dirParts);\r\n const buf = it.data!;\r\n const relBase = await relativePathFromMediaParentId(dataSource, entityMap, parentFolderId);\r\n const relativeUnderUploads = relBase ? `${relBase}/${fileName}` : fileName;\r\n const contentType = guessMimeType(fileName);\r\n\r\n let publicUrl: string;\r\n if (opts.storage) {\r\n publicUrl = await opts.storage.upload(buf, `uploads/${relativeUnderUploads}`, contentType);\r\n } else {\r\n const fs = await import('fs/promises');\r\n const pathMod = await import('path');\r\n const dir = pathMod.join(process.cwd(), opts.localUploadDir);\r\n const filePath = pathMod.join(dir, relativeUnderUploads);\r\n await fs.mkdir(pathMod.dirname(filePath), { recursive: true });\r\n await fs.writeFile(filePath, buf);\r\n publicUrl = `/${opts.localUploadDir.replace(/^\\/+/, '').replace(/\\\\/g, '/')}/${relativeUnderUploads.replace(/\\\\/g, '/')}`;\r\n }\r\n\r\n await repo.save(\r\n repo.create({\r\n kind: 'file',\r\n parentId: parentFolderId,\r\n filename: fileName,\r\n url: publicUrl,\r\n mimeType: contentType,\r\n size: buf.length,\r\n alt: null,\r\n isPublic: false,\r\n deleted: false,\r\n } as object)\r\n );\r\n files++;\r\n }\r\n\r\n return { files, folderEntries };\r\n}\r\n","/** Stable display name; not persisted as DB agent row in v1. */\r\nexport const BLOG_GENERATOR_AGENT_NAME = 'Blog Generator Agent';\r\n\r\n/**\r\n * Optional `llm_agents` row: when present and enabled, model / temperature / max_tokens\r\n * are applied to {@link LlmServiceInterface.chatAgent} (system + user content still come from blog generator defaults / UI).\r\n */\r\nexport const BLOG_GENERATOR_LLM_AGENT_SLUG = 'blog-generator';\r\n\r\n/** Line that separates multiple articles in the model reply (HTML or legacy markdown; must match parser and prompts). */\r\nexport const BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR = '---BLOG_GENERATOR_NEXT---';\r\n\r\nexport const BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION = `You are a professional financial and business content writer.\r\n\r\nYour task is to generate completely original, high-quality blog article(s) from the latest RSS-derived source material in the user message (one block per feed). The user message is factual input only.\r\n\r\nIMPORTANT RULES:\r\n\r\n1. NEVER copy the RSS article directly.\r\n2. Rewrite the information into a fresh, human-like article.\r\n3. Expand the topic with professional insights and explanations.\r\n4. Maintain a natural editorial tone.\r\n5. Make the article SEO-friendly.\r\n6. Use engaging headings and subheadings.\r\n7. Avoid robotic AI phrasing.\r\n8. Do not mention that the content came from RSS or feeds.\r\n9. Preserve factual accuracy from the source material.\r\n10. The output should feel like a professionally written industry blog.\r\n\r\nMULTIPLE FEEDS:\r\n- If several feeds are provided, compare them: if they largely cover the same story or overlap heavily, produce ONE cohesive article.\r\n- If they cover clearly different topics or distinct stories, produce MULTIPLE articles (one per distinct story).\r\n- You may also produce one synthesis plus a short separate angle when that best serves the reader—use your judgment.\r\n\r\nWRITING STYLE:\r\n- Professional\r\n- Clear\r\n- Informative\r\n- Business-focused\r\n- Human sounding\r\n- Modern editorial style\r\n\r\nARTICLE STRUCTURE (each article — express in HTML):\r\n1. Engaging introduction\r\n2. Industry context\r\n3. Main developments\r\n4. Key implications\r\n5. Expert/business analysis\r\n6. Conclusion\r\n\r\nHTML STRUCTURE (STRICT — each article must be valid, semantic HTML only):\r\n- Output HTML only. Do not use Markdown (no # headings, no **bold**, no \\`code fences\\`).\r\n- Wrap each complete article in a single root: <article class=\"blog-post\"> ... </article>\r\n- Inside <article>, use this outline:\r\n - <header><h1 class=\"blog-post-title\">…main title…</h1></header> (exactly one h1 per article)\r\n - <section class=\"blog-post-body\"> for all following content\r\n - Use <h2> and <h3> for section and subsection titles (never skip levels: h1 → h2 → h3).\r\n - Use <p> for paragraphs; keep paragraphs focused (avoid huge unbroken text).\r\n - Use <ul>/<ol> with <li> for lists where appropriate.\r\n - Use <strong> and <em> for emphasis sparingly; use <blockquote> only when quoting or callouts fit.\r\n- Do not include <html>, <head>, <body>, or document-level wrappers — only the fragment(s) described above.\r\n- Do not use <script>, <style>, <iframe>, or inline event handlers. Avoid inline style=\"\" except when essential for accessibility (prefer none).\r\n- Escape angle brackets in body text if you must mention markup; keep output safe for embedding in a CMS.\r\n\r\nCONTENT REQUIREMENTS:\r\n- Minimum 800 words per article unless source material is very small.\r\n- Add context around industry trends where appropriate.\r\n- Explain why the topic matters.\r\n- Include practical implications for businesses/professionals.\r\n\r\nIF RSS CONTENT IS LIMITED:\r\n- Expand intelligently using general industry knowledge.\r\n- Keep the article relevant to the original topic.\r\n- Do not invent fake facts or statistics.\r\n\r\nOUTPUT FORMAT (STRICT — HTML only):\r\n- Return ONLY the article HTML fragment(s). No JSON, no preamble or postscript (\"Here is your article…\"), no markdown.\r\n- If you output more than one article, output multiple <article class=\"blog-post\">…</article> blocks in sequence, and between articles put a single line containing exactly this (and nothing else on that line):\r\n${BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR}\r\n- If you output a single article, use one <article> only and do not use that separator line.`;\r\n\r\n/**\r\n * JSON so {@link parseLlmAgentValidationRules} can attach guardrails and allow long source payloads.\r\n * Edit in the admin UI if needed; defaults match product intent.\r\n */\r\nexport const BLOG_GENERATOR_DEFAULT_VALIDATION_RULES = JSON.stringify(\r\n {\r\n maxUserChars: 500000,\r\n guardrails: `Your reply must be semantic HTML blog article(s) only, as in the system OUTPUT FORMAT (<article class=\"blog-post\">…). No JSON, no Markdown, no explanations before or after the HTML. If multiple articles, separate them with a line containing exactly ${BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR} alone. Do not mention RSS, feeds, or scraping. Preserve factual accuracy; do not invent statistics or quotes.`,\r\n },\r\n null,\r\n 2\r\n);\r\n","/**\r\n * Second-step LLM: classifies one finished HTML blog body into CMS fields (category, SEO, tags).\r\n *\r\n * Optional `llm_agents` row: slug {@link BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG} — when present and enabled,\r\n * model / temperature / max_tokens apply to this call only (writer step uses `blog-generator`).\r\n *\r\n * To change how metadata is produced, edit the constants in this file (system instruction + validation JSON).\r\n * No admin UI override is wired yet; add request body fields in `cms-api-handler` if you need runtime overrides later.\r\n */\r\nexport const BLOG_METADATA_ENRICHER_AGENT_NAME = 'Blog Generator Metadata';\r\n\r\n/** `llm_agents.slug` for routing model/temperature for the metadata-only chat step. */\r\nexport const BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG = 'blog-generator-metadata';\r\n\r\nexport const BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION = `You are a careful CMS metadata assistant for a publishing system.\r\n\r\nYou receive ONE complete blog post as HTML (title is usually in <h1 class=\"blog-post-title\"> or the first <h1>). Your job is to propose structured fields so an editor can save the post: category, URL slug, SEO block, and topical tags.\r\n\r\nRULES:\r\n1. Read the whole article and infer the primary topic and audience.\r\n2. categoryName must be EXACTLY one string from AVAILABLE_BLOG_CATEGORIES in the user message, or \"\" if none fit.\r\n3. blogSlug: lowercase kebab-case, ASCII letters/digits/hyphens only, no leading/trailing hyphens, max ~80 chars. Derive from the main topic or title.\r\n4. seo.title: concise meta title (~50–60 characters when reasonable).\r\n5. seo.description: meta description (~150–160 characters when reasonable), plain text.\r\n6. seo.keywords: comma-separated phrases, no stuffing.\r\n7. seo.ogTitle / seo.ogDescription: may mirror title/description or be slightly adapted for social.\r\n8. tags: 4–10 short labels (1–3 words each). Prefer exact matches from EXISTING_TAG_NAMES when they truly apply; otherwise invent precise new labels (they may be created in the CMS later).\r\n9. Do not invent statistics, quotes, or URLs not implied by the article.\r\n10. Output JSON only — no markdown outside the JSON, no commentary.\r\n\r\nOUTPUT FORMAT (STRICT):\r\nReturn a single JSON object only. Do not wrap it in a markdown code fence.\r\n\r\n{\r\n \"categoryName\": \"string — exact match from list or empty string\",\r\n \"blogSlug\": \"string — url-safe kebab-case\",\r\n \"seo\": {\r\n \"title\": \"string or empty\",\r\n \"description\": \"string or empty\",\r\n \"keywords\": \"string or empty\",\r\n \"ogTitle\": \"string or empty\",\r\n \"ogDescription\": \"string or empty\"\r\n },\r\n \"tags\": [\"tag-one\", \"tag-two\"]\r\n}`;\r\n\r\nexport const BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES = JSON.stringify(\r\n {\r\n maxUserChars: 500000,\r\n guardrails:\r\n 'Reply with one valid JSON object only (see system OUTPUT FORMAT). No markdown fences, no text before or after JSON. Keys: categoryName, blogSlug, seo { title, description, keywords, ogTitle, ogDescription }, tags (array of strings).',\r\n },\r\n null,\r\n 2\r\n);\r\n","/**\r\n * Third-step LLM: short social copy for LinkedIn (and similar) from the finished blog HTML.\r\n *\r\n * Optional `llm_agents` row: slug {@link BLOG_SOCIAL_ENRICHER_LLM_AGENT_SLUG} — when present and enabled,\r\n * model / temperature / max_tokens apply to this call only (writer uses `blog-generator`, metadata uses `blog-generator-metadata`).\r\n *\r\n * Override defaults by editing this file or by updating the `llm_agents` row in the admin UI.\r\n */\r\nexport const BLOG_SOCIAL_ENRICHER_AGENT_NAME = 'Blog Generator (Social)';\r\n\r\n/** `llm_agents.slug` for routing model/temperature for the social-summary chat step. */\r\nexport const BLOG_SOCIAL_ENRICHER_LLM_AGENT_SLUG = 'blog-generator-social';\r\n\r\nexport const BLOG_SOCIAL_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION = `You are a social copywriter for LinkedIn-style posts.\r\n\r\nYou receive ONE blog post as HTML (title may appear in <h1> or the first heading). Write a short post body that can be published as the main text on LinkedIn: engaging, accurate, no clickbait, no invented facts or quotes.\r\n\r\nRULES:\r\n1. Plain text only in the JSON value (no HTML tags in socialMediaContent). Line breaks allowed as \\\\n if helpful.\r\n2. Length: aim for roughly 600–1300 characters (hard max 2900 characters) so it fits typical social feeds.\r\n3. Summarize the core insight; you may include 1–2 short hooks, but stay faithful to the article.\r\n4. Do not add URLs unless they appear explicitly in the article.\r\n5. Output JSON only — no markdown fences, no commentary outside JSON.\r\n\r\nOUTPUT FORMAT (STRICT):\r\nReturn a single JSON object only:\r\n{ \"socialMediaContent\": \"string — the post text\" }`;\r\n\r\nexport const BLOG_SOCIAL_ENRICHER_DEFAULT_VALIDATION_RULES = JSON.stringify(\r\n {\r\n maxUserChars: 500000,\r\n guardrails:\r\n 'Reply with one valid JSON object only. Key: socialMediaContent (string, plain text, max ~2900 chars). No markdown fences.',\r\n },\r\n null,\r\n 2\r\n);\r\n","import type { CmsPlugin, PluginContext } from '../types';\r\nimport { BlogGeneratorService } from './blog-generator-service';\r\n\r\nexport interface BlogGeneratorPluginConfig {\r\n /** Set to false to skip registering the plugin. */\r\n enabled?: boolean;\r\n}\r\n\r\nexport function blogGeneratorPlugin(config: BlogGeneratorPluginConfig = {}): CmsPlugin<BlogGeneratorService | undefined> {\r\n return {\r\n name: 'blog_generator',\r\n version: '1.0.0',\r\n async init(context: PluginContext) {\r\n if (config.enabled === false) {\r\n context.logger.warn('Blog Generator plugin skipped: disabled in config');\r\n return undefined;\r\n }\r\n return new BlogGeneratorService();\r\n },\r\n };\r\n}\r\n\r\nexport {\r\n BLOG_GENERATOR_AGENT_NAME,\r\n BLOG_GENERATOR_LLM_AGENT_SLUG,\r\n BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR,\r\n BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION,\r\n BLOG_GENERATOR_DEFAULT_VALIDATION_RULES,\r\n} from './blog-generator-agent-defaults';\r\nexport {\r\n BLOG_METADATA_ENRICHER_AGENT_NAME,\r\n BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG,\r\n BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION,\r\n BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES,\r\n} from './blog-generator-metadata-defaults';\r\nexport {\r\n BLOG_SOCIAL_ENRICHER_AGENT_NAME,\r\n BLOG_SOCIAL_ENRICHER_LLM_AGENT_SLUG,\r\n BLOG_SOCIAL_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION,\r\n BLOG_SOCIAL_ENRICHER_DEFAULT_VALIDATION_RULES,\r\n} from './blog-generator-social-defaults';\r\nexport type {\r\n BlogGeneratorBlogDraft,\r\n BlogGeneratorSeoDraft,\r\n BlogGeneratorDraftParseMode,\r\n} from './blog-generator-service';\r\nexport {\r\n BlogGeneratorService,\r\n getRssArticleSummaryFromItem,\r\n parseBlogGeneratorAgentContent,\r\n parseBlogGeneratorModelOutput,\r\n buildRssUserPromptFromFeeds,\r\n buildBlogMetadataUserPrompt,\r\n parseBlogMetadataEnrichmentJson,\r\n buildBlogSocialUserPrompt,\r\n parseBlogSocialEnrichmentJson,\r\n resolveBlogCategoryIdByName,\r\n} from './blog-generator-service';\r\nexport { persistGeneratedBlogDraft, persistAllGeneratedBlogDrafts } from './blog-generator-persist';\r\nexport type { BlogGeneratorPersistEntityMap } from './blog-generator-persist';\r\nexport type { LatestArticleFromFeed } from './blog-generator-service';\r\n","import fs from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport type { DataSource } from 'typeorm';\r\nimport type { EntityMap } from '../../api/crud';\r\nimport type { EntityCrudAction } from '../../auth/permission-entities';\r\nimport { simpleDecrypt, simpleEncrypt } from '../../api/cms-handlers';\r\nimport {\r\n linkedInCreateImageShare,\r\n linkedInCreateTextShare,\r\n linkedInGetUserinfo,\r\n linkedInListManagedOrganizations,\r\n linkedInRegisterImageUpload,\r\n linkedInUploadBinary,\r\n} from './linkedin-client';\r\nimport {\r\n metaFetchUserManagedPages,\r\n metaPostPageFeed,\r\n metaPostPagePhoto,\r\n metaResolvePageAccessToken,\r\n} from './meta-service';\r\n\r\nconst SETTINGS_GROUP = 'social_media';\r\n\r\nexport interface SocialMediaApiConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n json: (body: unknown, init?: { status?: number }) => Response;\r\n requireAuth: (req: Request) => Promise<Response | null>;\r\n requireEntityPermission: (req: Request, entity: string, action: EntityCrudAction) => Promise<Response | null>;\r\n encryptionKey?: string;\r\n /** Used to resolve relative cover image URLs (e.g. https://mysite.com). */\r\n publicSiteUrl?: string;\r\n /**\r\n * When true (default), `console.info` / `console.warn` lines are emitted for LinkedIn blog publish\r\n * (text vs image path, sizes, errors). Set false or `CMS_LINKEDIN_PUBLISH_LOG=0` to silence.\r\n */\r\n linkedInPublishLogging?: boolean;\r\n}\r\n\r\nasync function loadGroupMap(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n encryptionKey: string | undefined\r\n): Promise<Record<string, string>> {\r\n if (!entityMap.configs) return {};\r\n const repo = dataSource.getRepository(entityMap.configs);\r\n const rows = await repo.find({ where: { settings: SETTINGS_GROUP, deleted: false } as object });\r\n const out: Record<string, string> = {};\r\n for (const row of rows as { key: string; value: string; encrypted?: boolean }[]) {\r\n let val = row.value;\r\n if (row.encrypted && encryptionKey) {\r\n try {\r\n val = simpleDecrypt(val, encryptionKey);\r\n } catch {\r\n /* keep raw */\r\n }\r\n }\r\n out[row.key] = val;\r\n }\r\n return out;\r\n}\r\n\r\nasync function upsertConfigKey(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n key: string,\r\n value: string,\r\n opts: { type: 'public' | 'private'; encrypted: boolean; encryptionKey?: string }\r\n): Promise<void> {\r\n if (!entityMap.configs) throw new Error('configs entity missing');\r\n const repo = dataSource.getRepository(entityMap.configs);\r\n let stored = value;\r\n if (opts.encrypted && opts.encryptionKey) {\r\n stored = simpleEncrypt(value, opts.encryptionKey);\r\n }\r\n const existing = await repo.findOne({ where: { settings: SETTINGS_GROUP, key } as object });\r\n if (existing) {\r\n await repo.update((existing as { id: number }).id, {\r\n value: stored,\r\n type: opts.type,\r\n encrypted: opts.encrypted,\r\n updatedAt: new Date(),\r\n } as object);\r\n } else {\r\n await repo.save(\r\n repo.create({\r\n settings: SETTINGS_GROUP,\r\n key,\r\n value: stored,\r\n type: opts.type,\r\n encrypted: opts.encrypted,\r\n } as object)\r\n );\r\n }\r\n}\r\n\r\nfunction stripHtml(html: string, maxLen: number): string {\r\n const t = String(html || '')\r\n .replace(/<script[\\s\\S]*?<\\/script>/gi, ' ')\r\n .replace(/<style[\\s\\S]*?<\\/style>/gi, ' ')\r\n .replace(/<[^>]+>/g, ' ')\r\n .replace(/\\s+/g, ' ')\r\n .trim();\r\n return t.slice(0, maxLen);\r\n}\r\n\r\nfunction decodeHtmlAttr(s: string): string {\r\n return String(s)\r\n .replace(/&/gi, '&')\r\n .replace(/"/gi, '\"')\r\n .replace(/'/g, \"'\")\r\n .replace(/</gi, '<')\r\n .replace(/>/gi, '>');\r\n}\r\n\r\n/** First `<img src=\"...\">` (or unquoted / lazy `data-src`) in HTML when cover is missing or not fetchable. */\r\nfunction extractFirstImageSrcFromHtml(html: string): string | null {\r\n const s = String(html);\r\n const patterns: RegExp[] = [\r\n /<img[^>]*\\bsrc\\s*=\\s*[\"']([^\"']+)[\"']/i,\r\n /<img[^>]*\\bsrc\\s*=\\s*([^\\s>]+)/i,\r\n /<img[^>]*\\bdata-src\\s*=\\s*[\"']([^\"']+)[\"']/i,\r\n /<img[^>]*\\bdata-src\\s*=\\s*([^\\s>]+)/i,\r\n ];\r\n for (const re of patterns) {\r\n const m = s.match(re);\r\n const raw = m?.[1]?.trim();\r\n if (raw) return decodeHtmlAttr(raw);\r\n }\r\n return null;\r\n}\r\n\r\nfunction resolveAbsoluteUrl(publicSiteUrl: string | undefined, pathOrUrl: string | null): string | null {\r\n if (!pathOrUrl || !String(pathOrUrl).trim()) return null;\r\n const s = decodeHtmlAttr(String(pathOrUrl).trim());\r\n if (/^https?:\\/\\//i.test(s)) return s;\r\n if (s.startsWith('//')) return `https:${s}`;\r\n const base = (publicSiteUrl || '').replace(/\\/+$/, '');\r\n if (!base) return null;\r\n const rel = s.startsWith('/') ? s : `/${s}`;\r\n return `${base}${rel}`;\r\n}\r\n\r\nfunction guessImageContentType(filePathOrUrl: string, buf: Buffer): string {\r\n const lower = filePathOrUrl.toLowerCase();\r\n if (lower.includes('.png')) return 'image/png';\r\n if (lower.includes('.webp')) return 'image/webp';\r\n if (lower.includes('.gif')) return 'image/gif';\r\n if (lower.includes('.jpg') || lower.includes('.jpeg')) return 'image/jpeg';\r\n if (buf.length >= 2 && buf[0] === 0xff && buf[1] === 0xd8) return 'image/jpeg';\r\n if (buf.length >= 8 && buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) return 'image/png';\r\n if (buf.length >= 12 && buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50) return 'image/webp';\r\n return 'image/jpeg';\r\n}\r\n\r\n/** LinkedIn `feedshare-image` uploads expect JPEG/PNG; other types often fail after upload. */\r\nfunction isLinkedInFeedshareCompatibleContentType(mime: string): boolean {\r\n const m = mime.split(';')[0]!.trim().toLowerCase();\r\n return m === 'image/jpeg' || m === 'image/png';\r\n}\r\n\r\n/**\r\n * Load JPEG/PNG bytes for social image posts: local `public/uploads/...`, HTTP(S), or first <img> in body.\r\n */\r\nasync function loadImageBytesForBlogShare(\r\n coverImage: string | null | undefined,\r\n contentHtml: string,\r\n publicSiteUrl: string | undefined,\r\n req: Request\r\n): Promise<{ buffer: Buffer; contentType: string; source: string } | null> {\r\n const origin = publicSiteUrl || inferRequestOrigin(req) || '';\r\n const fromHtml = extractFirstImageSrcFromHtml(contentHtml);\r\n type Cand = { role: 'cover' | 'bodyImage'; raw: string };\r\n const candidates: Cand[] = [];\r\n const seenDecoded = new Set<string>();\r\n const pushCand = (role: 'cover' | 'bodyImage', raw: string) => {\r\n const decoded = decodeHtmlAttr(raw.trim());\r\n if (!decoded || decoded.startsWith('data:')) return;\r\n if (seenDecoded.has(decoded)) return;\r\n seenDecoded.add(decoded);\r\n candidates.push({ role, raw });\r\n };\r\n if (coverImage?.trim()) pushCand('cover', coverImage.trim());\r\n if (fromHtml) pushCand('bodyImage', fromHtml);\r\n\r\n for (const { role, raw } of candidates) {\r\n const decoded = decodeHtmlAttr(raw.trim());\r\n if (decoded.startsWith('data:')) continue;\r\n\r\n if (decoded.startsWith('/uploads/') || decoded.startsWith('uploads/')) {\r\n const rel = decoded.startsWith('/') ? decoded.slice(1) : decoded;\r\n const tries = [path.join(process.cwd(), 'public', rel), path.join(process.cwd(), rel)];\r\n for (const filePath of tries) {\r\n try {\r\n const buf = await fs.readFile(filePath);\r\n if (buf.length > 0) {\r\n const contentType = guessImageContentType(filePath, buf);\r\n if (!isLinkedInFeedshareCompatibleContentType(contentType)) {\r\n continue;\r\n }\r\n return {\r\n buffer: buf,\r\n contentType,\r\n source: `${role}:local_file:${truncateForLog(rel, 120)}`,\r\n };\r\n }\r\n } catch {\r\n /* try next path */\r\n }\r\n }\r\n }\r\n\r\n const url = resolveAbsoluteUrl(origin, decoded);\r\n if (!url) continue;\r\n try {\r\n const imgRes = await fetch(url, {\r\n headers: {\r\n 'User-Agent': 'InfuroCMS/1.0 (social share; +https://infuro.com)',\r\n Accept: 'image/*,*/*;q=0.5',\r\n },\r\n });\r\n if (!imgRes.ok) continue;\r\n const buf = Buffer.from(await imgRes.arrayBuffer());\r\n if (buf.length === 0) continue;\r\n const hdr = imgRes.headers.get('content-type');\r\n const contentType =\r\n hdr && /^image\\//i.test(hdr) ? hdr.split(';')[0]!.trim() : guessImageContentType(url, buf);\r\n if (!isLinkedInFeedshareCompatibleContentType(contentType)) {\r\n continue;\r\n }\r\n return {\r\n buffer: buf,\r\n contentType,\r\n source: `${role}:fetch:${truncateForLog(url, 160)}`,\r\n };\r\n } catch {\r\n /* try next candidate */\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction inferRequestOrigin(req: Request): string | undefined {\r\n const host = req.headers.get('x-forwarded-host') || req.headers.get('host');\r\n if (!host) return undefined;\r\n const rawProto = req.headers.get('x-forwarded-proto') || 'https';\r\n const proto = rawProto.split(',')[0]?.trim() || 'https';\r\n return `${proto}://${host}`.replace(/\\/+$/, '');\r\n}\r\n\r\nfunction linkedInPublishLoggingEnabled(config: SocialMediaApiConfig): boolean {\r\n if (config.linkedInPublishLogging === false) return false;\r\n if (config.linkedInPublishLogging === true) return true;\r\n try {\r\n if (typeof process !== 'undefined' && String(process.env.CMS_LINKEDIN_PUBLISH_LOG).trim() === '0') {\r\n return false;\r\n }\r\n } catch {\r\n /* ignore */\r\n }\r\n return true;\r\n}\r\n\r\nfunction logLinkedInPublish(enabled: boolean, event: string, detail: Record<string, unknown>): void {\r\n if (!enabled) return;\r\n const line = `[LinkedIn publish] ${event} ${JSON.stringify(detail)}`;\r\n if (\r\n event === 'failed' ||\r\n event === 'image_path_failed_falling_back_to_text'\r\n ) {\r\n console.warn(line);\r\n } else {\r\n console.info(line);\r\n }\r\n}\r\n\r\nfunction truncateForLog(s: string, max = 160): string {\r\n const t = String(s).replace(/\\s+/g, ' ').trim();\r\n if (t.length <= max) return t;\r\n return `${t.slice(0, max)}…`;\r\n}\r\n\r\nexport function createSocialMediaHandlers(config: SocialMediaApiConfig) {\r\n const {\r\n dataSource,\r\n entityMap,\r\n json,\r\n requireAuth,\r\n requireEntityPermission,\r\n encryptionKey,\r\n publicSiteUrl,\r\n } = config;\r\n const publishLog = linkedInPublishLoggingEnabled(config);\r\n\r\n return {\r\n async getLinkedInStatus(req: Request): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermission(req, 'blogs', 'read');\r\n if (pe) return pe;\r\n try {\r\n const map = await loadGroupMap(dataSource, entityMap, encryptionKey);\r\n const enabled = map.enabled !== 'false';\r\n const token = (map.linkedin_access_token ?? '').trim();\r\n const sub = (map.linkedin_person_sub ?? '').trim();\r\n const orgUrn = (map.linkedin_organization_urn ?? '').trim();\r\n return json({\r\n ok: true,\r\n linkedInReady: enabled && Boolean(token) && Boolean(orgUrn),\r\n enabled,\r\n hasToken: Boolean(token),\r\n hasPersonSub: Boolean(sub),\r\n hasOrganization: Boolean(orgUrn),\r\n organizationName: map.linkedin_organization_name?.trim() || null,\r\n });\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : 'Failed to load status';\r\n return json({ error: msg }, { status: 500 });\r\n }\r\n },\r\n\r\n async fetchLinkedInOrganizations(req: Request): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermission(req, 'settings', 'read');\r\n if (pe) return pe;\r\n let body: { accessToken?: unknown } = {};\r\n try {\r\n body = (await req.json()) as { accessToken?: unknown };\r\n } catch {\r\n /* optional body */\r\n }\r\n try {\r\n const map = await loadGroupMap(dataSource, entityMap, encryptionKey);\r\n const token = String(body?.accessToken ?? map.linkedin_access_token ?? '').trim();\r\n if (!token) {\r\n return json({ error: 'LinkedIn access token is required.' }, { status: 400 });\r\n }\r\n const organizations = await linkedInListManagedOrganizations(token);\r\n return json({ ok: true, organizations });\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : 'LinkedIn organizations request failed';\r\n return json({ error: msg }, { status: 502 });\r\n }\r\n },\r\n\r\n async syncLinkedInProfile(req: Request): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermission(req, 'blogs', 'read');\r\n if (pe) return pe;\r\n try {\r\n const map = await loadGroupMap(dataSource, entityMap, encryptionKey);\r\n const token = (map.linkedin_access_token ?? '').trim();\r\n if (!token) {\r\n return json({ error: 'Save a LinkedIn access token in Plugins → Social media first.' }, { status: 400 });\r\n }\r\n const info = await linkedInGetUserinfo(token);\r\n const sub = String(info.sub ?? '').trim();\r\n if (!sub) {\r\n return json({ error: 'LinkedIn userinfo did not return a subject (sub).' }, { status: 502 });\r\n }\r\n await upsertConfigKey(dataSource, entityMap, 'linkedin_person_sub', sub, {\r\n type: 'private',\r\n encrypted: false,\r\n encryptionKey,\r\n });\r\n return json({\r\n ok: true,\r\n linkedin_person_sub: sub,\r\n name: info.name ?? null,\r\n });\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : 'Sync failed';\r\n return json({ error: msg }, { status: 502 });\r\n }\r\n },\r\n\r\n async publishBlogToLinkedIn(req: Request, blogId: number): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermission(req, 'blogs', 'update');\r\n if (pe) return pe;\r\n if (!Number.isFinite(blogId) || blogId < 1) {\r\n return json({ error: 'Invalid blog id' }, { status: 400 });\r\n }\r\n if (!entityMap.blogs) {\r\n return json({ error: 'Blogs entity not configured' }, { status: 503 });\r\n }\r\n try {\r\n const map = await loadGroupMap(dataSource, entityMap, encryptionKey);\r\n if (map.enabled === 'false') {\r\n return json({ error: 'Social media plugin is disabled.' }, { status: 400 });\r\n }\r\n const token = (map.linkedin_access_token ?? '').trim();\r\n const authorUrn = (map.linkedin_organization_urn ?? '').trim();\r\n if (!token || !authorUrn) {\r\n return json(\r\n {\r\n error:\r\n 'Configure LinkedIn access token and target organization (Plugins → Social media → LinkedIn).',\r\n },\r\n { status: 400 }\r\n );\r\n }\r\n\r\n const blogRepo = dataSource.getRepository(entityMap.blogs);\r\n const blog = await blogRepo.findOne({\r\n where: { id: blogId, deleted: false } as object,\r\n });\r\n if (!blog) {\r\n return json({ error: 'Blog not found' }, { status: 404 });\r\n }\r\n const b = blog as {\r\n title?: string;\r\n content?: string;\r\n socialMediaContent?: string | null;\r\n coverImage?: string | null;\r\n published?: boolean;\r\n };\r\n\r\n const title = String(b.title ?? 'Blog').trim() || 'Blog';\r\n const social = String(b.socialMediaContent ?? '').trim();\r\n const excerpt = stripHtml(String(b.content ?? ''), 2800);\r\n const commentary = (social || `${title}\\n\\n${excerpt}`).trim().slice(0, 2900);\r\n const commentaryFrom = social ? 'socialMediaContent' : 'titleAndExcerpt';\r\n\r\n logLinkedInPublish(publishLog, 'start', {\r\n blogId,\r\n titleLen: title.length,\r\n commentaryFrom,\r\n commentaryChars: commentary.length,\r\n hasCover: Boolean(b.coverImage?.trim()),\r\n contentHtmlChars: String(b.content ?? '').length,\r\n });\r\n\r\n const imagePayload = await loadImageBytesForBlogShare(\r\n b.coverImage,\r\n String(b.content ?? ''),\r\n publicSiteUrl || inferRequestOrigin(req),\r\n req\r\n );\r\n\r\n if (imagePayload) {\r\n logLinkedInPublish(publishLog, 'image_bytes_ready', {\r\n blogId,\r\n source: imagePayload.source,\r\n bytes: imagePayload.buffer.length,\r\n contentType: imagePayload.contentType,\r\n });\r\n try {\r\n const { uploadUrl, asset } = await linkedInRegisterImageUpload(token, authorUrn);\r\n logLinkedInPublish(publishLog, 'image_registered', {\r\n blogId,\r\n asset: truncateForLog(asset, 120),\r\n uploadHost: (() => {\r\n try {\r\n return new URL(uploadUrl).host;\r\n } catch {\r\n return 'unknown';\r\n }\r\n })(),\r\n });\r\n await linkedInUploadBinary(token, uploadUrl, imagePayload.buffer, imagePayload.contentType);\r\n logLinkedInPublish(publishLog, 'image_uploaded', { blogId, bytes: imagePayload.buffer.length });\r\n const out = await linkedInCreateImageShare({\r\n accessToken: token,\r\n authorUrn,\r\n asset,\r\n commentary,\r\n title,\r\n description: title,\r\n });\r\n logLinkedInPublish(publishLog, 'success', {\r\n blogId,\r\n mode: 'image_plus_text',\r\n linkedinPostId: out.id ?? null,\r\n commentaryFrom,\r\n commentaryChars: commentary.length,\r\n imageSource: imagePayload.source,\r\n });\r\n return json({\r\n ok: true,\r\n linkedin: out,\r\n usedImage: true,\r\n publishSummary: {\r\n mode: 'image_plus_text',\r\n commentaryFrom,\r\n commentaryChars: commentary.length,\r\n image: {\r\n bytes: imagePayload.buffer.length,\r\n contentType: imagePayload.contentType,\r\n source: imagePayload.source,\r\n },\r\n linkedinPostId: out.id ?? null,\r\n },\r\n });\r\n } catch (imgErr) {\r\n const imgMsg = imgErr instanceof Error ? imgErr.message : String(imgErr);\r\n logLinkedInPublish(publishLog, 'image_path_failed_falling_back_to_text', {\r\n blogId,\r\n message: truncateForLog(imgMsg, 500),\r\n });\r\n const out = await linkedInCreateTextShare({\r\n accessToken: token,\r\n authorUrn,\r\n commentary,\r\n });\r\n logLinkedInPublish(publishLog, 'success', {\r\n blogId,\r\n mode: 'text_only_after_image_failure',\r\n linkedinPostId: out.id ?? null,\r\n commentaryFrom,\r\n commentaryChars: commentary.length,\r\n imageError: truncateForLog(imgMsg, 400),\r\n });\r\n return json({\r\n ok: true,\r\n linkedin: out,\r\n usedImage: false,\r\n usedTextOnly: true,\r\n imagePathError: imgMsg,\r\n publishSummary: {\r\n mode: 'text_only_after_image_failure',\r\n commentaryFrom,\r\n commentaryChars: commentary.length,\r\n linkedinPostId: out.id ?? null,\r\n imageAttempt: {\r\n bytes: imagePayload.buffer.length,\r\n contentType: imagePayload.contentType,\r\n source: imagePayload.source,\r\n },\r\n },\r\n });\r\n }\r\n }\r\n\r\n logLinkedInPublish(publishLog, 'no_image_bytes', {\r\n blogId,\r\n commentaryFrom,\r\n commentaryChars: commentary.length,\r\n note: 'posting_text_only',\r\n });\r\n const out = await linkedInCreateTextShare({\r\n accessToken: token,\r\n authorUrn,\r\n commentary,\r\n });\r\n logLinkedInPublish(publishLog, 'success', {\r\n blogId,\r\n mode: 'text_only',\r\n linkedinPostId: out.id ?? null,\r\n commentaryFrom,\r\n commentaryChars: commentary.length,\r\n });\r\n return json({\r\n ok: true,\r\n linkedin: out,\r\n usedTextOnly: true,\r\n publishSummary: {\r\n mode: 'text_only',\r\n commentaryFrom,\r\n commentaryChars: commentary.length,\r\n linkedinPostId: out.id ?? null,\r\n },\r\n hint:\r\n 'No image bytes loaded, or only non-JPEG/PNG images were found. Use JPEG or PNG for cover or an inline <img>, set CMS_PUBLIC_URL for absolute URLs, or paths under /uploads/. LinkedIn feedshare uploads expect JPEG or PNG.',\r\n });\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : 'Publish failed';\r\n logLinkedInPublish(publishLog, 'failed', { blogId, message: truncateForLog(msg, 600) });\r\n return json({ error: msg }, { status: 502 });\r\n }\r\n },\r\n\r\n async getFacebookStatus(req: Request): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermission(req, 'blogs', 'read');\r\n if (pe) return pe;\r\n try {\r\n const map = await loadGroupMap(dataSource, entityMap, encryptionKey);\r\n const enabled = map.enabled !== 'false';\r\n const userToken = (map.meta_user_access_token ?? '').trim();\r\n const pageId = (map.meta_facebook_page_id ?? '').trim();\r\n let hasPageToken = false;\r\n if (enabled && userToken && pageId) {\r\n try {\r\n const accounts = await metaFetchUserManagedPages(userToken);\r\n hasPageToken = Boolean(metaResolvePageAccessToken(accounts, pageId));\r\n } catch {\r\n hasPageToken = false;\r\n }\r\n }\r\n /** Show Push to Facebook when plugin is on and credentials + target Page ID are saved (publish still validates via Graph). */\r\n const facebookReady = enabled && Boolean(userToken) && Boolean(pageId);\r\n return json({\r\n ok: true,\r\n facebookReady,\r\n enabled,\r\n hasUserToken: Boolean(userToken),\r\n hasPageId: Boolean(pageId),\r\n hasPageToken,\r\n });\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : 'Failed to load status';\r\n return json({ error: msg }, { status: 500 });\r\n }\r\n },\r\n\r\n async publishBlogToFacebook(req: Request, blogId: number): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermission(req, 'blogs', 'update');\r\n if (pe) return pe;\r\n if (!Number.isFinite(blogId) || blogId < 1) {\r\n return json({ error: 'Invalid blog id' }, { status: 400 });\r\n }\r\n if (!entityMap.blogs) {\r\n return json({ error: 'Blogs entity not configured' }, { status: 503 });\r\n }\r\n try {\r\n const map = await loadGroupMap(dataSource, entityMap, encryptionKey);\r\n if (map.enabled === 'false') {\r\n return json({ error: 'Social media plugin is disabled.' }, { status: 400 });\r\n }\r\n const userToken = (map.meta_user_access_token ?? '').trim();\r\n const pageId = (map.meta_facebook_page_id ?? '').trim();\r\n if (!userToken || !pageId) {\r\n return json(\r\n {\r\n error:\r\n 'Configure Meta user access token and Facebook Page ID in Plugins → Social media → Facebook, then save.',\r\n },\r\n { status: 400 }\r\n );\r\n }\r\n\r\n let accounts;\r\n try {\r\n accounts = await metaFetchUserManagedPages(userToken);\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : 'Failed to load Facebook pages';\r\n return json({ error: msg }, { status: 502 });\r\n }\r\n const pageAccessToken = metaResolvePageAccessToken(accounts, pageId);\r\n if (!pageAccessToken) {\r\n return json(\r\n {\r\n error:\r\n 'No page access token for the saved Page ID. In Plugins → Facebook, use Fetch managed pages, copy a Page `id` you manage, set Target Page ID, and save.',\r\n },\r\n { status: 400 }\r\n );\r\n }\r\n\r\n const blogRepo = dataSource.getRepository(entityMap.blogs);\r\n const blog = await blogRepo.findOne({\r\n where: { id: blogId, deleted: false } as object,\r\n });\r\n if (!blog) {\r\n return json({ error: 'Blog not found' }, { status: 404 });\r\n }\r\n const b = blog as {\r\n title?: string;\r\n content?: string;\r\n socialMediaContent?: string | null;\r\n coverImage?: string | null;\r\n };\r\n\r\n const title = String(b.title ?? 'Blog').trim() || 'Blog';\r\n const social = String(b.socialMediaContent ?? '').trim();\r\n const excerpt = stripHtml(String(b.content ?? ''), 2800);\r\n const caption = (social || `${title}\\n\\n${excerpt}`).trim().slice(0, 2200);\r\n\r\n const imagePayload = await loadImageBytesForBlogShare(\r\n b.coverImage,\r\n String(b.content ?? ''),\r\n publicSiteUrl || inferRequestOrigin(req),\r\n req\r\n );\r\n\r\n if (imagePayload) {\r\n const out = await metaPostPagePhoto({\r\n pageId,\r\n pageAccessToken,\r\n imageBuffer: imagePayload.buffer,\r\n contentType: imagePayload.contentType,\r\n caption,\r\n });\r\n return json({\r\n ok: true,\r\n facebook: out,\r\n usedImage: true,\r\n publishSummary: {\r\n mode: 'page_photo',\r\n captionChars: caption.length,\r\n imageSource: imagePayload.source,\r\n facebookPostId: out.post_id ?? out.id ?? null,\r\n },\r\n });\r\n }\r\n\r\n const out = await metaPostPageFeed({\r\n pageId,\r\n pageAccessToken,\r\n message: caption,\r\n });\r\n return json({\r\n ok: true,\r\n facebook: out,\r\n usedImage: false,\r\n usedFeed: true,\r\n publishSummary: {\r\n mode: 'page_feed_text',\r\n messageChars: caption.length,\r\n facebookPostId: out.id ?? null,\r\n },\r\n hint:\r\n 'Posted as a Page text update (no JPEG/PNG cover or body image found). Add a JPEG/PNG cover or inline image for a photo post.',\r\n });\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : 'Facebook publish failed';\r\n return json({ error: msg }, { status: 502 });\r\n }\r\n },\r\n\r\n /**\r\n * POST JSON `{ appId, appSecret, userAccessToken }`. Calls Graph `GET /me/accounts` with the user token.\r\n * App ID and secret are validated but not used yet (reserved for future token flows).\r\n * Persist credentials via Plugins → Save: `meta_app_id` (public), `meta_app_secret` and `meta_user_access_token` (encrypted).\r\n */\r\n async fetchFacebookManagedPages(req: Request): Promise<Response> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermission(req, 'settings', 'read');\r\n if (pe) return pe;\r\n let body: { appId?: unknown; appSecret?: unknown; userAccessToken?: unknown };\r\n try {\r\n body = (await req.json()) as typeof body;\r\n } catch {\r\n return json({ error: 'Invalid JSON body' }, { status: 400 });\r\n }\r\n const appId = String(body?.appId ?? '').trim();\r\n const appSecret = String(body?.appSecret ?? '').trim();\r\n const userAccessToken = String(body?.userAccessToken ?? '').trim();\r\n if (!appId || !appSecret || !userAccessToken) {\r\n return json(\r\n { error: 'App ID, app secret, and user access token are required.' },\r\n { status: 400 }\r\n );\r\n }\r\n void appId;\r\n void appSecret;\r\n try {\r\n const graph = await metaFetchUserManagedPages(userAccessToken);\r\n return json({ ok: true, graph });\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : 'Facebook Graph request failed';\r\n return json({ error: msg }, { status: 502 });\r\n }\r\n },\r\n };\r\n}\r\n","/**\r\n * LinkedIn REST helpers (server-side). Uses fetch — no axios.\r\n * @see https://learn.microsoft.com/en-us/linkedin/marketing/integrations/community-management/shares/ugc-post-api\r\n */\r\n\r\nexport type LinkedInUserInfo = {\r\n sub: string;\r\n name?: string;\r\n email?: string;\r\n picture?: string;\r\n};\r\n\r\nexport type LinkedInOrganizationAcl = {\r\n roleAssignee?: string;\r\n state?: string;\r\n role?: string;\r\n organization?: string;\r\n};\r\n\r\nexport type LinkedInManagedOrganization = {\r\n urn: string;\r\n id: number;\r\n name: string;\r\n vanityName?: string;\r\n website?: string;\r\n role?: string;\r\n};\r\n\r\nconst RESTLI = '2.0.0';\r\n\r\nfunction linkedInHeaders(accessToken: string, json = false): Record<string, string> {\r\n return {\r\n Authorization: `Bearer ${accessToken}`,\r\n 'X-Restli-Protocol-Version': RESTLI,\r\n ...(json ? { 'Content-Type': 'application/json' } : {}),\r\n };\r\n}\r\n\r\nexport async function linkedInGetUserinfo(accessToken: string): Promise<LinkedInUserInfo> {\r\n const r = await fetch('https://api.linkedin.com/v2/userinfo', {\r\n headers: { Authorization: `Bearer ${accessToken}` },\r\n });\r\n const text = await r.text();\r\n if (!r.ok) {\r\n throw new Error(`LinkedIn userinfo failed (${r.status}): ${text.slice(0, 500)}`);\r\n }\r\n try {\r\n return JSON.parse(text) as LinkedInUserInfo;\r\n } catch {\r\n throw new Error('LinkedIn userinfo: invalid JSON');\r\n }\r\n}\r\n\r\nexport async function linkedInFetchOrganizationAcls(accessToken: string): Promise<LinkedInOrganizationAcl[]> {\r\n const r = await fetch('https://api.linkedin.com/v2/organizationAcls?q=roleAssignee', {\r\n headers: linkedInHeaders(accessToken),\r\n });\r\n const text = await r.text();\r\n if (!r.ok) {\r\n throw new Error(`LinkedIn organizationAcls failed (${r.status}): ${text.slice(0, 800)}`);\r\n }\r\n let data: { elements?: LinkedInOrganizationAcl[] };\r\n try {\r\n data = JSON.parse(text) as { elements?: LinkedInOrganizationAcl[] };\r\n } catch {\r\n throw new Error('LinkedIn organizationAcls: invalid JSON');\r\n }\r\n return Array.isArray(data.elements) ? data.elements : [];\r\n}\r\n\r\ntype LinkedInOrganizationRaw = {\r\n id?: number;\r\n localizedName?: string;\r\n vanityName?: string;\r\n localizedWebsite?: string;\r\n name?: { localized?: Record<string, string> };\r\n website?: { localized?: Record<string, string> };\r\n};\r\n\r\nfunction organizationDisplayName(org: LinkedInOrganizationRaw): string {\r\n if (org.localizedName?.trim()) return org.localizedName.trim();\r\n const localized = org.name?.localized;\r\n if (localized) {\r\n for (const v of Object.values(localized)) {\r\n if (v?.trim()) return v.trim();\r\n }\r\n }\r\n if (org.vanityName?.trim()) return org.vanityName.trim();\r\n if (org.id != null) return `Organization ${org.id}`;\r\n return 'Organization';\r\n}\r\n\r\nfunction organizationWebsite(org: LinkedInOrganizationRaw): string | undefined {\r\n if (org.localizedWebsite?.trim()) return org.localizedWebsite.trim();\r\n const localized = org.website?.localized;\r\n if (localized) {\r\n for (const v of Object.values(localized)) {\r\n if (v?.trim()) return v.trim();\r\n }\r\n }\r\n return undefined;\r\n}\r\n\r\nexport function linkedInOrganizationUrn(orgIdOrUrn: string | number): string {\r\n const s = String(orgIdOrUrn ?? '').trim();\r\n if (s.startsWith('urn:li:organization:')) return s;\r\n return `urn:li:organization:${s}`;\r\n}\r\n\r\nexport function linkedInOrganizationIdFromUrn(organizationUrn: string): string {\r\n const m = String(organizationUrn).trim().match(/urn:li:organization:(\\d+)/);\r\n if (!m?.[1]) throw new Error(`Invalid LinkedIn organization URN: ${organizationUrn}`);\r\n return m[1];\r\n}\r\n\r\nexport async function linkedInGetOrganization(\r\n accessToken: string,\r\n orgIdOrUrn: string | number\r\n): Promise<LinkedInOrganizationRaw> {\r\n const orgId = String(orgIdOrUrn).startsWith('urn:')\r\n ? linkedInOrganizationIdFromUrn(String(orgIdOrUrn))\r\n : String(orgIdOrUrn).trim();\r\n const r = await fetch(`https://api.linkedin.com/v2/organizations/${encodeURIComponent(orgId)}`, {\r\n headers: linkedInHeaders(accessToken),\r\n });\r\n const text = await r.text();\r\n if (!r.ok) {\r\n throw new Error(`LinkedIn organization ${orgId} failed (${r.status}): ${text.slice(0, 800)}`);\r\n }\r\n try {\r\n return JSON.parse(text) as LinkedInOrganizationRaw;\r\n } catch {\r\n throw new Error(`LinkedIn organization ${orgId}: invalid JSON`);\r\n }\r\n}\r\n\r\n/** Lists organizations the token holder can administer (APPROVED ACLs only). */\r\nexport async function linkedInListManagedOrganizations(accessToken: string): Promise<LinkedInManagedOrganization[]> {\r\n const acls = await linkedInFetchOrganizationAcls(accessToken);\r\n const approved = acls.filter((a) => a.state === 'APPROVED' && a.organization?.trim());\r\n const byUrn = new Map<string, LinkedInOrganizationAcl>();\r\n for (const acl of approved) {\r\n const urn = linkedInOrganizationUrn(acl.organization!);\r\n if (!byUrn.has(urn)) byUrn.set(urn, acl);\r\n }\r\n\r\n const out: LinkedInManagedOrganization[] = [];\r\n for (const [urn, acl] of byUrn) {\r\n try {\r\n const org = await linkedInGetOrganization(accessToken, urn);\r\n out.push({\r\n urn,\r\n id: org.id ?? Number(linkedInOrganizationIdFromUrn(urn)),\r\n name: organizationDisplayName(org),\r\n vanityName: org.vanityName,\r\n website: organizationWebsite(org),\r\n role: acl.role,\r\n });\r\n } catch {\r\n out.push({\r\n urn,\r\n id: Number(linkedInOrganizationIdFromUrn(urn)),\r\n name: linkedInOrganizationIdFromUrn(urn),\r\n role: acl.role,\r\n });\r\n }\r\n }\r\n out.sort((a, b) => a.name.localeCompare(b.name));\r\n return out;\r\n}\r\n\r\nfunction personUrn(personSub: string): string {\r\n const s = String(personSub || '').trim();\r\n if (s.startsWith('urn:li:person:')) return s;\r\n return `urn:li:person:${s}`;\r\n}\r\n\r\nfunction authorUrnFromParams(authorUrn?: string, personSub?: string): string {\r\n const direct = String(authorUrn ?? '').trim();\r\n if (direct.startsWith('urn:li:')) return direct;\r\n return personUrn(String(personSub ?? '').trim());\r\n}\r\n\r\ntype RegisterUploadValue = {\r\n uploadMechanism?: {\r\n 'com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest'?: { uploadUrl?: string };\r\n };\r\n asset?: string;\r\n};\r\n\r\nexport async function linkedInRegisterImageUpload(\r\n accessToken: string,\r\n author: string\r\n): Promise<{ uploadUrl: string; asset: string }> {\r\n const owner = authorUrnFromParams(author);\r\n const r = await fetch('https://api.linkedin.com/v2/assets?action=registerUpload', {\r\n method: 'POST',\r\n headers: linkedInHeaders(accessToken, true),\r\n body: JSON.stringify({\r\n registerUploadRequest: {\r\n recipes: ['urn:li:digitalmediaRecipe:feedshare-image'],\r\n owner,\r\n serviceRelationships: [\r\n {\r\n relationshipType: 'OWNER',\r\n identifier: 'urn:li:userGeneratedContent',\r\n },\r\n ],\r\n },\r\n }),\r\n });\r\n const text = await r.text();\r\n if (!r.ok) {\r\n throw new Error(`LinkedIn registerUpload failed (${r.status}): ${text.slice(0, 800)}`);\r\n }\r\n let data: { value?: RegisterUploadValue };\r\n try {\r\n data = JSON.parse(text) as { value?: RegisterUploadValue };\r\n } catch {\r\n throw new Error('LinkedIn registerUpload: invalid JSON');\r\n }\r\n const v = data.value;\r\n const uploadUrl =\r\n v?.uploadMechanism?.['com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest']?.uploadUrl;\r\n const asset = v?.asset;\r\n if (!uploadUrl || !asset) {\r\n throw new Error('LinkedIn registerUpload: missing uploadUrl or asset');\r\n }\r\n return { uploadUrl, asset };\r\n}\r\n\r\nexport async function linkedInUploadBinary(\r\n accessToken: string,\r\n uploadUrl: string,\r\n body: Buffer,\r\n contentType: string\r\n): Promise<void> {\r\n const r = await fetch(uploadUrl, {\r\n method: 'PUT',\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n 'X-Restli-Protocol-Version': RESTLI,\r\n 'Content-Type': contentType || 'application/octet-stream',\r\n },\r\n body: new Uint8Array(body),\r\n });\r\n if (!r.ok) {\r\n const t = await r.text();\r\n throw new Error(`LinkedIn binary upload failed (${r.status}): ${t.slice(0, 500)}`);\r\n }\r\n}\r\n\r\nexport async function linkedInCreateImageShare(params: {\r\n accessToken: string;\r\n /** Person sub, organization URN, or any `urn:li:*` author. */\r\n authorUrn: string;\r\n asset: string;\r\n commentary: string;\r\n title: string;\r\n description?: string;\r\n}): Promise<{ status: number; id?: string }> {\r\n const author = authorUrnFromParams(params.authorUrn);\r\n const commentary = params.commentary.slice(0, 2900);\r\n const title = params.title.slice(0, 200);\r\n const description = (params.description ?? title).slice(0, 200);\r\n\r\n const r = await fetch('https://api.linkedin.com/v2/ugcPosts', {\r\n method: 'POST',\r\n headers: {\r\n Authorization: `Bearer ${params.accessToken}`,\r\n 'X-Restli-Protocol-Version': RESTLI,\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n author,\r\n lifecycleState: 'PUBLISHED',\r\n specificContent: {\r\n 'com.linkedin.ugc.ShareContent': {\r\n shareCommentary: { attributes: [], text: commentary },\r\n shareMediaCategory: 'IMAGE',\r\n media: [\r\n {\r\n status: 'READY',\r\n description: { attributes: [], text: description },\r\n media: params.asset,\r\n title: { attributes: [], text: title },\r\n },\r\n ],\r\n },\r\n },\r\n visibility: {\r\n 'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC',\r\n },\r\n }),\r\n });\r\n const text = await r.text();\r\n if (!r.ok) {\r\n throw new Error(`LinkedIn ugcPosts failed (${r.status}): ${text.slice(0, 1200)}`);\r\n }\r\n let data: { id?: string };\r\n try {\r\n data = JSON.parse(text) as { id?: string };\r\n } catch {\r\n return { status: r.status };\r\n }\r\n return { status: r.status, id: data.id };\r\n}\r\n\r\nexport async function linkedInCreateTextShare(params: {\r\n accessToken: string;\r\n /** Person sub, organization URN, or any `urn:li:*` author. */\r\n authorUrn: string;\r\n commentary: string;\r\n}): Promise<{ status: number; id?: string }> {\r\n const author = authorUrnFromParams(params.authorUrn);\r\n const commentary = params.commentary.slice(0, 2900);\r\n\r\n const r = await fetch('https://api.linkedin.com/v2/ugcPosts', {\r\n method: 'POST',\r\n headers: {\r\n Authorization: `Bearer ${params.accessToken}`,\r\n 'X-Restli-Protocol-Version': RESTLI,\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n author,\r\n lifecycleState: 'PUBLISHED',\r\n specificContent: {\r\n 'com.linkedin.ugc.ShareContent': {\r\n shareCommentary: { attributes: [], text: commentary },\r\n shareMediaCategory: 'NONE',\r\n },\r\n },\r\n visibility: {\r\n 'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC',\r\n },\r\n }),\r\n });\r\n const text = await r.text();\r\n if (!r.ok) {\r\n throw new Error(`LinkedIn ugcPosts (text) failed (${r.status}): ${text.slice(0, 1200)}`);\r\n }\r\n let data: { id?: string };\r\n try {\r\n data = JSON.parse(text) as { id?: string };\r\n } catch {\r\n return { status: r.status };\r\n }\r\n return { status: r.status, id: data.id };\r\n}\r\n","/**\r\n * Meta (Facebook) Graph API helpers (server-side). Uses fetch — no SDK.\r\n * @see https://developers.facebook.com/docs/graph-api/reference/user/accounts\r\n */\r\n\r\nconst GRAPH_API_VERSION = 'v23.0';\r\nconst GRAPH_BASE = `https://graph.facebook.com/${GRAPH_API_VERSION}`;\r\n\r\nexport type FacebookPageAccount = {\r\n access_token?: string;\r\n category?: string;\r\n name?: string;\r\n id?: string;\r\n /** Graph may return additional fields */\r\n [key: string]: unknown;\r\n};\r\n\r\nexport type FacebookMeAccountsResponse = {\r\n data?: FacebookPageAccount[];\r\n paging?: Record<string, unknown>;\r\n error?: { message?: string; type?: string; code?: number; fbtrace_id?: string };\r\n};\r\n\r\n/**\r\n * Lists Facebook Pages the user manages (page access tokens + metadata).\r\n * Requires a User access token with `pages_show_list` or equivalent page permissions.\r\n */\r\nexport async function metaFetchUserManagedPages(userAccessToken: string): Promise<FacebookMeAccountsResponse> {\r\n const token = String(userAccessToken || '').trim();\r\n if (!token) {\r\n throw new Error('User access token is required');\r\n }\r\n\r\n const url = new URL(`${GRAPH_BASE}/me/accounts`);\r\n url.searchParams.set('access_token', token);\r\n\r\n const r = await fetch(url.toString(), { method: 'GET', headers: { Accept: 'application/json' } });\r\n const text = await r.text();\r\n\r\n let body: FacebookMeAccountsResponse;\r\n try {\r\n body = JSON.parse(text) as FacebookMeAccountsResponse;\r\n } catch {\r\n throw new Error(`Facebook Graph returned invalid JSON (${r.status})`);\r\n }\r\n\r\n if (body.error?.message) {\r\n const code = body.error.code != null ? ` (code ${body.error.code})` : '';\r\n throw new Error(`${body.error.message}${code}`);\r\n }\r\n\r\n if (!r.ok) {\r\n throw new Error(`Facebook Graph request failed (${r.status}): ${text.slice(0, 600)}`);\r\n }\r\n\r\n return body;\r\n}\r\n\r\nexport type MetaGraphMutationResponse = {\r\n id?: string;\r\n post_id?: string;\r\n error?: { message?: string; type?: string; code?: number; fbtrace_id?: string };\r\n};\r\n\r\nfunction parseGraphMutation(text: string, httpOk: boolean): MetaGraphMutationResponse {\r\n let body: MetaGraphMutationResponse;\r\n try {\r\n body = JSON.parse(text) as MetaGraphMutationResponse;\r\n } catch {\r\n throw new Error(`Facebook Graph returned invalid JSON (${httpOk ? '200' : 'error'})`);\r\n }\r\n if (body.error?.message) {\r\n const code = body.error.code != null ? ` (code ${body.error.code})` : '';\r\n throw new Error(`${body.error.message}${code}`);\r\n }\r\n if (!httpOk) {\r\n throw new Error(`Facebook Graph request failed: ${text.slice(0, 600)}`);\r\n }\r\n return body;\r\n}\r\n\r\n/** Resolves the long-lived page access token for a Page ID from `/me/accounts` data. */\r\nexport function metaResolvePageAccessToken(\r\n accounts: FacebookMeAccountsResponse,\r\n pageId: string\r\n): string | null {\r\n const id = String(pageId || '').trim();\r\n if (!id || !accounts.data?.length) return null;\r\n const row = accounts.data.find((p) => String(p.id ?? '').trim() === id);\r\n const tok = row?.access_token;\r\n return typeof tok === 'string' && tok.trim() ? tok.trim() : null;\r\n}\r\n\r\n/**\r\n * Upload a photo to a Page timeline (multipart).\r\n * @see https://developers.facebook.com/docs/graph-api/reference/page/photos#Creating\r\n */\r\nexport async function metaPostPagePhoto(opts: {\r\n pageId: string;\r\n pageAccessToken: string;\r\n imageBuffer: Buffer;\r\n contentType: string;\r\n caption: string;\r\n}): Promise<MetaGraphMutationResponse> {\r\n const { pageId, pageAccessToken, imageBuffer, contentType, caption } = opts;\r\n const pid = String(pageId || '').trim();\r\n const tok = String(pageAccessToken || '').trim();\r\n if (!pid || !tok) throw new Error('Page ID and page access token are required');\r\n if (!imageBuffer?.length) throw new Error('Image buffer is empty');\r\n\r\n const url = `${GRAPH_BASE}/${encodeURIComponent(pid)}/photos`;\r\n const lower = contentType.split(';')[0]!.trim().toLowerCase();\r\n const filename = lower.includes('png') ? 'photo.png' : 'photo.jpg';\r\n const blob = new Blob([new Uint8Array(imageBuffer)], { type: lower || 'image/jpeg' });\r\n\r\n const form = new FormData();\r\n form.append('access_token', tok);\r\n form.append('caption', String(caption || '').trim().slice(0, 2200));\r\n form.append('source', blob, filename);\r\n\r\n const r = await fetch(url, { method: 'POST', body: form });\r\n const text = await r.text();\r\n return parseGraphMutation(text, r.ok);\r\n}\r\n\r\n/**\r\n * Publish a text-only post to the Page feed (when no JPEG/PNG image is available).\r\n * @see https://developers.facebook.com/docs/graph-api/reference/page/feed#Creating\r\n */\r\nexport async function metaPostPageFeed(opts: {\r\n pageId: string;\r\n pageAccessToken: string;\r\n message: string;\r\n}): Promise<MetaGraphMutationResponse> {\r\n const { pageId, pageAccessToken, message } = opts;\r\n const pid = String(pageId || '').trim();\r\n const tok = String(pageAccessToken || '').trim();\r\n if (!pid || !tok) throw new Error('Page ID and page access token are required');\r\n\r\n const url = new URL(`${GRAPH_BASE}/${encodeURIComponent(pid)}/feed`);\r\n const params = new URLSearchParams();\r\n params.set('access_token', tok);\r\n params.set('message', String(message || '').trim().slice(0, 5000));\r\n\r\n const r = await fetch(url.toString(), {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/x-www-form-urlencoded', Accept: 'application/json' },\r\n body: params.toString(),\r\n });\r\n const text = await r.text();\r\n return parseGraphMutation(text, r.ok);\r\n}\r\n","import type { CmsPlugin, PluginContext } from '../types';\r\n\r\nexport interface SocialMediaPluginConfig {\r\n /** Set to false to skip registering the plugin instance (API routes still work if wired in the app handler). */\r\n enabled?: boolean;\r\n}\r\n\r\n/**\r\n * Optional CMS plugin instance for `getPlugin('social_media')`.\r\n * LinkedIn publishing is implemented in {@link createSocialMediaHandlers} and mounted from the CMS API handler.\r\n */\r\nexport function socialMediaPlugin(config: SocialMediaPluginConfig = {}): CmsPlugin<{ name: string } | undefined> {\r\n return {\r\n name: 'social_media',\r\n version: '1.0.0',\r\n async init(context: PluginContext) {\r\n if (config.enabled === false) {\r\n context.logger.warn('Social media plugin skipped: disabled in config');\r\n return undefined;\r\n }\r\n return { name: 'social_media' };\r\n },\r\n };\r\n}\r\n\r\nexport { createSocialMediaHandlers } from './social-media-api-handlers';\r\nexport type { SocialMediaApiConfig } from './social-media-api-handlers';\r\nexport * from './linkedin-client';\r\nexport * from './meta-service';\r\n","import { type ClassValue, clsx } from 'clsx';\r\nimport { twMerge } from 'tailwind-merge';\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs));\r\n}\r\n\r\nexport function generateSlug(title: string): string {\r\n return title\r\n .toLowerCase()\r\n .replace(/[^a-z0-9]+/g, '-')\r\n .replace(/(^-|-$)/g, '');\r\n}\r\n\r\nexport function validateSlug(slug: string): boolean {\r\n const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\r\n return slugRegex.test(slug) && slug.length >= 3 && slug.length <= 50;\r\n}\r\n\r\nexport function formatDate(date: Date | string): string {\r\n const d = new Date(date);\r\n return d.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\r\n}\r\n\r\nexport function formatDateTime(date: Date | string): string {\r\n const d = new Date(date);\r\n return d.toLocaleDateString('en-US', {\r\n year: 'numeric',\r\n month: 'short',\r\n day: 'numeric',\r\n hour: '2-digit',\r\n minute: '2-digit',\r\n });\r\n}\r\n\r\nexport function formatDateOnly(date: Date | string): string {\r\n const d = new Date(date);\r\n return d.toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\r\n}\r\n\r\nexport function truncateText(text: string, maxLength: number): string {\r\n if (text.length <= maxLength) return text;\r\n return text.substring(0, maxLength).trim() + '...';\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport type { Metadata } from 'next';\r\nimport type { EntityMap } from '../api/crud';\r\n\r\n/** Minimal SEO row shape (DB or API). */\r\nexport type SeoLike = {\r\n title?: string | null;\r\n description?: string | null;\r\n keywords?: string | null;\r\n ogTitle?: string | null;\r\n ogDescription?: string | null;\r\n ogImage?: string | null;\r\n};\r\n\r\nexport type SeoMetadataOverrides = {\r\n title?: string;\r\n description?: string;\r\n keywords?: string;\r\n ogTitle?: string;\r\n ogDescription?: string;\r\n ogImage?: string;\r\n};\r\n\r\nfunction pickStr(\r\n override: string | undefined,\r\n seoPrimary: string | null | undefined,\r\n seoSecondary: string | null | undefined,\r\n fallback: string | undefined,\r\n): string | undefined {\r\n const o = override?.trim();\r\n if (o) return o;\r\n const a = seoPrimary?.trim();\r\n if (a) return a;\r\n const b = seoSecondary?.trim();\r\n if (b) return b;\r\n return fallback?.trim() || undefined;\r\n}\r\n\r\nfunction pickSeo(row: unknown): SeoLike | null {\r\n if (!row || typeof row !== 'object') return null;\r\n const r = row as Record<string, unknown>;\r\n return {\r\n title: (r.title as string) ?? null,\r\n description: (r.description as string) ?? null,\r\n keywords: (r.keywords as string) ?? null,\r\n ogTitle: (r.ogTitle as string) ?? null,\r\n ogDescription: (r.ogDescription as string) ?? null,\r\n ogImage: (r.ogImage as string) ?? null,\r\n };\r\n}\r\n\r\n/** Per-field: join row wins over slug row. */\r\nexport function mergeSeoBySlug(join: SeoLike | null | undefined, bySlug: SeoLike | null): SeoLike | null {\r\n const a = join ? pickSeo(join) : null;\r\n const b = bySlug ? pickSeo(bySlug) : null;\r\n if (!a && !b) return null;\r\n return {\r\n title: a?.title ?? b?.title ?? null,\r\n description: a?.description ?? b?.description ?? null,\r\n keywords: a?.keywords ?? b?.keywords ?? null,\r\n ogTitle: a?.ogTitle ?? b?.ogTitle ?? null,\r\n ogDescription: a?.ogDescription ?? b?.ogDescription ?? null,\r\n ogImage: a?.ogImage ?? b?.ogImage ?? null,\r\n };\r\n}\r\n\r\nexport async function fetchSeoBySlug(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n slug: string,\r\n): Promise<SeoLike | null> {\r\n const trimmed = slug?.trim();\r\n if (!trimmed) return null;\r\n const SeoEntity = entityMap.seos;\r\n if (!SeoEntity) return null;\r\n const repo = dataSource.getRepository(SeoEntity);\r\n const row = await repo.findOne({\r\n where: { slug: trimmed, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n return row ? pickSeo(row) : null;\r\n}\r\n\r\nfunction toAbsoluteImage(url: string, metadataBase: URL | undefined): string {\r\n const u = url.trim();\r\n if (!u) return u;\r\n if (u.startsWith('http://') || u.startsWith('https://')) return u;\r\n if (metadataBase) {\r\n try {\r\n const path = u.startsWith('/') ? u : `/${u}`;\r\n return new URL(path, metadataBase).toString();\r\n } catch {\r\n return u;\r\n }\r\n }\r\n return u;\r\n}\r\n\r\n/**\r\n * Build Next.js Metadata from merged SEO + optional layers.\r\n * `overrides` win over SEO; `fallbacks` apply when SEO (and overrides) omit a field.\r\n * Returns a partial object; omit fields so the root layout defaults apply.\r\n */\r\nexport async function resolvePublicMetadata(args: {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n slug: string;\r\n seoFromJoin?: SeoLike | null;\r\n overrides?: SeoMetadataOverrides;\r\n fallbacks?: SeoMetadataOverrides;\r\n canonicalPath?: string;\r\n metadataBase?: URL;\r\n}): Promise<Metadata> {\r\n const { dataSource, entityMap, slug, seoFromJoin, overrides, fallbacks, canonicalPath, metadataBase } = args;\r\n const bySlug = await fetchSeoBySlug(dataSource, entityMap, slug);\r\n const seo = mergeSeoBySlug(seoFromJoin, bySlug);\r\n const o = overrides ?? {};\r\n const f = fallbacks ?? {};\r\n\r\n const title = pickStr(o.title, seo?.title, seo?.ogTitle, f.title);\r\n\r\n const description = pickStr(o.description, seo?.description, seo?.ogDescription, f.description);\r\n\r\n const keywordsRaw =\r\n o.keywords?.trim() || seo?.keywords?.trim() || f.keywords?.trim() || undefined;\r\n const keywords = keywordsRaw\r\n ? keywordsRaw.split(',').map((k) => k.trim()).filter(Boolean)\r\n : undefined;\r\n\r\n const ogTitle =\r\n o.ogTitle?.trim() ||\r\n seo?.ogTitle?.trim() ||\r\n seo?.title?.trim() ||\r\n o.title?.trim() ||\r\n f.ogTitle?.trim() ||\r\n title;\r\n\r\n const ogDescription =\r\n o.ogDescription?.trim() ||\r\n seo?.ogDescription?.trim() ||\r\n seo?.description?.trim() ||\r\n o.description?.trim() ||\r\n f.ogDescription?.trim() ||\r\n description;\r\n\r\n const ogImageRaw =\r\n o.ogImage?.trim() || seo?.ogImage?.trim() || f.ogImage?.trim() || undefined;\r\n\r\n const out: Metadata = {};\r\n\r\n if (title) out.title = title;\r\n if (description) out.description = description;\r\n if (keywords?.length) out.keywords = keywords;\r\n\r\n if (ogTitle || ogDescription || ogImageRaw) {\r\n const images = ogImageRaw\r\n ? [{ url: toAbsoluteImage(ogImageRaw, metadataBase), alt: ogTitle || title || '' }]\r\n : undefined;\r\n out.openGraph = {\r\n ...(ogTitle && { title: ogTitle }),\r\n ...(ogDescription && { description: ogDescription }),\r\n ...(images && { images }),\r\n };\r\n out.twitter = {\r\n card: 'summary_large_image',\r\n ...(ogTitle && { title: ogTitle }),\r\n ...(ogDescription && { description: ogDescription }),\r\n ...(images?.[0] && { images: [images[0].url] }),\r\n };\r\n }\r\n\r\n if (canonicalPath?.trim() && metadataBase) {\r\n try {\r\n const path = canonicalPath.startsWith('/') ? canonicalPath : `/${canonicalPath}`;\r\n out.alternates = { canonical: new URL(path, metadataBase).toString() };\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n\r\n return out;\r\n}\r\n","import { createHmac, randomInt, timingSafeEqual } from 'crypto';\r\nimport type { DataSource } from 'typeorm';\r\nimport type { EntityTarget, ObjectLiteral } from 'typeorm';\r\nimport { IsNull, MoreThan } from 'typeorm';\r\n\r\nexport type OtpPurpose = 'login' | 'verify_email' | 'verify_phone';\r\nexport type OtpChannel = 'email' | 'sms';\r\n\r\nconst OTP_TTL_MS = 10 * 60 * 1000;\r\nconst MAX_SENDS_PER_HOUR = 5;\r\nconst MAX_VERIFY_ATTEMPTS = 8;\r\n\r\nfunction getPepper(explicit?: string): string {\r\n return (explicit || process.env.OTP_PEPPER || process.env.NEXTAUTH_SECRET || 'dev-otp-pepper').trim();\r\n}\r\n\r\nexport function hashOtpCode(code: string, purpose: string, identifier: string, pepper?: string): string {\r\n return createHmac('sha256', getPepper(pepper)).update(`${purpose}|${identifier}|${code}`).digest('hex');\r\n}\r\n\r\nexport function verifyOtpCodeHash(code: string, storedHash: string, purpose: string, identifier: string, pepper?: string): boolean {\r\n const h = hashOtpCode(code, purpose, identifier, pepper);\r\n try {\r\n return timingSafeEqual(Buffer.from(h, 'utf8'), Buffer.from(storedHash, 'utf8'));\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\nexport function generateNumericOtp(length = 6): string {\r\n const max = 10 ** length;\r\n return randomInt(0, max).toString().padStart(length, '0');\r\n}\r\n\r\n/** Normalize to E.164-like +digits */\r\nexport function normalizePhoneE164(raw: string, defaultCountryCode?: string): string | null {\r\n const t = raw.trim();\r\n const digitsOnly = t.replace(/\\D/g, '');\r\n if (digitsOnly.length < 10) return null;\r\n if (t.startsWith('+')) return `+${digitsOnly}`;\r\n const cc = (defaultCountryCode || process.env.DEFAULT_PHONE_COUNTRY_CODE || '91').replace(/\\D/g, '');\r\n if (digitsOnly.length > 10) return `+${digitsOnly}`;\r\n return `+${cc}${digitsOnly}`;\r\n}\r\n\r\ntype EntityMap = Record<string, EntityTarget<ObjectLiteral>>;\r\n\r\nexport async function countRecentOtpSends(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n purpose: OtpPurpose,\r\n identifier: string,\r\n since: Date\r\n): Promise<number> {\r\n const repo = dataSource.getRepository(entityMap.otp_challenges);\r\n return repo.count({\r\n where: { purpose, identifier, createdAt: MoreThan(since) } as ObjectLiteral,\r\n });\r\n}\r\n\r\nexport async function createOtpChallenge(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n input: { purpose: OtpPurpose; channel: OtpChannel; identifier: string; code: string; pepper?: string }\r\n): Promise<{ ok: true } | { ok: false; error: string; status: number }> {\r\n const { purpose, channel, identifier, code, pepper } = input;\r\n const since = new Date(Date.now() - 60 * 60 * 1000);\r\n const recent = await countRecentOtpSends(dataSource, entityMap, purpose, identifier, since);\r\n if (recent >= MAX_SENDS_PER_HOUR) {\r\n return { ok: false, error: 'Too many codes sent. Try again later.', status: 429 };\r\n }\r\n\r\n const repo = dataSource.getRepository(entityMap.otp_challenges);\r\n await repo.delete({\r\n purpose,\r\n identifier,\r\n consumedAt: IsNull(),\r\n } as ObjectLiteral);\r\n\r\n const expiresAt = new Date(Date.now() + OTP_TTL_MS);\r\n const codeHash = hashOtpCode(code, purpose, identifier, pepper);\r\n await repo.save(\r\n repo.create({\r\n purpose,\r\n channel,\r\n identifier,\r\n codeHash,\r\n expiresAt,\r\n attempts: 0,\r\n consumedAt: null,\r\n } as ObjectLiteral)\r\n );\r\n return { ok: true };\r\n}\r\n\r\nexport async function verifyAndConsumeOtpChallenge(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n input: { purpose: OtpPurpose; identifier: string; code: string; pepper?: string }\r\n): Promise<{ ok: true } | { ok: false; error: string; status: number }> {\r\n const { purpose, identifier, code, pepper } = input;\r\n const repo = dataSource.getRepository(entityMap.otp_challenges);\r\n const row = await repo.findOne({\r\n where: { purpose, identifier, consumedAt: IsNull() } as ObjectLiteral,\r\n order: { id: 'DESC' },\r\n });\r\n if (!row) {\r\n return { ok: false, error: 'Invalid or expired code', status: 400 };\r\n }\r\n const r = row as ObjectLiteral;\r\n if (new Date(r.expiresAt as Date) < new Date()) {\r\n await repo.delete((row as { id: number }).id);\r\n return { ok: false, error: 'Invalid or expired code', status: 400 };\r\n }\r\n const attempts = (r.attempts as number) || 0;\r\n if (attempts >= MAX_VERIFY_ATTEMPTS) {\r\n await repo.delete((row as { id: number }).id);\r\n return { ok: false, error: 'Too many attempts', status: 400 };\r\n }\r\n\r\n const valid = verifyOtpCodeHash(code, r.codeHash as string, purpose, identifier, pepper);\r\n if (!valid) {\r\n await repo.update((row as { id: number }).id, { attempts: attempts + 1 } as ObjectLiteral);\r\n return { ok: false, error: 'Invalid or expired code', status: 400 };\r\n }\r\n\r\n await repo.update((row as { id: number }).id, { consumedAt: new Date(), attempts: attempts + 1 } as ObjectLiteral);\r\n return { ok: true };\r\n}\r\n","import Redis from 'ioredis';\r\nimport { NextResponse } from 'next/server';\r\n\r\nfunction clientIp(req: Request): string {\r\n const cf = req.headers.get('cf-connecting-ip')?.trim();\r\n if (cf) return cf;\r\n const xff = req.headers.get('x-forwarded-for')?.trim();\r\n if (xff) return xff.split(',')[0]!.trim();\r\n return req.headers.get('x-real-ip')?.trim() || 'unknown';\r\n}\r\n\r\nconst WINDOW_MS = Math.max(1000, parseInt(process.env.RATE_LIMIT_WINDOW_MS ?? '60000', 10) || 60000);\r\nconst MAX_REQ = Math.max(1, parseInt(process.env.RATE_LIMIT_MAX ?? '120', 10) || 120);\r\n\r\nlet redisClient: Redis | null | undefined;\r\n\r\nfunction getRedis(): Redis | null {\r\n const url = process.env.RATE_LIMIT_REDIS_URL?.trim();\r\n if (!url) return null;\r\n if (redisClient === undefined) {\r\n try {\r\n redisClient = new Redis(url, { maxRetriesPerRequest: 2, enableOfflineQueue: false });\r\n } catch {\r\n redisClient = null;\r\n }\r\n }\r\n return redisClient;\r\n}\r\n\r\nconst memoryHits = new Map<string, number[]>();\r\n\r\nfunction pruneMemory(now: number, stamps: number[]): void {\r\n const cutoff = now - WINDOW_MS;\r\n while (stamps.length && stamps[0]! < cutoff) stamps.shift();\r\n}\r\n\r\nasync function allowMemory(key: string): Promise<boolean> {\r\n const now = Date.now();\r\n let stamps = memoryHits.get(key);\r\n if (!stamps) {\r\n stamps = [];\r\n memoryHits.set(key, stamps);\r\n }\r\n pruneMemory(now, stamps);\r\n if (stamps.length >= MAX_REQ) return false;\r\n stamps.push(now);\r\n return true;\r\n}\r\n\r\nasync function allowRedis(key: string): Promise<boolean> {\r\n const r = getRedis();\r\n if (!r) return allowMemory(key);\r\n const bucket = Math.floor(Date.now() / WINDOW_MS);\r\n const redisKey = `rl:${key}:${bucket}`;\r\n try {\r\n const n = await r.incr(redisKey);\r\n if (n === 1) await r.pexpire(redisKey, WINDOW_MS + 1000);\r\n return n <= MAX_REQ;\r\n } catch {\r\n return allowMemory(key);\r\n }\r\n}\r\n\r\n/** Returns true if request is allowed; false if rate limited. */\r\nexport async function allowRateLimit(key: string): Promise<boolean> {\r\n if (getRedis()) return allowRedis(key);\r\n return allowMemory(key);\r\n}\r\n\r\nexport type ExtraPublicWriteRule = (method: string, segments: string[]) => boolean;\r\n\r\n/** Segments are path parts after `/api/` (e.g. `['form-submissions']`). */\r\nexport function shouldRateLimitPublicWrite(\r\n method: string,\r\n segments: string[],\r\n extraRule?: ExtraPublicWriteRule\r\n): boolean {\r\n if (!['POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) return false;\r\n if (segments[0] === 'webhooks') return false;\r\n if (segments[0] === 'health') return false;\r\n if (segments[0] === 'public') return false;\r\n if (segments[0] === 'payment-config') return false;\r\n\r\n if (segments[0] === 'storefront') {\r\n if (segments[1] === 'cart' && segments[2] === 'items') return true;\r\n if (segments[1] === 'wishlist' && segments[2] === 'items') return true;\r\n if (segments[1] === 'checkout') return true;\r\n if (segments[1] === 'register' && method === 'POST') return true;\r\n if (extraRule?.(method, segments)) return true;\r\n return false;\r\n }\r\n\r\n if (segments[0] === 'contacts' && method === 'POST') return true;\r\n if (segments[0] === 'form-submissions' && method === 'POST') return true;\r\n if (segments[0] === 'auth' && method === 'POST') return true;\r\n if (segments[0] === 'users' && segments[1] === 'forgot-password' && method === 'POST') return true;\r\n if (segments[0] === 'users' && segments[1] === 'set-password' && method === 'POST') return true;\r\n if (segments[0] === 'users' && segments[1] === 'invite' && method === 'POST') return true;\r\n\r\n if (extraRule?.(method, segments)) return true;\r\n return false;\r\n}\r\n\r\nexport function rateLimitKeyForApiRequest(req: Request, segments: string[]): string {\r\n return `${clientIp(req)}:${segments.join('/')}`;\r\n}\r\n\r\nexport async function rateLimitPublicApiIfNeeded(\r\n req: Request,\r\n method: string,\r\n segments: string[],\r\n options?: { extraRule?: ExtraPublicWriteRule }\r\n): Promise<Response | null> {\r\n if (!shouldRateLimitPublicWrite(method, segments, options?.extraRule)) return null;\r\n const key = rateLimitKeyForApiRequest(req, segments);\r\n const ok = await allowRateLimit(key);\r\n if (ok) return null;\r\n return NextResponse.json({ error: 'Too many requests' }, { status: 429 });\r\n}\r\n\r\nconst CHECKOUT_PREFIX = 'checkout:';\r\n\r\nexport async function rateLimitCheckoutPost(req: Request): Promise<Response | null> {\r\n const key = `${CHECKOUT_PREFIX}${clientIp(req)}`;\r\n const ok = await allowRateLimit(key);\r\n if (ok) return null;\r\n return NextResponse.json({ error: 'Too many requests' }, { status: 429 });\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport type { CmsApp } from '../plugins/registry';\r\nimport { mergeEmailLayoutCompanyDetails, queueOrderPlacedEmails } from '../plugins/email';\r\nimport { parseEmailRecipientsFromConfig } from './email-recipients';\r\n\r\ninterface EntityMapLike {\r\n configs: unknown;\r\n orders: unknown;\r\n order_items: unknown;\r\n}\r\n\r\ninterface SendOrderPlacedEmailDeps {\r\n getDataSource: () => Promise<DataSource>;\r\n entityMap: EntityMapLike;\r\n getCms: () => Promise<CmsApp>;\r\n}\r\n\r\nasync function getSettingsGroup(\r\n deps: SendOrderPlacedEmailDeps,\r\n group: string\r\n): Promise<Record<string, string>> {\r\n const ds = await deps.getDataSource();\r\n const rows = await ds.getRepository(deps.entityMap.configs as any).find({\r\n where: { settings: group, deleted: false } as object,\r\n });\r\n return Object.fromEntries(\r\n rows.map((r) => [(r as { key: string; value: string }).key, (r as { key: string; value: string }).value])\r\n );\r\n}\r\n\r\n/** After payment confirmation: email customer + each sales team address from plugin settings. */\r\nexport async function sendOrderPlacedEmailsAfterConfirmation(\r\n orderId: number,\r\n deps: SendOrderPlacedEmailDeps\r\n): Promise<void> {\r\n try {\r\n const ds = await deps.getDataSource();\r\n const order = await ds.getRepository(deps.entityMap.orders as any).findOne({\r\n where: { id: orderId },\r\n relations: ['contact', 'billingAddress', 'shippingAddress'],\r\n });\r\n if (!order) return;\r\n\r\n const o = order as {\r\n orderNumber: string;\r\n total: number | string;\r\n subtotal: number | string;\r\n tax: number | string;\r\n currency: string;\r\n contact?: { email?: string | null; name?: string | null };\r\n billingAddress?: {\r\n line1?: string | null;\r\n line2?: string | null;\r\n city?: string | null;\r\n state?: string | null;\r\n postalCode?: string | null;\r\n country?: string | null;\r\n } | null;\r\n shippingAddress?: {\r\n line1?: string | null;\r\n line2?: string | null;\r\n city?: string | null;\r\n state?: string | null;\r\n postalCode?: string | null;\r\n country?: string | null;\r\n } | null;\r\n };\r\n const contact = o.contact;\r\n const customerEmail = contact?.email?.trim() || null;\r\n const customerName = contact?.name?.trim() || undefined;\r\n\r\n const itemRows = await ds.getRepository(deps.entityMap.order_items as any).find({\r\n where: { orderId },\r\n relations: ['product'],\r\n order: { id: 'ASC' },\r\n });\r\n function addrToRecord(\r\n a:\r\n | {\r\n line1?: string | null;\r\n line2?: string | null;\r\n city?: string | null;\r\n state?: string | null;\r\n postalCode?: string | null;\r\n country?: string | null;\r\n }\r\n | null\r\n | undefined\r\n ): Record<string, string> | undefined {\r\n if (!a) return undefined;\r\n const out: Record<string, string> = {};\r\n const set = (k: string, v: string | null | undefined) => {\r\n const t = v != null ? String(v).trim() : '';\r\n if (t) out[k] = t;\r\n };\r\n set('line1', a.line1);\r\n set('line2', a.line2);\r\n set('city', a.city);\r\n set('state', a.state);\r\n set('postalCode', a.postalCode);\r\n set('country', a.country);\r\n return Object.keys(out).length ? out : undefined;\r\n }\r\n\r\n const lineItems = itemRows.map((row) => {\r\n const r = row as {\r\n quantity: number;\r\n unitPrice: number | string;\r\n total: number | string;\r\n tax?: number | string;\r\n hsn?: string | null;\r\n productId: number;\r\n product?: { name?: string | null; sku?: string | null } | null;\r\n };\r\n const name =\r\n (r.product?.name && String(r.product.name).trim()) || `Product #${r.productId}`;\r\n return {\r\n productName: name,\r\n quantity: Math.max(0, Math.floor(Number(r.quantity) || 0)),\r\n unitPrice: r.unitPrice,\r\n lineTotal: r.total,\r\n sku: r.product?.sku && String(r.product.sku).trim() ? r.product.sku : undefined,\r\n tax: r.tax != null && Number(r.tax) !== 0 ? r.tax : undefined,\r\n hsn: r.hsn && String(r.hsn).trim() ? r.hsn : undefined,\r\n };\r\n });\r\n\r\n const [branding, emailSettings] = await Promise.all([\r\n getSettingsGroup(deps, 'branding'),\r\n getSettingsGroup(deps, 'email'),\r\n ]);\r\n const companyDetails = mergeEmailLayoutCompanyDetails(branding, emailSettings);\r\n const salesTeamEmails = parseEmailRecipientsFromConfig(\r\n emailSettings.salesTeamEmails ?? emailSettings.salesTeamEmail\r\n );\r\n\r\n const cms = await deps.getCms();\r\n await queueOrderPlacedEmails(cms, {\r\n orderNumber: o.orderNumber,\r\n total: o.total,\r\n subtotal: o.subtotal,\r\n tax: o.tax,\r\n currency: o.currency,\r\n customerName,\r\n customerEmail,\r\n salesTeamEmails,\r\n companyDetails,\r\n lineItems,\r\n billingAddress: addrToRecord(o.billingAddress),\r\n shippingAddress: addrToRecord(o.shippingAddress),\r\n });\r\n } catch {\r\n // do not throw from checkout / webhook\r\n }\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport { queueVendorOnboardEmails, type CmsAppLike } from '../plugins/email/email-queue';\r\nimport { mergeEmailLayoutCompanyDetails } from '../plugins/email/templates/types';\r\nimport { parseEmailRecipientsFromConfig } from './email-recipients';import type {\r\n VendorOnboardedActivation,\r\n VendorOnboardedKind,\r\n} from '../plugins/email/templates/vendorOnboarded';\r\n\r\ninterface EntityMapLike {\r\n configs: unknown;\r\n}\r\n\r\nexport interface SendVendorOnboardEmailInput {\r\n vendorName: string;\r\n vendorSlug?: string;\r\n ownerName: string;\r\n ownerEmail: string;\r\n activation: VendorOnboardedActivation;\r\n inviteLink?: string;\r\n signInLink: string;\r\n kind?: VendorOnboardedKind;\r\n /** When false, skips owner email but still notifies internal recipients. Default true. */\r\n sendToOwner?: boolean;\r\n}\r\n\r\ninterface SendVendorOnboardEmailDeps {\r\n getDataSource: () => Promise<DataSource>;\r\n entityMap: EntityMapLike;\r\n getCms: () => Promise<CmsAppLike>;\r\n}\r\n\r\nasync function getSettingsGroup(\r\n deps: SendVendorOnboardEmailDeps,\r\n group: string\r\n): Promise<Record<string, string>> {\r\n const ds = await deps.getDataSource();\r\n const rows = await ds.getRepository(deps.entityMap.configs as never).find({\r\n where: { settings: group, deleted: false } as object,\r\n });\r\n return Object.fromEntries(\r\n rows.map((r) => [(r as { key: string; value: string }).key, (r as { key: string; value: string }).value])\r\n );\r\n}\r\n\r\n/** After vendor onboard / team invite: email owner + platform team from plugin settings. */\r\nexport async function sendVendorOnboardEmails(\r\n input: SendVendorOnboardEmailInput,\r\n deps: SendVendorOnboardEmailDeps\r\n): Promise<{ ownerEmailSent: boolean }> {\r\n let ownerEmailSent = false;\r\n try {\r\n const [branding, emailSettings] = await Promise.all([\r\n getSettingsGroup(deps, 'branding'),\r\n getSettingsGroup(deps, 'email'),\r\n ]);\r\n const companyDetails = mergeEmailLayoutCompanyDetails(branding, emailSettings);\r\n const notifyEmails = parseEmailRecipientsFromConfig(\r\n emailSettings.salesTeamEmails ?? emailSettings.salesTeamEmail\r\n );\r\n const sendToOwner = input.sendToOwner !== false;\r\n const ownerEmail = input.ownerEmail?.trim() || '';\r\n\r\n const cms = await deps.getCms();\r\n await queueVendorOnboardEmails(cms, {\r\n vendorName: input.vendorName,\r\n vendorSlug: input.vendorSlug,\r\n ownerName: input.ownerName,\r\n ownerEmail,\r\n activation: input.activation,\r\n inviteLink: input.inviteLink,\r\n signInLink: input.signInLink,\r\n kind: input.kind ?? 'vendor_onboard',\r\n notifyEmails,\r\n companyDetails,\r\n sendToOwner: sendToOwner && Boolean(ownerEmail),\r\n });\r\n ownerEmailSent = sendToOwner && Boolean(ownerEmail);\r\n } catch {\r\n // do not throw from onboard handlers\r\n }\r\n return { ownerEmailSent };\r\n}\r\n","import 'reflect-metadata';\r\nimport { DataSource } from 'typeorm';\r\n\r\ntype EntityTargetList = (Function | import('typeorm').EntitySchema<unknown>)[];\r\n\r\nexport interface DataSourceManager {\r\n getDataSource: () => DataSource;\r\n getDataSourceInitialized: () => Promise<DataSource>;\r\n resetDataSource: () => void;\r\n registerOnReset: (cb: () => void) => void;\r\n isConnectionError: (e: unknown) => boolean;\r\n}\r\n\r\nexport function createDataSourceManager(\r\n entityMap: Record<string, unknown>,\r\n options?: { databaseUrl?: string; idleTimeoutMillis?: number }\r\n): DataSourceManager {\r\n const entities = Object.values(entityMap) as EntityTargetList;\r\n const databaseUrl = options?.databaseUrl ?? process.env.DATABASE_URL;\r\n const idleTimeoutMillis = options?.idleTimeoutMillis ?? 60000;\r\n\r\n let dataSource: DataSource | null = null;\r\n const onResetCallbacks: (() => void)[] = [];\r\n\r\n function registerOnReset(cb: () => void): void {\r\n onResetCallbacks.push(cb);\r\n }\r\n\r\n function resetDataSource(): void {\r\n dataSource = null;\r\n onResetCallbacks.forEach((cb) => cb());\r\n }\r\n\r\n function isConnectionError(e: unknown): boolean {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n const driverMsg =\r\n e && typeof e === 'object' && 'driverError' in e && e.driverError instanceof Error\r\n ? e.driverError.message\r\n : '';\r\n return (\r\n /Connection terminated|Connection.*is not established/i.test(msg) ||\r\n /Connection terminated|Connection.*is not established/i.test(driverMsg)\r\n );\r\n }\r\n\r\n function getDataSource(): DataSource {\r\n if (!dataSource) {\r\n dataSource = new DataSource({\r\n type: 'postgres',\r\n url: databaseUrl,\r\n entities,\r\n synchronize: false,\r\n extra: { idleTimeoutMillis },\r\n ...(process.env.TYPEORM_CLI && {\r\n migrations: [\r\n 'src/migrations/*.ts',\r\n 'node_modules/@infuro/cms-core/dist/migrations/*.ts',\r\n ],\r\n }),\r\n });\r\n }\r\n return dataSource;\r\n }\r\n\r\n async function getDataSourceInitialized(): Promise<DataSource> {\r\n const ds = getDataSource();\r\n if (!ds.isInitialized) {\r\n try {\r\n await ds.initialize();\r\n } catch (e) {\r\n dataSource = null;\r\n throw e;\r\n }\r\n }\r\n return ds;\r\n }\r\n\r\n return {\r\n getDataSource,\r\n getDataSourceInitialized,\r\n resetDataSource,\r\n registerOnReset,\r\n isConnectionError,\r\n };\r\n}\r\n","import bcrypt from 'bcryptjs';\r\nimport type { DataSource } from 'typeorm';\r\n\r\ninterface SeedEntityMap {\r\n users: unknown;\r\n user_groups: unknown;\r\n}\r\n\r\nexport async function seedDefaultAdmin(\r\n ds: DataSource,\r\n entityMap: SeedEntityMap,\r\n opts?: { email?: string; password?: string }\r\n): Promise<void> {\r\n const userRepo = ds.getRepository(entityMap.users as any);\r\n const groupRepo = ds.getRepository(entityMap.user_groups as any);\r\n const adminGroup = await groupRepo.findOne({ where: { name: 'Administrator' } });\r\n\r\n const email = opts?.email || process.env.ADMIN_EMAIL || 'admin@example.com';\r\n const password = opts?.password || process.env.ADMIN_PASSWORD || 'changeme';\r\n\r\n const existing = await userRepo.findOne({ where: { email } });\r\n if (!existing) {\r\n const hashedPassword = await bcrypt.hash(password, 10);\r\n await userRepo.save(\r\n userRepo.create({\r\n name: 'Admin',\r\n email,\r\n password: hashedPassword,\r\n groupId: adminGroup?.id ?? null,\r\n adminAccess: true,\r\n })\r\n );\r\n console.log(\r\n adminGroup\r\n ? `Default admin user created (group: ${adminGroup.name})`\r\n : 'Default admin user created (no Administrator group — run migrations and assign a group)'\r\n );\r\n } else {\r\n if (adminGroup?.id && existing.groupId !== adminGroup.id) {\r\n await userRepo.update({ id: existing.id }, { groupId: adminGroup.id, adminAccess: true });\r\n console.log(`Default admin user already exists; assigned group: ${adminGroup.name}`);\r\n } else {\r\n console.log('Default admin user already exists');\r\n }\r\n }\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport type { VendorUserRole } from '../entities/vendor-user.entity';\r\n\r\n/** Load vendor membership for session (call from app `getUserByEmail`).\r\n *\r\n * Uses a raw SQL query so it works even when the consuming app's DataSource\r\n * does not explicitly register the VendorUser entity.\r\n */\r\nexport async function loadUserVendorContext(\r\n dataSource: DataSource,\r\n userId: number,\r\n preferredVendorId?: number | null\r\n): Promise<{ vendorIds: number[]; activeVendorId: number | null; vendorRole: VendorUserRole | null }> {\r\n const rows = (await dataSource.query(\r\n `SELECT \"vendorId\", \"role\" FROM \"vendor_users\" WHERE \"userId\" = $1 ORDER BY id ASC`,\r\n [userId]\r\n )) as Array<{ vendorId: number; role: VendorUserRole }>;\r\n\r\n const vendorIds = rows.map((r) => Number(r.vendorId));\r\n const activeRow =\r\n preferredVendorId != null ? rows.find((r) => Number(r.vendorId) === preferredVendorId) : undefined;\r\n const primary = activeRow ?? rows[0];\r\n return {\r\n vendorIds,\r\n activeVendorId: primary != null ? Number(primary.vendorId) : (vendorIds[0] ?? null),\r\n vendorRole: (primary?.role as VendorUserRole) ?? null,\r\n };\r\n}\r\n","import type { DataSource } from 'typeorm';\r\r\nimport type { NextAuthUser } from '../auth/nextauth-options';\r\r\nimport { loadUserVendorContext } from './load-user-vendor-context';\r\r\n\r\r\n/** Attach vendorIds / activeVendorId / vendorRole for NextAuth (use in app getUserByEmail). */\r\r\nexport async function enrichUserWithVendorContext(\r\r\n dataSource: DataSource,\r\r\n user: NextAuthUser | null\r\r\n): Promise<NextAuthUser | null> {\r\r\n if (!user) return null;\r\r\n const { vendorIds, activeVendorId, vendorRole } = await loadUserVendorContext(dataSource, user.id);\r\r\n return { ...user, vendorIds, activeVendorId, vendorRole };\r\r\n}\r\r\n\r","import type { DataSource } from 'typeorm';\r\n\r\nimport type { SessionUser } from '../auth/helpers';\r\nimport { logRbac } from '../auth/rbac-debug';\r\nimport { isSuperAdmin } from '../auth/role-helpers';\r\nimport { vendorPortalFlagsFromUser } from '../auth/vendor-scope';\r\n\r\nimport { loadUserVendorContext } from './load-user-vendor-context';\r\n\r\n/** Merge DB group + vendor_users into session (JWT often missing these). Server/API only. */\r\nexport async function hydrateVendorSessionUser(\r\n dataSource: DataSource,\r\n user: SessionUser | null | undefined\r\n): Promise<SessionUser | null | undefined> {\r\n if (!user?.email) return user;\r\n let id = Number(user.id);\r\n if (!Number.isFinite(id)) {\r\n const byEmailRows = (await dataSource.query(\r\n `\r\n SELECT u.id AS id, u.\"adminAccess\" AS \"adminAccess\", u.\"groupId\" AS \"groupId\", g.name AS \"groupName\"\r\n FROM users u\r\n LEFT JOIN user_groups g ON g.id = u.\"groupId\" AND g.deleted = false\r\n WHERE LOWER(TRIM(u.email)) = LOWER(TRIM($1)) AND u.deleted = false\r\n LIMIT 1\r\n `,\r\n [user.email]\r\n )) as Array<{ id: number; adminAccess: boolean; groupId: number | null; groupName: string | null }>;\r\n const resolvedId = Number(byEmailRows[0]?.id);\r\n if (!Number.isFinite(resolvedId)) {\r\n logRbac('hydrateVendorSessionUser: unable to resolve numeric user id', {\r\n email: user.email,\r\n rawSessionId: user.id ?? null,\r\n });\r\n return user;\r\n }\r\n id = resolvedId;\r\n }\r\n\r\n const rows = (await dataSource.query(\r\n `\r\n SELECT u.\"adminAccess\" AS \"adminAccess\", u.\"groupId\" AS \"groupId\", g.name AS \"groupName\"\r\n FROM users u\r\n LEFT JOIN user_groups g ON g.id = u.\"groupId\" AND g.deleted = false\r\n WHERE u.id = $1\r\n LIMIT 1\r\n `,\r\n [id]\r\n )) as Array<{ adminAccess: boolean; groupId: number | null; groupName: string | null }>;\r\n\r\n const groupName = rows[0]?.groupName ?? user.groupName ?? null;\r\n const groupId = rows[0]?.groupId ?? user.groupId ?? undefined;\r\n const adminAccess = rows[0]?.adminAccess ?? user.adminAccess;\r\n const isRBACAdmin = user.isRBACAdmin ?? isSuperAdmin({ groupId, groupName, isRBACAdmin: user.isRBACAdmin });\r\n\r\n const ctx = await loadUserVendorContext(dataSource, id, user.activeVendorId);\r\n const flags = vendorPortalFlagsFromUser({\r\n email: user.email,\r\n isRBACAdmin,\r\n groupName,\r\n vendorIds: ctx.vendorIds,\r\n vendorRole: ctx.vendorRole,\r\n });\r\n\r\n const hydrated = {\r\n ...user,\r\n groupId,\r\n groupName: groupName ?? undefined,\r\n adminAccess,\r\n isRBACAdmin,\r\n vendorIds: ctx.vendorIds,\r\n activeVendorId: ctx.activeVendorId,\r\n vendorRole: ctx.vendorRole,\r\n isVendorPortal: flags.isVendorPortal,\r\n isVendorOwner: flags.isVendorOwner,\r\n };\r\n\r\n logRbac('hydrateVendorSessionUser', {\r\n email: user.email,\r\n userId: id,\r\n groupName,\r\n vendorIds: ctx.vendorIds,\r\n vendorRole: ctx.vendorRole,\r\n isVendorPortal: flags.isVendorPortal,\r\n isVendorOwner: flags.isVendorOwner,\r\n adminAccess,\r\n });\r\n\r\n return hydrated;\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport type { FooterConfig, NavbarConfig } from '../theme/types';\r\nimport { getPublicSettingsGroup } from '../api/cms-handlers';\r\nimport type { EntityMap } from '../api/crud';\r\n\r\nconst defaultNavbar: NavbarConfig = {\r\n logo: '',\r\n items: [],\r\n ctaLabel: '',\r\n ctaUrl: '',\r\n};\r\n\r\nexport interface PublicThemeSettingsPayload {\r\n activeThemeId: string;\r\n primaryColor: string;\r\n secondaryColor: string;\r\n navbarConfig: NavbarConfig;\r\n footerOverrides: Partial<FooterConfig>;\r\n}\r\n\r\nexport async function loadPublicThemeSettings(config: {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n encryptionKey?: string;\r\n defaultActiveThemeId?: string;\r\n defaultPrimaryColor?: string;\r\n defaultSecondaryColor?: string;\r\n}): Promise<PublicThemeSettingsPayload> {\r\n const fallback: PublicThemeSettingsPayload = {\r\n activeThemeId: config.defaultActiveThemeId ?? '',\r\n primaryColor: config.defaultPrimaryColor ?? '#305898',\r\n secondaryColor: config.defaultSecondaryColor ?? '#44ACED',\r\n navbarConfig: defaultNavbar,\r\n footerOverrides: {},\r\n };\r\n\r\n try {\r\n const raw = await getPublicSettingsGroup(\r\n {\r\n dataSource: config.dataSource,\r\n entityMap: config.entityMap,\r\n encryptionKey: config.encryptionKey,\r\n },\r\n 'theme'\r\n );\r\n\r\n const activeThemeId = raw.activeThemeId\r\n ? String(raw.activeThemeId).trim()\r\n : fallback.activeThemeId;\r\n const primaryColor = raw.primaryColor || fallback.primaryColor;\r\n const secondaryColor = raw.secondaryColor || fallback.secondaryColor;\r\n\r\n let navbarConfig: NavbarConfig = defaultNavbar;\r\n if (raw.navbar) {\r\n try {\r\n navbarConfig = JSON.parse(raw.navbar) as NavbarConfig;\r\n } catch {\r\n /* keep default */\r\n }\r\n }\r\n\r\n let footerOverrides: Partial<FooterConfig> = {};\r\n if (raw.footer) {\r\n try {\r\n footerOverrides = JSON.parse(raw.footer) as Partial<FooterConfig>;\r\n } catch {\r\n /* keep default */\r\n }\r\n }\r\n\r\n return { activeThemeId, primaryColor, secondaryColor, navbarConfig, footerOverrides };\r\n } catch {\r\n return fallback;\r\n }\r\n}\r\n","import type { DataSource } from 'typeorm';\r\n\r\n/**\r\n * Executes `fn` inside a transaction where the PostgreSQL GUC\r\n * `app.vendor_id` is set for the duration of that transaction.\r\n *\r\n * This activates the `vendor_isolation` RLS policy added by the\r\n * `VendorRls1775940000000` migration.\r\n *\r\n * vendorId = 0 → admin / all-access (policy allows everything)\r\n * vendorId > 0 → only rows whose `vendorId` column matches\r\n *\r\n * Example:\r\n * const orders = await withVendorRlsContext(dataSource, 4, (ds) =>\r\n * ds.getRepository(Order).find({ where: { deleted: false } })\r\n * );\r\n */\r\nexport async function withVendorRlsContext<T>(\r\n dataSource: DataSource,\r\n vendorId: number,\r\n fn: (dataSource: DataSource) => Promise<T>\r\n): Promise<T> {\r\n const qr = dataSource.createQueryRunner();\r\n await qr.connect();\r\n await qr.startTransaction();\r\n try {\r\n // SET LOCAL persists only for this transaction; safe with connection pooling.\r\n await qr.query(`SET LOCAL app.vendor_id = '${vendorId}'`);\r\n const result = await fn(dataSource);\r\n await qr.commitTransaction();\r\n return result;\r\n } catch (err) {\r\n await qr.rollbackTransaction();\r\n throw err;\r\n } finally {\r\n await qr.release();\r\n }\r\n}\r\n\r\n/**\r\n * Convenience wrapper: sets admin mode (vendor_id = '0') so all rows are\r\n * visible regardless of their vendorId. Use for platform-admin queries.\r\n */\r\nexport async function withAdminRlsContext<T>(\r\n dataSource: DataSource,\r\n fn: (dataSource: DataSource) => Promise<T>\r\n): Promise<T> {\r\n return withVendorRlsContext(dataSource, 0, fn);\r\n}\r\n","import type { DataSource, SelectQueryBuilder } from 'typeorm';\r\nimport type { EntityMap } from '../api/crud';\r\nimport type { VendorScope } from '../auth/vendor-scope';\r\n\r\nexport function isCustomerTypeContact(type: unknown): boolean {\r\n return String(type ?? '').trim().toLowerCase() === 'customer';\r\n}\r\n\r\n/** Restrict contact list to rows linked in `vendor_customers` with type customer. */\r\nexport function applyVendorCustomersContactFilter(\r\n qb: SelectQueryBuilder<import('typeorm').ObjectLiteral>,\r\n contactAlias: string,\r\n scope: VendorScope,\r\n vendorIdFilter: number | null\r\n): void {\r\n qb.innerJoin('vendor_customers', 'vc', `vc.\"contactId\" = ${contactAlias}.id`);\r\n\r\n if (scope.type === 'vendor') {\r\n qb.andWhere('vc.\"vendorId\" = :vcVendorId', { vcVendorId: scope.vendorId });\r\n return;\r\n }\r\n if (vendorIdFilter != null && Number.isFinite(vendorIdFilter)) {\r\n qb.andWhere('vc.\"vendorId\" = :vcVendorId', { vcVendorId: vendorIdFilter });\r\n }\r\n}\r\n\r\nexport async function contactIsVendorCustomer(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n vendorId: number,\r\n contactId: number\r\n): Promise<boolean> {\r\n if (!Number.isFinite(vendorId) || !Number.isFinite(contactId)) return false;\r\n const vcEntity = entityMap.vendor_customers;\r\n const contactEntity = entityMap.contacts;\r\n if (!vcEntity || !contactEntity) return false;\r\n\r\n const vcRepo = dataSource.getRepository(vcEntity);\r\n const contactRepo = dataSource.getRepository(contactEntity);\r\n const contact = await contactRepo.findOne({\r\n where: { id: contactId, deleted: false } as import('typeorm').ObjectLiteral\r\n });\r\n if (!contact) return false;\r\n const email = (contact as { email?: string | null }).email;\r\n\r\n if (entityMap.customer && email){\r\n const customerRepo = dataSource.getRepository(entityMap.customer);\r\n const customer = await customerRepo.findOne({\r\n where: { email, deleted: false } as import(\"typeorm\").ObjectLiteral\r\n });\r\n if (customer){\r\n const customerId = Number((customer as { id: number }).id);\r\n const customerLink = await vcRepo.findOne({\r\n where: { vendorId, customerId } as import(\"typeorm\").ObjectLiteral\r\n });\r\n if (customerLink != null) return true;\r\n }\r\n }\r\n\r\n const vcMeta = dataSource.getRepository(vcEntity).metadata;\r\n const hasContactIdCol = vcMeta.columns.some((c) => c.propertyName === 'contactId');\r\n if (hasContactIdCol){\r\n const directLink = await vcRepo.findOne({\r\n where: { vendorId, contactId } as import('typeorm').ObjectLiteral\r\n });\r\n if (directLink){\r\n const t = (contact as { type?: string | null }).type;\r\n return t == null || t == '' || isCustomerTypeContact(t);\r\n }\r\n }\r\n return false;\r\n}\r\n\r\n/** Returns an error message when the contact is not a vendor-linked customer; otherwise null. */\r\nexport async function assertContactAllowedForVendorOrder(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n vendorId: number,\r\n contactId: number\r\n): Promise<string | null> {\r\n if (!Number.isFinite(contactId)) {\r\n return 'Valid contactId is required.';\r\n }\r\n if (!Number.isFinite(vendorId)) {\r\n return 'Vendor scope is required to assign a customer.';\r\n }\r\n const ok = await contactIsVendorCustomer(dataSource, entityMap, vendorId, contactId);\r\n if (!ok) {\r\n return 'Customer must be linked to your store (type customer in vendor customers).';\r\n }\r\n return null;\r\n}\r\n\r\nexport function resolveVendorIdForContactCheck(\r\n scope: VendorScope,\r\n bodyOrRow: Record<string, unknown>\r\n): number | null {\r\n if (scope.type === 'vendor') return scope.vendorId;\r\n const n = Number(bodyOrRow.vendorId);\r\n return Number.isFinite(n) ? n : null;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { UserGroup } from './user-group.entity';\r\n\r\n@Entity('users')\r\nexport class User {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n @Column('varchar', { unique: true })\r\n email: string;\r\n\r\n /** E.164 when set; unique among non-null values (partial index in DB). */\r\n @Column('varchar', { nullable: true })\r\n phone: string | null;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n phoneVerifiedAt: Date | null;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n emailVerifiedAt: Date | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n password: string | null;\r\n\r\n @Column('boolean', { default: false })\r\n blocked: boolean;\r\n\r\n @Column('boolean', { default: false })\r\n adminAccess: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n groupId: number | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @ManyToOne(() => UserGroup, (g) => g.users, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'groupId' })\r\n group: UserGroup | null;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';\r\nimport { Permission } from './permission.entity';\r\nimport { User } from './user.entity';\r\n\r\n@Entity('user_groups')\r\nexport class UserGroup {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar', { unique: true })\r\n name: string;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @OneToMany(() => Permission, (p) => p.group)\r\n permissions: Permission[];\r\n\r\n @OneToMany(() => User, (u) => u.group)\r\n users: User[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { UserGroup } from './user-group.entity';\r\n\r\n@Entity('permissions')\r\nexport class Permission {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n groupId: number;\r\n\r\n @Column('varchar')\r\n entity: string;\r\n\r\n @Column('boolean', { default: false })\r\n canCreate: boolean;\r\n\r\n @Column('boolean', { default: false })\r\n canRead: boolean;\r\n\r\n @Column('boolean', { default: false })\r\n canUpdate: boolean;\r\n\r\n @Column('boolean', { default: false })\r\n canDelete: boolean;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @ManyToOne(() => UserGroup, (g) => g.permissions, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'groupId' })\r\n group: UserGroup;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, Index } from 'typeorm';\r\n\r\n@Entity('otp_challenges')\r\n@Index(['purpose', 'identifier'])\r\nexport class OtpChallenge {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n purpose: string;\r\n\r\n @Column('varchar')\r\n channel: string;\r\n\r\n @Column('varchar')\r\n identifier: string;\r\n\r\n @Column('varchar')\r\n codeHash: string;\r\n\r\n @Column({ type: 'timestamp' })\r\n expiresAt: Date;\r\n\r\n @Column('int', { default: 0 })\r\n attempts: number;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n consumedAt: Date | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';\r\n\r\n@Entity('password_reset_tokens')\r\nexport class PasswordResetToken {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n email: string;\r\n\r\n @Column('varchar', { unique: true })\r\n token: string;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n expiresAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n}\r\n","import {\r\n Entity,\r\n PrimaryGeneratedColumn,\r\n Column,\r\n ManyToOne,\r\n OneToMany,\r\n ManyToMany,\r\n JoinTable,\r\n JoinColumn,\r\n} from 'typeorm';\r\nimport { User } from './user.entity';\r\nimport { Category } from './category.entity';\r\nimport { Seo } from './seo.entity';\r\nimport { Comment } from './comment.entity';\r\nimport { Tag } from './tag.entity';\r\n\r\n@Entity('blogs')\r\nexport class Blog {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n title: string;\r\n\r\n @Column('text')\r\n content: string;\r\n\r\n /** LLM-generated short copy for social (e.g. LinkedIn); preferred over scraping full HTML for share text. */\r\n @Column('text', { nullable: true })\r\n socialMediaContent: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n coverImage: string | null;\r\n\r\n @Column('int')\r\n authorId: number;\r\n\r\n @Column('int', { nullable: true })\r\n categoryId: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n seoId: number | null;\r\n\r\n @Column('boolean', { default: false })\r\n published: boolean;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @Column('varchar', { unique: true })\r\n slug: string;\r\n\r\n @ManyToOne(() => User, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'authorId' })\r\n author: User;\r\n\r\n @ManyToOne(() => Category, (c) => c.blogs, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'categoryId' })\r\n category: Category | null;\r\n\r\n @ManyToOne(() => Seo, (s) => s.blogs, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'seoId' })\r\n seo: Seo | null;\r\n\r\n @OneToMany(() => Comment, (c) => c.blog)\r\n comments: Comment[];\r\n\r\n @ManyToMany(() => Tag, (t) => t.blogs)\r\n @JoinTable({\r\n name: 'blog_tags',\r\n joinColumn: { name: 'blogId', referencedColumnName: 'id' },\r\n inverseJoinColumn: { name: 'tagId', referencedColumnName: 'id' },\r\n })\r\n tags: Tag[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';\r\nimport type { Blog } from './blog.entity';\r\n\r\n@Entity('categories')\r\nexport class Category {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar', { unique: true })\r\n name: string;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @OneToMany('Blog', 'category')\r\n blogs: Blog[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';\r\nimport { Blog } from './blog.entity';\r\n\r\n@Entity('seos')\r\nexport class Seo {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar', { nullable: true })\r\n title: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n description: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n keywords: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n ogTitle: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n ogDescription: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n ogImage: string | null;\r\n\r\n @Column('varchar', { unique: true })\r\n slug: string;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @OneToMany(() => Blog, (blog) => blog.seo)\r\n blogs: Blog[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { User } from './user.entity';\r\nimport { Blog } from './blog.entity';\r\n\r\n@Entity('comments')\r\nexport class Comment {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('text')\r\n content: string;\r\n\r\n @Column('int')\r\n blogId: number;\r\n\r\n @Column('int')\r\n authorId: number;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @ManyToOne(() => User, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'authorId' })\r\n author: User;\r\n\r\n @ManyToOne(() => Blog, (b) => b.comments, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'blogId' })\r\n blog: Blog;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from 'typeorm';\r\nimport { Blog } from './blog.entity';\r\n\r\n@Entity('tags')\r\nexport class Tag {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar', { unique: true })\r\n name: string;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @ManyToMany(() => Blog, (blog) => blog.tags)\r\n blogs: Blog[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { User } from './user.entity';\r\nimport { FormSubmission } from './form-submission.entity';\r\nimport { Address } from './address.entity';\r\nimport { Order } from './order.entity';\r\nimport { Payment } from './payment.entity';\r\nimport { ChatConversation } from './chat-conversation.entity';\r\nimport { OrderAddresses } from './order_addresses.entity';\r\n\r\n@Entity('contacts')\r\nexport class Contact {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n @Column('varchar', { unique: true })\r\n email: string;\r\n\r\n @Column('varchar', { nullable: true })\r\n phone: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n type: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n company: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n taxId: string | null;\r\n\r\n @Column('text', { nullable: true })\r\n notes: string | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n userId: number | null;\r\n\r\n @ManyToOne(() => User, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'userId' })\r\n user: User | null;\r\n\r\n @OneToMany(() => FormSubmission, (fs) => fs.contact)\r\n form_submissions: FormSubmission[];\r\n\r\n @OneToMany(() => Address, (a) => a.contact)\r\n addresses: Address[];\r\n\r\n @OneToMany(() => Order, (o) => o.contact)\r\n orders: Order[];\r\n\r\n @OneToMany(() => Payment, (p) => p.contact)\r\n payments: Payment[];\r\n\r\n @OneToMany(() => ChatConversation, (c) => c.contact)\r\n chatConversations: ChatConversation[];\r\n\r\n @OneToMany(() => OrderAddresses, (orderAddresses) => orderAddresses.contact)\r\n orderAddresses: OrderAddresses[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { Form } from './form.entity';\r\nimport { Contact } from './contact.entity';\r\n\r\n@Entity('form_submissions')\r\nexport class FormSubmission {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n formId: number;\r\n\r\n @Column('int', { nullable: true })\r\n contactId: number | null;\r\n\r\n @Column('jsonb')\r\n data: Record<string, unknown>;\r\n\r\n @Column('varchar', { nullable: true })\r\n ipAddress: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n userAgent: string | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @ManyToOne(() => Form, (f) => f.submissions, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'formId' })\r\n form: Form;\r\n\r\n @ManyToOne(() => Contact, (c) => c.form_submissions, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'contactId' })\r\n contact: Contact | null;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';\r\nimport { FormField } from './form-field.entity';\r\nimport { FormSubmission } from './form-submission.entity';\r\n\r\n@Entity('forms')\r\nexport class Form {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n @Column('text', { nullable: true })\r\n description: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n campaign: string | null;\r\n\r\n @Column('varchar', { unique: true })\r\n slug: string;\r\n\r\n @Column('boolean', { default: false })\r\n published: boolean;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @OneToMany(() => FormField, (f) => f.form)\r\n fields: FormField[];\r\n\r\n @OneToMany(() => FormSubmission, (s) => s.form)\r\n submissions: FormSubmission[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { Form } from './form.entity';\r\n\r\n@Entity('form_fields')\r\nexport class FormField {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n formId: number;\r\n\r\n @Column('varchar')\r\n label: string;\r\n\r\n @Column('varchar')\r\n type: string;\r\n\r\n @Column('varchar', { nullable: true })\r\n placeholder: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n options: string | null;\r\n\r\n @Column('boolean', { default: false })\r\n required: boolean;\r\n\r\n @Column('varchar', { nullable: true })\r\n validation: string | null;\r\n\r\n @Column('int')\r\n order: number;\r\n\r\n @Column('int', { default: 1 })\r\n groupId: number;\r\n\r\n @Column('int', { default: 12 })\r\n columnWidth: number;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @ManyToOne(() => Form, (f) => f.fields, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'formId' })\r\n form: Form;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { Contact } from './contact.entity';\r\n\r\n@Entity('addresses')\r\nexport class Address {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n contactId: number;\r\n\r\n @Column('varchar', { nullable: true })\r\n tag: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n line1: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n line2: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n city: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n state: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n postalCode: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n country: string | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @ManyToOne(() => Contact, (c) => c.addresses, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'contactId' })\r\n contact: Contact;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany, JoinColumn, Unique } from 'typeorm';\r\nimport { Contact } from './contact.entity';\r\nimport { Address } from './address.entity';\r\nimport { Vendor } from './vendor.entity';\r\nimport type { OrderItem } from './order-item.entity';\r\nimport type { Payment } from './payment.entity';\r\nimport { OrderAddresses } from './order_addresses.entity';\r\nimport { Customer_Contacts } from './customer_contacts.entity';\r\n\r\nexport type OrderKind = 'sale' | 'return' | 'replacement';\r\n\r\n@Entity('orders')\r\n@Unique('UQ_orders_vendor_orderNumber', ['vendorId', 'orderNumber'])\r\nexport class Order {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n vendorId: number;\r\n\r\n @Column('varchar')\r\n orderNumber: string;\r\n\r\n @Column('varchar', { unique: true, nullable: true })\r\n qrToken: string | null;\r\n\r\n @Column('varchar', { default: 'sale' })\r\n orderKind: OrderKind;\r\n\r\n @Column('int', { nullable: true })\r\n parentOrderId: number | null;\r\n\r\n @Column('int')\r\n contactId: number;\r\n\r\n /** Junction row linking the account customer to the checkout contact (storefront checkout). */\r\n @Column('int', { nullable: true })\r\n customerContactId: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n billingAddressId: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n shippingAddressId: number | null;\r\n\r\n @Column('varchar', { default: 'pending' })\r\n status: 'pending' | 'confirmed' | 'processing' | 'completed' | 'cancelled';\r\n\r\n @Column('decimal', { precision: 12, scale: 2, default: 0 })\r\n subtotal: number;\r\n\r\n @Column('decimal', { precision: 12, scale: 2, default: 0 })\r\n tax: number;\r\n\r\n @Column('decimal', { precision: 12, scale: 2, default: 0 })\r\n discount: number;\r\n\r\n @Column('decimal', { precision: 12, scale: 2, default: 0 })\r\n total: number;\r\n\r\n @Column('varchar', { default: 'INR' })\r\n currency: string;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @ManyToOne(() => Vendor, { onDelete: 'RESTRICT' })\r\n @JoinColumn({ name: 'vendorId' })\r\n vendor: Vendor;\r\n\r\n @ManyToOne(() => Order, (o) => o.children, { nullable: true, onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'parentOrderId' })\r\n parentOrder: Order | null;\r\n\r\n @OneToMany(() => Order, (o) => o.parentOrder)\r\n children: Order[];\r\n\r\n @ManyToOne(() => Contact, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'contactId' })\r\n contact: Contact;\r\n\r\n @ManyToOne(() => Customer_Contacts, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'customerContactId' })\r\n customerContact: Customer_Contacts | null;\r\n\r\n @ManyToOne(() => OrderAddresses, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'billingAddressId' })\r\n billingAddress: OrderAddresses | null;\r\n\r\n @ManyToOne(() => OrderAddresses, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'shippingAddressId' })\r\n shippingAddress: OrderAddresses | null;\r\n\r\n @OneToMany('OrderItem', 'order')\r\n items: OrderItem[];\r\n\r\n @OneToMany('Payment', 'order')\r\n payments: Payment[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';\r\nimport type { VendorUser } from './vendor-user.entity';\r\n\r\nexport type VendorInviteStatus = 'none' | 'pending' | 'expired' | 'accepted';\r\n\r\n@Entity('vendors')\r\nexport class Vendor {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n @Column('varchar', { unique: true })\r\n slug: string;\r\n\r\n @Column('varchar', { nullable: true })\r\n email: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n phone: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n logo: string | null;\r\n\r\n @Column('text', { nullable: true })\r\n description: string | null;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column('boolean', { default: true })\r\n active: boolean;\r\n\r\n /** Primary owner user for this vendor (set on onboard). */\r\n @Column('int', { nullable: true })\r\n userId: number | null;\r\n\r\n @Column({\r\n type: 'enum',\r\n enum: ['none', 'pending', 'expired', 'accepted'],\r\n default: 'none',\r\n })\r\n inviteStatus: VendorInviteStatus;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @OneToMany('VendorUser', 'vendor')\r\n vendorUsers: VendorUser[];\r\n}\r\n","import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn, OneToMany } from 'typeorm';\r\nimport { Contact } from './contact.entity';\r\nimport { Order } from './order.entity';\r\n\r\nexport enum AddressType{\r\n SHIPPING_ADDRESS = \"shipping_address\",\r\n BILLING_ADDRESS = \"billing_address\"\r\n}\r\n\r\n@Entity('order_addresses')\r\nexport class OrderAddresses{\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column({ type: 'int' })\r\n contactId: number;\r\n\r\n @Column({ type: 'enum', enum: AddressType })\r\n addressType: AddressType;\r\n\r\n @Column({ type: 'varchar'})\r\n line1: string;\r\n \r\n @Column({ type: 'varchar', nullable: true })\r\n line2: string | null;\r\n \r\n @Column({ type: 'varchar'})\r\n city: string;\r\n \r\n @Column({ type: 'varchar'})\r\n state: string;\r\n \r\n @Column({ type: 'varchar'})\r\n postalCode: string;\r\n \r\n @Column({ type: 'varchar'})\r\n country: string;\r\n \r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n \r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n \r\n @ManyToOne(() => Contact, (contact) => contact.orderAddresses, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'contactId' })\r\n contact: Contact;\r\n\r\n @OneToMany(() => Order, (order) => order.billingAddress)\r\n billingOrders: Order[];\r\n\r\n @OneToMany(() => Order, (order) => order.shippingAddress)\r\n shippingOrders: Order[];\r\n}","import { Column, Entity, PrimaryGeneratedColumn, ManyToOne, JoinColumn } from \"typeorm\";\r\nimport { Customer } from \"./customer.entity\";\r\nimport { Contact } from \"./contact.entity\";\r\n\r\n@Entity('customer_contacts')\r\nexport class Customer_Contacts{\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n customerId: number;\r\n\r\n @ManyToOne(() => Customer, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'customerId' })\r\n customer: Customer\r\n\r\n @Column('int')\r\n contactId: number;\r\n\r\n @ManyToOne(() => Contact, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'contactId' })\r\n contact: Contact\r\n}","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { User } from './user.entity';\r\n\r\n@Entity('customer')\r\nexport class Customer{\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n userId: number;\r\n\r\n @ManyToOne(() => User, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'userId' })\r\n user: User | null;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n @Column('varchar', { unique: true })\r\n email: string;\r\n\r\n @Column('varchar', { unique: true })\r\n phone: string;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n}","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { Order } from './order.entity';\r\nimport { Contact } from './contact.entity';\r\nimport { Vendor } from './vendor.entity';\r\n\r\n@Entity('payments')\r\nexport class Payment {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n vendorId: number;\r\n\r\n @Column('int')\r\n orderId: number;\r\n\r\n @Column('int', { nullable: true })\r\n contactId: number | null;\r\n\r\n @Column('decimal', { precision: 12, scale: 2 })\r\n amount: number;\r\n\r\n @Column('varchar', { default: 'INR' })\r\n currency: string;\r\n\r\n @Column('varchar', { default: 'pending' })\r\n status: 'pending' | 'processing' | 'completed' | 'failed' | 'refunded';\r\n\r\n @Column('varchar', { nullable: true })\r\n method: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n externalReference: string | null;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n paidAt: Date | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @ManyToOne(() => Vendor, { onDelete: 'RESTRICT' })\r\n @JoinColumn({ name: 'vendorId' })\r\n vendor: Vendor;\r\n\r\n @ManyToOne(() => Order, (o) => o.payments, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'orderId' })\r\n order: Order;\r\n\r\n @ManyToOne(() => Contact, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'contactId' })\r\n contact: Contact | null;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany, JoinColumn } from 'typeorm';\r\nimport { Contact } from './contact.entity';\r\nimport { ChatMessage } from './chat-message.entity';\r\n\r\n@Entity('chat_conversations')\r\nexport class ChatConversation {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n contactId: number;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n /** Set when a chat lead email was sent for this conversation (intent tool). */\r\n @Column({ type: 'timestamp', nullable: true })\r\n leadEmailSentAt: Date | null;\r\n\r\n @ManyToOne(() => Contact, (c) => c.chatConversations, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'contactId' })\r\n contact: Contact;\r\n\r\n @OneToMany(() => ChatMessage, (m) => m.conversation)\r\n messages: ChatMessage[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { ChatConversation } from './chat-conversation.entity';\r\n\r\n@Entity('chat_messages')\r\nexport class ChatMessage {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n conversationId: number;\r\n\r\n @Column('varchar')\r\n role: 'user' | 'assistant' | 'system';\r\n\r\n @Column('text')\r\n content: string;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @ManyToOne(() => ChatConversation, (c) => c.messages, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'conversationId' })\r\n conversation: ChatConversation;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, Unique } from 'typeorm';\r\n\r\n@Entity('configs')\r\n@Unique(['settings', 'key'])\r\nexport class Config {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n settings: string;\r\n\r\n @Column('varchar')\r\n key: string;\r\n\r\n @Column('varchar')\r\n value: string;\r\n\r\n @Column('varchar', { default: 'private' })\r\n type: 'public' | 'private';\r\n\r\n @Column('boolean', { default: false })\r\n encrypted: boolean;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';\r\n\r\n@Entity('message_templates')\r\nexport class MessageTemplate {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n channel: string;\r\n\r\n @Column('varchar', { name: 'template_key' })\r\n templateKey: string;\r\n\r\n @Column('varchar', { nullable: true })\r\n name: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n subject: string | null;\r\n\r\n @Column('text', { default: '' })\r\n body: string;\r\n\r\n @Column('varchar', { name: 'external_template_ref', nullable: true })\r\n externalTemplateRef: string | null;\r\n\r\n @Column({ type: 'jsonb', nullable: true })\r\n providerMeta: Record<string, unknown> | null;\r\n\r\n @Column('boolean', { default: true })\r\n enabled: boolean;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany, JoinColumn } from 'typeorm';\r\n\r\n@Entity('media')\r\nexport class Media {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column({ type: 'varchar', length: 16, default: 'file' })\r\n kind: 'file' | 'folder';\r\n\r\n @Column({ type: 'int', nullable: true })\r\n parentId: number | null;\r\n\r\n @ManyToOne(() => Media, (m) => m.children, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'parentId' })\r\n parent: Media | null;\r\n\r\n @OneToMany(() => Media, (m) => m.parent)\r\n children: Media[];\r\n\r\n @Column('varchar')\r\n filename: string;\r\n\r\n @Column('varchar', { nullable: true })\r\n url: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n mimeType: string | null;\r\n\r\n @Column('int', { default: 0 })\r\n size: number;\r\n\r\n @Column('varchar', { nullable: true })\r\n alt: string | null;\r\n\r\n @Column('boolean', { default: false })\r\n isPublic: boolean;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { Seo } from './seo.entity';\r\n\r\n@Entity('pages')\r\nexport class Page {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n title: string;\r\n\r\n @Column('varchar', { unique: true })\r\n slug: string;\r\n\r\n @Column({ type: 'jsonb', default: {} })\r\n content: object;\r\n\r\n @Column('boolean', { default: false })\r\n published: boolean;\r\n\r\n @Column('varchar', { default: 'default' })\r\n theme: string;\r\n\r\n @Column('int', { nullable: true })\r\n parentId: number | null;\r\n\r\n @ManyToOne(() => Page, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'parentId' })\r\n parent: Page | null;\r\n\r\n @Column('int', { nullable: true })\r\n seoId: number | null;\r\n\r\n @ManyToOne(() => Seo, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'seoId' })\r\n seo: Seo | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany, JoinColumn, Unique } from 'typeorm';\r\nimport { Vendor } from './vendor.entity';\r\nimport type { Product } from './product.entity';\r\nimport type { Collection } from './collection.entity';\r\n\r\n@Entity('product_categories')\r\n@Unique('UQ_product_categories_vendor_slug', ['vendorId', 'slug'])\r\nexport class ProductCategory {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n vendorId: number;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n @Column('varchar')\r\n slug: string;\r\n\r\n @Column('int', { nullable: true })\r\n parentId: number | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n image: string | null;\r\n\r\n @Column('text', { nullable: true })\r\n description: string | null;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column('boolean', { default: true })\r\n active: boolean;\r\n\r\n @Column('int', { default: 0 })\r\n sortOrder: number;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @ManyToOne(() => Vendor, { onDelete: 'RESTRICT' })\r\n @JoinColumn({ name: 'vendorId' })\r\n vendor: Vendor;\r\n\r\n @ManyToOne(() => ProductCategory, (c) => c.children, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'parentId' })\r\n parent: ProductCategory | null;\r\n\r\n @OneToMany(() => ProductCategory, (c) => c.parent)\r\n children: ProductCategory[];\r\n\r\n @OneToMany('Product', 'category')\r\n products: Product[];\r\n\r\n @OneToMany('Collection', 'category')\r\n collections: Collection[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany, JoinColumn, Unique } from 'typeorm';\r\nimport { ProductCategory } from './product-category.entity';\r\nimport { Brand } from './brand.entity';\r\nimport { Seo } from './seo.entity';\r\nimport { Vendor } from './vendor.entity';\r\nimport type { Product } from './product.entity';\r\n\r\n@Entity('collections')\r\n@Unique('UQ_collections_vendor_slug', ['vendorId', 'slug'])\r\nexport class Collection {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n vendorId: number;\r\n\r\n @Column('int', { nullable: true })\r\n categoryId: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n brandId: number | null;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n @Column('varchar')\r\n slug: string;\r\n\r\n @Column('varchar', { nullable: true })\r\n hsn: string | null;\r\n\r\n @Column('text', { nullable: true })\r\n description: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n image: string | null;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column('jsonb', { nullable: true })\r\n variants: Array<Record<string, unknown>> | null;\r\n\r\n @Column('boolean', { default: true })\r\n active: boolean;\r\n\r\n @Column('int', { default: 0 })\r\n sortOrder: number;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n seoId: number | null;\r\n\r\n @ManyToOne(() => Vendor, { onDelete: 'RESTRICT' })\r\n @JoinColumn({ name: 'vendorId' })\r\n vendor: Vendor;\r\n\r\n @ManyToOne(() => Seo, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'seoId' })\r\n seo: Seo | null;\r\n\r\n @ManyToOne(() => ProductCategory, (c) => c.collections, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'categoryId' })\r\n category: ProductCategory | null;\r\n\r\n @ManyToOne(() => Brand, (b) => b.collections, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'brandId' })\r\n brand: Brand | null;\r\n\r\n @OneToMany('Product', 'collection')\r\n products: Product[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, JoinColumn, Unique } from 'typeorm';\r\nimport { Seo } from './seo.entity';\r\nimport { Vendor } from './vendor.entity';\r\nimport type { Product } from './product.entity';\r\nimport type { Collection } from './collection.entity';\r\n\r\n@Entity('brands')\r\n@Unique('UQ_brands_vendor_slug', ['vendorId', 'slug'])\r\nexport class Brand {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n vendorId: number;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n @Column('varchar')\r\n slug: string;\r\n\r\n @Column('varchar', { nullable: true })\r\n logo: string | null;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column('text', { nullable: true })\r\n description: string | null;\r\n\r\n @Column('boolean', { default: true })\r\n active: boolean;\r\n\r\n @Column('int', { default: 0 })\r\n sortOrder: number;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n seoId: number | null;\r\n\r\n @ManyToOne(() => Vendor, { onDelete: 'RESTRICT' })\r\n @JoinColumn({ name: 'vendorId' })\r\n vendor: Vendor;\r\n\r\n @ManyToOne(() => Seo, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'seoId' })\r\n seo: Seo | null;\r\n\r\n @OneToMany('Product', 'brand')\r\n products: Product[];\r\n\r\n @OneToMany('Collection', 'brand')\r\n collections: Collection[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany, JoinColumn, Unique } from 'typeorm';\r\nimport { Collection } from './collection.entity';\r\nimport { Brand } from './brand.entity';\r\nimport { ProductCategory } from './product-category.entity';\r\nimport { Seo } from './seo.entity';\r\nimport { Vendor } from './vendor.entity';\r\nimport type { ProductAttribute } from './product-attribute.entity';\r\nimport type { ProductTax } from './product-tax.entity';\r\n\r\n@Entity('products')\r\n@Unique('UQ_products_vendor_slug', ['vendorId', 'slug'])\r\nexport class Product {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n vendorId: number;\r\n\r\n @Column('int', { nullable: true })\r\n collectionId: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n brandId: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n categoryId: number | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n sku: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n hsn: string | null;\r\n\r\n /** Unit of measure, e.g. pcs, kg, hrs */\r\n @Column('varchar', { nullable: true })\r\n uom: string | null;\r\n\r\n @Column('varchar', { default: 'product' })\r\n type: 'product' | 'service';\r\n\r\n @Column('varchar', { nullable: true })\r\n slug: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n name: string | null;\r\n\r\n @Column('decimal', { precision: 12, scale: 2 })\r\n price: number;\r\n\r\n @Column('decimal', { precision: 12, scale: 2, nullable: true })\r\n compareAtPrice: number | null;\r\n\r\n @Column('int', { default: 0 })\r\n quantity: number;\r\n\r\n @Column('varchar', { default: 'draft' })\r\n status: 'draft' | 'available' | 'reserved' | 'sold';\r\n\r\n @Column('boolean', { default: false })\r\n featured: boolean;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n seoId: number | null;\r\n\r\n @ManyToOne(() => Vendor, { onDelete: 'RESTRICT' })\r\n @JoinColumn({ name: 'vendorId' })\r\n vendor: Vendor;\r\n\r\n @ManyToOne(() => Seo, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'seoId' })\r\n seo: Seo | null;\r\n\r\n @ManyToOne(() => Collection, (c) => c.products, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'collectionId' })\r\n collection: Collection | null;\r\n\r\n @ManyToOne(() => Brand, (b) => b.products, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'brandId' })\r\n brand: Brand | null;\r\n\r\n @ManyToOne(() => ProductCategory, (c) => c.products, { onDelete: 'SET NULL' })\r\n @JoinColumn({ name: 'categoryId' })\r\n category: ProductCategory | null;\r\n\r\n @OneToMany('ProductAttribute', 'product')\r\n attributes: ProductAttribute[];\r\n\r\n @OneToMany('ProductTax', 'product')\r\n taxes: ProductTax[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Unique } from 'typeorm';\r\nimport { Vendor } from './vendor.entity';\r\n\r\n@Entity('attributes')\r\n@Unique('UQ_attributes_vendor_slug', ['vendorId', 'slug'])\r\nexport class Attribute {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n vendorId: number;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n @Column('varchar')\r\n slug: string;\r\n\r\n @Column('varchar', { default: 'text' })\r\n type: 'text' | 'number' | 'select' | 'boolean';\r\n\r\n @Column('jsonb', { nullable: true })\r\n options: string[] | null;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column('boolean', { default: true })\r\n active: boolean;\r\n\r\n @Column('int', { default: 0 })\r\n sortOrder: number;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @ManyToOne(() => Vendor, { onDelete: 'RESTRICT' })\r\n @JoinColumn({ name: 'vendorId' })\r\n vendor: Vendor;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { Product } from './product.entity';\r\nimport { Attribute } from './attribute.entity';\r\n\r\n@Entity('product_attributes')\r\nexport class ProductAttribute {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n productId: number;\r\n\r\n @Column('int')\r\n attributeId: number;\r\n\r\n @Column('varchar')\r\n value: string;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @ManyToOne(() => Product, (p) => p.attributes, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'productId' })\r\n product: Product;\r\n\r\n @ManyToOne(() => Attribute, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'attributeId' })\r\n attribute: Attribute;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Unique } from 'typeorm';\r\nimport { Vendor } from './vendor.entity';\r\n\r\n@Entity('taxes')\r\n@Unique('UQ_taxes_vendor_slug', ['vendorId', 'slug'])\r\nexport class Tax {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n vendorId: number;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n @Column('varchar')\r\n slug: string;\r\n\r\n @Column('decimal', { precision: 5, scale: 2 })\r\n rate: number;\r\n\r\n @Column('boolean', { default: false })\r\n isDefault: boolean;\r\n\r\n @Column('text', { nullable: true })\r\n description: string | null;\r\n\r\n @Column('boolean', { default: true })\r\n active: boolean;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n deletedAt: Date | null;\r\n\r\n @Column('boolean', { default: false })\r\n deleted: boolean;\r\n\r\n @Column('int', { nullable: true })\r\n createdBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n updatedBy: number | null;\r\n\r\n @Column('int', { nullable: true })\r\n deletedBy: number | null;\r\n\r\n @ManyToOne(() => Vendor, { onDelete: 'RESTRICT' })\r\n @JoinColumn({ name: 'vendorId' })\r\n vendor: Vendor;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { Product } from './product.entity';\r\nimport { Tax } from './tax.entity';\r\n\r\n@Entity('product_taxes')\r\nexport class ProductTax {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n productId: number;\r\n\r\n @Column('int')\r\n taxId: number;\r\n\r\n @Column('decimal', { precision: 5, scale: 2, nullable: true })\r\n rate: number | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @ManyToOne(() => Product, (p) => p.taxes, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'productId' })\r\n product: Product;\r\n\r\n @ManyToOne(() => Tax, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'taxId' })\r\n tax: Tax;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { Order } from './order.entity';\r\nimport { Product } from './product.entity';\r\n\r\n@Entity('order_items')\r\nexport class OrderItem {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n orderId: number;\r\n\r\n @Column('int')\r\n productId: number;\r\n\r\n @Column({ type: 'int', array: true, nullable: true, default: () => 'ARRAY[]::INTEGER[]' })\r\n discountIds: number[]; \r\n\r\n @Column('int', { default: 1 })\r\n quantity: number;\r\n\r\n @Column({ type:\"decimal\", precision: 10, scale: 2, transformer: { to: (value:number) => value, from: (value:string) => parseFloat(value) } })\r\n unitPrice: number;\r\n\r\n @Column({ type:\"decimal\", precision: 10, scale: 2, transformer: { to: (value:number) => value, from: (value:string) => parseFloat(value) } })\r\n subTotal: number;\r\n\r\n @Column({ type: \"decimal\", precision: 10, scale: 2, transformer: { to: (value:number) => value, from: (value:string) => parseFloat(value) } })\r\n discount: number;\r\n\r\n @Column({ type: \"decimal\", precision: 10, scale: 2, transformer: { to: (value:number) => value, from: (value:string) => parseFloat(value) } })\r\n discountedAmount: number;\r\n\r\n @Column('decimal', { precision: 12, scale: 2, default: 0 })\r\n tax: number;\r\n\r\n @Column('decimal', { precision: 12, scale: 2 })\r\n total: number;\r\n\r\n /** Snapshot at order time */\r\n @Column('varchar', { nullable: true })\r\n hsn: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n uom: string | null;\r\n\r\n @Column('varchar', { nullable: true })\r\n productType: string | null;\r\n\r\n @Column('decimal', { precision: 5, scale: 2, nullable: true })\r\n taxRate: number | null;\r\n\r\n /** Tax slug snapshot (from taxes.slug) */\r\n @Column('varchar', { nullable: true })\r\n taxCode: string | null;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @ManyToOne(() => Order, (o) => o.items, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'orderId' })\r\n order: Order;\r\n\r\n @ManyToOne(() => Product, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'productId' })\r\n product: Product;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';\r\nimport { KnowledgeBaseChunk } from './knowledge-base-chunk.entity';\r\n\r\n@Entity('knowledge_base_documents')\r\nexport class KnowledgeBaseDocument {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar')\r\n name: string;\r\n\r\n @Column('varchar', { nullable: true })\r\n sourceUrl: string | null;\r\n\r\n @Column('text')\r\n content: string;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @OneToMany(() => KnowledgeBaseChunk, (c) => c.document)\r\n chunks: KnowledgeBaseChunk[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { KnowledgeBaseDocument } from './knowledge-base-document.entity';\r\n\r\n@Entity('knowledge_base_chunks')\r\nexport class KnowledgeBaseChunk {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n documentId: number;\r\n\r\n @Column('text')\r\n content: string;\r\n\r\n @Column('int', { default: 0 })\r\n chunkIndex: number;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @ManyToOne(() => KnowledgeBaseDocument, (d) => d.chunks, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'documentId' })\r\n document: KnowledgeBaseDocument;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany, JoinColumn } from 'typeorm';\r\nimport { Contact } from './contact.entity';\r\nimport type { CartItem } from './cart-item.entity';\r\n\r\n@Entity('carts')\r\nexport class Cart {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar', { nullable: true })\r\n guestToken: string | null;\r\n\r\n @Column('int', { nullable: true })\r\n contactId: number | null;\r\n\r\n @Column('varchar', { default: 'INR' })\r\n currency: string;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n expiresAt: Date | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @ManyToOne(() => Contact, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'contactId' })\r\n contact: Contact | null;\r\n\r\n @OneToMany('CartItem', 'cart')\r\n items: CartItem[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { Cart } from './cart.entity';\r\nimport { Product } from './product.entity';\r\n\r\n@Entity('cart_items')\r\nexport class CartItem {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n cartId: number;\r\n\r\n @Column('int')\r\n productId: number;\r\n\r\n @Column('int', { default: 1 })\r\n quantity: number;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @ManyToOne(() => Cart, (c) => c.items, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'cartId' })\r\n cart: Cart;\r\n\r\n @ManyToOne(() => Product, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'productId' })\r\n product: Product;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany, JoinColumn } from 'typeorm';\r\nimport { Contact } from './contact.entity';\r\nimport type { WishlistItem } from './wishlist-item.entity';\r\n\r\n@Entity('wishlists')\r\nexport class Wishlist {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('varchar', { nullable: true })\r\n guestId: string | null;\r\n\r\n @Column('int', { nullable: true })\r\n contactId: number | null;\r\n\r\n @Column('varchar', { default: 'default' })\r\n name: string;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @ManyToOne(() => Contact, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'contactId' })\r\n contact: Contact | null;\r\n\r\n @OneToMany('WishlistItem', 'wishlist')\r\n items: WishlistItem[];\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';\r\nimport { Wishlist } from './wishlist.entity';\r\nimport { Product } from './product.entity';\r\n\r\n@Entity('wishlist_items')\r\nexport class WishlistItem {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n wishlistId: number;\r\n\r\n @Column('int')\r\n productId: number;\r\n\r\n @Column('jsonb', { nullable: true })\r\n metadata: Record<string, unknown> | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @ManyToOne(() => Wishlist, (w) => w.items, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'wishlistId' })\r\n wishlist: Wishlist;\r\n\r\n @ManyToOne(() => Product, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'productId' })\r\n product: Product;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Index, Unique } from 'typeorm';\r\nimport { LlmAgent } from './llm-agent.entity';\r\nimport { KnowledgeBaseDocument } from './knowledge-base-document.entity';\r\n\r\n@Entity('llm_agent_knowledge_documents')\r\n@Unique('UQ_llm_agent_knowledge_agent_document', ['agentId', 'documentId'])\r\n@Index('IDX_llm_agent_knowledge_agent', ['agentId'])\r\nexport class LlmAgentKnowledgeDocument {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n agentId: number;\r\n\r\n @Column('int')\r\n documentId: number;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @ManyToOne(() => LlmAgent, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'agentId' })\r\n agent: LlmAgent;\r\n\r\n @ManyToOne(() => KnowledgeBaseDocument, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'documentId' })\r\n document: KnowledgeBaseDocument;\r\n}\r\n","import { Entity, Column, PrimaryGeneratedColumn } from \"typeorm\";\r\n\r\n@Entity(\"currency\")\r\nexport class Currency {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column({ type: 'varchar', unique: true })\r\n code: string; \r\n\r\n @Column({ type: 'varchar' })\r\n name: string; \r\n\r\n @Column({ type: 'varchar' })\r\n symbol: string; \r\n\r\n @Column({ type: \"boolean\", default: true })\r\n isActive: boolean;\r\n\r\n @Column({ type: \"boolean\", default: false })\r\n isBaseCurrency: boolean;\r\n}","import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';\r\n\r\n@Entity(\"currency_exchange\")\r\nexport class CurrencyExchange {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column({ type: \"varchar\" })\r\n fromCurrency: string; \r\n\r\n @Column({ type: \"varchar\" })\r\n toCurrency: string; \r\n\r\n @Column(\"decimal\", { precision: 12, scale: 6, transformer: { to: (value: number) => value, from: (value: string) => parseFloat(value) }})\r\n rate: number; \r\n}","import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, JoinColumn } from \"typeorm\";\r\nimport { DiscountRules } from \"./discount_rules.entity\";\r\nimport { Vendor } from \"./vendor.entity\";\r\n\r\nexport enum DiscountType {\r\n PERCENTAGE = \"PERCENTAGE\",\r\n FLAT = \"FLAT\",\r\n}\r\n\r\nexport enum DiscountStatus {\r\n ACTIVE = \"ACTIVE\",\r\n INACTIVE = \"INACTIVE\",\r\n EXPIRED = \"EXPIRED\",\r\n}\r\n\r\n@Entity('discounts')\r\nexport class Discount {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n vendorId: number;\r\n\r\n @ManyToOne(() => Vendor, { onDelete: 'RESTRICT' })\r\n @JoinColumn({ name: 'vendorId' })\r\n vendor: Vendor;\r\n\r\n @Column({ type: 'varchar' })\r\n name: string;\r\n\r\n @Column({ type: 'varchar', nullable: true })\r\n couponCode: string;\r\n\r\n @Column({ type: 'varchar', nullable: true })\r\n description?: string;\r\n\r\n @Column({ type: 'enum', enum: DiscountType, })\r\n discountType: DiscountType;\r\n\r\n @Column({ type: 'decimal', precision: 10, scale: 2, transformer: { to: (value:number) => value, from: (value:string) => parseFloat(value) } })\r\n value: number; \r\n\r\n @Column({ type: 'decimal', precision: 10, scale: 2, transformer: { to: (value:number) => value, from: (value:string) => parseFloat(value) } })\r\n maxDiscountAmount?: number;\r\n\r\n @Column({ type: 'int', nullable: true })\r\n maxTotalUsage?: number;\r\n\r\n @Column({ type: 'int', nullable: true })\r\n maxUsagePerUser?: number;\r\n\r\n @Column({ type: 'int', default: 0 })\r\n usedCount: number;\r\n\r\n @Column({ type: 'timestamp' })\r\n validFrom: Date;\r\n\r\n @Column({ type: 'timestamp' })\r\n validUntil: Date;\r\n\r\n @Column({ type: 'enum', enum: DiscountStatus, default: DiscountStatus.ACTIVE })\r\n status: DiscountStatus;\r\n\r\n @Column({ type: 'boolean' })\r\n canCombineWithOtherDiscounts: boolean;\r\n\r\n @Column({ type:'boolean', default: false })\r\n isAutomatic: boolean;\r\n\r\n @Column({ type:'varchar', default: 'INR' })\r\n currency: string;\r\n\r\n @OneToMany(() => DiscountRules, (rule) => rule.discount, {\r\n cascade: true,\r\n })\r\n rules: DiscountRules[];\r\n}","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, OneToMany } from \"typeorm\";\r\nimport { Discount } from \"./discount.entity\";\r\n\r\nexport enum Type{\r\n MIN_AMOUNT = \"minAmount\",\r\n USER = \"user\",\r\n PRODUCT = \"product\",\r\n CATEGORY = \"category\",\r\n CART = \"cart\",\r\n PAYMENT_METHOD = \"paymentMethod\",\r\n ORDER = \"order\",\r\n QUANTITY = \"quantity\",\r\n TIME = \"time\",\r\n SHIPPING = \"shipping\",\r\n REFERRAL = \"referral\",\r\n REWARD = \"reward\",\r\n}\r\n\r\nexport enum SubType{\r\n USER_TYPE = \"userType\",\r\n USER_ID = \"userId\",\r\n PRODUCT_ID = \"productId\",\r\n CATEGORY_ID = \"categoryId\",\r\n CART_ID = \"cartId\",\r\n ORDER_ID = \"orderId\",\r\n FIRST_ORDER = \"firstOrder\",\r\n NTH_ORDER = \"nthOrder\",\r\n DATE_RANGE = \"dateRange\",\r\n DAY_OF_WEEK = \"dayOfWeek\",\r\n TIME_RANGE = \"timeRange\" \r\n}\r\n\r\nexport enum ConditionType{\r\n GROUP = \"group\",\r\n RULE = \"rule\"\r\n}\r\n\r\nexport enum ConditionOperator{\r\n AND = \"and\",\r\n OR = \"or\"\r\n}\r\n\r\nexport enum ComparisonOperator{\r\n EQ = \"eq\",\r\n NEQ = \"neq\",\r\n GT = \"gt\",\r\n GTE = \"gte\",\r\n LT = \"lt\",\r\n LTE = \"lte\",\r\n IN = \"in\",\r\n NOT_IN = \"notIn\",\r\n BETWEEN = \"between\",\r\n}\r\n\r\n@Entity(\"discount_rules\")\r\nexport class DiscountRules {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @ManyToOne(() => Discount, (discount) => discount.rules, { onDelete: \"CASCADE\" })\r\n @JoinColumn({ name: \"discountId\" })\r\n discount: Discount;\r\n\r\n @Column({ type: 'int' })\r\n discountId: number;\r\n\r\n @ManyToOne(() => DiscountRules, (rule) => rule.children, { nullable: true, onDelete: \"CASCADE\" })\r\n @JoinColumn({ name: \"parentId\" })\r\n parent?: DiscountRules;\r\n\r\n @OneToMany(() => DiscountRules, (rule) => rule.parent)\r\n children: DiscountRules[];\r\n\r\n @Column({ type: 'int', nullable: true })\r\n parentId?: number;\r\n \r\n @Column({ type: \"enum\", enum: ConditionType })\r\n conditionType: ConditionType;\r\n\r\n @Column({ type: \"enum\", enum: ConditionOperator, nullable: true })\r\n conditionOperator?: ConditionOperator;\r\n\r\n @Column({ type: \"enum\", enum: Type, nullable: true })\r\n type?: Type;\r\n\r\n @Column({ type:\"enum\", enum: SubType, nullable: true })\r\n subType?: SubType;\r\n\r\n @Column({ type:\"enum\", enum: ComparisonOperator, nullable: true })\r\n comparisonOperator?: ComparisonOperator;\r\n\r\n @Column({ type: \"jsonb\" })\r\n value: Record<string, any>;\r\n}","import { Column, Entity, PrimaryGeneratedColumn, ManyToOne, JoinColumn } from \"typeorm\";\r\nimport { Discount } from \"./discount.entity\";\r\nimport { Order } from \"./order.entity\";\r\nimport { OrderItem } from \"./order-item.entity\";\r\n\r\n@Entity(\"order_discounts\")\r\nexport class OrderDiscounts{\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @ManyToOne(() => Order, (o) => o.items, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'orderId' })\r\n order: Order;\r\n\r\n @Column({ type: 'int' })\r\n orderId: number;\r\n\r\n @ManyToOne(() => OrderItem, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'orderItemId' })\r\n orderItem: OrderItem;\r\n\r\n @Column({ type: 'int' })\r\n orderItemId: number;\r\n\r\n @Column({ type: 'int' })\r\n userId: number;\r\n\r\n @ManyToOne(() => Discount, { onDelete: \"CASCADE\" })\r\n @JoinColumn({ name: \"discountId\" })\r\n discount?: Discount;\r\n\r\n @Column({ type: 'int' })\r\n discountId: number;\r\n \r\n @Column({ type: 'varchar' })\r\n discountCode: string;\r\n\r\n @Column({ type: \"decimal\", precision: 10, scale: 2, transformer: { to: (value:number) => value, from: (value:string) => parseFloat(value) } })\r\n discountAmount: number;\r\n\r\n @Column({ type: \"jsonb\", nullable: true })\r\n metaData?: Record<string, any>\r\n}","import {\r\n Entity,\r\n PrimaryGeneratedColumn,\r\n Column,\r\n CreateDateColumn,\r\n UpdateDateColumn,\r\n OneToMany,\r\n} from 'typeorm';\r\nimport { RssArticle } from './rss-article.entity';\r\n\r\n@Entity('rss_feeds')\r\nexport class RssFeed {\r\n @PrimaryGeneratedColumn('uuid')\r\n id: string;\r\n\r\n @Column({ type: 'text' })\r\n name: string;\r\n\r\n @Column({ type: 'text', unique: true })\r\n rssUrl: string;\r\n\r\n @Column({ type: 'text', nullable: true })\r\n websiteUrl: string | null;\r\n\r\n @Column({ type: 'boolean', default: true })\r\n isActive: boolean;\r\n\r\n @Column({ type: 'int', default: 60 })\r\n fetchFrequencyMinutes: number;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n lastFetchedAt: Date | null;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n lastArticleDate: Date | null;\r\n\r\n @OneToMany(() => RssArticle, (article) => article.rssFeed)\r\n articles: RssArticle[];\r\n\r\n @CreateDateColumn()\r\n createdAt: Date;\r\n\r\n @UpdateDateColumn()\r\n updatedAt: Date;\r\n}\r\n","import {\r\n Entity,\r\n PrimaryGeneratedColumn,\r\n Column,\r\n ManyToOne,\r\n JoinColumn,\r\n CreateDateColumn,\r\n Unique,\r\n} from 'typeorm';\r\nimport { RssFeed } from './rss-feed.entity';\r\n\r\n@Entity('rss_articles')\r\n@Unique('UQ_rss_articles_feed_article_url', ['rssFeedId', 'articleUrl'])\r\nexport class RssArticle {\r\n @PrimaryGeneratedColumn('uuid')\r\n id: string;\r\n\r\n @Column('uuid')\r\n rssFeedId: string;\r\n\r\n @ManyToOne(() => RssFeed, (f) => f.articles, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'rssFeedId' })\r\n rssFeed: RssFeed;\r\n\r\n @Column({ type: 'text', nullable: true })\r\n externalId: string | null;\r\n\r\n @Column({ type: 'text' })\r\n title: string;\r\n\r\n @Column({ type: 'text' })\r\n articleUrl: string;\r\n\r\n @Column({ type: 'text', nullable: true })\r\n summary: string | null;\r\n\r\n @Column({ type: 'text', nullable: true })\r\n content: string | null;\r\n\r\n @Column({ type: 'text', nullable: true })\r\n author: string | null;\r\n\r\n @Column({ type: 'timestamp', nullable: true })\r\n publishedAt: Date | null;\r\n\r\n @Column({ type: 'text', nullable: true })\r\n imageUrl: string | null;\r\n\r\n @Column({ type: 'jsonb', nullable: true })\r\n rawData: Record<string, unknown> | null;\r\n\r\n @Column({ type: 'text', nullable: true })\r\n contentHash: string | null;\r\n\r\n @Column({ type: 'boolean', default: false })\r\n isProcessed: boolean;\r\n\r\n @CreateDateColumn()\r\n createdAt: Date;\r\n}\r\n","import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Unique, Index } from 'typeorm';\r\nimport { Vendor } from './vendor.entity';\r\nimport { User } from './user.entity';\r\n\r\n/** Links a staff user to a vendor store. */\r\nexport type VendorUserRole = 'owner' | 'staff';\r\n\r\n@Entity('vendor_users')\r\n@Unique('UQ_vendor_users_vendor_user', ['vendorId', 'userId'])\r\n@Index('IDX_vendor_users_vendor', ['vendorId'])\r\n@Index('IDX_vendor_users_user', ['userId'])\r\nexport class VendorUser {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n vendorId: number;\r\n\r\n @Column('int')\r\n userId: number;\r\n\r\n @Column('varchar', { default: 'staff' })\r\n role: VendorUserRole;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @ManyToOne(() => Vendor, (v) => v.vendorUsers, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'vendorId' })\r\n vendor: Vendor;\r\n\r\n @ManyToOne(() => User, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'userId' })\r\n user: User;\r\n}\r\n","import {\r\n Entity,\r\n PrimaryGeneratedColumn,\r\n Column,\r\n ManyToOne,\r\n JoinColumn,\r\n Index,\r\n} from 'typeorm';\r\nimport { Vendor } from './vendor.entity';\r\nimport { Contact } from './contact.entity';\r\nimport { Customer } from './customer.entity';\r\n\r\n/** Links a contact (customer) to a vendor store. One contact can belong to multiple vendors. */\r\n@Entity('vendor_customers')\r\n@Index('IDX_vendor_customers_vendor', ['vendorId'])\r\n@Index('IDX_vendor_customers_contact', ['contactId'])\r\nexport class VendorCustomer {\r\n @PrimaryGeneratedColumn()\r\n id: number;\r\n\r\n @Column('int')\r\n vendorId: number;\r\n\r\n @Column('int', { nullable: true })\r\n contactId: number | null;\r\n\r\n @Column('int')\r\n customerId: number;\r\n\r\n /** Optional vendor-specific notes about this customer. */\r\n @Column('text', { nullable: true })\r\n notes: string | null;\r\n\r\n /** Optional vendor-specific tags/labels. */\r\n @Column('simple-array', { nullable: true })\r\n tags: string[] | null;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n createdAt: Date;\r\n\r\n @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })\r\n updatedAt: Date;\r\n\r\n @ManyToOne(() => Vendor, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'vendorId' })\r\n vendor: Vendor;\r\n\r\n @ManyToOne(() => Contact, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'contactId' })\r\n contact: Contact | null;\r\n\r\n @ManyToOne(() => Customer, { onDelete: 'CASCADE' })\r\n @JoinColumn({ name: 'customerId' })\r\n customer: Customer\r\n}\r\n","import type { EntityTarget } from 'typeorm';\r\nimport { User } from './user.entity';\r\nimport { OtpChallenge } from './otp-challenge.entity';\r\nimport { PasswordResetToken } from './password-reset-token.entity';\r\nimport { UserGroup } from './user-group.entity';\r\nimport { Permission } from './permission.entity';\r\nimport { Blog } from './blog.entity';\r\nimport { Tag } from './tag.entity';\r\nimport { Category } from './category.entity';\r\nimport { Comment } from './comment.entity';\r\nimport { Contact } from './contact.entity';\r\nimport { Address } from './address.entity';\r\nimport { Form } from './form.entity';\r\nimport { FormField } from './form-field.entity';\r\nimport { FormSubmission } from './form-submission.entity';\r\nimport { Seo } from './seo.entity';\r\nimport { Config } from './config.entity';\r\nimport { MessageTemplate } from './message-template.entity';\r\nimport { Media } from './media.entity';\r\nimport { Page } from './page.entity';\r\nimport { ProductCategory } from './product-category.entity';\r\nimport { Collection } from './collection.entity';\r\nimport { Product } from './product.entity';\r\nimport { Attribute } from './attribute.entity';\r\nimport { ProductAttribute } from './product-attribute.entity';\r\nimport { Tax } from './tax.entity';\r\nimport { ProductTax } from './product-tax.entity';\r\nimport { Order } from './order.entity';\r\nimport { OrderItem } from './order-item.entity';\r\nimport { Payment } from './payment.entity';\r\nimport { Brand } from './brand.entity';\r\nimport { KnowledgeBaseDocument } from './knowledge-base-document.entity';\r\nimport { KnowledgeBaseChunk } from './knowledge-base-chunk.entity';\r\nimport { ChatConversation } from './chat-conversation.entity';\r\nimport { ChatMessage } from './chat-message.entity';\r\nimport { Cart } from './cart.entity';\r\nimport { CartItem } from './cart-item.entity';\r\nimport { Wishlist } from './wishlist.entity';\r\nimport { WishlistItem } from './wishlist-item.entity';\r\nimport { LlmAgent, llmAgentToChatAgentOptions } from './llm-agent.entity';\r\nimport { LlmAgentKnowledgeDocument } from './llm-agent-knowledge-document.entity';\r\nimport { Currency } from './currency.entity';\r\nimport { CurrencyExchange } from './currency_exchange.entity';\r\nimport { Discount } from \"./discount.entity\";\r\nimport { DiscountRules } from './discount_rules.entity';\r\nimport { OrderDiscounts } from './order_discounts.entity';\r\nimport { OrderAddresses } from './order_addresses.entity';\r\nimport { RssFeed } from './rss-feed.entity';\r\nimport { RssArticle } from './rss-article.entity';\r\nimport { JobSchedule } from './job-schedule.entity';\r\nimport { JobScheduleRun } from './job-schedule-run.entity';\r\nimport { Vendor } from './vendor.entity';\r\nimport { VendorUser } from './vendor-user.entity';\r\nimport { VendorCustomer } from './vendor-customer.entity';\r\nimport { Customer } from './customer.entity';\r\nimport { Customer_Contacts } from './customer_contacts.entity';\r\n\r\nexport {\r\n User,\r\n OtpChallenge,\r\n PasswordResetToken,\r\n UserGroup,\r\n Permission,\r\n Blog,\r\n Tag,\r\n Category,\r\n Comment,\r\n Contact,\r\n Address,\r\n Form,\r\n FormField,\r\n FormSubmission,\r\n Seo,\r\n Config,\r\n MessageTemplate,\r\n Media,\r\n Page,\r\n ProductCategory,\r\n Collection,\r\n Product,\r\n Attribute,\r\n ProductAttribute,\r\n Tax,\r\n ProductTax,\r\n Order,\r\n OrderItem,\r\n Payment,\r\n Brand,\r\n KnowledgeBaseDocument,\r\n KnowledgeBaseChunk,\r\n ChatConversation,\r\n ChatMessage,\r\n Cart,\r\n CartItem,\r\n Wishlist,\r\n WishlistItem,\r\n LlmAgent,\r\n llmAgentToChatAgentOptions,\r\n Currency,\r\n CurrencyExchange,\r\n Discount,\r\n DiscountRules,\r\n OrderDiscounts,\r\n OrderAddresses,\r\n RssFeed,\r\n RssArticle,\r\n JobSchedule,\r\n JobScheduleRun,\r\n Vendor,\r\n VendorUser,\r\n VendorCustomer,\r\n Customer,\r\n Customer_Contacts,\r\n};\r\n\r\n/** Map API resource segment (e.g. \"blogs\", \"form_submissions\") to entity. Used by CRUD handler. */\r\nexport const CMS_ENTITY_MAP: Record<string, EntityTarget<import('typeorm').ObjectLiteral>> = {\r\n users: User,\r\n otp_challenges: OtpChallenge,\r\n password_reset_tokens: PasswordResetToken,\r\n user_groups: UserGroup,\r\n permissions: Permission,\r\n blogs: Blog,\r\n tags: Tag,\r\n categories: Category,\r\n comments: Comment,\r\n contacts: Contact,\r\n addresses: Address,\r\n forms: Form,\r\n form_fields: FormField,\r\n form_submissions: FormSubmission,\r\n seos: Seo,\r\n configs: Config,\r\n message_templates: MessageTemplate,\r\n media: Media,\r\n pages: Page,\r\n product_categories: ProductCategory,\r\n collections: Collection,\r\n products: Product,\r\n attributes: Attribute,\r\n product_attributes: ProductAttribute,\r\n taxes: Tax,\r\n product_taxes: ProductTax,\r\n orders: Order,\r\n order_items: OrderItem,\r\n payments: Payment,\r\n brands: Brand,\r\n knowledge_base_documents: KnowledgeBaseDocument,\r\n knowledge_base_chunks: KnowledgeBaseChunk,\r\n chat_conversations: ChatConversation,\r\n chat_messages: ChatMessage,\r\n carts: Cart,\r\n cart_items: CartItem,\r\n wishlists: Wishlist,\r\n wishlist_items: WishlistItem,\r\n llm_agents: LlmAgent,\r\n llm_agent_knowledge_documents: LlmAgentKnowledgeDocument,\r\n currency: Currency,\r\n currency_exchange: CurrencyExchange,\r\n discounts: Discount,\r\n discount_rules: DiscountRules,\r\n order_discounts: OrderDiscounts,\r\n order_addresses: OrderAddresses,\r\n rss_feeds: RssFeed,\r\n rss_articles: RssArticle,\r\n job_schedules: JobSchedule,\r\n job_schedule_runs: JobScheduleRun,\r\n vendors: Vendor,\r\n vendor_users: VendorUser,\r\n vendor_customers: VendorCustomer,\r\n customer: Customer,\r\n customer_contacts: Customer_Contacts,\r\n};\r\n","import type { EntityCrudAction, EntityPermissionFlags } from './permission-entities';\r\nimport { explainSessionEntityAccess, logRbac } from './rbac-debug';\r\nimport { isVendorPortalUser } from './vendor-scope';\r\n\r\n/**\r\n * @deprecated Administrator bypass is now full entity access via `isRBACAdmin` in `sessionHasEntityAccess`.\r\n * Kept for backwards-compatible imports.\r\n */\r\nexport const RBAC_ADMIN_ONLY_ENTITIES = new Set(['users', 'user_groups', 'permissions']);\r\n\r\nexport interface SessionUser {\r\n id?: string;\r\n email?: string | null;\r\n name?: string | null;\r\n groupId?: number;\r\n /** User group display name (from login). */\r\n groupName?: string | null;\r\n /** @deprecated use entityPerms / isRBACAdmin */\r\n permissions?: string[];\r\n /** Administrator group: bypasses entity-level RBAC on all resources */\r\n isRBACAdmin?: boolean;\r\n entityPerms?: Record<string, EntityPermissionFlags>;\r\n /** When false and not isRBACAdmin, admin API/UI is denied. */\r\n adminAccess?: boolean;\r\n /** Vendor stores this user can access (from vendor_users). */\r\n vendorIds?: number[];\r\n /** Active vendor for scoped CRUD (vendor staff). */\r\n activeVendorId?: number | null;\r\n /** Role for the active vendor link (`vendor_users.role`). */\r\n vendorRole?: 'owner' | 'staff' | null;\r\n /** Set at login: vendor store portal (not platform admin). */\r\n isVendorPortal?: boolean;\r\n /** Set at login: vendor store owner (team + permissions). */\r\n isVendorOwner?: boolean;\r\n}\r\n\r\nexport function sessionHasEntityAccess(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): boolean {\r\n return explainSessionEntityAccess(user, entity, action).allowed;\r\n}\r\n\r\nexport function canManageRoles(user: SessionUser | null | undefined): boolean {\r\n return !!(user?.email && user.isRBACAdmin);\r\n}\r\n\r\nexport type GetSession = () => Promise<{ user?: SessionUser } | null>;\r\n\r\nexport const OPEN_ENDPOINTS: Array<Record<string, string[]>> = [\r\n { '/api/contacts': ['POST'] },\r\n { '/api/form-submissions': ['POST'] },\r\n { '/api/blogs': ['GET'] },\r\n];\r\n\r\nexport const PERMISSION_REQUIRED_ENDPOINTS: Record<string, string[]> = {};\r\n\r\nexport function isOpenEndpoint(pathname: string): boolean {\r\n return OPEN_ENDPOINTS.some((endpoint) => pathname.startsWith(Object.keys(endpoint)[0]));\r\n}\r\n\r\nexport function getRequiredPermission(pathname: string): string[] | null {\r\n return null;\r\n}\r\n\r\nexport function isPublicMethod(pathname: string, method: string): boolean {\r\n for (const endpoint of OPEN_ENDPOINTS) {\r\n const key = Object.keys(endpoint)[0];\r\n if (pathname.startsWith(key) && endpoint[key].includes(method)) return true;\r\n }\r\n return false;\r\n}\r\n\r\nexport interface AuthHelpers {\r\n requireAuth(req: Request): Promise<Response | null>;\r\n requirePermission(req: Request, permission: string): Promise<Response | null>;\r\n requireEntityPermission(req: Request, entity: string, action: EntityCrudAction): Promise<Response | null>;\r\n requireAdminAccess(req: Request): Promise<Response | null>;\r\n getAuthenticatedUser(): Promise<SessionUser | null>;\r\n}\r\n\r\nexport function createAuthHelpers(getSession: GetSession, NextResponse: { json: (body: unknown, init?: { status?: number }) => Response }): AuthHelpers {\r\n return createAuthHelpersFromGetSession(getSession, NextResponse);\r\n}\r\n\r\n/** Pass return value into `createCmsApiHandler` (includes `getSessionUser` for vendor store APIs). */\r\nexport function createCmsAuthBundle(\r\n getSession: GetSession,\r\n NextResponse: { json: (body: unknown, init?: { status?: number }) => Response }\r\n) {\r\n const auth = createAuthHelpers(getSession, NextResponse);\r\n return {\r\n requireAuth: auth.requireAuth,\r\n requireAdminAccess: auth.requireAdminAccess,\r\n requireEntityPermission: auth.requireEntityPermission,\r\n getSessionUser: auth.getAuthenticatedUser,\r\n getAuthenticatedUser: auth.getAuthenticatedUser,\r\n };\r\n}\r\n\r\nfunction createAuthHelpersFromGetSession(\r\n getSession: GetSession,\r\n NextResponse: { json: (body: unknown, init?: { status?: number }) => Response }\r\n): AuthHelpers {\r\n return {\r\n async requireAuth() {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n return null;\r\n },\r\n async requirePermission() {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n return null;\r\n },\r\n async requireEntityPermission(_req: Request, entity: string, action: EntityCrudAction) {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n const u = session.user as SessionUser;\r\n const allowed = sessionHasEntityAccess(u, entity, action);\r\n const { reason } = explainSessionEntityAccess(u, entity, action);\r\n logRbac('authHelpers.requireEntityPermission', {\r\n entity,\r\n action,\r\n allowed,\r\n reason,\r\n email: u.email,\r\n groupName: u.groupName,\r\n vendorIds: u.vendorIds,\r\n isVendorPortal: u.isVendorPortal,\r\n isVendorOwner: u.isVendorOwner,\r\n });\r\n if (allowed) return null;\r\n return NextResponse.json({ error: 'Forbidden', entity, action, reason }, { status: 403 });\r\n },\r\n async requireAdminAccess() {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n const u = session.user as SessionUser;\r\n if (u.isRBACAdmin) return null;\r\n // Vendor portal users always have admin UI access for their store — check\r\n // before adminAccess so that vendor users (who have adminAccess:false from\r\n // the DB default) are not incorrectly denied.\r\n if (isVendorPortalUser(u)) return null;\r\n if (u.adminAccess === true) return null;\r\n if (u.adminAccess === false) {\r\n logRbac('requireAdminAccess denied (adminAccess:false)', {\r\n email: u.email,\r\n groupName: u.groupName,\r\n isVendorPortal: u.isVendorPortal,\r\n });\r\n return NextResponse.json({ error: 'Forbidden', reason: 'admin_access' }, { status: 403 });\r\n }\r\n logRbac('requireAdminAccess denied (no matching rule)', {\r\n email: u.email,\r\n adminAccess: u.adminAccess,\r\n groupName: u.groupName,\r\n isVendorPortal: u.isVendorPortal,\r\n });\r\n return NextResponse.json({ error: 'Forbidden', reason: 'admin_access' }, { status: 403 });\r\n },\r\n async getAuthenticatedUser() {\r\n const session = await getSession();\r\n return (session?.user as SessionUser) ?? null;\r\n },\r\n };\r\n}\r\n","export {\r\n createAuthHelpers,\r\n createCmsAuthBundle,\r\n OPEN_ENDPOINTS,\r\n PERMISSION_REQUIRED_ENDPOINTS,\r\n isOpenEndpoint,\r\n isPublicMethod,\r\n getRequiredPermission,\r\n} from './helpers';\r\nexport type { SessionUser, GetSession, AuthHelpers } from './helpers';\r\nexport { sessionHasEntityAccess, canManageRoles, RBAC_ADMIN_ONLY_ENTITIES } from './helpers';\r\nexport {\r\n isRbacDebugEnabled,\r\n logRbac,\r\n explainSessionEntityAccess,\r\n logEntityAccessDecision,\r\n summarizeEntityPerms,\r\n} from './rbac-debug';\r\nexport {\r\n isSuperAdmin,\r\n isVendorAdmin,\r\n SUPER_ADMIN_GROUP_ID,\r\n VENDOR_ADMIN_GROUP_ID,\r\n} from './role-helpers';\r\nexport {\r\n resolveVendorScopeFromSessionUser,\r\n VENDOR_SCOPED_STORE_ENTITIES,\r\n VENDOR_STORE_RBAC_ENTITIES,\r\n VENDOR_OWNER_GROUP_NAME,\r\n isVendorStaff,\r\n isVendorPortalUser,\r\n isVendorOwner,\r\n isVendorGroupName,\r\n isPlatformAdministrator,\r\n vendorPortalFlagsFromUser,\r\n canOnboardVendors,\r\n canManageVendorTeam,\r\n canManageVendorRoles,\r\n} from './vendor-scope';\r\nexport {\r\n getPermissionableEntityKeys,\r\n ADMIN_GROUP_NAME,\r\n isSuperAdminGroupName,\r\n permissionRowsToRecord,\r\n hasEntityPermission,\r\n} from './permission-entities';\r\nexport { seedAdministratorPermissions } from './seed-permissions';\r\nexport type { EntityCrudAction, EntityPermissionFlags } from './permission-entities';\r\nexport { createCmsMiddleware, defaultPublicApiMethods } from './middleware';\r\nexport type { CmsMiddlewareConfig, CmsMiddlewareRequest } from './middleware';\r\nexport {\r\n isAuthDebugEnabled,\r\n isAuthDebugClientEnabled,\r\n logAuth,\r\n logAuthClient,\r\n summarizeSessionUserForLog,\r\n nextAuthCookieDebugInfo,\r\n} from './auth-debug';\r\nexport { getNextAuthOptions, getStorefrontNextAuthOptions } from './nextauth-options';\r\nexport type { NextAuthOptionsConfig, NextAuthUser, AuthorizeOtpInput } from './nextauth-options';\r\n","import type { DataSource } from 'typeorm';\r\nimport type { EntityTarget } from 'typeorm';\r\nimport type { ObjectLiteral } from 'typeorm';\r\nimport { getPermissionableEntityKeys, ADMIN_GROUP_NAME } from './permission-entities';\r\n\r\n/**\r\n * Ensures the Administrator group has full CRUD on every permissionable entity\r\n * for the given entity map. Idempotent: upserts per entity.\r\n */\r\nexport async function seedAdministratorPermissions(\r\n dataSource: DataSource,\r\n entityMap: Record<string, unknown>\r\n): Promise<void> {\r\n const entities = getPermissionableEntityKeys(entityMap);\r\n const groupRepo = dataSource.getRepository(entityMap.user_groups as EntityTarget<ObjectLiteral>);\r\n const permRepo = dataSource.getRepository(entityMap.permissions as EntityTarget<ObjectLiteral>);\r\n\r\n const adminGroup = await groupRepo.findOne({ where: { name: ADMIN_GROUP_NAME, deleted: false } });\r\n console.log(\"ADMIN GROUP\", adminGroup);\r\n if (!adminGroup) return;\r\n\r\n const fullCrud = { canCreate: true, canRead: true, canUpdate: true, canDelete: true };\r\n\r\n for (const entity of entities) {\r\n const existing = await permRepo.findOne({\r\n where: { groupId: adminGroup.id, entity },\r\n });\r\n console.log(\"EXISTING\", existing);\r\n if (existing) {\r\n existing.canCreate = true;\r\n existing.canRead = true;\r\n existing.canUpdate = true;\r\n existing.canDelete = true;\r\n await permRepo.save(existing);\r\n } else {\r\n await permRepo.save(\r\n permRepo.create({\r\n groupId: adminGroup.id,\r\n entity,\r\n ...fullCrud,\r\n })\r\n );\r\n }\r\n }\r\n}\r\n","import { getToken } from 'next-auth/jwt';\r\nimport { logAuth } from './auth-debug';\r\n\r\nexport interface CmsMiddlewareRequest {\r\n nextUrl: { pathname: string };\r\n url: string;\r\n method: string;\r\n cookies: { get: (name: string) => { value?: string } | undefined };\r\n /**\r\n * Full Next.js request (e.g. `NextRequest`). When provided, session is resolved via\r\n * `getToken()` so chunked `next-auth.session-token.N` cookies work.\r\n */\r\n req?: Parameters<typeof getToken>[0]['req'];\r\n}\r\n\r\nexport interface CmsMiddlewareConfig {\r\n publicAdminPaths?: string[];\r\n publicApiPaths?: string[];\r\n /** path -> allowed methods */\r\n publicApiMethods?: Record<string, string[]>;\r\n signInPath?: string;\r\n /** @deprecated Prefer passing `req` on the request; used only when `req` is omitted. */\r\n getSessionToken?: (request: CmsMiddlewareRequest) => string | undefined;\r\n secret?: string;\r\n}\r\n\r\n/** Default public API paths (no auth). Sites should extend this with their own routes. */\r\nexport const defaultPublicApiMethods: Record<string, string[]> = {\r\n '/api/contacts': ['POST'],\r\n '/api/form-submissions': ['POST'],\r\n '/api/blogs': ['GET'],\r\n '/api/forms': ['GET'],\r\n '/api/auth': ['GET', 'POST'],\r\n '/api/health': ['GET'],\r\n '/api/users/forgot-password': ['POST'],\r\n '/api/users/set-password': ['POST'],\r\n '/api/users/invite': ['POST'],\r\n};\r\n\r\nfunction legacyGetSessionToken(request: CmsMiddlewareRequest): string | undefined {\r\n const secure = request.cookies.get('__Secure-next-auth.session-token')?.value;\r\n const regular = request.cookies.get('next-auth.session-token')?.value;\r\n return secure ?? regular;\r\n}\r\n\r\nfunction sessionCookiePresence(request: CmsMiddlewareRequest) {\r\n const secure = request.cookies.get('__Secure-next-auth.session-token')?.value;\r\n const regular = request.cookies.get('next-auth.session-token')?.value;\r\n const hasChunked =\r\n Boolean(request.cookies.get('next-auth.session-token.0')?.value) ||\r\n Boolean(request.cookies.get('__Secure-next-auth.session-token.0')?.value);\r\n return {\r\n hasSecureToken: Boolean(secure),\r\n hasRegularToken: Boolean(regular),\r\n hasChunkedToken: hasChunked,\r\n resolved: Boolean(secure ?? regular),\r\n };\r\n}\r\n\r\nfunction isPublicMethod(pathname: string, method: string, publicApiMethods: Record<string, string[]>): boolean {\r\n for (const [endpoint, methods] of Object.entries(publicApiMethods)) {\r\n if (pathname.startsWith(endpoint) && methods.includes(method)) return true;\r\n }\r\n return false;\r\n}\r\n\r\nasync function hasValidSession(\r\n request: CmsMiddlewareRequest,\r\n secret: string | undefined,\r\n legacyGetToken: (request: CmsMiddlewareRequest) => string | undefined\r\n): Promise<boolean> {\r\n if (request.req) {\r\n const token = await getToken({ req: request.req, secret });\r\n return token != null;\r\n }\r\n return Boolean(legacyGetToken(request));\r\n}\r\n\r\n/**\r\n * Returns middleware logic. Use from Next.js middleware:\r\n * import { createCmsMiddleware } from '@infuro/cms-core';\r\n * export async function middleware(request: NextRequest) {\r\n * const result = await cmsMiddleware({ ...request fields, req: request });\r\n * ...\r\n * }\r\n * export const config = { matcher: ['/admin/:path*', '/api/:path*'] };\r\n */\r\nexport function createCmsMiddleware(config: CmsMiddlewareConfig = {}) {\r\n const {\r\n publicAdminPaths = ['/admin/signin', '/admin/forgot-password', '/admin/reset-password', '/admin/invite'],\r\n publicApiMethods = defaultPublicApiMethods,\r\n signInPath = '/admin/signin',\r\n getSessionToken = legacyGetSessionToken,\r\n secret = process.env.NEXTAUTH_SECRET,\r\n } = config;\r\n\r\n return async function cmsMiddleware(\r\n request: CmsMiddlewareRequest\r\n ): Promise<{ type: 'next' } | { type: 'redirect'; url: string } | { type: 'json'; status: number; body: unknown }> {\r\n const pathname = request.nextUrl.pathname;\r\n const method = request.method;\r\n\r\n if (publicAdminPaths.some((p) => pathname === p || pathname.startsWith(p + '/'))) {\r\n return { type: 'next' };\r\n }\r\n\r\n if (pathname.startsWith('/admin')) {\r\n const authenticated = await hasValidSession(request, secret, getSessionToken);\r\n const cookies = sessionCookiePresence(request);\r\n if (!authenticated) {\r\n logAuth('middleware: admin redirect to signin (no session)', {\r\n pathname,\r\n method,\r\n usesGetToken: Boolean(request.req),\r\n ...cookies,\r\n expectedCookieName: process.env.NEXTAUTH_URL?.startsWith('https')\r\n ? '__Secure-next-auth.session-token'\r\n : 'next-auth.session-token',\r\n });\r\n return { type: 'redirect', url: new URL(signInPath, request.url).toString() };\r\n }\r\n logAuth('middleware: admin allowed', {\r\n pathname,\r\n method,\r\n usesGetToken: Boolean(request.req),\r\n ...cookies,\r\n });\r\n }\r\n\r\n if (pathname.startsWith('/api')) {\r\n if (isPublicMethod(pathname, method, publicApiMethods)) {\r\n return { type: 'next' };\r\n }\r\n const authenticated = await hasValidSession(request, secret, getSessionToken);\r\n if (!authenticated) {\r\n logAuth('middleware: api 401 (no session)', {\r\n pathname,\r\n method,\r\n usesGetToken: Boolean(request.req),\r\n ...sessionCookiePresence(request),\r\n });\r\n return { type: 'json', status: 401, body: { error: 'Unauthorized' } };\r\n }\r\n }\r\n\r\n return { type: 'next' };\r\n };\r\n}\r\n","const LOG_PREFIX = '[cms-auth]';\r\n\r\n/** Set `CMS_AUTH_DEBUG=false` to silence server auth logs in development. */\r\nexport function isAuthDebugEnabled(): boolean {\r\n const v = process.env.CMS_AUTH_DEBUG?.trim().toLowerCase();\r\n if (v === '1' || v === 'true' || v === 'yes') return true;\r\n if (v === '0' || v === 'false' || v === 'no') return false;\r\n return process.env.NODE_ENV === 'development';\r\n}\r\n\r\n/** Browser console logs; set `NEXT_PUBLIC_CMS_AUTH_DEBUG=false` to silence. */\r\nexport function isAuthDebugClientEnabled(): boolean {\r\n if (typeof window === 'undefined') return false;\r\n const v = process.env.NEXT_PUBLIC_CMS_AUTH_DEBUG?.trim().toLowerCase();\r\n if (v === '1' || v === 'true' || v === 'yes') return true;\r\n if (v === '0' || v === 'false' || v === 'no') return false;\r\n return process.env.NODE_ENV === 'development';\r\n}\r\n\r\nexport function logAuth(message: string, data?: Record<string, unknown>): void {\r\n if (!isAuthDebugEnabled()) return;\r\n if (data) console.info(LOG_PREFIX, message, data);\r\n else console.info(LOG_PREFIX, message);\r\n}\r\n\r\nexport function logAuthClient(message: string, data?: Record<string, unknown>): void {\r\n if (!isAuthDebugClientEnabled()) return;\r\n if (data) console.info(LOG_PREFIX, message, data);\r\n else console.info(LOG_PREFIX, message);\r\n}\r\n\r\nexport function summarizeSessionUserForLog(user: unknown): Record<string, unknown> {\r\n if (!user || typeof user !== 'object') return { present: false };\r\n const u = user as Record<string, unknown>;\r\n return {\r\n present: true,\r\n email: u.email ?? null,\r\n id: u.id ?? null,\r\n adminAccess: u.adminAccess ?? null,\r\n isRBACAdmin: u.isRBACAdmin ?? null,\r\n isVendorPortal: u.isVendorPortal ?? null,\r\n groupName: u.groupName ?? null,\r\n };\r\n}\r\n\r\nexport function nextAuthCookieDebugInfo(): Record<string, unknown> {\r\n const nextAuthUrl = process.env.NEXTAUTH_URL ?? '(unset)';\r\n const isHttps = nextAuthUrl.startsWith('https');\r\n return {\r\n nextAuthUrl,\r\n hasSecret: Boolean(process.env.NEXTAUTH_SECRET),\r\n cookieName: isHttps ? '__Secure-next-auth.session-token' : 'next-auth.session-token',\r\n cookieSecure: isHttps,\r\n nodeEnv: process.env.NODE_ENV ?? '(unset)',\r\n };\r\n}\r\n","/**\r\n * Build NextAuth options for credentials auth. App can extend/override via extend().\r\n */\r\nimport type { NextAuthOptions } from 'next-auth';\r\nimport _CredentialsProvider from 'next-auth/providers/credentials';\r\nconst CredentialsProvider = (_CredentialsProvider as unknown as { default: typeof _CredentialsProvider }).default ?? _CredentialsProvider;\r\nimport { permissionRowsToRecord } from './permission-entities';\r\nimport { isSuperAdmin } from './role-helpers';\r\nimport { vendorPortalFlagsFromUser } from './vendor-scope';\r\nimport { logAuth, nextAuthCookieDebugInfo, summarizeSessionUserForLog } from './auth-debug';\r\n\r\nexport interface NextAuthUser {\r\n id: number;\r\n email: string;\r\n name: string | null;\r\n password: string | null;\r\n blocked?: boolean;\r\n deleted?: boolean;\r\n groupId?: number | null;\r\n adminAccess?: boolean;\r\n group?: {\r\n name?: string;\r\n permissions?: Array<{\r\n entity: string;\r\n canCreate: boolean;\r\n canRead: boolean;\r\n canUpdate: boolean;\r\n canDelete: boolean;\r\n }>;\r\n };\r\n vendorIds?: number[];\r\n activeVendorId?: number | null;\r\n vendorRole?: 'owner' | 'staff' | null;\r\n}\r\n\r\nexport interface AuthorizeOtpInput {\r\n identifier: string;\r\n channel: 'email' | 'sms';\r\n code: string;\r\n}\r\n\r\nexport interface NextAuthOptionsConfig {\r\n /** Resolve user by email (e.g. from TypeORM). Return null if not found. */\r\n getUserByEmail: (email: string) => Promise<NextAuthUser | null>;\r\n comparePassword: (plain: string, hash: string) => Promise<boolean>;\r\n signInPage?: string;\r\n secret?: string;\r\n extend?: (options: NextAuthOptions) => NextAuthOptions;\r\n /** When false, password CredentialsProvider is omitted. Default true. */\r\n enablePasswordLogin?: boolean;\r\n /** When true, registers CredentialsProvider id `otp`. Requires authorizeOtp. Default false. */\r\n enableOtpLogin?: boolean;\r\n /** Validate OTP and return user (same shape as password flow) or null. */\r\n authorizeOtp?: (input: AuthorizeOtpInput) => Promise<NextAuthUser | null>;\r\n /**\r\n * Customer group sign-in policy for credentials/OTP on a shared `/api/auth` route:\r\n * - `true` — always allow (dedicated storefront auth)\r\n * - `false` — always block\r\n * - omitted — auto: allow unless `callbackUrl` targets `/admin` (storefront `/signin` works unchanged)\r\n */\r\n allowCustomerLogin?: boolean;\r\n}\r\n\r\nfunction sessionUserFromNextAuthUser(user: NextAuthUser) {\r\n const g = user.group;\r\n const isRBACAdmin = isSuperAdmin({\r\n groupId: user.groupId ?? undefined,\r\n groupName: g?.name,\r\n isRBACAdmin: false,\r\n });\r\n const entityPerms = permissionRowsToRecord(g?.permissions);\r\n // Preserve the DB value as-is: true → true, false → false, null/undefined → undefined.\r\n // Coercing null to false would make requireAdminAccess deny vendor/unset users before\r\n // the vendor-portal check can allow them.\r\n const rawAdminAccess = (user as NextAuthUser & { adminAccess?: boolean }).adminAccess;\r\n const adminAccess: boolean | undefined =\r\n rawAdminAccess === true ? true : rawAdminAccess === false ? false : undefined;\r\n const vendorIds = user.vendorIds ?? [];\r\n const vendorRole = user.vendorRole ?? null;\r\n const { isVendorPortal, isVendorOwner } = vendorPortalFlagsFromUser({\r\n email: user.email,\r\n isRBACAdmin,\r\n groupName: g?.name,\r\n vendorIds,\r\n vendorRole,\r\n });\r\n return {\r\n id: user.id.toString(),\r\n email: user.email,\r\n name: user.name,\r\n groupId: user.groupId ?? undefined,\r\n groupName: g?.name ?? undefined,\r\n isRBACAdmin,\r\n entityPerms,\r\n adminAccess,\r\n vendorIds,\r\n activeVendorId: user.activeVendorId ?? vendorIds[0] ?? null,\r\n vendorRole,\r\n isVendorPortal,\r\n isVendorOwner,\r\n };\r\n}\r\n\r\nfunction isCustomerGroupUser(user: NextAuthUser): boolean {\r\n return user.group?.name?.toLocaleLowerCase().trim() === 'customer';\r\n}\r\n\r\nfunction callbackUrlTargetsAdmin(callbackUrl: string): boolean {\r\n const raw = callbackUrl.trim();\r\n if (!raw) return false;\r\n if (raw.startsWith('/admin')) return true;\r\n try {\r\n const path = raw.startsWith('http') ? new URL(raw).pathname : raw.split('?')[0] ?? raw;\r\n return path.startsWith('/admin');\r\n } catch {\r\n return raw.includes('/admin');\r\n }\r\n}\r\n\r\n/** Whether a Customer-group user may complete this credentials/OTP sign-in attempt. */\r\nfunction permitsCustomerLogin(\r\n allowCustomerLogin: boolean | undefined,\r\n credentials: Record<string, string> | undefined\r\n): boolean {\r\n if (allowCustomerLogin === true) return true;\r\n if (allowCustomerLogin === false) return false;\r\n const callbackUrl = typeof credentials?.callbackUrl === 'string' ? credentials.callbackUrl : '';\r\n return !callbackUrlTargetsAdmin(callbackUrl);\r\n}\r\n\r\nexport function getNextAuthOptions(config: NextAuthOptionsConfig): NextAuthOptions {\r\n const {\r\n getUserByEmail,\r\n comparePassword,\r\n signInPage = '/admin/signin',\r\n secret,\r\n extend,\r\n enablePasswordLogin = true,\r\n enableOtpLogin = false,\r\n authorizeOtp,\r\n allowCustomerLogin,\r\n } = config;\r\n\r\n logAuth('getNextAuthOptions init', nextAuthCookieDebugInfo());\r\n\r\n const providers: NextAuthOptions['providers'] = [];\r\n\r\n if (enablePasswordLogin) {\r\n providers.push(\r\n CredentialsProvider({\r\n name: 'credentials',\r\n credentials: {\r\n email: { label: 'Email', type: 'email' },\r\n password: { label: 'Password', type: 'password' },\r\n },\r\n async authorize(credentials) {\r\n const creds = credentials as Record<string, string> | undefined;\r\n const email = creds?.email?.trim() ?? '';\r\n if (!email || !creds?.password) {\r\n logAuth('authorize(credentials) rejected', { reason: 'missing_email_or_password' });\r\n return null;\r\n }\r\n try {\r\n const user = await getUserByEmail(email);\r\n if (!user) {\r\n logAuth('authorize(credentials) rejected', { reason: 'user_not_found', email });\r\n return null;\r\n }\r\n if (user.blocked) {\r\n logAuth('authorize(credentials) rejected', { reason: 'blocked', email, userId: user.id });\r\n return null;\r\n }\r\n if ((user as { deleted?: boolean }).deleted) {\r\n logAuth('authorize(credentials) rejected', { reason: 'deleted', email, userId: user.id });\r\n return null;\r\n }\r\n if (!user.password) {\r\n logAuth('authorize(credentials) rejected', { reason: 'no_password', email, userId: user.id });\r\n return null;\r\n }\r\n const valid = await comparePassword(creds.password, user.password);\r\n if (!valid) {\r\n logAuth('authorize(credentials) rejected', { reason: 'invalid_password', email, userId: user.id });\r\n return null;\r\n }\r\n if (isCustomerGroupUser(user) && !permitsCustomerLogin(allowCustomerLogin, creds)) {\r\n logAuth('authorize(credentials) rejected', {\r\n reason: 'customer_group',\r\n email,\r\n userId: user.id,\r\n callbackUrl: creds?.callbackUrl ?? null,\r\n });\r\n return null;\r\n }\r\n const sessionUser = sessionUserFromNextAuthUser(user);\r\n logAuth('authorize(credentials) ok', summarizeSessionUserForLog(sessionUser));\r\n return sessionUser;\r\n } catch (err) {\r\n // Log so infrastructure errors (DB down, missing entity, etc.) are\r\n // visible in server logs rather than silently failing as \"wrong password\".\r\n console.error('[cms-auth] authorize error (credentials):', err instanceof Error ? err.message : err);\r\n logAuth('authorize(credentials) error', {\r\n email,\r\n message: err instanceof Error ? err.message : String(err),\r\n });\r\n return null;\r\n }\r\n },\r\n })\r\n );\r\n }\r\n\r\n if (enableOtpLogin && authorizeOtp) {\r\n providers.push(\r\n CredentialsProvider({\r\n id: 'otp',\r\n name: 'otp',\r\n credentials: {\r\n identifier: { label: 'Email or phone', type: 'text' },\r\n code: { label: 'Code', type: 'text' },\r\n channel: { label: 'Channel', type: 'text' },\r\n },\r\n async authorize(credentials) {\r\n const creds = credentials as Record<string, string> | undefined;\r\n const identifier = typeof creds?.identifier === 'string' ? creds.identifier.trim() : '';\r\n const code = typeof creds?.code === 'string' ? creds.code.trim() : '';\r\n const ch = creds?.channel === 'sms' ? 'sms' : 'email';\r\n if (!identifier || !code) return null;\r\n try {\r\n const user = await authorizeOtp({ identifier, channel: ch, code });\r\n if (!user || user.blocked || (user as { deleted?: boolean }).deleted) return null;\r\n if (isCustomerGroupUser(user) && !permitsCustomerLogin(allowCustomerLogin, creds)) {\r\n logAuth('authorize(otp) rejected', {\r\n reason: 'customer_group',\r\n identifier,\r\n callbackUrl: creds?.callbackUrl ?? null,\r\n });\r\n return null;\r\n }\r\n return sessionUserFromNextAuthUser(user);\r\n } catch (err) {\r\n console.error('[cms-auth] authorize error (otp):', err instanceof Error ? err.message : err);\r\n return null;\r\n }\r\n },\r\n })\r\n );\r\n }\r\n\r\n const options: NextAuthOptions = {\r\n secret: secret ?? process.env.NEXTAUTH_SECRET,\r\n providers,\r\n session: { strategy: 'jwt' },\r\n pages: { signIn: signInPage },\r\n cookies: {\r\n sessionToken: {\r\n name: process.env.NEXTAUTH_URL?.startsWith('https')\r\n ? '__Secure-next-auth.session-token'\r\n : 'next-auth.session-token',\r\n options: {\r\n httpOnly: true,\r\n sameSite: 'lax',\r\n path: '/',\r\n secure: process.env.NEXTAUTH_URL?.startsWith('https') ?? false,\r\n },\r\n },\r\n },\r\n callbacks: {\r\n async jwt({ token, user, trigger, session }) {\r\n if (user) {\r\n logAuth('jwt callback: new sign-in', {\r\n trigger,\r\n user: summarizeSessionUserForLog(user),\r\n });\r\n const u = user as unknown as Record<string, unknown>;\r\n (token as Record<string, unknown>).id = u.id;\r\n (token as Record<string, unknown>).groupId = u.groupId;\r\n (token as Record<string, unknown>).groupName = u.groupName;\r\n (token as Record<string, unknown>).isRBACAdmin = u.isRBACAdmin;\r\n (token as Record<string, unknown>).entityPerms = u.entityPerms;\r\n (token as Record<string, unknown>).adminAccess = u.adminAccess;\r\n (token as Record<string, unknown>).vendorIds = u.vendorIds;\r\n (token as Record<string, unknown>).activeVendorId = u.activeVendorId;\r\n (token as Record<string, unknown>).vendorRole = u.vendorRole;\r\n (token as Record<string, unknown>).isVendorPortal = u.isVendorPortal;\r\n (token as Record<string, unknown>).isVendorOwner = u.isVendorOwner;\r\n }\r\n if (trigger === 'update' && session && typeof session === 'object') {\r\n logAuth('jwt callback: session update', { trigger });\r\n const s = session as Record<string, unknown>;\r\n const t = token as Record<string, unknown>;\r\n if (typeof s.name === 'string') t.name = s.name;\r\n if (typeof s.email === 'string') t.email = s.email;\r\n if (typeof s.activeVendorId === 'number') t.activeVendorId = s.activeVendorId;\r\n }\r\n return token;\r\n },\r\n async session({ session, token }) {\r\n const t = token as Record<string, unknown>;\r\n logAuth('session callback', {\r\n tokenHasId: t.id != null,\r\n tokenEmail: typeof t.email === 'string' ? t.email : null,\r\n sessionUser: summarizeSessionUserForLog(session.user),\r\n });\r\n if (session.user) {\r\n if (typeof t.name === 'string') session.user.name = t.name;\r\n if (typeof t.email === 'string') session.user.email = t.email;\r\n (session.user as Record<string, unknown>).id = t.id;\r\n (session.user as Record<string, unknown>).groupId = t.groupId;\r\n (session.user as Record<string, unknown>).groupName = t.groupName;\r\n (session.user as Record<string, unknown>).isRBACAdmin = t.isRBACAdmin;\r\n (session.user as Record<string, unknown>).entityPerms = t.entityPerms;\r\n (session.user as Record<string, unknown>).adminAccess = t.adminAccess;\r\n (session.user as Record<string, unknown>).vendorIds = t.vendorIds;\r\n (session.user as Record<string, unknown>).activeVendorId = t.activeVendorId;\r\n (session.user as Record<string, unknown>).vendorRole = t.vendorRole;\r\n (session.user as Record<string, unknown>).isVendorPortal = t.isVendorPortal;\r\n (session.user as Record<string, unknown>).isVendorOwner = t.isVendorOwner;\r\n }\r\n return session;\r\n },\r\n },\r\n };\r\n\r\n return extend ? extend(options) : options;\r\n}\r\n\r\n/** Storefront sign-in: allows Customer group; use with signInPage `/signin`. */\r\nexport function getStorefrontNextAuthOptions(\r\n config: Omit<NextAuthOptionsConfig, 'allowCustomerLogin'>\r\n): NextAuthOptions {\r\n return getNextAuthOptions({ ...config, allowCustomerLogin: true });\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport { Between, Brackets, ILike, LessThanOrEqual, MoreThan, MoreThanOrEqual, Not } from 'typeorm';\r\nimport type { EntityMetadata, Repository } from 'typeorm';\r\nimport type { EntityCrudAction } from '../auth/permission-entities';\r\nimport type { SessionUser } from '../auth/helpers';\r\nimport type { VendorScope } from '../auth/vendor-scope';\r\nimport {\r\n applyVendorScopeToQueryBuilder,\r\n mergeVendorScopeIntoWhere,\r\n requireVendorIdForScopedCreate,\r\n resourceUsesVendorScope,\r\n vendorScopeRowAccess,\r\n type VendorScopedCreateContext,\r\n} from './vendor-scope-crud';\r\nimport { queueErpCreateContactIfEnabled } from '../plugins/erp/erp-contact-sync';\r\nimport { queueErpProductUpsertIfEnabled } from '../plugins/erp/erp-product-sync';\r\nimport { validateAndNormalizeAddressRow } from '../lib/address-geo-validation';\r\nimport {\r\n applyVendorCustomersContactFilter,\r\n assertContactAllowedForVendorOrder,\r\n resolveVendorIdForContactCheck,\r\n} from '../lib/vendor-customer-contacts';\r\nimport crypto from 'crypto';\r\nimport { validateLlmAgentScopeForWrite } from '../plugins/llm/llm-agent-scope-crud';\r\n\r\nexport type EntityMap = Record<string, import('typeorm').EntityTarget<import('typeorm').ObjectLiteral>>;\r\n\r\nexport interface CrudHandlerOptions {\r\n requireAuth: (req: Request) => Promise<Response | null>;\r\n json: (body: unknown, init?: { status?: number }) => Response;\r\n requireEntityPermission?: (req: Request, entity: string, action: EntityCrudAction) => Promise<Response | null>;\r\n /** When set, contact create/update enqueues ERP `create-contact` (non-fatal). */\r\n getCms?: () => Promise<{ getPlugin: (name: string) => unknown }>;\r\n /** When set, soft-delete sets `deletedBy` from the current admin user. */\r\n getDeletedByUserId?: (req: Request) => Promise<number | null>;\r\n /** When set, store rows are filtered by session vendor (platform admin bypasses). */\r\n getVendorScope?: () => Promise<VendorScope>;\r\n /** Hydrated session (group + vendor context) for vendorId resolution on create. */\r\n getHydratedSessionUser?: () => Promise<SessionUser | null>;\r\n}\r\n\r\nconst CRUD_LOG = '[cms-crud]';\r\n\r\nfunction logCrudClientError(op: string, detail: Record<string, unknown>): void {\r\n console.warn(CRUD_LOG, op, detail);\r\n}\r\n\r\nfunction logCrudServerError(op: string, detail: Record<string, unknown>): void {\r\n console.error(CRUD_LOG, op, detail);\r\n}\r\n\r\n/** Recursive sum of `size` for all `file` descendants under each folder id (Postgres). */\r\nasync function aggregateMediaFolderFileSizes(dataSource: DataSource, folderIds: number[]): Promise<Map<number, number>> {\r\n const map = new Map<number, number>();\r\n if (folderIds.length === 0) return map;\r\n try {\r\n const rows = (await dataSource.query(\r\n `\r\n WITH RECURSIVE walk AS (\r\n SELECT m.\"parentId\" AS root_id, m.id, m.kind, m.size\r\n FROM media m\r\n WHERE m.\"parentId\" = ANY($1) AND m.deleted = false\r\n UNION ALL\r\n SELECT w.root_id, m.id, m.kind, m.size\r\n FROM walk w\r\n INNER JOIN media m ON m.\"parentId\" = w.id AND m.deleted = false\r\n )\r\n SELECT root_id AS \"rootId\", COALESCE(SUM(size) FILTER (WHERE kind = 'file'), 0)::bigint AS \"totalSize\"\r\n FROM walk\r\n GROUP BY root_id\r\n `,\r\n [folderIds]\r\n )) as { rootId: number; totalSize: string | number }[];\r\n for (const r of rows) {\r\n map.set(Number(r.rootId), Number(r.totalSize));\r\n }\r\n for (const id of folderIds) {\r\n if (!map.has(id)) map.set(id, 0);\r\n }\r\n } catch (err) {\r\n logCrudServerError('media folder size aggregate failed', {\r\n message: err instanceof Error ? err.message : String(err),\r\n });\r\n }\r\n return map;\r\n}\r\n\r\nconst DATE_COLUMN_TYPES = new Set([\r\n 'date', 'datetime', 'datetime2', 'timestamp', 'timestamptz', 'timetz', 'smalldatetime', 'timestamp with time zone', 'timestamp without time zone',\r\n]);\r\n\r\nconst TIMESTAMP_PROP_NAMES = new Set(['createdAt', 'updatedAt', 'deletedAt']);\r\n\r\nfunction isInvalidDateValue(v: unknown): boolean {\r\n if (v === '' || v == null) return true;\r\n if (typeof v === 'string') return isNaN(Date.parse(v)) || /NaN|Invalid/i.test(v);\r\n if (v instanceof Date) return isNaN(v.getTime());\r\n return false;\r\n}\r\n\r\n/** Strip empty/invalid values for boolean, number, and date columns so DB defaults apply. */\r\nfunction sanitizeBodyForEntity(repo: Repository<import('typeorm').ObjectLiteral>, body: Record<string, unknown>): void {\r\n const meta = repo.metadata;\r\n for (const col of meta.columns) {\r\n if (!(col.propertyName in body)) continue;\r\n const v = body[col.propertyName];\r\n const t = typeof col.type === 'string' ? col.type : (col.type as Function)?.name ?? '';\r\n const isBoolean = t === 'boolean' || t === 'bool' || col.type === Boolean;\r\n const isNumber = ['int', 'integer', 'int2', 'int4', 'int8', 'smallint', 'bigint', 'number', 'Number'].includes(t) || col.type === Number;\r\n const isDate = DATE_COLUMN_TYPES.has(t) || col.type === Date || TIMESTAMP_PROP_NAMES.has(col.propertyName);\r\n if (v === '' && (isBoolean || isNumber)) {\r\n delete body[col.propertyName];\r\n } else if (isDate && isInvalidDateValue(v)) {\r\n delete body[col.propertyName];\r\n }\r\n }\r\n}\r\n\r\n/** Keep only scalar columns (excludes relations like tags) so repo.update() does not throw. */\r\nfunction pickColumnUpdates(\r\n repo: Repository<import('typeorm').ObjectLiteral>,\r\n body: Record<string, unknown>\r\n): Record<string, unknown> {\r\n const cols = new Set(repo.metadata.columns.map((c) => c.propertyName));\r\n const out: Record<string, unknown> = {};\r\n for (const k of Object.keys(body)) {\r\n if (cols.has(k)) out[k] = body[k];\r\n }\r\n return out;\r\n}\r\n\r\n/** OR search on columns that exist on the entity (avoids Tag/Category etc. without `title`). */\r\nfunction buildSearchWhereClause(\r\n repo: Repository<import('typeorm').ObjectLiteral>,\r\n search: string\r\n): Record<string, unknown>[] | Record<string, unknown> {\r\n const cols = new Set(repo.metadata.columns.map((c) => c.propertyName));\r\n const term = ILike(`%${search}%`);\r\n const ors: Record<string, unknown>[] = [];\r\n for (const field of ['name', 'title', 'slug', 'email', 'filename'] as const) {\r\n if (cols.has(field)) ors.push({ [field]: term });\r\n }\r\n if (ors.length === 0) return {};\r\n return ors.length === 1 ? ors[0]! : ors;\r\n}\r\n\r\nfunction entityHasSoftDelete(repo: Repository<import('typeorm').ObjectLiteral>): boolean {\r\n return repo.metadata.columns.some((c) => c.propertyName === 'deleted');\r\n}\r\n\r\nconst LIST_QUERY_RESERVED = new Set(['page', 'limit', 'sortField', 'sortOrder', 'search']);\r\n\r\nfunction dayStartUtc(isoDay: string): Date {\r\n return new Date(isoDay + 'T00:00:00.000Z');\r\n}\r\n\r\nfunction dayEndUtc(isoDay: string): Date {\r\n return new Date(isoDay + 'T23:59:59.999Z');\r\n}\r\n\r\nfunction columnTypeLabel(col: { type: unknown }): string {\r\n const t = col.type;\r\n if (typeof t === 'string') return t.toLowerCase();\r\n if (typeof t === 'function') return (t as { name?: string }).name?.toLowerCase?.() ?? '';\r\n if (t && typeof t === 'object' && 'name' in t && typeof (t as { name: unknown }).name === 'string') {\r\n return String((t as { name: string }).name).toLowerCase();\r\n }\r\n return '';\r\n}\r\n\r\ntype ListColumnMeta = import('typeorm').EntityMetadata['columns'][number];\r\n\r\nfunction isListDateColumn(col: ListColumnMeta): boolean {\r\n const tl = columnTypeLabel(col);\r\n return DATE_COLUMN_TYPES.has(tl) || col.type === Date || TIMESTAMP_PROP_NAMES.has(col.propertyName);\r\n}\r\n\r\nfunction isListNumericColumn(col: ListColumnMeta): boolean {\r\n const tl = columnTypeLabel(col);\r\n if (col.type === Number) return true;\r\n const patterns = [\r\n 'int',\r\n 'integer',\r\n 'int2',\r\n 'int4',\r\n 'int8',\r\n 'smallint',\r\n 'bigint',\r\n 'float',\r\n 'double',\r\n 'decimal',\r\n 'numeric',\r\n 'real',\r\n 'tinyint',\r\n 'mediumint',\r\n ];\r\n if (patterns.some((x) => tl.includes(x))) return true;\r\n if (tl.includes('unsigned') && (tl.includes('int') || tl.includes('bigint') || tl.includes('small'))) return true;\r\n // Driver/metadata quirks: FK columns are almost always integers\r\n if (!tl && /Id$/i.test(col.propertyName) && !TIMESTAMP_PROP_NAMES.has(col.propertyName)) return true;\r\n return false;\r\n}\r\n\r\nfunction isListBooleanColumn(col: ListColumnMeta): boolean {\r\n const tl = columnTypeLabel(col);\r\n return tl === 'boolean' || tl === 'bool' || col.type === Boolean;\r\n}\r\n\r\nfunction isListStringColumn(col: ListColumnMeta): boolean {\r\n const tl = columnTypeLabel(col);\r\n if (isListDateColumn(col) || isListNumericColumn(col) || isListBooleanColumn(col)) return false;\r\n if (\r\n ['varchar', 'character varying', 'text', 'citext', 'uuid', 'char', 'character', 'enum'].some((x) =>\r\n tl.includes(x)\r\n )\r\n ) {\r\n return true;\r\n }\r\n if (col.type === String) return true;\r\n return false;\r\n}\r\n\r\n/** Merge `patch` into list `where` (OR-array or single object) the same way as int/bool filters. */\r\nfunction mergeListWhereAnd(\r\n where: Record<string, unknown>[] | Record<string, unknown>,\r\n patch: Record<string, unknown>\r\n): Record<string, unknown>[] | Record<string, unknown> {\r\n if (Object.keys(patch).length === 0) return where;\r\n if (Array.isArray(where)) {\r\n if (where.length === 0) return [patch];\r\n return where.map((w) => ({ ...w, ...patch }));\r\n }\r\n if (where && typeof where === 'object' && Object.keys(where).length > 0) {\r\n return { ...where, ...patch };\r\n }\r\n return patch;\r\n}\r\n\r\n/**\r\n * Scalar list filters from query params: `{col}From`/`{col}To` (dates), `{col}Min`/`{col}Max` (numbers),\r\n * and `{col}` (ILIKE) for string columns. Skips reserved keys and int FK params handled elsewhere.\r\n */\r\nfunction buildListFilterAndFromSearchParams(\r\n repo: Repository<import('typeorm').ObjectLiteral>,\r\n searchParams: URLSearchParams\r\n): Record<string, unknown> {\r\n const and: Record<string, unknown> = {};\r\n const columnNames = new Set(repo.metadata.columns.map((c) => c.propertyName));\r\n\r\n for (const col of repo.metadata.columns) {\r\n const name = col.propertyName;\r\n if (!columnNames.has(name)) continue;\r\n if (name === 'deleted' || name === 'deletedAt' || name === 'deletedBy') continue;\r\n if (!isListDateColumn(col)) continue;\r\n const from = searchParams.get(`${name}From`)?.trim();\r\n const to = searchParams.get(`${name}To`)?.trim();\r\n if (!from && !to) continue;\r\n if (from && to) {\r\n and[name] = Between(dayStartUtc(from), dayEndUtc(to));\r\n } else if (from) {\r\n and[name] = MoreThanOrEqual(dayStartUtc(from));\r\n } else if (to) {\r\n and[name] = LessThanOrEqual(dayEndUtc(to));\r\n }\r\n }\r\n\r\n for (const col of repo.metadata.columns) {\r\n const name = col.propertyName;\r\n if (!columnNames.has(name)) continue;\r\n if (name === 'deleted' || name === 'deletedAt' || name === 'deletedBy') continue;\r\n if (!isListNumericColumn(col)) continue;\r\n if (Object.prototype.hasOwnProperty.call(and, name)) continue;\r\n const minRaw = searchParams.get(`${name}Min`)?.trim();\r\n const maxRaw = searchParams.get(`${name}Max`)?.trim();\r\n if (!minRaw && !maxRaw) continue;\r\n const parseNum = (s: string): number | null => {\r\n const n = Number(s);\r\n return Number.isFinite(n) ? n : null;\r\n };\r\n const nMin = minRaw ? parseNum(minRaw) : null;\r\n const nMax = maxRaw ? parseNum(maxRaw) : null;\r\n if (nMin != null && nMax != null) {\r\n and[name] = Between(nMin, nMax);\r\n } else if (nMin != null) {\r\n and[name] = MoreThanOrEqual(nMin);\r\n } else if (nMax != null) {\r\n and[name] = LessThanOrEqual(nMax);\r\n }\r\n }\r\n\r\n for (const col of repo.metadata.columns) {\r\n const name = col.propertyName;\r\n if (!columnNames.has(name)) continue;\r\n if (LIST_QUERY_RESERVED.has(name)) continue;\r\n if (name === 'deleted' || name === 'deletedAt' || name === 'deletedBy') continue;\r\n if (!isListStringColumn(col)) continue;\r\n if (Object.prototype.hasOwnProperty.call(and, name)) continue;\r\n /** `scope` must match exactly (`chatbot` ≠ `email_intent_chatbot`). */\r\n if (name === 'scope') continue;\r\n const raw = searchParams.get(name)?.trim();\r\n if (!raw) continue;\r\n and[name] = ILike(`%${raw}%`);\r\n }\r\n return and;\r\n}\r\n\r\nfunction buildExactListParamWhere(\r\n repo: Repository<import('typeorm').ObjectLiteral>,\r\n searchParams: URLSearchParams\r\n): Record<string, unknown> {\r\n const extraWhere: Record<string, unknown> = {};\r\n const columnNames = new Set(repo.metadata.columns.map((c) => c.propertyName));\r\n\r\n for (const col of repo.metadata.columns) {\r\n const name = col.propertyName;\r\n if (!columnNames.has(name)) continue;\r\n if (name === 'deleted' || name === 'deletedAt' || name === 'deletedBy') continue;\r\n if (!isListNumericColumn(col)) continue;\r\n const v = searchParams.get(name)?.trim();\r\n if (v == null || v === '') continue;\r\n const n = Number(v);\r\n if (!Number.isFinite(n)) continue;\r\n extraWhere[name] = n;\r\n }\r\n for (const col of repo.metadata.columns) {\r\n if (String(col.type) !== 'boolean') continue;\r\n const name = col.propertyName;\r\n if (!columnNames.has(name)) continue;\r\n const raw = searchParams.get(name)?.trim();\r\n if (raw === 'true' || raw === 'false') {\r\n extraWhere[name] = raw === 'true';\r\n }\r\n }\r\n const scopeParam = searchParams.get('scope')?.trim();\r\n if (scopeParam && columnNames.has('scope')) {\r\n extraWhere.scope = scopeParam;\r\n }\r\n return extraWhere;\r\n}\r\n\r\nfunction mergeDeletedFalseWhere(\r\n repo: Repository<import('typeorm').ObjectLiteral>,\r\n where: Record<string, unknown>[] | Record<string, unknown>\r\n): Record<string, unknown>[] | Record<string, unknown> {\r\n if (!entityHasSoftDelete(repo)) return where;\r\n const d = { deleted: false };\r\n if (Array.isArray(where)) {\r\n if (where.length === 0) return [d];\r\n return where.map((w) => ({ ...w, ...d }));\r\n }\r\n return Object.keys(where).length > 0 ? { ...where, ...d } : d;\r\n}\r\n\r\n/** Prefer common list sort keys that exist on the entity (custom tables may omit `createdAt`). */\r\nfunction pickDefaultListSortField(\r\n columnNames: Set<string>,\r\n columns: readonly { propertyName: string }[]\r\n): string {\r\n for (const candidate of ['createdAt', 'updatedAt', 'id', 'name', 'sortOrder', 'title'] as const) {\r\n if (columnNames.has(candidate)) return candidate;\r\n }\r\n return columns[0]?.propertyName ?? 'id';\r\n}\r\n\r\nfunction normalizeProductSku(value: unknown): string | null {\r\n if (value == null) return null;\r\n const s = String(value).trim();\r\n return s === '' ? null : s;\r\n}\r\n\r\nasync function assertProductSkuUnique(\r\n repo: Repository<import('typeorm').ObjectLiteral>,\r\n sku: string,\r\n excludeId?: number\r\n): Promise<boolean> {\r\n const where: import('typeorm').ObjectLiteral =\r\n excludeId != null\r\n ? ({ sku, deleted: false, id: Not(excludeId) } as import('typeorm').ObjectLiteral)\r\n : ({ sku, deleted: false } as import('typeorm').ObjectLiteral);\r\n const row = await repo.findOne({ where });\r\n return row == null;\r\n}\r\n\r\nfunction buildSoftDeletePayload(meta: EntityMetadata, deletedBy: number | null): Record<string, unknown> {\r\n const payload: Record<string, unknown> = { deleted: true };\r\n if (meta.columns.some((c) => c.propertyName === 'deletedAt')) {\r\n payload.deletedAt = new Date();\r\n }\r\n if (deletedBy != null && meta.columns.some((c) => c.propertyName === 'deletedBy')) {\r\n payload.deletedBy = deletedBy;\r\n }\r\n return payload;\r\n}\r\n\r\nfunction makeContactErpSync(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n getCms: CrudHandlerOptions['getCms']\r\n): (row: import('typeorm').ObjectLiteral) => Promise<void> {\r\n return async function syncContactRowToErp(row: import('typeorm').ObjectLiteral): Promise<void> {\r\n if (!getCms) return;\r\n try {\r\n const cms = await getCms();\r\n const c = row as {\r\n name: string;\r\n email: string;\r\n phone?: string | null;\r\n type?: string | null;\r\n company?: string | null;\r\n notes?: string | null;\r\n };\r\n await queueErpCreateContactIfEnabled(cms, dataSource, entityMap, {\r\n name: c.name,\r\n email: c.email,\r\n phone: c.phone,\r\n type: c.type,\r\n company: c.company,\r\n notes: c.notes,\r\n });\r\n } catch {\r\n /* ignore */\r\n }\r\n };\r\n}\r\n\r\n// ─── Discount validation ──────────────────────────────────────────────────────\r\n\r\nfunction validateDiscountBody(body: Record<string, unknown>): string | null {\r\n if ('validFrom' in body && 'validUntil' in body) {\r\n const from = body.validFrom ? new Date(body.validFrom as string) : null;\r\n const until = body.validUntil ? new Date(body.validUntil as string) : null;\r\n if (from && until && from > until) {\r\n return 'validFrom must be before validUntil';\r\n }\r\n }\r\n if ('value' in body) {\r\n const v = Number(body.value);\r\n if (!Number.isFinite(v) || v < 0) return 'value must be a non-negative number';\r\n if (body.discountType === 'PERCENTAGE' && v > 100) {\r\n return 'Percentage discount value cannot exceed 100';\r\n }\r\n }\r\n if ('maxDiscountAmount' in body && body.maxDiscountAmount != null && body.maxDiscountAmount !== '') {\r\n const m = Number(body.maxDiscountAmount);\r\n if (!Number.isFinite(m) || m < 0) return 'maxDiscountAmount must be a non-negative number';\r\n }\r\n return null;\r\n}\r\n\r\nasync function assertDiscountCouponCodeUnique(\r\n repo: Repository<import('typeorm').ObjectLiteral>,\r\n couponCode: string,\r\n vendorId: number,\r\n excludeId?: number\r\n): Promise<boolean> {\r\n if (!Number.isFinite(vendorId) || vendorId <= 0) return false;\r\n const where: import('typeorm').ObjectLiteral =\r\n excludeId != null\r\n ? ({ couponCode, vendorId, id: Not(excludeId) } as import('typeorm').ObjectLiteral)\r\n : ({ couponCode, vendorId } as import('typeorm').ObjectLiteral);\r\n const row = await repo.findOne({ where });\r\n return row == null;\r\n}\r\n\r\nfunction withDiscountVendorWhere(\r\n base: import('typeorm').ObjectLiteral,\r\n vendorId?: number | null\r\n): import('typeorm').ObjectLiteral {\r\n if (vendorId != null && Number.isFinite(vendorId) && vendorId > 0) {\r\n return { ...base, vendorId };\r\n }\r\n return base;\r\n}\r\n\r\n// ─── persistDiscountRules (from persistDiscountRules.ts) ──────────────────────\r\n// Generation-aware insert: roots first, then each child generation once its\r\n// parent has a real DB id. Replaces the old naive loop that caused FK violations\r\n// when a child arrived before its parent in the array.\r\n\r\nexport async function persistDiscountRules(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n discountId: number,\r\n rules: unknown[]\r\n): Promise<void> {\r\n if (!entityMap['discount_rules']) return;\r\n const rulesRepo = dataSource.getRepository(entityMap['discount_rules']);\r\n\r\n // 1. Clean slate\r\n await rulesRepo.delete({ discountId } as import('typeorm').ObjectLiteral);\r\n\r\n if (!Array.isArray(rules) || rules.length === 0) return;\r\n\r\n type IncomingRule = Record<string, unknown> & {\r\n _clientId: string;\r\n _parentClientId: string | null;\r\n };\r\n\r\n // 2. Normalise — attach discountId, ensure tracking fields exist\r\n const incoming: IncomingRule[] = rules.map((r) => {\r\n const rule = r as Record<string, unknown>;\r\n return {\r\n ...rule,\r\n discountId,\r\n _clientId: String(rule._clientId ?? Math.random().toString(36).slice(2)),\r\n _parentClientId: rule._parentClientId != null ? String(rule._parentClientId) : null,\r\n };\r\n });\r\n\r\n // clientId → real DB id, filled as each generation is inserted\r\n const clientIdToDbId = new Map<string, number>();\r\n\r\n let remaining = [...incoming];\r\n let MAX_PASSES = 100; // safety valve against cycles\r\n\r\n while (remaining.length > 0) {\r\n const insertThisPass: IncomingRule[] = [];\r\n const nextRemaining: IncomingRule[] = [];\r\n\r\n for (const node of remaining) {\r\n const isRoot = node._parentClientId === null;\r\n const parentResolved =\r\n node._parentClientId !== null && clientIdToDbId.has(node._parentClientId);\r\n\r\n if (isRoot || parentResolved) {\r\n insertThisPass.push(node);\r\n } else {\r\n nextRemaining.push(node);\r\n }\r\n }\r\n\r\n if (insertThisPass.length === 0) {\r\n // Stuck — remaining nodes have unresolvable parents (orphaned)\r\n console.warn(\r\n '[persistDiscountRules] orphaned rules — inserting as roots:',\r\n nextRemaining.map((n) => n._clientId)\r\n );\r\n for (const orphan of nextRemaining) {\r\n orphan._parentClientId = null;\r\n insertThisPass.push(orphan);\r\n }\r\n remaining = [];\r\n } else {\r\n remaining = nextRemaining;\r\n }\r\n\r\n // 3. Insert this generation sequentially to get DB ids back\r\n for (const node of insertThisPass) {\r\n const { _clientId, _parentClientId, ...persistFields } = node;\r\n\r\n const resolvedParentId =\r\n _parentClientId !== null ? (clientIdToDbId.get(_parentClientId) ?? null) : null;\r\n\r\n const saved = (await rulesRepo.save(\r\n rulesRepo.create({ ...persistFields, parentId: resolvedParentId } as object)\r\n )) as { id: number };\r\n\r\n clientIdToDbId.set(_clientId, saved.id);\r\n }\r\n\r\n if (--MAX_PASSES <= 0) {\r\n console.error('[persistDiscountRules] MAX_PASSES exceeded — aborting');\r\n break;\r\n }\r\n }\r\n}\r\n\r\ntype DiscountRuleValue = Record<string, unknown>;\r\n\r\ninterface DiscountFlatRule {\r\n id: number;\r\n parentId: number | null;\r\n conditionType: 'group' | 'rule';\r\n conditionOperator?: 'and' | 'or' | null;\r\n type?: string | null;\r\n subType?: string | null;\r\n comparisonOperator?: string | null;\r\n value: DiscountRuleValue;\r\n}\r\n\r\ninterface DiscountForEval {\r\n id: number;\r\n discountType: 'PERCENTAGE' | 'FLAT';\r\n value: number;\r\n maxDiscountAmount?: number | null;\r\n maxTotalUsage?: number | null;\r\n maxUsagePerUser?: number | null;\r\n usedCount: number;\r\n validFrom: Date | string;\r\n validUntil: Date | string;\r\n status: string;\r\n rules: DiscountFlatRule[];\r\n}\r\n\r\ninterface DiscountCartLine {\r\n productId: number;\r\n quantity: number;\r\n unitPrice: number;\r\n subtotal: number;\r\n}\r\n\r\ninterface DiscountEvalResult {\r\n rewardLines: Array<{\r\n productId: number;\r\n quantity: number;\r\n discountRate: number;\r\n discountType: 'PERCENTAGE' | 'FLAT';\r\n }>;\r\n conditionsMet: boolean;\r\n reason?: string;\r\n}\r\n\r\ninterface DiscountTreeNode extends DiscountFlatRule {\r\n children: DiscountTreeNode[];\r\n}\r\n\r\nfunction discountBuildTree(flat: DiscountFlatRule[]): DiscountTreeNode[] {\r\n if (!flat?.length) return [];\r\n const map = new Map<number, DiscountTreeNode>();\r\n const roots: DiscountTreeNode[] = [];\r\n for (const r of flat) map.set(r.id, { ...r, children: [] });\r\n for (const r of flat) {\r\n const node = map.get(r.id)!;\r\n if (r.parentId == null) {\r\n roots.push(node);\r\n } else {\r\n const parent = map.get(r.parentId);\r\n if (parent) parent.children.push(node);\r\n else roots.push(node); // orphan → treat as root\r\n }\r\n }\r\n return roots;\r\n}\r\n\r\nfunction discountExtractValue(val: DiscountRuleValue): unknown {\r\n if (val == null) return null;\r\n if (Object.keys(val).length === 1 && 'v' in val) {\r\n const raw = val.v;\r\n if (typeof raw === 'string' && raw.trim() !== '' && !isNaN(Number(raw))) return Number(raw);\r\n return raw;\r\n }\r\n return val;\r\n}\r\n\r\nfunction discountCompare(cartValue: unknown, op: string | null | undefined, ruleValue: unknown): boolean {\r\n if (!op) return false;\r\n const a = cartValue;\r\n const b = ruleValue;\r\n switch (op) {\r\n case 'eq': return a == b;\r\n case 'neq': return a != b;\r\n case 'gt': return Number(a) > Number(b);\r\n case 'gte': return Number(a) >= Number(b);\r\n case 'lt': return Number(a) < Number(b);\r\n case 'lte': return Number(a) <= Number(b);\r\n case 'in': {\r\n const list = Array.isArray(b) ? b : String(b).split(',').map((s) => s.trim());\r\n return list.some((v) => v == a);\r\n }\r\n case 'notIn': {\r\n const list = Array.isArray(b) ? b : String(b).split(',').map((s) => s.trim());\r\n return !list.some((v) => v == a);\r\n }\r\n case 'between': {\r\n if (Array.isArray(b) && b.length === 2) return Number(a) >= Number(b[0]) && Number(a) <= Number(b[1]);\r\n return false;\r\n }\r\n default: return false;\r\n }\r\n}\r\n\r\nfunction discountEvaluateRule(rule: DiscountTreeNode, cartLines: DiscountCartLine[], cartTotal: number): boolean {\r\n if (rule.conditionType === 'group') return discountEvaluateGroup(rule, cartLines, cartTotal);\r\n if (rule.type === 'reward') return true; // reward rules are not conditions\r\n const ruleValue = discountExtractValue(rule.value);\r\n switch (rule.type) {\r\n case 'minAmount':\r\n return discountCompare(cartTotal, rule.comparisonOperator, ruleValue);\r\n case 'quantity': {\r\n if (rule.subType === 'productId' && rule.value?.productId){\r\n const targetProductId = Number(rule.value.productId);\r\n const requiredQty = Number(rule.value.v);\r\n const productQty = cartLines\r\n .filter((l) => l.productId === targetProductId)\r\n .reduce((s,l) => s + l.quantity, 0);\r\n return discountCompare(productQty, rule.comparisonOperator, requiredQty);\r\n }\r\n const totalQty = cartLines.reduce((s, l) => s + l.quantity, 0);\r\n return discountCompare(totalQty, rule.comparisonOperator, ruleValue);\r\n }\r\n case 'product':\r\n if (rule.subType === 'productId') {\r\n return cartLines.some((l) => discountCompare(l.productId, rule.comparisonOperator, ruleValue));\r\n }\r\n return false;\r\n // These require external context (user session, payment method, time) —\r\n // pass by default here; enforce them at checkout middleware level.\r\n case 'category':\r\n case 'cart':\r\n case 'paymentMethod':\r\n case 'order': {\r\n if (rule.subType === 'nthOrder'){\r\n // cartLines doesn't have order count — pass through here,\r\n // actual check happens in validateCoupon where we have contactId\r\n return true;\r\n }\r\n }\r\n case 'user':\r\n case 'time':\r\n case 'shipping':\r\n case 'referral':\r\n return true;\r\n default:\r\n return true;\r\n }\r\n}\r\n\r\nfunction discountEvaluateGroup(group: DiscountTreeNode, cartLines: DiscountCartLine[], cartTotal: number): boolean {\r\n if (!group.children?.length) return true;\r\n const op = (group.conditionOperator ?? 'and').toLowerCase();\r\n if (op === 'and') return group.children.every((child) => discountEvaluateRule(child, cartLines, cartTotal));\r\n if (op === 'or') return group.children.some((child) => discountEvaluateRule(child, cartLines, cartTotal));\r\n return true;\r\n}\r\n\r\nfunction discountCollectRewardRules(nodes: DiscountTreeNode[]): DiscountTreeNode[] {\r\n const rewards: DiscountTreeNode[] = [];\r\n for (const node of nodes) {\r\n if (node.conditionType === 'rule' && node.type === 'reward') rewards.push(node);\r\n if (node.children?.length) rewards.push(...discountCollectRewardRules(node.children));\r\n }\r\n return rewards;\r\n}\r\n\r\nfunction discountExtractRequiredBuyQty(nodes: DiscountTreeNode[]): number {\r\n for (const node of nodes) {\r\n if (node.conditionType === 'rule' && node.type === 'quantity') {\r\n const v = discountExtractValue(node.value);\r\n const n = Number(v);\r\n if (Number.isFinite(n) && n > 0) return n;\r\n }\r\n if (node.children?.length) {\r\n const found = discountExtractRequiredBuyQty(node.children);\r\n if (found > 0) return found;\r\n }\r\n }\r\n return 1;\r\n}\r\n\r\nfunction discountExtractBuyProductId(nodes: DiscountTreeNode[]): number | null {\r\n for (const node of nodes) {\r\n if (node.conditionType === 'rule' && node.type === 'product' && node.subType === 'productId') {\r\n const v = discountExtractValue(node.value);\r\n const n = Number(v);\r\n if (Number.isFinite(n) && n > 0) return n;\r\n }\r\n if (node.conditionType === 'rule' && node.type === 'quantity' && node.subType === 'productId'){\r\n const n = Number(node.value?.productId);\r\n if (Number.isFinite(n) && n > 0) return n;\r\n }\r\n if (node.children?.length) {\r\n const found = discountExtractBuyProductId(node.children);\r\n if (found !== null) return found;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction discountBuildUniversalResult(discount: DiscountForEval, cartLines: DiscountCartLine[]): DiscountEvalResult {\r\n return {\r\n rewardLines: cartLines.map((l) => ({\r\n productId: l.productId,\r\n quantity: l.quantity,\r\n discountRate: Number(discount.value),\r\n discountType: discount.discountType,\r\n })),\r\n conditionsMet: true,\r\n };\r\n}\r\n\r\nfunction evaluateDiscount(discount: DiscountForEval, cartLines: DiscountCartLine[]): DiscountEvalResult {\r\n const empty: DiscountEvalResult = { rewardLines: [], conditionsMet: false };\r\n const now = new Date();\r\n if (new Date(discount.validFrom) > now) return { ...empty, reason: 'discount not yet active' };\r\n if (new Date(discount.validUntil) < now) return { ...empty, reason: 'discount expired' };\r\n if (discount.status !== 'ACTIVE') return { ...empty, reason: 'discount inactive' };\r\n if (discount.maxTotalUsage != null && discount.usedCount >= discount.maxTotalUsage) {\r\n return { ...empty, reason: 'discount usage limit reached' };\r\n }\r\n\r\n const cartTotal = cartLines.reduce((s, l) => s + l.subtotal, 0);\r\n const tree = discountBuildTree(discount.rules ?? []);\r\n\r\n if (tree.length === 0) return discountBuildUniversalResult(discount, cartLines);\r\n\r\n const conditionsMet = tree.every((node) => discountEvaluateRule(node, cartLines, cartTotal));\r\n if (!conditionsMet) return { ...empty, reason: 'conditions not met' };\r\n\r\n const rewardRules = discountCollectRewardRules(tree);\r\n if (rewardRules.length === 0) return discountBuildUniversalResult(discount, cartLines);\r\n\r\n // BUY X GET Y path\r\n const requiredBuyQty = discountExtractRequiredBuyQty(tree);\r\n const buyProductId = discountExtractBuyProductId(tree);\r\n\r\n let dealMultiplier = 1;\r\n if (buyProductId !== null && requiredBuyQty > 1) {\r\n const buyLine = cartLines.find((l) => l.productId === buyProductId);\r\n const cartQty = buyLine?.quantity ?? 0;\r\n dealMultiplier = Math.max(1, Math.floor(cartQty / requiredBuyQty));\r\n }\r\n\r\n const rewardLines: DiscountEvalResult['rewardLines'] = [];\r\n for (const rewardRule of rewardRules) {\r\n const rewardProductId = Number(discountExtractValue(rewardRule.value));\r\n if (!Number.isFinite(rewardProductId) || rewardProductId <= 0) continue;\r\n const isSameAsBuyProduct = rewardProductId === buyProductId;\r\n if (isSameAsBuyProduct){\r\n // Buy 2 Get 3 free- reward qty is dealMultiplier extra units\r\n rewardLines.push({\r\n productId: rewardProductId,\r\n quantity: dealMultiplier,\r\n discountRate: Number(discount.value),\r\n discountType: discount.discountType,\r\n });\r\n } else {\r\n // Normal BXGY- reward is different product\r\n const rewardCartLine = cartLines.find((l) => l.productId === rewardProductId);\r\n const rewardQty = rewardCartLine\r\n ? Math.min(dealMultiplier, rewardCartLine.quantity)\r\n : dealMultiplier;\r\n rewardLines.push({\r\n productId: rewardProductId,\r\n quantity: rewardQty,\r\n discountRate: Number(discount.value),\r\n discountType: discount.discountType,\r\n });\r\n }\r\n }\r\n return { rewardLines, conditionsMet: true };\r\n}\r\n\r\nfunction applyDiscountToOrderLines(\r\n lines: OrderTotalsLine[],\r\n evalResult: DiscountEvalResult,\r\n maxDiscountAmount: number | null | undefined\r\n): number {\r\n if (!evalResult.conditionsMet || evalResult.rewardLines.length === 0) return 0;\r\n\r\n let totalDiscountApplied = 0;\r\n\r\n for (const reward of evalResult.rewardLines) {\r\n const line = lines.find((l) => l.productId === reward.productId);\r\n if (!line) continue;\r\n\r\n let discountPerUnit: number;\r\n if (reward.discountType === 'PERCENTAGE') {\r\n discountPerUnit = (line.unitPrice * reward.discountRate) / 100;\r\n } else {\r\n discountPerUnit = Math.min(reward.discountRate, line.unitPrice);\r\n }\r\n\r\n const discountForLine = discountPerUnit * reward.quantity;\r\n totalDiscountApplied += discountForLine;\r\n\r\n line.discount = (line.discount ?? 0) + discountForLine;\r\n line.subtotal = line.unitPrice * line.quantity; // gross stays the same\r\n // Tax and total will be recomputed after this function returns\r\n line.total = Math.max(0, line.subtotal - (line.discount ?? 0)); // temp, tax added after\r\n }\r\n\r\n // Apply maxDiscountAmount cap — roll back excess from last reward line\r\n if (maxDiscountAmount != null && totalDiscountApplied > maxDiscountAmount) {\r\n const excess = totalDiscountApplied - maxDiscountAmount;\r\n for (let i = evalResult.rewardLines.length - 1; i >= 0; i--) {\r\n const reward = evalResult.rewardLines[i];\r\n const line = lines.find((l) => l.productId === reward.productId);\r\n if (!line) continue;\r\n const rollback = Math.min(excess, line.discount ?? 0);\r\n line.discount = (line.discount ?? 0) - rollback;\r\n line.total = Math.max(0, line.total + rollback);\r\n if (rollback > 0) break;\r\n }\r\n totalDiscountApplied = maxDiscountAmount;\r\n }\r\n\r\n return totalDiscountApplied;\r\n}\r\n\r\nasync function checkAndIncrementDiscountUsage(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n discountId: number,\r\n contactId: number\r\n): Promise<string | null> {\r\n if (!entityMap['discounts']) return null;\r\n\r\n const discountRepo = dataSource.getRepository(entityMap['discounts']);\r\n const discount = await discountRepo.findOne({\r\n where: { id: discountId } as import('typeorm').ObjectLiteral,\r\n });\r\n if (!discount) return `Discount #${discountId} not found`;\r\n\r\n const d = discount as {\r\n usedCount: number;\r\n maxTotalUsage?: number | null;\r\n maxUsagePerUser?: number | null;\r\n status: string;\r\n };\r\n\r\n // Atomic increment to avoid race conditions\r\n await dataSource.query(\r\n `UPDATE discounts SET \"usedCount\" = \"usedCount\" + 1 WHERE id = $1`,\r\n [discountId]\r\n );\r\n\r\n return null;\r\n}\r\n\r\nasync function decrementDiscountUsage(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n discountId: number,\r\n orderId: number\r\n): Promise<void> {\r\n if (!entityMap['discounts']) return;\r\n try {\r\n await dataSource.query(\r\n `UPDATE discounts SET \"usedCount\" = GREATEST(\"usedCount\" - 1, 0) WHERE id = $1`,\r\n [discountId]\r\n );\r\n if (entityMap['order_discounts']) {\r\n await dataSource.getRepository(entityMap['order_discounts']).delete({\r\n orderId,\r\n discountId,\r\n } as import('typeorm').ObjectLiteral);\r\n }\r\n } catch (err) {\r\n console.error('[discountEngine] decrementDiscountUsage failed:', err);\r\n }\r\n}\r\n\r\nasync function recordDiscountUsage(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n orderId: number,\r\n discountId: number,\r\n contactId: number,\r\n discountAmount: number\r\n): Promise<void> {\r\n if (!entityMap['order_discounts']) return;\r\n try {\r\n // Fetch couponCode from discounts table\r\n let discountCode = '';\r\n if (entityMap['discounts']) {\r\n const discountRow = await dataSource.getRepository(entityMap['discounts']).findOne({\r\n where: { id: discountId } as import('typeorm').ObjectLiteral,\r\n });\r\n discountCode = (discountRow as { couponCode?: string } | null)?.couponCode ?? '';\r\n }\r\n\r\n const odRepo = dataSource.getRepository(entityMap['order_discounts']);\r\n const orderItemRepo = dataSource.getRepository(entityMap.order_items);\r\n const items = await orderItemRepo.find({\r\n where: { orderId } as import('typeorm').ObjectLiteral,\r\n });\r\n\r\n const discountedItems = items.filter(\r\n (item) => Number((item as { discount?: number }).discount ?? 0) > 0\r\n );\r\n\r\n if (discountedItems.length === 0) {\r\n const firstItem = items[0];\r\n if (!firstItem) return;\r\n await odRepo.save(\r\n odRepo.create({\r\n orderId,\r\n orderItemId: (firstItem as { id: number }).id,\r\n discountId,\r\n discountCode,\r\n discountAmount,\r\n userId: contactId,\r\n } as object)\r\n );\r\n return;\r\n }\r\n\r\n for (const item of discountedItems) {\r\n const i = item as { id: number; discount?: number };\r\n await odRepo.save(\r\n odRepo.create({\r\n orderId,\r\n orderItemId: i.id,\r\n discountId,\r\n discountCode,\r\n discountAmount: Number(i.discount ?? 0),\r\n userId: contactId,\r\n } as object)\r\n );\r\n }\r\n } catch (err) {\r\n console.error('[discountEngine] recordDiscountUsage failed:', err);\r\n }\r\n}\r\n\r\nexport async function validateCoupon(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n couponCode: string,\r\n orderLines: Array<{ productId: number; quantity: number }>,\r\n currency: string = 'INR',\r\n contactId?: number | null,\r\n isAutomatic?: boolean,\r\n discountId?: number,\r\n vendorId?: number | null,\r\n): Promise<{\r\n valid: boolean;\r\n error?: string;\r\n discount?: {\r\n id: number;\r\n name: string;\r\n value: number;\r\n discountType: 'PERCENTAGE' | 'FLAT';\r\n canCombineWithOtherDiscounts: boolean;\r\n maxDiscountAmount?: number | null;\r\n rewardProductIds: number[];\r\n rewardLines: Array<{ productId: number; quantity: number }>;\r\n calculatedDiscount: number;\r\n };\r\n}> {\r\n if (!entityMap['discounts']) return { valid: false, error: 'Discounts not configured' };\r\n\r\n const discountRepo = dataSource.getRepository(entityMap['discounts']);\r\n let row: import('typeorm').ObjectLiteral | null = null;\r\n if (discountId) {\r\n row = await discountRepo.findOne({\r\n where: withDiscountVendorWhere({ id: discountId, status: 'ACTIVE' }, vendorId),\r\n });\r\n } else if (isAutomatic) {\r\n row = await discountRepo.findOne({\r\n where: withDiscountVendorWhere({ isAutomatic: true, status: 'ACTIVE' }, vendorId),\r\n order: { value: 'DESC' } as import('typeorm').ObjectLiteral,\r\n });\r\n } else {\r\n row = await discountRepo.findOne({\r\n where: withDiscountVendorWhere(\r\n { couponCode: couponCode.trim().toUpperCase(), status: 'ACTIVE' },\r\n vendorId\r\n ),\r\n });\r\n }\r\n if (!row) return { valid: false, error: 'Invalid or expired coupon code' };\r\n\r\n const d = row as {\r\n id: number;\r\n name: string;\r\n value: number;\r\n discountType: 'PERCENTAGE' | 'FLAT';\r\n canCombineWithOtherDiscounts: boolean;\r\n maxDiscountAmount?: number | null;\r\n validFrom: Date | string;\r\n validUntil: Date | string;\r\n status: string;\r\n usedCount: number;\r\n maxTotalUsage?: number | null;\r\n maxUsagePerUser?: number | null;\r\n };\r\n\r\n // Check max total usage\r\n if (d.maxTotalUsage != null && d.usedCount >= d.maxTotalUsage) {\r\n return { valid: false, error: 'Discount usage limit has been reached' };\r\n }\r\n\r\n // Check max usage per user\r\n if (contactId != null && d.maxUsagePerUser != null) {\r\n try {\r\n const userUsage = await dataSource.query(\r\n `SELECT COUNT(DISTINCT od.\"orderId\") as count FROM order_discounts od\r\n WHERE od.\"discountId\" = $1 \r\n AND od.\"userId\" = $2`,\r\n [d.id, contactId]\r\n );\r\n const usageCount = Number(userUsage?.[0]?.count ?? 0);\r\n if (usageCount >= d.maxUsagePerUser) {\r\n return { valid: false, error: 'You have reached the maximum usage limit for this discount' };\r\n }\r\n } catch { /* ignore */ }\r\n }\r\n\r\n // Build flat rules\r\n const flatRules: DiscountFlatRule[] = entityMap['discount_rules']\r\n ? (await dataSource.getRepository(entityMap['discount_rules']).find({\r\n where: { discountId: d.id } as import('typeorm').ObjectLiteral,\r\n })) as DiscountFlatRule[]\r\n : [];\r\n\r\n const discountForEval: DiscountForEval = { ...d, rules: flatRules };\r\n\r\n // Check Nth order condition\r\n const nthOrderRule = flatRules.find(\r\n (r) => r.type === 'order' && r.subType === 'nthOrder'\r\n );\r\n if (nthOrderRule && contactId != null) {\r\n try {\r\n const v = nthOrderRule.value && 'v' in nthOrderRule.value\r\n ? Number(nthOrderRule.value.v)\r\n : 1;\r\n const orderCount = await dataSource.query(\r\n `SELECT COUNT(*) as count FROM orders WHERE \"contactId\" = $1 AND deleted = false`,\r\n [contactId]\r\n );\r\n const count = Number(orderCount?.[0]?.count ?? 0);\r\n if (count < v - 1) {\r\n return {\r\n valid: false,\r\n error: `This discount requires at least ${v} orders. You have ${count + 1}.`,\r\n };\r\n }\r\n } catch { /* ignore */ }\r\n }\r\n\r\n // Calculate preview totals\r\n const { lines } = await calculateOrderTotalsFromLines(\r\n dataSource,\r\n entityMap,\r\n orderLines,\r\n currency,\r\n null,\r\n vendorId\r\n );\r\n\r\n const cartLines: DiscountCartLine[] = lines\r\n .filter((l) => l.found && l.productId != null)\r\n .map((l) => ({\r\n productId: l.productId as number,\r\n quantity: l.quantity,\r\n unitPrice: l.unitPrice,\r\n subtotal: l.subtotal,\r\n }));\r\n\r\n const evalResult = evaluateDiscount(discountForEval, cartLines);\r\n\r\n if (!evalResult.conditionsMet) {\r\n return { valid: false, error: evalResult.reason ?? 'Discount conditions not met' };\r\n }\r\n\r\n // Clone lines to apply discount on\r\n const clonedLines = lines.map((l) => ({ ...l }));\r\n const calculatedDiscount = applyDiscountToOrderLines(clonedLines, evalResult, d.maxDiscountAmount);\r\n\r\n // Collect reward product ids for BXGY\r\n const rewardProductIds = evalResult.rewardLines.map((r) => r.productId);\r\n\r\n return {\r\n valid: true,\r\n discount: {\r\n id: d.id,\r\n name: d.name,\r\n value: d.value,\r\n discountType: d.discountType,\r\n canCombineWithOtherDiscounts: d.canCombineWithOtherDiscounts,\r\n maxDiscountAmount: d.maxDiscountAmount,\r\n rewardProductIds,\r\n rewardLines: evalResult.rewardLines.map((r) => ({\r\n productId: r.productId,\r\n quantity: r.quantity,\r\n })),\r\n calculatedDiscount,\r\n },\r\n };\r\n}\r\n\r\n// ─── Order totals types ───────────────────────────────────────────────────────\r\n\r\nexport type OrderTotalsLine = {\r\n productId: number | null;\r\n productName: string;\r\n found: boolean;\r\n unitPrice: number;\r\n quantity: number;\r\n subtotal: number;\r\n taxRate: number;\r\n taxCode: string | null;\r\n tax: number;\r\n discount: number;\r\n total: number;\r\n};\r\n\r\n/** When present on the request body, `orderLines` replaces comma-separated product-name `itemsSummary`. */\r\nexport function normalizeOrderLinesInput(raw: unknown): Array<{ productId: number; quantity: number }> | null {\r\n if (raw === undefined) return null;\r\n if (!Array.isArray(raw)) return null;\r\n const merged = new Map<number, number>();\r\n for (const row of raw) {\r\n if (row == null || typeof row !== 'object') continue;\r\n const r = row as Record<string, unknown>;\r\n const productId = Number(r.productId);\r\n if (!Number.isFinite(productId) || productId <= 0) continue;\r\n const qRaw = Number(r.quantity ?? 1);\r\n const q = Number.isFinite(qRaw) ? Math.min(99999, Math.max(1, Math.floor(qRaw))) : 1;\r\n merged.set(productId, (merged.get(productId) ?? 0) + q);\r\n }\r\n return [...merged.entries()].map(([productId, quantity]) => ({ productId, quantity }));\r\n}\r\n\r\nconst ORDER_STATUS_CONFIRMED = 'confirmed';\r\n\r\nexport type OrderInventorySnapshot = {\r\n status: string;\r\n lines: Array<{ productId: number; quantity: number }>;\r\n};\r\n\r\nexport function orderInventorySnapshotFromRow(order: {\r\n status?: string;\r\n items?: Array<{ productId: number; quantity: unknown }>;\r\n}): OrderInventorySnapshot {\r\n return {\r\n status: order.status ?? 'pending',\r\n lines: (order.items ?? [])\r\n .map((i) => ({\r\n productId: Number(i.productId),\r\n quantity: Math.max(0, Math.floor(Number(i.quantity) || 0)),\r\n }))\r\n .filter((l) => l.productId > 0 && l.quantity > 0),\r\n };\r\n}\r\n\r\nfunction mergeInventoryLinesByProduct(\r\n lines: Array<{ productId: number; quantity: number }>\r\n): Map<number, number> {\r\n const m = new Map<number, number>();\r\n for (const { productId, quantity } of lines) {\r\n if (!Number.isFinite(productId) || productId <= 0 || quantity <= 0) continue;\r\n m.set(productId, (m.get(productId) ?? 0) + quantity);\r\n }\r\n return m;\r\n}\r\n\r\n/** Validate physical products have enough stock for a confirmed deduction. */\r\nexport async function validateInventoryForConfirmedOrderLines(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n calcLines: OrderTotalsLine[]\r\n): Promise<string | null> {\r\n const productRepo = dataSource.getRepository(entityMap.products);\r\n const merged = mergeInventoryLinesByProduct(\r\n calcLines\r\n .filter((l) => l.found && l.productId != null)\r\n .map((l) => ({ productId: l.productId as number, quantity: l.quantity }))\r\n );\r\n for (const [productId, qty] of merged) {\r\n const row = await productRepo.findOne({\r\n where: { id: productId, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n if (!row) return `Product #${productId} not found`;\r\n if ((row as { type?: string }).type === 'service') continue;\r\n const cur = Number((row as { quantity: number }).quantity ?? 0);\r\n if (cur < qty) {\r\n const name = (row as { name?: string | null }).name ?? String(productId);\r\n return `Insufficient stock for ${name}: available ${cur}, required ${qty}`;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nasync function applyInventoryDeltaForMergedLines(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n merged: Map<number, number>,\r\n sign: -1 | 1,\r\n validateDeduct: boolean\r\n): Promise<string | null> {\r\n const productRepo = dataSource.getRepository(entityMap.products);\r\n for (const [productId, qty] of merged) {\r\n const row = await productRepo.findOne({\r\n where: { id: productId, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n if (!row) return `Product #${productId} not found`;\r\n if ((row as { type?: string }).type === 'service') continue;\r\n const cur = Number((row as { quantity: number }).quantity ?? 0);\r\n if (sign === -1) {\r\n if (validateDeduct && cur < qty) {\r\n const name = (row as { name?: string | null }).name ?? String(productId);\r\n return `Insufficient stock for ${name}: available ${cur}, required ${qty}`;\r\n }\r\n await productRepo.update(productId, { quantity: Math.max(0, cur - qty) } as import('typeorm').ObjectLiteral);\r\n } else {\r\n await productRepo.update(productId, { quantity: cur + qty } as import('typeorm').ObjectLiteral);\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/** Use when an order may already be confirmed (stock already deducted): DB qty + prior committed lines must cover the next confirmed need. */\r\nexport async function validateInventoryForOrderBecomingConfirmed(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n prevSnap: OrderInventorySnapshot | null,\r\n nextLines: Array<{ productId: number; quantity: number }>\r\n): Promise<string | null> {\r\n const mergedNext = mergeInventoryLinesByProduct(nextLines);\r\n const productRepo = dataSource.getRepository(entityMap.products);\r\n const prevByProduct =\r\n prevSnap?.status === ORDER_STATUS_CONFIRMED\r\n ? mergeInventoryLinesByProduct(prevSnap.lines)\r\n : new Map<number, number>();\r\n\r\n for (const [productId, need] of mergedNext) {\r\n const row = await productRepo.findOne({\r\n where: { id: productId, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n if (!row) return `Product #${productId} not found`;\r\n if ((row as { type?: string }).type === 'service') continue;\r\n let available = Number((row as { quantity: number }).quantity ?? 0);\r\n available += prevByProduct.get(productId) ?? 0;\r\n if (available < need) {\r\n const name = (row as { name?: string | null }).name ?? String(productId);\r\n return `Insufficient stock for ${name}: available ${available}, required ${need}`;\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/**\r\n * When an order leaves \"confirmed\", restore stock for its lines; when it becomes \"confirmed\", deduct.\r\n * Restore runs before deduct so line edits while staying confirmed net correctly.\r\n */\r\nexport async function reconcileOrderInventoryBetweenSnapshots(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n prev: OrderInventorySnapshot,\r\n next: OrderInventorySnapshot\r\n): Promise<string | null> {\r\n const wasConfirmed = prev.status === ORDER_STATUS_CONFIRMED;\r\n const isConfirmed = next.status === ORDER_STATUS_CONFIRMED;\r\n if (wasConfirmed) {\r\n const merged = mergeInventoryLinesByProduct(prev.lines);\r\n const err = await applyInventoryDeltaForMergedLines(dataSource, entityMap, merged, 1, false);\r\n if (err) return err;\r\n }\r\n if (isConfirmed) {\r\n const merged = mergeInventoryLinesByProduct(next.lines);\r\n const err = await applyInventoryDeltaForMergedLines(dataSource, entityMap, merged, -1, true);\r\n if (err) return err;\r\n }\r\n return null;\r\n}\r\n\r\n/** Resolve GST/tax rate for a product (product_taxes link, else vendor default / GST tax). */\r\nasync function resolveProductTaxRate(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n productId: number,\r\n productVendorId?: number | null\r\n): Promise<{ taxRate: number; taxCode: string | null }> {\r\n if (!entityMap.product_taxes || !entityMap.taxes) {\r\n return { taxRate: 0, taxCode: null };\r\n }\r\n const productTaxRepo = dataSource.getRepository(entityMap.product_taxes);\r\n const taxRepo = dataSource.getRepository(entityMap.taxes);\r\n\r\n const productTax = await productTaxRepo.findOne({\r\n where: { productId } as import('typeorm').ObjectLiteral,\r\n });\r\n if (productTax) {\r\n const taxId = Number((productTax as { taxId: number }).taxId);\r\n const taxRecord = await taxRepo.findOne({\r\n where: { id: taxId } as import('typeorm').ObjectLiteral,\r\n });\r\n if (taxRecord) {\r\n const ptRate = (productTax as { rate?: number | string | null }).rate;\r\n const fromLink =\r\n ptRate != null && String(ptRate).trim() !== '' ? Number(ptRate) : NaN;\r\n const taxRate = Number.isFinite(fromLink)\r\n ? fromLink\r\n : Number((taxRecord as { rate?: number }).rate ?? 0);\r\n return {\r\n taxRate: Number.isFinite(taxRate) ? taxRate : 0,\r\n taxCode: (taxRecord as { slug?: string | null }).slug ?? null,\r\n };\r\n }\r\n }\r\n\r\n let vendorId = productVendorId;\r\n if ((vendorId == null || !Number.isFinite(vendorId)) && entityMap.products) {\r\n const product = await dataSource.getRepository(entityMap.products).findOne({\r\n where: { id: productId, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n const vid = Number((product as { vendorId?: number } | null)?.vendorId);\r\n if (Number.isFinite(vid) && vid > 0) vendorId = vid;\r\n }\r\n\r\n if (vendorId != null && Number.isFinite(vendorId) && vendorId > 0) {\r\n const defaultTax = await taxRepo.findOne({\r\n where: {\r\n vendorId,\r\n isDefault: true,\r\n active: true,\r\n deleted: false,\r\n } as import('typeorm').ObjectLiteral,\r\n });\r\n if (defaultTax) {\r\n return {\r\n taxRate: Number((defaultTax as { rate?: number }).rate ?? 0),\r\n taxCode: (defaultTax as { slug?: string | null }).slug ?? null,\r\n };\r\n }\r\n const gstTax = await taxRepo\r\n .createQueryBuilder('tax')\r\n .where('tax.vendorId = :vendorId', { vendorId })\r\n .andWhere('tax.deleted = :del', { del: false })\r\n .andWhere('tax.active = :act', { act: true })\r\n .andWhere('(LOWER(tax.slug) = :gst OR LOWER(tax.name) LIKE :gstName)', {\r\n gst: 'gst',\r\n gstName: '%gst%',\r\n })\r\n .orderBy('tax.id', 'ASC')\r\n .getOne();\r\n if (gstTax) {\r\n return {\r\n taxRate: Number((gstTax as { rate?: number }).rate ?? 0),\r\n taxCode: (gstTax as { slug?: string | null }).slug ?? null,\r\n };\r\n }\r\n }\r\n\r\n return { taxRate: 0, taxCode: null };\r\n}\r\n\r\n// ─── calculateOrderTotalsFromLines ────────────────────────────────────────────\r\n// [Step 5+6] Added optional discountId parameter. When provided, evaluates the\r\n// discount rules against the built lines and applies the result before returning.\r\n\r\nexport async function calculateOrderTotalsFromLines(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n lineInputs: Array<{ productId: number; quantity: number }>,\r\n currency: string = 'INR',\r\n discountId?: number | null,\r\n vendorId?: number | null\r\n): Promise<{\r\n subtotal: number;\r\n discount: number;\r\n tax: number;\r\n total: number;\r\n lines: OrderTotalsLine[];\r\n}> {\r\n const productRepo = dataSource.getRepository(entityMap.products);\r\n const productTaxRepo = dataSource.getRepository(entityMap.product_taxes);\r\n const taxRepo = dataSource.getRepository(entityMap.taxes);\r\n\r\n let exchangeRate = 1;\r\n if (currency !== 'INR' && entityMap['currency_exchange']){\r\n const exchangeRepo = dataSource.getRepository(entityMap['currency_exchange']);\r\n const directRate = await exchangeRepo.findOne({\r\n where: { fromCurrency: 'INR', toCurrency: currency } as import('typeorm').ObjectLiteral\r\n });\r\n if (directRate){\r\n exchangeRate = Number((directRate as { rate: number }).rate);\r\n } else {\r\n const inverseRate = await exchangeRepo.findOne({\r\n where: { fromCurrency: currency, toCurrency: 'INR' } as import('typeorm').ObjectLiteral\r\n });\r\n if (inverseRate){\r\n exchangeRate = 1 / Number((inverseRate as { rate: number }).rate);\r\n }\r\n }\r\n }\r\n let orderSubTotal = 0;\r\n let orderDiscount = 0;\r\n let orderTax = 0;\r\n let orderTotal = 0;\r\n\r\n const lines: OrderTotalsLine[] = [];\r\n\r\n for (const { productId, quantity } of lineInputs) {\r\n const product = await productRepo.findOne({\r\n where: { id: productId, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n\r\n if (!product) {\r\n lines.push({\r\n productId,\r\n productName: `Product #${productId}`,\r\n found: false,\r\n unitPrice: 0,\r\n quantity,\r\n subtotal: 0,\r\n taxRate: 0,\r\n taxCode: null,\r\n tax: 0,\r\n discount: 0,\r\n total: 0,\r\n });\r\n continue;\r\n }\r\n\r\n const p = product as {\r\n id: number;\r\n name: string | null;\r\n price: number;\r\n hsn?: string | null;\r\n uom?: string | null;\r\n type?: string | null;\r\n vendorId?: number;\r\n };\r\n\r\n const { taxRate, taxCode } = await resolveProductTaxRate(\r\n dataSource,\r\n entityMap,\r\n p.id,\r\n vendorId ?? p.vendorId\r\n );\r\n\r\n const unitPrice = Math.round(Number(p.price ?? 0) * exchangeRate * 100) / 100;\r\n const subtotal = unitPrice * quantity;\r\n // discount starts at 0 — applyDiscountToOrderLines fills it in below\r\n const discount = 0;\r\n const discountedAmount = subtotal - discount;\r\n const tax = (discountedAmount * taxRate) / 100;\r\n const total = discountedAmount + tax;\r\n\r\n orderSubTotal += subtotal;\r\n orderDiscount += discount;\r\n orderTax += tax;\r\n orderTotal += total;\r\n\r\n lines.push({\r\n productId: p.id,\r\n productName: p.name ?? `Product #${p.id}`,\r\n found: true,\r\n unitPrice,\r\n quantity,\r\n subtotal,\r\n taxRate,\r\n taxCode,\r\n tax,\r\n discount,\r\n total,\r\n });\r\n }\r\n\r\n // [Step 5+6] Evaluate and apply discount when discountId is provided\r\n if (discountId && entityMap['discounts']) {\r\n try {\r\n const discountRepo = dataSource.getRepository(entityMap['discounts']);\r\n const rulesRepo = entityMap['discount_rules']\r\n ? dataSource.getRepository(entityMap['discount_rules'])\r\n : null;\r\n\r\n const discountRow = await discountRepo.findOne({\r\n where: withDiscountVendorWhere({ id: discountId }, vendorId),\r\n });\r\n\r\n if (discountRow) {\r\n const flatRules: DiscountFlatRule[] = rulesRepo\r\n ? (await rulesRepo.find({ where: { discountId } as import('typeorm').ObjectLiteral })) as DiscountFlatRule[]\r\n : [];\r\n\r\n const discountForEval: DiscountForEval = {\r\n ...(discountRow as object),\r\n rules: flatRules,\r\n } as DiscountForEval;\r\n\r\n const cartLines: DiscountCartLine[] = lines\r\n .filter((l) => l.found && l.productId != null)\r\n .map((l) => ({\r\n productId: l.productId as number,\r\n quantity: l.quantity,\r\n unitPrice: l.unitPrice,\r\n subtotal: l.subtotal,\r\n }));\r\n\r\n const evalResult = evaluateDiscount(discountForEval, cartLines);\r\n\r\n if (evalResult.conditionsMet) {\r\n const totalDiscountApplied = applyDiscountToOrderLines(\r\n lines,\r\n evalResult,\r\n (discountRow as { maxDiscountAmount?: number | null }).maxDiscountAmount\r\n );\r\n // Recompute tax on discounted amount for each line\r\n for (const line of lines){\r\n if (!line.found || line.taxRate === 0) continue;\r\n const discountedAmount = line.subtotal - (line.discount ?? 0);\r\n line.tax = (discountedAmount * line.taxRate) / 100;\r\n line.total = discountedAmount + line.tax;\r\n }\r\n // Recompute order-level totals after discount is applied\r\n orderDiscount = totalDiscountApplied;\r\n orderTotal = lines.reduce((s, l) => s + l.total, 0);\r\n orderSubTotal = lines.reduce((s, l) => s + l.subtotal, 0);\r\n orderTax = lines.reduce((s, l) => s + l.tax, 0);\r\n }\r\n }\r\n } catch (err) {\r\n logCrudServerError('discount evaluation failed', {\r\n discountId,\r\n message: err instanceof Error ? err.message : String(err),\r\n });\r\n // Non-fatal — fall through with no discount applied\r\n }\r\n }\r\n\r\n return {\r\n subtotal: orderSubTotal,\r\n discount: orderDiscount,\r\n tax: orderTax,\r\n total: orderTotal,\r\n lines,\r\n };\r\n}\r\n\r\nexport async function calculateOrderTotals(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n itemsSummary: string,\r\n discountId?: number | null,\r\n vendorId?: number | null\r\n): Promise<{\r\n subtotal: number;\r\n discount: number;\r\n tax: number;\r\n total: number;\r\n lines: OrderTotalsLine[];\r\n}> {\r\n const productRepo = dataSource.getRepository(entityMap.products);\r\n const productTaxRepo = dataSource.getRepository(entityMap.product_taxes);\r\n const taxRepo = dataSource.getRepository(entityMap.taxes);\r\n\r\n const names = String(itemsSummary || '')\r\n .split(',')\r\n .map((s: string) => s.trim())\r\n .filter(Boolean);\r\n\r\n let orderSubTotal = 0;\r\n let orderDiscount = 0;\r\n let orderTax = 0;\r\n let orderTotal = 0;\r\n\r\n const lines: OrderTotalsLine[] = [];\r\n\r\n for (const itemName of names) {\r\n const product = await productRepo.findOne({\r\n where: { name: itemName, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n\r\n if (!product) {\r\n lines.push({\r\n productId: null,\r\n productName: itemName,\r\n found: false,\r\n unitPrice: 0,\r\n quantity: 0,\r\n subtotal: 0,\r\n taxRate: 0,\r\n taxCode: null,\r\n tax: 0,\r\n discount: 0,\r\n total: 0,\r\n });\r\n\r\n continue;\r\n }\r\n\r\n const { taxRate, taxCode } = await resolveProductTaxRate(\r\n dataSource,\r\n entityMap,\r\n Number((product as { id: number }).id),\r\n Number((product as { vendorId?: number }).vendorId)\r\n );\r\n\r\n const unitPrice = Number(product.price ?? 0);\r\n\r\n // TEMPORARY until proper quantity support added\r\n const quantity = 1;\r\n\r\n const subtotal = unitPrice * quantity;\r\n\r\n // will be updated by applyDiscountToOrderLines below\r\n const discount = 0;\r\n\r\n const discountedAmount = subtotal - discount;\r\n\r\n const tax = (discountedAmount * taxRate) / 100;\r\n\r\n const total = discountedAmount + tax;\r\n\r\n orderSubTotal += subtotal;\r\n orderDiscount += discount;\r\n orderTax += tax;\r\n orderTotal += total;\r\n\r\n lines.push({\r\n productId: product.id,\r\n productName: itemName,\r\n found: true,\r\n unitPrice,\r\n quantity,\r\n subtotal,\r\n taxRate,\r\n taxCode,\r\n tax,\r\n discount,\r\n total,\r\n });\r\n }\r\n\r\n // ADD before return statement:\r\n if (discountId && entityMap['discounts']) {\r\n try {\r\n const discountRepo = dataSource.getRepository(entityMap['discounts']);\r\n const rulesRepo = entityMap['discount_rules']\r\n ? dataSource.getRepository(entityMap['discount_rules'])\r\n : null;\r\n\r\n const discountRow = await discountRepo.findOne({\r\n where: withDiscountVendorWhere({ id: discountId }, vendorId),\r\n });\r\n\r\n if (discountRow) {\r\n const flatRules: DiscountFlatRule[] = rulesRepo\r\n ? (await rulesRepo.find({ where: { discountId } as import('typeorm').ObjectLiteral })) as DiscountFlatRule[]\r\n : [];\r\n\r\n const discountForEval: DiscountForEval = {\r\n ...(discountRow as object),\r\n rules: flatRules,\r\n } as DiscountForEval;\r\n\r\n const cartLines: DiscountCartLine[] = lines\r\n .filter((l) => l.found && l.productId != null)\r\n .map((l) => ({\r\n productId: l.productId as number,\r\n quantity: l.quantity,\r\n unitPrice: l.unitPrice,\r\n subtotal: l.subtotal,\r\n }));\r\n\r\n const evalResult = evaluateDiscount(discountForEval, cartLines);\r\n\r\n if (evalResult.conditionsMet) {\r\n const totalDiscountApplied = applyDiscountToOrderLines(\r\n lines,\r\n evalResult,\r\n (discountRow as { maxDiscountAmount?: number | null }).maxDiscountAmount\r\n );\r\n // Recompute tax on discounted amount for each line\r\n for (const line of lines) {\r\n if (!line.found || line.taxRate === 0) continue;\r\n const discountedAmount = line.subtotal - (line.discount ?? 0);\r\n line.tax = (discountedAmount * line.taxRate) / 100;\r\n line.total = discountedAmount + line.tax;\r\n }\r\n orderDiscount = totalDiscountApplied;\r\n orderTotal = lines.reduce((s, l) => s + l.total, 0);\r\n orderSubTotal = lines.reduce((s, l) => s + l.subtotal, 0);\r\n orderTax = lines.reduce((s, l) => s + l.tax, 0);\r\n }\r\n }\r\n } catch (err) {\r\n logCrudServerError('discount evaluation failed', {\r\n discountId,\r\n message: err instanceof Error ? err.message : String(err),\r\n });\r\n }\r\n }\r\n\r\n return {\r\n subtotal: orderSubTotal,\r\n discount: orderDiscount,\r\n tax: orderTax,\r\n total: orderTotal,\r\n lines,\r\n };\r\n}\r\n\r\nexport function createCrudHandler(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n options: CrudHandlerOptions\r\n) {\r\n const { requireAuth, json, requireEntityPermission: reqPerm, getCms, getVendorScope, getHydratedSessionUser } =\r\n options;\r\n const syncContactRowToErp = makeContactErpSync(dataSource, entityMap, getCms);\r\n const resolveScope = getVendorScope ?? (async (): Promise<VendorScope> => ({ type: 'all' }));\r\n\r\n async function vendorCreateContext(rawBody?: Record<string, unknown>): Promise<VendorScopedCreateContext> {\r\n const session = (await getHydratedSessionUser?.()) ?? null;\r\n return { rawBody, session };\r\n }\r\n\r\n async function authz(req: Request, resource: string, action: EntityCrudAction): Promise<Response | null> {\r\n const authError = await requireAuth(req);\r\n if (authError) return authError;\r\n if (!reqPerm) {\r\n return json({ error: 'Forbidden', reason: 'entity_rbac_required', entity: resource, action }, { status: 403 });\r\n }\r\n const pe = await reqPerm(req, resource, action);\r\n if (pe) return pe;\r\n return null;\r\n }\r\n\r\n /**\r\n * Admin (all-scope) create requests for vendor-owned resources must include vendorId.\r\n * For single-vendor installs, auto-assign that only vendor to keep create flows simple.\r\n */\r\n async function tryAssignSingleVendorOnAdminCreate(\r\n resource: string,\r\n scope: VendorScope,\r\n persistBody: Record<string, unknown>\r\n ): Promise<void> {\r\n if (!resourceUsesVendorScope(resource) || scope.type !== 'all') return;\r\n const currentVendorId = Number(persistBody.vendorId);\r\n if (Number.isFinite(currentVendorId) && currentVendorId > 0) return;\r\n if (!entityMap.vendors) return;\r\n\r\n const vendorRepo = dataSource.getRepository(entityMap.vendors);\r\n const where = mergeDeletedFalseWhere(vendorRepo, {});\r\n const rows = await vendorRepo.find({\r\n where: where as import('typeorm').ObjectLiteral,\r\n order: { id: 'ASC' } as import('typeorm').ObjectLiteral,\r\n take: 2,\r\n });\r\n if (rows.length === 1) {\r\n const onlyVendorId = Number((rows[0] as Record<string, unknown>).id);\r\n if (Number.isFinite(onlyVendorId) && onlyVendorId > 0) {\r\n persistBody.vendorId = onlyVendorId;\r\n }\r\n }\r\n }\r\n\r\n return {\r\n async GET(req: Request, resource: string) {\r\n const authError = await authz(req, resource, 'read');\r\n if (authError) return authError;\r\n const entity = entityMap[resource];\r\n if (!resource || !entity) {\r\n logCrudClientError('GET list', {\r\n reason: 'invalid_resource',\r\n resource,\r\n hasEntity: Boolean(entity),\r\n entityMapHasLlmAgents: Boolean(entityMap.llm_agents),\r\n entityMapKeyCount: Object.keys(entityMap).length,\r\n });\r\n return json({ error: 'Invalid resource' }, { status: 400 });\r\n }\r\n const { searchParams } = new URL(req.url);\r\n const page = Number(searchParams.get('page')) || 1;\r\n const limit = Math.min(Number(searchParams.get('limit')) || 10, 100);\r\n const skip = (page - 1) * limit;\r\n const sortFieldRaw = searchParams.get('sortField') || 'createdAt';\r\n const sortOrder = searchParams.get('sortOrder') === 'desc' ? 'DESC' : 'ASC';\r\n const search = searchParams.get('search');\r\n\r\n if (resource === 'discounts') {\r\n const scope = await resolveScope();\r\n const repo = dataSource.getRepository(entity);\r\n const allowedSort = ['id', 'name', 'couponCode', 'discountType', 'value', 'status', 'validFrom', 'validUntil', 'usedCount'];\r\n const sortField = allowedSort.includes(sortFieldRaw) ? sortFieldRaw : 'id';\r\n const sortOrderDiscounts = searchParams.get('sortOrder') === 'asc' ? 'ASC' : 'DESC';\r\n\r\n const statusFilter = searchParams.get('status')?.trim();\r\n const typeFilter = searchParams.get('discountType')?.trim();\r\n const validFromFrom = searchParams.get('validFromFrom')?.trim();\r\n const validFromTo = searchParams.get('validFromTo')?.trim();\r\n const validUntilFrom = searchParams.get('validUntilFrom')?.trim();\r\n const validUntilTo = searchParams.get('validUntilTo')?.trim();\r\n const canCombine = searchParams.get('canCombineWithOtherDiscounts')?.trim();\r\n\r\n const qb = repo\r\n .createQueryBuilder('discount')\r\n .loadRelationCountAndMap('discount._rulesCount', 'discount.rules')\r\n .orderBy(`discount.${sortField}`, sortOrderDiscounts)\r\n .skip(skip)\r\n .take(limit);\r\n\r\n applyVendorScopeToQueryBuilder(qb, 'discount', scope);\r\n\r\n if (search && typeof search === 'string' && search.trim()) {\r\n const term = `%${search.trim()}%`;\r\n qb.andWhere(\r\n '(discount.name ILIKE :term OR discount.couponCode ILIKE :term OR discount.description ILIKE :term)',\r\n { term }\r\n );\r\n }\r\n if (statusFilter) qb.andWhere('discount.status = :status', { status: statusFilter });\r\n if (typeFilter) qb.andWhere('discount.discountType = :discountType', { discountType: typeFilter });\r\n if (canCombine === 'true' || canCombine === 'false') {\r\n qb.andWhere('discount.canCombineWithOtherDiscounts = :canCombine', { canCombine: canCombine === 'true' });\r\n }\r\n if (validFromFrom) qb.andWhere('discount.validFrom >= :validFromFrom', { validFromFrom: dayStartUtc(validFromFrom) });\r\n if (validFromTo) qb.andWhere('discount.validFrom <= :validFromTo', { validFromTo: dayEndUtc(validFromTo) });\r\n if (validUntilFrom) qb.andWhere('discount.validUntil >= :validUntilFrom', { validUntilFrom: dayStartUtc(validUntilFrom) });\r\n if (validUntilTo) qb.andWhere('discount.validUntil <= :validUntilTo', { validUntilTo: dayEndUtc(validUntilTo) });\r\n\r\n const valueMin = searchParams.get('valueMin')?.trim();\r\n const valueMax = searchParams.get('valueMax')?.trim();\r\n if (valueMin) {\r\n const n = Number(valueMin);\r\n if (Number.isFinite(n)) qb.andWhere('discount.value >= :valueMin', { valueMin: n });\r\n }\r\n if (valueMax) {\r\n const n = Number(valueMax);\r\n if (Number.isFinite(n)) qb.andWhere('discount.value <= :valueMax', { valueMax: n });\r\n }\r\n\r\n const [rows, total] = await qb.getManyAndCount();\r\n // Fetch store currency once\r\n let storeCurrency = 'INR';\r\n if (entityMap['configs']){\r\n try{\r\n const configRepo = dataSource.getRepository(entityMap['configs']);\r\n const curr = await configRepo.findOne({\r\n where: { settings: 'store', key: 'currency' } as import('typeorm').ObjectLiteral\r\n });\r\n storeCurrency = (curr as {value?: string} | null)?.value?.toUpperCase() ?? 'INR';\r\n } catch {/* fall back to INR */}\r\n }\r\n // Fetch exchange rates for all unique FLAT discount currencies in one pass\r\n const flatCurrencies = [\r\n ...new Set(\r\n (rows as Record<string, unknown>[])\r\n .filter((d) => d.discountType === 'FLAT' && d.currency !== storeCurrency)\r\n .map((d) => d.currency as string)\r\n ),\r\n ];\r\n const rateMap = new Map<string, number>();\r\n if (flatCurrencies.length > 0 && entityMap['currency_exchange']) {\r\n const exchangeRepo = dataSource.getRepository(entityMap['currency_exchange']);\r\n for (const fromCurrency of flatCurrencies) {\r\n try {\r\n const direct = await exchangeRepo.findOne({\r\n where: { fromCurrency, toCurrency: storeCurrency } as import('typeorm').ObjectLiteral,\r\n });\r\n if (direct) {\r\n rateMap.set(fromCurrency, Number((direct as { rate: number }).rate));\r\n } else {\r\n const inverse = await exchangeRepo.findOne({\r\n where: { fromCurrency: storeCurrency, toCurrency: fromCurrency } as import('typeorm').ObjectLiteral,\r\n });\r\n if (inverse) rateMap.set(fromCurrency, 1 / Number((inverse as { rate: number }).rate));\r\n }\r\n } catch { /* keep no entry — UI falls back to rate 1 */ }\r\n }\r\n }\r\n\r\n const data = (rows as Record<string, unknown>[]).map((d) => {\r\n const { _rulesCount, ...rest } = d as { _rulesCount?: number } & Record<string, unknown>;\r\n const discountCurrency = rest.currency as string;\r\n const exchangeRate =\r\n rest.discountType === 'FLAT' && discountCurrency !== storeCurrency\r\n ? (rateMap.get(discountCurrency) ?? 1)\r\n : 1;\r\n return {\r\n ...rest,\r\n rulesCount: _rulesCount ?? 0,\r\n storeCurrency: storeCurrency,\r\n exchangeRate: exchangeRate,\r\n };\r\n });\r\n return json({ total, page, limit, totalPages: Math.ceil(total / limit), data });\r\n }\r\n\r\n if (resource === 'orders') {\r\n const scope = await resolveScope();\r\n const repo = dataSource.getRepository(entity);\r\n const allowedSort = ['id', 'orderNumber', 'contactId', 'status', 'total', 'currency', 'createdAt', 'updatedAt'];\r\n const sortField = allowedSort.includes(sortFieldRaw) ? sortFieldRaw : 'createdAt';\r\n const sortOrderOrders = searchParams.get('sortOrder') === 'asc' ? 'ASC' : 'DESC';\r\n const statusFilter = searchParams.get('status')?.trim();\r\n const dateFrom = searchParams.get('dateFrom')?.trim();\r\n const dateTo = searchParams.get('dateTo')?.trim();\r\n const paymentRef = searchParams.get('paymentRef')?.trim();\r\n\r\n let orderIdsFromPayment: number[] | null = null;\r\n if (paymentRef && entityMap['payments']) {\r\n const paymentRepo = dataSource.getRepository(entityMap['payments']);\r\n const payments = await paymentRepo\r\n .createQueryBuilder('p')\r\n .select('p.orderId')\r\n .where('p.externalReference = :ref', { ref: paymentRef })\r\n .orWhere(\"p.metadata->>'razorpayPaymentId' = :ref\", { ref: paymentRef })\r\n .getRawMany<{ orderId: number }>();\r\n orderIdsFromPayment = payments.map((r) => r.orderId);\r\n if (orderIdsFromPayment.length === 0) {\r\n return json({ total: 0, page, limit, totalPages: 0, data: [] });\r\n }\r\n }\r\n\r\n const qb = repo\r\n .createQueryBuilder('order')\r\n .leftJoinAndSelect('order.contact', 'contact')\r\n .leftJoinAndSelect('order.items', 'items')\r\n .leftJoinAndSelect('items.product', 'product')\r\n .leftJoinAndSelect('product.collection', 'collection')\r\n .andWhere('order.deleted = :orderDel', { orderDel: false })\r\n .orderBy(`order.${sortField}`, sortOrderOrders)\r\n .skip(skip)\r\n .take(limit);\r\n\r\n applyVendorScopeToQueryBuilder(qb, 'order', scope);\r\n\r\n if (search && typeof search === 'string' && search.trim()) {\r\n const term = `%${search.trim()}%`;\r\n qb.andWhere(\r\n '(order.orderNumber ILIKE :term OR contact.name ILIKE :term OR contact.email ILIKE :term)',\r\n { term }\r\n );\r\n }\r\n if (statusFilter) qb.andWhere('order.status = :status', { status: statusFilter });\r\n if (dateFrom) qb.andWhere('order.createdAt >= :dateFrom', { dateFrom: new Date(dateFrom + 'T00:00:00.000Z') });\r\n if (dateTo) qb.andWhere('order.createdAt <= :dateTo', { dateTo: new Date(dateTo + 'T23:59:59.999Z') });\r\n const totalMin = searchParams.get('totalMin')?.trim();\r\n const totalMax = searchParams.get('totalMax')?.trim();\r\n if (totalMin) {\r\n const n = Number(totalMin);\r\n if (Number.isFinite(n)) qb.andWhere('order.total >= :totalMin', { totalMin: n });\r\n }\r\n if (totalMax) {\r\n const n = Number(totalMax);\r\n if (Number.isFinite(n)) qb.andWhere('order.total <= :totalMax', { totalMax: n });\r\n }\r\n const currency = searchParams.get('currency')?.trim();\r\n if (currency) qb.andWhere('order.currency ILIKE :orderCurrency', { orderCurrency: `%${currency}%` });\r\n if (orderIdsFromPayment && orderIdsFromPayment.length) qb.andWhere('order.id IN (:...orderIds)', { orderIds: orderIdsFromPayment });\r\n\r\n const [rows, total] = await qb.getManyAndCount();\r\n const data = (rows as Record<string, unknown>[]).map((order: Record<string, unknown>) => {\r\n const contact = order.contact as Record<string, unknown> | undefined;\r\n const items = (order.items as Array<{ product?: { name?: string; collection?: { name?: string } }; quantity: number }>) ?? [];\r\n const itemsSummary = items\r\n .map((i) => {\r\n const label = i.product?.collection?.name ?? i.product?.name ?? 'Product';\r\n return `${label} × ${i.quantity}`;\r\n })\r\n .join(', ') || '—';\r\n return {\r\n ...order,\r\n contact: contact ? { id: contact.id, name: contact.name, email: contact.email, phone: contact.phone } : null,\r\n itemsSummary,\r\n };\r\n });\r\n return json({ total, page, limit, totalPages: Math.ceil(total / limit), data });\r\n }\r\n\r\n // Payments list: include order + contact; search (customer), status, date, method, orderNumber\r\n if (resource === 'payments') {\r\n const scope = await resolveScope();\r\n const repo = dataSource.getRepository(entity);\r\n const allowedSort = ['id', 'orderId', 'amount', 'currency', 'status', 'method', 'paidAt', 'createdAt', 'updatedAt'];\r\n const sortField = allowedSort.includes(sortFieldRaw) ? sortFieldRaw : 'createdAt';\r\n const sortOrderPayments = searchParams.get('sortOrder') === 'asc' ? 'ASC' : 'DESC';\r\n const statusFilter = searchParams.get('status')?.trim();\r\n const dateFrom = searchParams.get('dateFrom')?.trim();\r\n const dateTo = searchParams.get('dateTo')?.trim();\r\n const methodFilter = searchParams.get('method')?.trim();\r\n const orderNumberParam = searchParams.get('orderNumber')?.trim();\r\n\r\n const qb = repo\r\n .createQueryBuilder('payment')\r\n .leftJoinAndSelect('payment.order', 'ord')\r\n .leftJoinAndSelect('ord.contact', 'orderContact')\r\n .leftJoinAndSelect('payment.contact', 'contact')\r\n .andWhere('payment.deleted = :payDel', { payDel: false })\r\n .orderBy(`payment.${sortField}`, sortOrderPayments)\r\n .skip(skip)\r\n .take(limit);\r\n\r\n applyVendorScopeToQueryBuilder(qb, 'payment', scope);\r\n\r\n if (search && typeof search === 'string' && search.trim()) {\r\n const term = `%${search.trim()}%`;\r\n qb.andWhere(\r\n '(orderContact.name ILIKE :term OR orderContact.email ILIKE :term OR contact.name ILIKE :term OR contact.email ILIKE :term)',\r\n { term }\r\n );\r\n }\r\n if (statusFilter) qb.andWhere('payment.status = :status', { status: statusFilter });\r\n if (dateFrom) qb.andWhere('payment.createdAt >= :dateFrom', { dateFrom: new Date(dateFrom + 'T00:00:00.000Z') });\r\n if (dateTo) qb.andWhere('payment.createdAt <= :dateTo', { dateTo: new Date(dateTo + 'T23:59:59.999Z') });\r\n const paidAtFrom = searchParams.get('paidAtFrom')?.trim();\r\n const paidAtTo = searchParams.get('paidAtTo')?.trim();\r\n if (paidAtFrom) {\r\n qb.andWhere('payment.paidAt >= :paidAtFrom', { paidAtFrom: new Date(paidAtFrom + 'T00:00:00.000Z') });\r\n }\r\n if (paidAtTo) {\r\n qb.andWhere('payment.paidAt <= :paidAtTo', { paidAtTo: new Date(paidAtTo + 'T23:59:59.999Z') });\r\n }\r\n if (methodFilter) qb.andWhere('payment.method = :method', { method: methodFilter });\r\n if (orderNumberParam) qb.andWhere('ord.orderNumber ILIKE :orderNumber', { orderNumber: `%${orderNumberParam}%` });\r\n const amountMin = searchParams.get('amountMin')?.trim();\r\n const amountMax = searchParams.get('amountMax')?.trim();\r\n if (amountMin) {\r\n const n = Number(amountMin);\r\n if (Number.isFinite(n)) qb.andWhere('payment.amount >= :amountMin', { amountMin: n });\r\n }\r\n if (amountMax) {\r\n const n = Number(amountMax);\r\n if (Number.isFinite(n)) qb.andWhere('payment.amount <= :amountMax', { amountMax: n });\r\n }\r\n const extRef = searchParams.get('externalReference')?.trim();\r\n if (extRef) {\r\n qb.andWhere('payment.externalReference ILIKE :extRef', { extRef: `%${extRef}%` });\r\n }\r\n\r\n const [rows, total] = await qb.getManyAndCount();\r\n const data = (rows as Record<string, unknown>[]).map((payment: Record<string, unknown>) => {\r\n const order = payment.order as Record<string, unknown> | undefined;\r\n const orderContact = order?.contact as Record<string, unknown> | undefined;\r\n const contact = payment.contact as Record<string, unknown> | undefined;\r\n const customer = orderContact ?? contact;\r\n return {\r\n ...payment,\r\n order: order ? { id: order.id, orderNumber: order.orderNumber, contact: orderContact ? { name: orderContact.name, email: orderContact.email } : null } : null,\r\n contact: customer ? { id: customer.id, name: customer.name, email: customer.email } : null,\r\n };\r\n });\r\n return json({ total, page, limit, totalPages: Math.ceil(total / limit), data });\r\n }\r\n\r\n // Vendor customers: join contact for list display\r\n if (resource === 'vendor_customers' && entityMap['customer']) {\r\n const scope = await resolveScope();\r\n const repo = dataSource.getRepository(entity);\r\n const qb = repo\r\n .createQueryBuilder('vc')\r\n .leftJoinAndSelect('vc.customer', 'customer')\r\n .leftJoinAndSelect('customer.user', 'user')\r\n .orderBy('vc.createdAt', sortOrder === 'DESC' ? 'DESC' : 'ASC')\r\n .skip(skip)\r\n .take(limit);\r\n applyVendorScopeToQueryBuilder(qb, 'vc', scope);\r\n if (search && typeof search === 'string' && search.trim()) {\r\n const term = `%${search.trim()}%`;\r\n qb.andWhere(\r\n '(customer.name ILIKE :term OR customer.email ILIKE :term OR customer.phone ILIKE :term)',\r\n { term }\r\n );\r\n }\r\n const [rows, total] = await qb.getManyAndCount();\r\n const data = (rows as Record<string, unknown>[]).map((row) => {\r\n const customer = row.customer as Record<string, unknown> | undefined;\r\n return {\r\n ...row,\r\n name: customer?.name ?? null,\r\n email: customer?.email ?? null,\r\n phone: customer?.phone ?? null,\r\n company: customer?.company ?? null,\r\n };\r\n });\r\n return json({ total, page, limit, totalPages: Math.ceil(total / limit), data });\r\n }\r\n\r\n // Products list: status and inventory filters\r\n if (resource === 'products') {\r\n const scope = await resolveScope();\r\n const repo = dataSource.getRepository(entity);\r\n const statusFilter = searchParams.get('status')?.trim();\r\n const inventory = searchParams.get('inventory')?.trim();\r\n let productWhere: Record<string, unknown> = {\r\n deleted: false,\r\n ...buildListFilterAndFromSearchParams(repo, searchParams),\r\n };\r\n productWhere = mergeVendorScopeIntoWhere(productWhere, scope, resource) as Record<string, unknown>;\r\n if (statusFilter) productWhere.status = statusFilter;\r\n if (inventory === 'in_stock') productWhere.quantity = MoreThan(0);\r\n if (inventory === 'out_of_stock') productWhere.quantity = 0;\r\n for (const key of ['brandId', 'categoryId', 'collectionId'] as const) {\r\n const raw = searchParams.get(key)?.trim();\r\n if (raw) {\r\n const n = Number(raw);\r\n if (Number.isFinite(n)) productWhere[key] = n;\r\n }\r\n }\r\n const featuredRaw = searchParams.get('featured')?.trim();\r\n if (featuredRaw === 'true' || featuredRaw === 'false') {\r\n productWhere.featured = featuredRaw === 'true';\r\n }\r\n if (search && typeof search === 'string' && search.trim()) {\r\n productWhere.name = ILike(`%${search.trim()}%`);\r\n }\r\n const productColumnNames = new Set(repo.metadata.columns.map((c) => c.propertyName));\r\n const defaultProductSort = pickDefaultListSortField(productColumnNames, repo.metadata.columns);\r\n const sortParam = (searchParams.get('sortField') ?? '').trim();\r\n const productSortField =\r\n sortParam && productColumnNames.has(sortParam) ? sortParam : defaultProductSort;\r\n const [rawData, total] = await repo.findAndCount({\r\n where: Object.keys(productWhere).length ? productWhere : undefined,\r\n skip,\r\n take: limit,\r\n order: { [productSortField]: sortOrder },\r\n });\r\n let convertedData: typeof rawData = rawData;\r\n try {\r\n if (entityMap['configs'] && entityMap['currency_exchange']) {\r\n const configRepo = dataSource.getRepository(entityMap['configs']);\r\n const currencyConfig = await configRepo.findOne({ where: { settings: 'store', key: 'currency' } as import('typeorm').ObjectLiteral });\r\n const activeCurrency = (currencyConfig as { value?: string } | null)?.value ?? 'INR';\r\n\r\n if (activeCurrency !== 'INR') {\r\n const exchangeRepo = dataSource.getRepository(entityMap['currency_exchange']);\r\n let rate: number | null = null;\r\n const directRate = await exchangeRepo.findOne({ where: { fromCurrency: 'INR', toCurrency: activeCurrency } as import('typeorm').ObjectLiteral });\r\n if (directRate) {\r\n rate = Number((directRate as { rate: number }).rate);\r\n } else {\r\n const inverseRate = await exchangeRepo.findOne({ where: { fromCurrency: activeCurrency, toCurrency: 'INR' } as import('typeorm').ObjectLiteral });\r\n if (inverseRate) rate = 1 / Number((inverseRate as { rate: number }).rate);\r\n }\r\n if (rate !== null) {\r\n convertedData = rawData.map((product) => {\r\n const p = product as Record<string, unknown>;\r\n return {\r\n ...p,\r\n price: p.price != null ? Math.round(Number(p.price) * rate! * 100) / 100 : p.price,\r\n compareAtPrice: p.compareAtPrice != null ? Math.round(Number(p.compareAtPrice) * rate! * 100) / 100 : p.compareAtPrice,\r\n _displayCurrency: activeCurrency,\r\n };\r\n });\r\n }\r\n }\r\n }\r\n } catch {\r\n convertedData = rawData;\r\n }\r\n return json({ total, page, limit, totalPages: Math.ceil(total / limit), data: convertedData });\r\n }\r\n\r\n // Contacts list: filters (type, orderId), optional includeSummary (orderCount, totalPaid)\r\n if (resource === 'contacts') {\r\n const repo = dataSource.getRepository(entity);\r\n const allowedSort = ['id', 'name', 'email', 'createdAt', 'type'];\r\n const sortField = allowedSort.includes(sortFieldRaw) ? sortFieldRaw : 'createdAt';\r\n const sortOrderContacts = searchParams.get('sortOrder') === 'asc' ? 'ASC' : 'DESC';\r\n const typeFilter = searchParams.get('type')?.trim();\r\n const orderIdParam = searchParams.get('orderId')?.trim();\r\n const includeSummary = searchParams.get('includeSummary') === '1';\r\n const vendorCustomersOnly = searchParams.get('vendorCustomers') === '1';\r\n const vendorIdParam = searchParams.get('vendorId')?.trim();\r\n const vendorIdFilter =\r\n vendorIdParam && !Number.isNaN(Number(vendorIdParam)) ? Number(vendorIdParam) : null;\r\n\r\n const qb = repo\r\n .createQueryBuilder('contact')\r\n .andWhere('contact.deleted = :contactDel', { contactDel: false })\r\n .orderBy(`contact.${sortField}`, sortOrderContacts)\r\n .skip(skip)\r\n .take(limit);\r\n\r\n if (search && typeof search === 'string' && search.trim()) {\r\n const term = `%${search.trim()}%`;\r\n qb.andWhere('(contact.name ILIKE :term OR contact.email ILIKE :term OR contact.phone ILIKE :term)', { term });\r\n }\r\n if (vendorCustomersOnly && entityMap.vendor_customers) {\r\n const scopeContacts = await resolveScope();\r\n applyVendorCustomersContactFilter(qb, 'contact', scopeContacts, vendorIdFilter);\r\n } else if (typeFilter) {\r\n qb.andWhere('contact.type = :type', { type: typeFilter });\r\n }\r\n if (orderIdParam) {\r\n const orderId = Number(orderIdParam);\r\n if (!Number.isNaN(orderId)) {\r\n qb.andWhere('contact.id IN (SELECT \"contactId\" FROM orders WHERE id = :orderId)', { orderId });\r\n }\r\n }\r\n\r\n if (includeSummary && entityMap['orders'] && entityMap['payments']) {\r\n qb.loadRelationCountAndMap('contact._orderCount', 'contact.orders');\r\n const [rows, total] = await qb.getManyAndCount();\r\n const contactIds = (rows as { id: number }[]).map((c) => c.id);\r\n const paymentRepo = dataSource.getRepository(entityMap['payments']);\r\n const paidByContact = await paymentRepo\r\n .createQueryBuilder('p')\r\n .select('p.contactId', 'contactId')\r\n .addSelect('COALESCE(SUM(CAST(p.amount AS DECIMAL)), 0)', 'total')\r\n .where('p.contactId IN (:...ids)', { ids: contactIds.length ? contactIds : [0] })\r\n .andWhere('p.status = :status', { status: 'completed' })\r\n .groupBy('p.contactId')\r\n .getRawMany<{ contactId: number; total: string }>();\r\n const totalPaidMap = new Map<number, number>(paidByContact.map((r) => [r.contactId, Number(r.total)]));\r\n const data = (rows as Record<string, unknown>[]).map((c) => {\r\n const { _orderCount, ...rest } = c as { _orderCount?: number; id: number };\r\n return {\r\n ...rest,\r\n orderCount: _orderCount ?? 0,\r\n totalPaid: totalPaidMap.get((rest as { id: number }).id) ?? 0,\r\n };\r\n });\r\n return json({ total, page, limit, totalPages: Math.ceil(total / limit), data });\r\n }\r\n\r\n const [data, total] = await qb.getManyAndCount();\r\n return json({ total, page, limit, totalPages: Math.ceil(total / limit), data });\r\n }\r\n\r\n const repo = dataSource.getRepository(entity);\r\n const typeFilter = searchParams.get('type');\r\n const columnNames = new Set(repo.metadata.columns.map((c) => c.propertyName));\r\n\r\n if (resource === 'media') {\r\n const qb = repo.createQueryBuilder('m');\r\n const parentIdParam = searchParams.get('parentId');\r\n if (parentIdParam != null && parentIdParam !== '') {\r\n const n = Number(parentIdParam);\r\n if (!Number.isFinite(n)) return json({ error: 'Invalid parentId' }, { status: 400 });\r\n qb.where('m.deleted = :mediaDel AND m.parentId = :pid', { mediaDel: false, pid: n });\r\n } else {\r\n qb.where('m.deleted = :mediaDel AND m.parentId IS NULL', { mediaDel: false });\r\n }\r\n if (search && typeof search === 'string' && search.trim()) {\r\n qb.andWhere('m.filename ILIKE :search', { search: `%${search.trim()}%` });\r\n }\r\n if (typeFilter) {\r\n if (typeFilter === 'folder') {\r\n qb.andWhere('m.kind = :folderKind', { folderKind: 'folder' });\r\n }\r\n else if (typeFilter === 'file') {\r\n qb.andWhere('m.kind = :fileKind', { fileKind: 'file' });\r\n }\r\n else if (typeFilter === 'image') {\r\n qb.andWhere('m.mimeType LIKE :imageMimeType', { imageMimeType: 'image/%' });\r\n }\r\n else if (typeFilter === 'video') {\r\n qb.andWhere('m.mimeType LIKE :videoMimeType', { videoMimeType: 'video/%' });\r\n }\r\n else if (typeFilter === 'audio') {\r\n qb.andWhere('m.mimeType LIKE :audioMimeType', { audioMimeType: 'audio/%' });\r\n }\r\n else if (typeFilter === 'Document') {\r\n qb.andWhere('m.mimeType LIKE :documentMimeType', { documentMimeType: 'application/pdf' });\r\n }\r\n else if (typeFilter === 'application') {\r\n qb.andWhere('m.kind = :folderKind', { folderKind: 'folder' });\r\n }\r\n }\r\n const allowedSort = ['filename', 'createdAt', 'id'];\r\n const sf = allowedSort.includes(sortFieldRaw) ? sortFieldRaw : 'filename';\r\n const so = sortOrder === 'DESC' ? 'DESC' : 'ASC';\r\n // qb.orderBy('CASE WHEN m.kind = :fk THEN 0 ELSE 1 END', 'ASC')\r\n // .addOrderBy(`m.${sf}`, so)\r\n // .setParameter('fk', 'folder')\r\n qb.orderBy(`m.${sf}`, so)\r\n .skip(skip)\r\n .take(limit);\r\n const [rows, total] = await qb.getManyAndCount();\r\n const mediaRows = rows as { id: number; kind?: string; size?: number }[];\r\n const folderIds = mediaRows.filter((m) => m.kind === 'folder').map((m) => m.id);\r\n let data: typeof rows = rows;\r\n if (folderIds.length > 0) {\r\n const sizeMap = await aggregateMediaFolderFileSizes(dataSource, folderIds);\r\n data = mediaRows.map((m) =>\r\n m.kind === 'folder' ? { ...m, size: sizeMap.get(m.id) ?? 0 } : m\r\n ) as typeof rows;\r\n }\r\n return json({ total, page, limit, totalPages: Math.ceil(total / limit), data });\r\n }\r\n\r\n const defaultSortField = pickDefaultListSortField(columnNames, repo.metadata.columns);\r\n const sortParam = (searchParams.get('sortField') ?? '').trim();\r\n const sortField = sortParam && columnNames.has(sortParam) ? sortParam : defaultSortField;\r\n let where: Record<string, unknown>[] | Record<string, unknown> = {};\r\n if (search) {\r\n where = buildSearchWhereClause(repo, search);\r\n }\r\n where = mergeListWhereAnd(where, buildListFilterAndFromSearchParams(repo, searchParams));\r\n const exactParamWhere = buildExactListParamWhere(repo, searchParams);\r\n if (Object.keys(exactParamWhere).length > 0) {\r\n if (Array.isArray(where)) {\r\n where = where.map((w) => ({ ...w, ...exactParamWhere }));\r\n } else if (where && typeof where === 'object' && Object.keys(where).length > 0) {\r\n where = { ...where, ...exactParamWhere };\r\n } else {\r\n where = exactParamWhere;\r\n }\r\n }\r\n where = mergeDeletedFalseWhere(repo, where);\r\n if (resourceUsesVendorScope(resource)) {\r\n const scope = await resolveScope();\r\n where = mergeVendorScopeIntoWhere(where, scope, resource);\r\n }\r\n let data: import('typeorm').ObjectLiteral[];\r\n let total: number;\r\n try {\r\n const r = await repo.findAndCount({\r\n skip,\r\n take: limit,\r\n order: { [sortField]: sortOrder },\r\n where,\r\n });\r\n data = r[0];\r\n total = r[1];\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n logCrudServerError('GET list query failed', { resource, sortField, sortOrder, message });\r\n throw err;\r\n }\r\n return json({ total, page, limit, totalPages: Math.ceil(total / limit), data });\r\n },\r\n\r\n async POST(req: Request, resource: string) {\r\n const authError = await authz(req, resource, 'create');\r\n if (authError) return authError;\r\n const entity = entityMap[resource];\r\n if (!resource || !entity) {\r\n logCrudClientError('POST create', {\r\n reason: 'invalid_resource',\r\n resource,\r\n hasEntity: Boolean(entity),\r\n entityMapHasLlmAgents: Boolean(entityMap.llm_agents),\r\n });\r\n return json({ error: 'Invalid resource' }, { status: 400 });\r\n }\r\n const rawPostBody = await req.json();\r\n if (!rawPostBody || typeof rawPostBody !== 'object' || Object.keys(rawPostBody).length === 0) {\r\n logCrudClientError('POST create', {\r\n reason: 'invalid_request_payload',\r\n resource,\r\n rawType: rawPostBody == null ? 'nullish' : typeof rawPostBody,\r\n keyCount: rawPostBody && typeof rawPostBody === 'object' ? Object.keys(rawPostBody).length : 0,\r\n });\r\n return json({ error: 'Invalid request payload' }, { status: 400 });\r\n }\r\n const body = rawPostBody as Record<string, unknown>;\r\n\r\n if (resource === 'discounts') {\r\n const repo = dataSource.getRepository(entity);\r\n if (!body.name || String(body.name).trim() === '') return json({ error: 'name is required' }, { status: 400 });\r\n if (!body.isAutomatic && (!body.couponCode || String(body.couponCode).trim() === '')) {\r\n return json({ error: 'couponCode is required' }, { status: 400 });\r\n }\r\n if (!body.discountType) return json({ error: 'discountType is required' }, { status: 400 });\r\n if (body.value == null || body.value === '') return json({ error: 'value is required' }, { status: 400 });\r\n if (!body.validFrom || !body.validUntil) {\r\n return json({ error: 'validFrom and validUntil are required' }, { status: 400 });\r\n }\r\n const validationErr = validateDiscountBody(body);\r\n if (validationErr) return json({ error: validationErr }, { status: 400 });\r\n\r\n const couponCode = String(body.couponCode).trim().toUpperCase();\r\n const persistBody = pickColumnUpdates(repo, { ...body, couponCode });\r\n const scopeDiscount = await resolveScope();\r\n await tryAssignSingleVendorOnAdminCreate(resource, scopeDiscount, persistBody);\r\n const vendorIdCheck = requireVendorIdForScopedCreate(\r\n resource,\r\n persistBody,\r\n scopeDiscount,\r\n repo,\r\n await vendorCreateContext(body)\r\n );\r\n if (!vendorIdCheck.ok) {\r\n return json({ error: vendorIdCheck.error }, { status: vendorIdCheck.status });\r\n }\r\n const discountVendorId = Number(persistBody.vendorId);\r\n const isUnique = await assertDiscountCouponCodeUnique(repo, couponCode, discountVendorId);\r\n if (!isUnique && !body.isAutomatic) {\r\n return json({ error: 'Coupon code already exists for this store. Please use a unique coupon code.' }, { status: 400 });\r\n }\r\n\r\n sanitizeBodyForEntity(repo, persistBody);\r\n let created: import('typeorm').ObjectLiteral;\r\n try {\r\n created = await repo.save(repo.create(persistBody as object));\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n logCrudServerError('POST discounts save failed', { message, persistKeys: Object.keys(persistBody) });\r\n throw err;\r\n }\r\n if (Array.isArray(body.rules) && body.rules.length > 0) {\r\n await persistDiscountRules(dataSource, entityMap, (created as { id: number }).id, body.rules as unknown[]);\r\n }\r\n const reloaded = await repo.findOne({\r\n where: { id: (created as { id: number }).id } as import('typeorm').ObjectLiteral,\r\n relations: ['rules'],\r\n });\r\n return json(reloaded ?? created, { status: 201 });\r\n }\r\n\r\n if (resource === 'vendor_customers'){\r\n if (!entityMap['customer']){\r\n return json({ error: 'Customer entity not configured' }, { status: 503 });\r\n }\r\n if (!entityMap['users']){\r\n return json({ error: 'Users entity not configured' }, { status: 503 });\r\n }\r\n let customerGroupId: number | null = null;\r\n if (entityMap['user_groups']){\r\n const userGroupRepo = dataSource.getRepository(entityMap['user_groups']);\r\n const customerGroup = await userGroupRepo.findOne({\r\n where: { name: 'Customer', deleted: false } as import('typeorm').ObjectLiteral\r\n });\r\n if (!customerGroup) {\r\n return json({ error: \"User group 'customer' not found\" }, { status: 500 });\r\n }\r\n customerGroupId = Number((customerGroup as { id: number }).id);\r\n } else {\r\n return json({ error: 'user_groups entity not configured' }, { status: 503 });\r\n }\r\n\r\n const name = String(body.name ?? '').trim();\r\n const email = String(body.email ?? '').trim();\r\n const phone = String(body.phone ?? '').trim();\r\n const rawPw = String(body._password ?? '').trim();\r\n\r\n // Field Validation\r\n if (!name) return json({ error: 'name is required' }, { status: 400 });\r\n if (!email) return json({ error: 'email is required' }, { status: 400 });\r\n if (!phone) return json({ error: 'phone is required' }, { status: 400 });\r\n if (!rawPw) return json({ error: 'password is required' }, { status: 400 });\r\n if (rawPw.length < 6){\r\n return json({ error: 'Password must be at least 6 characters' }, { status: 400 });\r\n }\r\n\r\n const customerRepo = dataSource.getRepository(entityMap['customer']);\r\n const userRepo = dataSource.getRepository(entityMap['users']);\r\n\r\n // Uniqueness: customer table\r\n const dupCustEmail = await customerRepo.findOne({\r\n where: { email, deleted: false } as import('typeorm').ObjectLiteral\r\n });\r\n if (dupCustEmail){\r\n return json({ error: 'A customer with this email already exists' }, { status: 409 });\r\n }\r\n\r\n const dupCustPhone = await customerRepo.findOne({\r\n where: { phone, deleted: false } as import('typeorm').ObjectLiteral\r\n });\r\n if (dupCustPhone){\r\n return json({ error: 'A customer with this phone number already exists' }, { status: 409 });\r\n }\r\n\r\n // Uniqueness users table -> link if exists else create\r\n let userId: number;\r\n const dupUser = await userRepo.findOne({\r\n where: { email, deleted: false } as import('typeorm').ObjectLiteral\r\n });\r\n if (dupUser){\r\n userId = Number((dupUser as { id: number }).id);\r\n } else {\r\n const bcrypt = await import('bcryptjs');\r\n const hashedPassword = await bcrypt.hash(rawPw, 10);\r\n const savedUser = await userRepo.save(\r\n userRepo.create({\r\n name,\r\n email,\r\n phone: phone,\r\n password: hashedPassword,\r\n groupId: customerGroupId,\r\n adminAccess: false,\r\n blocked: false,\r\n } as import('typeorm').ObjectLiteral)\r\n );\r\n userId = Number((savedUser as { id: number }).id);\r\n }\r\n\r\n // Create Customer \r\n const { _password, ...customerFields } = body;\r\n const customerRepo2 = dataSource.getRepository(entityMap['customer']);\r\n const persistCustomer = pickColumnUpdates(customerRepo2, {\r\n ...customerFields,\r\n name,\r\n email,\r\n phone,\r\n userId,\r\n });\r\n sanitizeBodyForEntity(customerRepo2, persistCustomer);\r\n const savedCustomer = await customerRepo2.save(\r\n customerRepo2.create(persistCustomer as object)\r\n )as { id: number };\r\n\r\n // Also create a row in contacts table\r\n if (entityMap['contacts']){\r\n const contactRepo = dataSource.getRepository(entityMap['contacts']);\r\n const existingContact = await contactRepo.findOne({\r\n where: { email, deleted: false } as import('typeorm').ObjectLiteral\r\n });\r\n if (!existingContact){\r\n await contactRepo.save(\r\n contactRepo.create({\r\n name,\r\n email,\r\n phone: phone || null,\r\n type: 'customer',\r\n } as import('typeorm').ObjectLiteral)\r\n );\r\n } else {\r\n // Update type to customer if not already set\r\n const t = (existingContact as { type?: string | null }).type;\r\n if (t == null || t === '' || String(t).toLowerCase() !== 'customer'){\r\n await contactRepo.update(\r\n (existingContact as { id: number }).id,\r\n { type: 'customer' } as import('typeorm').ObjectLiteral\r\n );\r\n }\r\n }\r\n }\r\n\r\n // Create Vendor Customers\r\n const scope = await resolveScope();\r\n let vendorId: number | null = null;\r\n if (scope.type === 'vendor'){\r\n vendorId = scope.vendorId;\r\n } else if (scope.type === 'all'){\r\n const n = Number(body.vendorId);\r\n if (Number.isFinite(n)) vendorId = n;\r\n }\r\n if (vendorId == null){\r\n return json({ error: 'Vendor scope required to link customer' }, { status: 400 });\r\n }\r\n const vcRepo = dataSource.getRepository(entity);\r\n const existingLink = await vcRepo.findOne({\r\n where: { customerId: savedCustomer.id } as import('typeorm').ObjectLiteral\r\n });\r\n if (!existingLink){\r\n await vcRepo.save(\r\n vcRepo.create({\r\n customerId: savedCustomer.id,\r\n vendorId\r\n } as import('typeorm').ObjectLiteral)\r\n );\r\n }\r\n return json(savedCustomer, { status: 201 });\r\n }\r\n\r\n if (resource === 'media') {\r\n const b = body;\r\n const kind = b.kind === 'folder' ? 'folder' : 'file';\r\n b.kind = kind;\r\n const fn = String(b.filename ?? '').trim().slice(0, 255);\r\n if (!fn) return json({ error: 'filename required' }, { status: 400 });\r\n b.filename = fn;\r\n let pid: number | null = null;\r\n if (b.parentId != null && b.parentId !== '') {\r\n const n = Number(b.parentId);\r\n if (!Number.isFinite(n)) return json({ error: 'Invalid parentId' }, { status: 400 });\r\n pid = n;\r\n }\r\n b.parentId = pid;\r\n const mediaRepo = dataSource.getRepository(entityMap.media);\r\n if (pid != null) {\r\n const parent = await mediaRepo.findOne({ where: { id: pid } });\r\n if (!parent || (parent as { kind: string }).kind !== 'folder') {\r\n return json({ error: 'parent must be a folder' }, { status: 400 });\r\n }\r\n }\r\n if (kind === 'folder') {\r\n b.url = null;\r\n b.mimeType = 'inode/directory';\r\n b.size = 0;\r\n } else {\r\n if (!b.url || typeof b.url !== 'string') return json({ error: 'url required for files' }, { status: 400 });\r\n if (!b.mimeType || typeof b.mimeType !== 'string') b.mimeType = 'application/octet-stream';\r\n }\r\n }\r\n\r\n const repo = dataSource.getRepository(entity);\r\n const persistBody = resource === 'media' ? body : pickColumnUpdates(repo, body);\r\n if (resource === 'contacts' && 'type' in persistBody) {\r\n const t = persistBody.type;\r\n if (t === '' || t === 'none' || t == null) persistBody.type = null;\r\n }\r\n if (resource !== 'media' && Object.keys(persistBody).length === 0) {\r\n logCrudClientError('POST create', {\r\n reason: 'no_scalar_columns_after_pick',\r\n resource,\r\n incomingKeys: Object.keys(body),\r\n });\r\n return json({ error: 'Invalid request payload' }, { status: 400 });\r\n }\r\n if (resource === 'llm_agents' && 'scope' in persistBody) {\r\n const scopeErr = await validateLlmAgentScopeForWrite(dataSource, entityMap, persistBody.scope);\r\n if (scopeErr) return json({ error: scopeErr }, { status: 400 });\r\n }\r\n if (resource === 'products') {\r\n if ('sku' in persistBody) {\r\n const skuNorm = normalizeProductSku(persistBody.sku);\r\n if (skuNorm) {\r\n const ok = await assertProductSkuUnique(repo, skuNorm);\r\n if (!ok) return json({ error: 'SKU already exists. Please use a unique SKU.' }, { status: 400 });\r\n persistBody.sku = skuNorm;\r\n } else {\r\n persistBody.sku = null;\r\n }\r\n }\r\n }\r\n if (resource === 'addresses') {\r\n const cid = Number(persistBody.contactId);\r\n if (!Number.isFinite(cid)) return json({ error: 'Valid contactId is required.' }, { status: 400 });\r\n if (persistBody.tag === '') persistBody.tag = null;\r\n const addrErr = validateAndNormalizeAddressRow(persistBody);\r\n if (addrErr) return json({ error: addrErr }, { status: 400 });\r\n }\r\n if (\r\n (resource === 'orders' || resource === 'payments') &&\r\n persistBody.contactId != null &&\r\n entityMap.vendor_customers\r\n ) {\r\n const scopeOrder = await resolveScope();\r\n const vendorId = resolveVendorIdForContactCheck(scopeOrder, persistBody);\r\n console.log('[ORDER CREATE] vendor check', {\r\n resource,\r\n contactId: persistBody.contactId,\r\n vendorId,\r\n scopeType: scopeOrder.type,\r\n persistBodyVendorId: persistBody.vendorId,\r\n hasVendorCustomers: !!entityMap.vendor_customers,\r\n hasCustomer: !!entityMap.customer,\r\n hasContacts: !!entityMap.contacts,\r\n });\r\n const contactErr = await assertContactAllowedForVendorOrder(\r\n dataSource,\r\n entityMap,\r\n vendorId ?? NaN,\r\n Number(persistBody.contactId)\r\n );\r\n console.log('[ORDER CREATE] vendor check result:', contactErr);\r\n if (contactErr) {\r\n return json({ error: contactErr }, { status: 400 });\r\n }\r\n }\r\n if (resource === 'vendor_customers') {\r\n if (!entityMap.contacts) {\r\n return json({ error: 'Contacts are not configured' }, { status: 503 });\r\n }\r\n const scope = await resolveScope();\r\n let vendorId: number | null = null;\r\n if (scope.type === 'vendor') vendorId = scope.vendorId;\r\n else if (scope.type === 'all') {\r\n const n = Number(body.vendorId);\r\n if (Number.isFinite(n)) vendorId = n;\r\n }\r\n if (vendorId == null) {\r\n return json({ error: 'Vendor scope required' }, { status: 400 });\r\n }\r\n const contactRepo = dataSource.getRepository(entityMap.contacts);\r\n const vcRepo = dataSource.getRepository(entity);\r\n let contactId = Number(body.contactId);\r\n if (Number.isFinite(contactId)) {\r\n const linked = await contactRepo.findOne({\r\n where: { id: contactId, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n if (!linked) {\r\n return json({ error: 'Contact not found' }, { status: 404 });\r\n }\r\n const t = (linked as { type?: string | null }).type;\r\n if (t != null && t !== '' && String(t).toLowerCase() !== 'customer') {\r\n await contactRepo.update({ id: contactId }, { type: 'customer' } as import('typeorm').ObjectLiteral);\r\n } else if (t == null || t === '') {\r\n await contactRepo.update({ id: contactId }, { type: 'customer' } as import('typeorm').ObjectLiteral);\r\n }\r\n }\r\n if (!Number.isFinite(contactId)) {\r\n const name = String(body.name ?? '').trim();\r\n const email = String(body.email ?? '').trim();\r\n if (!name || !email) {\r\n return json({ error: 'Name and email are required for a new customer' }, { status: 400 });\r\n }\r\n const existing = await contactRepo.findOne({\r\n where: { email, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n if (existing) {\r\n contactId = Number((existing as { id: number }).id);\r\n const t = (existing as { type?: string | null }).type;\r\n if (t == null || t === '' || String(t).toLowerCase() !== 'customer') {\r\n await contactRepo.update({ id: contactId }, { type: 'customer' } as import('typeorm').ObjectLiteral);\r\n }\r\n } else {\r\n const createdContact = await contactRepo.save(\r\n contactRepo.create({\r\n name,\r\n email,\r\n phone: typeof body.phone === 'string' ? body.phone.trim() || null : null,\r\n company: typeof body.company === 'string' ? body.company.trim() || null : null,\r\n type: 'customer',\r\n } as import('typeorm').ObjectLiteral)\r\n );\r\n contactId = Number((createdContact as { id: number }).id);\r\n }\r\n }\r\n const existingLink = await vcRepo.findOne({\r\n where: { vendorId, contactId } as import('typeorm').ObjectLiteral,\r\n });\r\n if (existingLink) {\r\n return json({ error: 'This customer is already linked to your store' }, { status: 409 });\r\n }\r\n const notes = typeof body.notes === 'string' ? body.notes.trim() || null : null;\r\n const created = await vcRepo.save(\r\n vcRepo.create({ vendorId, contactId, notes } as import('typeorm').ObjectLiteral)\r\n );\r\n const contact = await contactRepo.findOne({ where: { id: contactId } as import('typeorm').ObjectLiteral });\r\n const c = contact as Record<string, unknown> | null;\r\n return json(\r\n {\r\n ...created,\r\n name: c?.name ?? null,\r\n email: c?.email ?? null,\r\n phone: c?.phone ?? null,\r\n company: c?.company ?? null,\r\n },\r\n { status: 201 }\r\n );\r\n }\r\n const scopeCreate = await resolveScope();\r\n await tryAssignSingleVendorOnAdminCreate(resource, scopeCreate, persistBody);\r\n const vendorIdCheck = requireVendorIdForScopedCreate(\r\n resource,\r\n persistBody,\r\n scopeCreate,\r\n repo,\r\n await vendorCreateContext(body)\r\n );\r\n if (!vendorIdCheck.ok) {\r\n return json({ error: vendorIdCheck.error }, { status: vendorIdCheck.status });\r\n }\r\n\r\n sanitizeBodyForEntity(repo, persistBody);\r\n let created: import('typeorm').ObjectLiteral;\r\n try {\r\n if (resource === 'orders') {\r\n const contactRepo = dataSource.getRepository(entityMap.contacts);\r\n const explicitId = Number(body.contactId);\r\n const emailRaw = String(body['contact.email'] ?? '').trim();\r\n let contact: import('typeorm').ObjectLiteral | null = null;\r\n\r\n if (Number.isFinite(explicitId) && explicitId > 0) {\r\n contact = await contactRepo.findOne({\r\n where: { id: explicitId, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n }\r\n if (!contact) {\r\n if (!emailRaw) {\r\n return json(\r\n { error: 'Select a customer from the list or enter an email address' },\r\n { status: 400 }\r\n );\r\n }\r\n contact = await contactRepo.findOne({\r\n where: { email: emailRaw, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n }\r\n if (!contact) {\r\n const nameRaw = String(body['contact.name'] ?? '').trim();\r\n const phoneRaw = body['contact.phone'];\r\n contact = await contactRepo.save(\r\n contactRepo.create({\r\n name: nameRaw || emailRaw.split('@')[0] || 'Customer',\r\n email: emailRaw,\r\n phone:\r\n phoneRaw == null || phoneRaw === ''\r\n ? null\r\n : String(phoneRaw),\r\n })\r\n );\r\n }\r\n const randomPart = Math.floor(10000 + Math.random() * 90000);\r\n persistBody.contactId = (contact as { id: number }).id;\r\n persistBody.orderNumber = `ORD00${randomPart}`;\r\n persistBody.qrToken = crypto.randomBytes(16).toString('hex');\r\n }\r\n created = await repo.save(repo.create(persistBody as object));\r\n\r\n if (resource === 'orders') {\r\n const orderItemRepo = dataSource.getRepository(entityMap.order_items);\r\n const productRepo = dataSource.getRepository(entityMap.products);\r\n const orderLinesNorm = normalizeOrderLinesInput(body.orderLines);\r\n const orderCurrency = String(persistBody.currency ?? 'INR').trim().toUpperCase();\r\n\r\n // [Step 5+6] Pass discountId so discount is evaluated inside totals calculation\r\n const orderDiscountId = body.discountId ? Number(body.discountId) : null;\r\n const orderVendorId =\r\n scopeCreate.type === 'vendor'\r\n ? scopeCreate.vendorId\r\n : Number.isFinite(Number(persistBody.vendorId))\r\n ? Number(persistBody.vendorId)\r\n : null;\r\n\r\n const { subtotal, discount, tax, total, lines } =\r\n orderLinesNorm && orderLinesNorm.length > 0\r\n ? await calculateOrderTotalsFromLines(\r\n dataSource,\r\n entityMap,\r\n orderLinesNorm,\r\n orderCurrency,\r\n orderDiscountId,\r\n orderVendorId\r\n )\r\n : await calculateOrderTotals(\r\n dataSource,\r\n entityMap,\r\n String(body.itemsSummary || ''),\r\n orderDiscountId,\r\n orderVendorId\r\n );\r\n \r\n // ADD — auto-apply automatic discounts if no manual discount provided:\r\n let effectiveDiscountId = orderDiscountId;\r\n if (!effectiveDiscountId && entityMap['discounts']) {\r\n try {\r\n const autoDiscounts = await dataSource.getRepository(entityMap['discounts']).find({\r\n where: withDiscountVendorWhere(\r\n { isAutomatic: true, status: 'ACTIVE' },\r\n orderVendorId\r\n ) as import('typeorm').ObjectLiteral,\r\n order: { id: 'ASC' } as import('typeorm').ObjectLiteral,\r\n });\r\n const contactIdForAuto = persistBody.contactId as number | null;\r\n for (const ad of autoDiscounts) {\r\n const adRow = ad as { id: number; couponCode: string };\r\n const linesForValidation = (orderLinesNorm ?? []).map((l) => ({ productId: l.productId, quantity: l.quantity }));\r\n const result = await validateCoupon(\r\n dataSource, entityMap,\r\n adRow.couponCode,\r\n linesForValidation,\r\n orderCurrency,\r\n contactIdForAuto,\r\n true,\r\n adRow.id,\r\n orderVendorId\r\n );\r\n if (result.valid) {\r\n effectiveDiscountId = adRow.id;\r\n break;\r\n }\r\n }\r\n } catch (err) {\r\n logCrudServerError('auto-discount evaluation failed', {\r\n message: err instanceof Error ? err.message : String(err),\r\n });\r\n }\r\n }\r\n\r\n const createdStatus = String((persistBody as { status?: string }).status ?? 'pending');\r\n if (createdStatus === ORDER_STATUS_CONFIRMED) {\r\n const stockErr = await validateInventoryForConfirmedOrderLines(dataSource, entityMap, lines);\r\n if (stockErr) {\r\n await repo.delete((created as { id: number }).id);\r\n return json({ error: stockErr }, { status: 400 });\r\n }\r\n }\r\n\r\n for (const line of lines) {\r\n if (!line.found || !line.productId) continue;\r\n const prod = await productRepo.findOne({\r\n where: { id: line.productId, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n const pr = prod as { hsn?: string | null; uom?: string | null; type?: string | null } | null;\r\n await orderItemRepo.save(\r\n orderItemRepo.create({\r\n orderId: created.id,\r\n productId: line.productId,\r\n quantity: line.quantity,\r\n unitPrice: line.unitPrice,\r\n subTotal: line.subtotal,\r\n discount: line.discount ?? 0,\r\n discountedAmount: line.subtotal - (line.discount ?? 0),\r\n taxRate: line.taxRate,\r\n taxCode: line.taxCode,\r\n tax: line.tax,\r\n total: line.total,\r\n hsn: pr?.hsn ?? null,\r\n uom: pr?.uom ?? null,\r\n productType: pr?.type ?? null,\r\n })\r\n );\r\n }\r\n\r\n await repo.update(created.id, { subtotal, discount, tax, total });\r\n\r\n const billingAddress = body.billingAddress && typeof body.billingAddress === 'object'\r\n ? (body.billingAddress as Record<string, unknown>) : null;\r\n const shippingAddress = body.shippingAddress && typeof body.shippingAddress === 'object'\r\n ? (body.shippingAddress as Record<string, unknown>) : null;\r\n if (entityMap['order_addresses']) {\r\n const orderAddressRepo = dataSource.getRepository(entityMap['order_addresses']);\r\n async function saveAddress(addr: Record<string, unknown> | null, addressType: string) {\r\n if (!addr) return null;\r\n const line1 = String(addr.line1 ?? '').trim();\r\n if (!line1) return null;\r\n const contactId = persistBody.contactId as number;\r\n const payload = {\r\n line1,\r\n line2: String(addr.line2 ?? '').trim() || null,\r\n city: String(addr.city ?? '').trim(),\r\n state: String(addr.state ?? '').trim(),\r\n country: String(addr.country ?? '').trim(),\r\n postalCode: String(addr.postalCode ?? '').trim(),\r\n };\r\n const existing = await orderAddressRepo.findOne({\r\n where: { contactId, addressType } as import('typeorm').ObjectLiteral,\r\n });\r\n if (existing) {\r\n await orderAddressRepo.update((existing as { id: number }).id, payload as object);\r\n return orderAddressRepo.findOne({\r\n where: { id: (existing as { id: number }).id } as import('typeorm').ObjectLiteral,\r\n });\r\n }\r\n return orderAddressRepo.save(\r\n orderAddressRepo.create({\r\n contactId,\r\n addressType,\r\n ...payload,\r\n })\r\n );\r\n }\r\n const savedBilling = await saveAddress(billingAddress, 'billing_address');\r\n const savedShipping = await saveAddress(shippingAddress, 'shipping_address');\r\n await repo.update(created.id, {\r\n billingAddressId: savedBilling?.id ?? null,\r\n shippingAddressId: savedShipping?.id ?? null,\r\n });\r\n }\r\n\r\n const reloadedOrder = await repo.findOne({\r\n where: { id: created.id, deleted: false } as import('typeorm').ObjectLiteral,\r\n relations: ['items'],\r\n });\r\n if (reloadedOrder) {\r\n const invErr = await reconcileOrderInventoryBetweenSnapshots(\r\n dataSource, entityMap,\r\n { status: 'pending', lines: [] },\r\n orderInventorySnapshotFromRow(reloadedOrder as { status?: string; items?: { productId: number; quantity: unknown }[] })\r\n );\r\n if (invErr) {\r\n logCrudServerError('POST order inventory reconcile failed', {\r\n message: invErr,\r\n orderId: (created as { id: number }).id,\r\n });\r\n return json({ error: invErr }, { status: 500 });\r\n }\r\n }\r\n\r\n // [Step 7] When order is created as confirmed, check+record discount usage\r\n if (orderDiscountId) {\r\n // Only check+increment usage limit when confirmed\r\n if (createdStatus === ORDER_STATUS_CONFIRMED){\r\n const usageErr = await checkAndIncrementDiscountUsage(\r\n dataSource, entityMap,\r\n orderDiscountId,\r\n persistBody.contactId as number\r\n );\r\n if (usageErr) {\r\n await repo.delete((created as { id: number }).id);\r\n return json({ error: usageErr }, { status: 400 });\r\n }\r\n }\r\n // Always record which discount was applied to this order\r\n await recordDiscountUsage(\r\n dataSource, entityMap,\r\n (created as { id: number }).id,\r\n orderDiscountId,\r\n persistBody.contactId as number,\r\n discount,\r\n );\r\n }\r\n }\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n logCrudServerError('POST create save failed', { resource, message, persistKeys: Object.keys(persistBody) });\r\n throw err;\r\n }\r\n if (resource === 'contacts') {\r\n await syncContactRowToErp(created as import('typeorm').ObjectLiteral);\r\n }\r\n if (resource === 'products' && getCms) {\r\n const cms = await getCms();\r\n await queueErpProductUpsertIfEnabled(cms, dataSource, entityMap, created as import('typeorm').ObjectLiteral);\r\n }\r\n return json(created, { status: 201 });\r\n },\r\n\r\n async GET_METADATA(req: Request, resource: string) {\r\n const authError = await authz(req, resource, 'read');\r\n if (authError) return authError;\r\n const entity = entityMap[resource];\r\n if (!resource || !entity) {\r\n logCrudClientError('GET_METADATA', { reason: 'invalid_resource', resource });\r\n return json({ error: 'Invalid resource' }, { status: 400 });\r\n }\r\n const repo = dataSource.getRepository(entity);\r\n const meta = repo.metadata;\r\n const uniqueFromIndices = new Set<string>();\r\n for (const idx of meta.indices) {\r\n if (idx.isUnique && idx.columns.length === 1) uniqueFromIndices.add(idx.columns[0].propertyName);\r\n }\r\n for (const uniq of meta.uniques) {\r\n if (uniq.columns.length === 1) uniqueFromIndices.add(uniq.columns[0].propertyName);\r\n }\r\n const columns = meta.columns.map((col) => ({\r\n name: col.propertyName,\r\n type: typeof col.type === 'string' ? col.type : (col.type as { name?: string })?.name ?? 'unknown',\r\n nullable: col.isNullable,\r\n isUnique: uniqueFromIndices.has(col.propertyName),\r\n isPrimary: col.isPrimary,\r\n default: col.default,\r\n }));\r\n return json({ columns, uniqueColumns: [...uniqueFromIndices] });\r\n },\r\n\r\n async BULK_POST(req: Request, resource: string) {\r\n const authError = await authz(req, resource, 'update');\r\n if (authError) return authError;\r\n const entity = entityMap[resource];\r\n if (!resource || !entity) {\r\n logCrudClientError('BULK_POST', { reason: 'invalid_resource', resource });\r\n return json({ error: 'Invalid resource' }, { status: 400 });\r\n }\r\n const body = await req.json();\r\n const { records, upsertKey = 'id' } = body as { records: object[]; upsertKey?: string };\r\n if (!Array.isArray(records) || records.length === 0) {\r\n logCrudClientError('BULK_POST', {\r\n reason: 'records_required',\r\n resource,\r\n recordsIsArray: Array.isArray(records),\r\n recordCount: Array.isArray(records) ? records.length : 0,\r\n });\r\n return json({ error: 'Records array is required' }, { status: 400 });\r\n }\r\n const repo = dataSource.getRepository(entity);\r\n for (const record of records) sanitizeBodyForEntity(repo, record as Record<string, unknown>);\r\n try {\r\n const result = await repo.upsert(records, { conflictPaths: [upsertKey], skipUpdateIfNoValuesChanged: true });\r\n return json({ success: true, imported: result.identifiers.length, identifiers: result.identifiers });\r\n } catch (error) {\r\n const message = error instanceof Error ? error.message : 'Bulk import failed';\r\n logCrudClientError('BULK_POST upsert failed', { resource, upsertKey, message });\r\n return json({ error: message }, { status: 400 });\r\n }\r\n },\r\n\r\n async GET_EXPORT(req: Request, resource: string) {\r\n const authError = await authz(req, resource, 'read');\r\n if (authError) return authError;\r\n const entity = entityMap[resource];\r\n if (!resource || !entity) {\r\n logCrudClientError('GET_EXPORT', { reason: 'invalid_resource', resource });\r\n return json({ error: 'Invalid resource' }, { status: 400 });\r\n }\r\n const { searchParams } = new URL(req.url);\r\n const format = searchParams.get('format') || 'csv';\r\n const repo = dataSource.getRepository(entity);\r\n const meta = repo.metadata;\r\n const hasDeleted = meta.columns.some((c) => c.propertyName === 'deleted');\r\n const where = hasDeleted ? { deleted: false } : {};\r\n const data = await repo.find({ where });\r\n const excludeCols = new Set(['deletedAt', 'deletedBy', 'deleted']);\r\n const columns = meta.columns.filter((c) => !excludeCols.has(c.propertyName)).map((c) => c.propertyName);\r\n if (format === 'json') return json(data);\r\n const escapeCSV = (val: unknown): string => {\r\n if (val === null || val === undefined) return '';\r\n const str = typeof val === 'object' ? JSON.stringify(val) : String(val);\r\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) return `\"${str.replace(/\"/g, '\"\"')}\"`;\r\n return str;\r\n };\r\n const header = columns.join(',');\r\n const rows = data.map((row) => columns.map((col) => escapeCSV((row as Record<string, unknown>)[col])).join(','));\r\n const csv = [header, ...rows].join('\\n');\r\n return new Response(csv, {\r\n headers: {\r\n 'Content-Type': 'text/csv; charset=utf-8',\r\n 'Content-Disposition': `attachment; filename=\"${resource}.csv\"`,\r\n },\r\n });\r\n },\r\n };\r\n}\r\n\r\nexport function createCrudByIdHandler(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n options: CrudHandlerOptions\r\n) {\r\n const { requireAuth, json, requireEntityPermission: reqPerm, getCms, getDeletedByUserId, getVendorScope } = options;\r\n const syncContactRowToErp = makeContactErpSync(dataSource, entityMap, getCms);\r\n const resolveScopeById = getVendorScope ?? (async (): Promise<VendorScope> => ({ type: 'all' }));\r\n\r\n function vendorScopeAccessJson(\r\n row: Record<string, unknown> | null | undefined,\r\n scope: VendorScope,\r\n resource: string\r\n ): Response | null {\r\n const access = vendorScopeRowAccess(row, scope, resource);\r\n if (access === 'ok') return null;\r\n if (access === 'forbidden') return json({ error: 'Forbidden' }, { status: 403 });\r\n return json({ message: 'Not found' }, { status: 404 });\r\n }\r\n\r\n async function authz(req: Request, resource: string, action: EntityCrudAction): Promise<Response | null> {\r\n const authError = await requireAuth(req);\r\n if (authError) return authError;\r\n if (!reqPerm) {\r\n return json({ error: 'Forbidden', reason: 'entity_rbac_required', entity: resource, action }, { status: 403 });\r\n }\r\n const pe = await reqPerm(req, resource, action);\r\n if (pe) return pe;\r\n return null;\r\n }\r\n\r\n return {\r\n async GET(req: Request, resource: string, id: string) {\r\n const authError = await authz(req, resource, 'read');\r\n if (authError) return authError;\r\n const entity = entityMap[resource];\r\n if (!entity) {\r\n logCrudClientError('GET by id', { reason: 'invalid_resource', resource, id });\r\n return json({ error: 'Invalid resource' }, { status: 400 });\r\n }\r\n const repo = dataSource.getRepository(entity);\r\n\r\n if (resource === 'discounts') {\r\n const scope = await resolveScopeById();\r\n const discount = await repo.findOne({\r\n where: { id: Number(id) } as import('typeorm').ObjectLiteral,\r\n relations: ['rules'],\r\n });\r\n const discountDenied = vendorScopeAccessJson(discount as Record<string, unknown>, scope, resource);\r\n if (discountDenied) return discountDenied;\r\n\r\n // Nest the rule tree so the frontend can use children directly\r\n type FlatRule = Record<string, unknown> & { id: number; parentId: number | null };\r\n function nestDiscountRules(flat: FlatRule[]): FlatRule[] {\r\n const byId = new Map<number, FlatRule & { children: FlatRule[] }>();\r\n for (const r of flat) byId.set(r.id, { ...r, children: [] });\r\n const roots: (FlatRule & { children: FlatRule[] })[] = [];\r\n for (const r of flat) {\r\n const node = byId.get(r.id)!;\r\n if (r.parentId == null) {\r\n roots.push(node);\r\n } else {\r\n const parent = byId.get(r.parentId);\r\n if (parent) parent.children.push(node);\r\n else roots.push(node);\r\n }\r\n }\r\n return roots;\r\n }\r\n const flatRules = ((discount as Record<string, unknown>).rules ?? []) as FlatRule[];\r\n const nestedRules = nestDiscountRules(flatRules);\r\n\r\n // Attach store currency so edit page skips a separate /api/settings/store fetch\r\n let storeCurrency = 'INR';\r\n if (entityMap['configs']) {\r\n try {\r\n const configRepo = dataSource.getRepository(entityMap['configs']);\r\n const curr = await configRepo.findOne({\r\n where: { settings: 'store', key: 'currency' } as import('typeorm').ObjectLiteral,\r\n });\r\n storeCurrency = (curr as { value?: string } | null)?.value?.toUpperCase() ?? 'INR';\r\n } catch { /* fall back to INR */ }\r\n }\r\n\r\n let usageSummary: { totalUsed: number; uniqueUsers: number } = { totalUsed: 0, uniqueUsers: 0 };\r\n if (entityMap['order_discounts']) {\r\n const odRepo = dataSource.getRepository(entityMap['order_discounts']);\r\n const usageRaw = await odRepo\r\n .createQueryBuilder('od')\r\n .select('COUNT(*)', 'totalUsed')\r\n .addSelect('COUNT(DISTINCT od.userId)', 'uniqueUsers')\r\n .where('od.discountId = :discountId', { discountId: Number(id) })\r\n .getRawOne<{ totalUsed: string; uniqueUsers: string }>();\r\n if (usageRaw) {\r\n usageSummary = {\r\n totalUsed: Number(usageRaw.totalUsed ?? 0),\r\n uniqueUsers: Number(usageRaw.uniqueUsers ?? 0),\r\n };\r\n }\r\n }\r\n\r\n return json({\r\n ...(discount as Record<string, unknown>),\r\n rules: nestedRules,\r\n _storeCurrency: storeCurrency,\r\n usageSummary,\r\n });\r\n }\r\n\r\n if (resource === 'orders') {\r\n const scope = await resolveScopeById();\r\n const order = await repo.findOne({\r\n where: { id: Number(id), deleted: false } as import('typeorm').ObjectLiteral,\r\n relations: ['contact', 'billingAddress', 'shippingAddress', 'items', 'items.product', 'items.product.collection', 'payments'],\r\n });\r\n const orderDenied = vendorScopeAccessJson(order as Record<string, unknown>, scope, resource);\r\n if (orderDenied) return orderDenied;\r\n const relatedOrders = await repo.find({\r\n where: { parentOrderId: Number(id), deleted: false } as import('typeorm').ObjectLiteral,\r\n order: { id: 'ASC' },\r\n });\r\n return json({ ...order, relatedOrders });\r\n }\r\n\r\n if (resource === 'contacts') {\r\n const contact = await repo.findOne({\r\n where: { id: Number(id), deleted: false } as import('typeorm').ObjectLiteral,\r\n relations: ['form_submissions', 'form_submissions.form', 'orders', 'payments', 'addresses'],\r\n });\r\n if (!contact) return json({ message: 'Not found' }, { status: 404 });\r\n const orders = (contact as { orders?: { total?: unknown; createdAt?: string }[] }).orders ?? [];\r\n const payments = (contact as { payments?: { status: string; amount?: number }[] }).payments ?? [];\r\n const totalPaid = payments\r\n .filter((p) => p.status === 'completed')\r\n .reduce((sum, p) => sum + Number(p.amount ?? 0), 0);\r\n const lastOrderAt = orders.length > 0\r\n ? orders.reduce((latest, o) => {\r\n const t = o.createdAt ? new Date(o.createdAt).getTime() : 0;\r\n return t > latest ? t : latest;\r\n }, 0)\r\n : null;\r\n return json({\r\n ...contact,\r\n summary: {\r\n totalOrders: orders.length,\r\n totalPaid,\r\n lastOrderAt: lastOrderAt ? new Date(lastOrderAt).toISOString() : null,\r\n },\r\n });\r\n }\r\n\r\n if (resource === 'payments') {\r\n const scope = await resolveScopeById();\r\n const payment = await repo.findOne({\r\n where: { id: Number(id), deleted: false } as import('typeorm').ObjectLiteral,\r\n relations: ['order', 'order.contact', 'contact'],\r\n });\r\n const paymentDenied = vendorScopeAccessJson(payment as Record<string, unknown>, scope, resource);\r\n if (paymentDenied) return paymentDenied;\r\n const p = payment as Record<string, unknown>;\r\n const order = p.order as Record<string, unknown> | undefined;\r\n const orderContact = order?.contact as Record<string, unknown> | undefined;\r\n const contact = p.contact as Record<string, unknown> | undefined;\r\n const customer = orderContact ?? contact;\r\n return json({\r\n ...p,\r\n order: order ? { id: order.id, orderNumber: order.orderNumber, contact: orderContact ? { name: orderContact.name, email: orderContact.email } : null } : null,\r\n contact: customer ? { id: customer.id, name: customer.name, email: customer.email } : null,\r\n });\r\n }\r\n\r\n if (resource === 'products') {\r\n const scope = await resolveScopeById();\r\n const product = await repo.findOne({\r\n where: { id: Number(id), deleted: false } as import('typeorm').ObjectLiteral,\r\n relations: ['collection', 'brand', 'category', 'attributes', 'attributes.attribute'],\r\n });\r\n const productDenied = vendorScopeAccessJson(product as Record<string, unknown>, scope, resource);\r\n if (productDenied) return productDenied;\r\n return product ? json(product) : json({ message: 'Not found' }, { status: 404 });\r\n }\r\n\r\n if (resource === 'vendor_customers' && entityMap.contacts) {\r\n const scope = await resolveScopeById();\r\n const row = await repo.findOne({\r\n where: { id: Number(id) } as import('typeorm').ObjectLiteral,\r\n relations: ['contact'],\r\n });\r\n const vcDenied = vendorScopeAccessJson(row as Record<string, unknown>, scope, resource);\r\n if (vcDenied) return vcDenied;\r\n const contact = (row as { contact?: Record<string, unknown> }).contact;\r\n return json({\r\n ...row,\r\n name: contact?.name ?? null,\r\n email: contact?.email ?? null,\r\n phone: contact?.phone ?? null,\r\n company: contact?.company ?? null,\r\n });\r\n }\r\n\r\n if (resource === 'blogs') {\r\n const blog = await repo.findOne({\r\n where: { id: Number(id), deleted: false } as import('typeorm').ObjectLiteral,\r\n relations: ['category', 'seo', 'tags'],\r\n });\r\n return blog ? json(blog) : json({ message: 'Not found' }, { status: 404 });\r\n }\r\n\r\n const scope = await resolveScopeById();\r\n const idWhere: import('typeorm').ObjectLiteral = entityHasSoftDelete(repo)\r\n ? ({ id: Number(id), deleted: false } as import('typeorm').ObjectLiteral)\r\n : ({ id: Number(id) } as import('typeorm').ObjectLiteral);\r\n const item = await repo.findOne({ where: idWhere });\r\n if (resourceUsesVendorScope(resource)) {\r\n const itemDenied = vendorScopeAccessJson(item as Record<string, unknown>, scope, resource);\r\n if (itemDenied) return itemDenied;\r\n } else if (!item) {\r\n return json({ message: 'Not found' }, { status: 404 });\r\n }\r\n return json(item);\r\n },\r\n\r\n async PUT(req: Request, resource: string, id: string) {\r\n const authError = await authz(req, resource, 'update');\r\n if (authError) return authError;\r\n const entity = entityMap[resource];\r\n if (!entity) {\r\n logCrudClientError('PUT by id', { reason: 'invalid_resource', resource, id });\r\n return json({ error: 'Invalid resource' }, { status: 400 });\r\n }\r\n const rawBody = (await req.json()) as Record<string, unknown> | null;\r\n const repo = dataSource.getRepository(entity);\r\n const numericId = Number(id);\r\n let orderInvPrev: OrderInventorySnapshot | null = null;\r\n\r\n if (\r\n resource === 'blogs' &&\r\n rawBody &&\r\n typeof rawBody === 'object' &&\r\n entityMap.categories &&\r\n entityMap.seos &&\r\n entityMap.tags\r\n ) {\r\n const existing = await repo.findOne({ where: { id: numericId, deleted: false } as import('typeorm').ObjectLiteral });\r\n if (!existing) return json({ message: 'Not found' }, { status: 404 });\r\n const updatePayload = pickColumnUpdates(repo, rawBody);\r\n if ('category' in rawBody) {\r\n const c = rawBody.category;\r\n if (typeof c === 'string' && c.trim()) {\r\n const cat = await dataSource.getRepository(entityMap.categories).findOne({ where: { name: c.trim() } });\r\n updatePayload.categoryId = cat?.id ?? null;\r\n } else {\r\n updatePayload.categoryId = null;\r\n }\r\n }\r\n const blogSlug =\r\n (typeof updatePayload.slug === 'string' && updatePayload.slug) ||\r\n (existing as { slug: string }).slug;\r\n const seoRepo = dataSource.getRepository(entityMap.seos);\r\n const seoField = (k: string): string | null | undefined => {\r\n if (!(k in rawBody)) return undefined;\r\n const v = rawBody[k];\r\n if (v == null || v === '') return null;\r\n return String(v);\r\n };\r\n if ('metaTitle' in rawBody || 'metaDescription' in rawBody || 'metaKeywords' in rawBody || 'ogImage' in rawBody) {\r\n const title = seoField('metaTitle');\r\n const description = seoField('metaDescription');\r\n const keywords = seoField('metaKeywords');\r\n const ogImage = seoField('ogImage');\r\n const exSeoId = (existing as { seoId: number | null }).seoId;\r\n if (exSeoId) {\r\n const seo = await seoRepo.findOne({ where: { id: exSeoId } });\r\n if (seo) {\r\n const s = seo as Record<string, unknown>;\r\n if (title !== undefined) s.title = title;\r\n if (description !== undefined) s.description = description;\r\n if (keywords !== undefined) s.keywords = keywords;\r\n if (ogImage !== undefined) s.ogImage = ogImage;\r\n s.slug = blogSlug;\r\n await seoRepo.save(seo);\r\n }\r\n } else {\r\n let seoSlug = blogSlug;\r\n const taken = await seoRepo.findOne({ where: { slug: seoSlug } });\r\n if (taken) seoSlug = `blog-${numericId}-${blogSlug}`;\r\n const seo = await seoRepo.save(\r\n seoRepo.create({ slug: seoSlug, title: title ?? null, description: description ?? null, keywords: keywords ?? null, ogImage: ogImage ?? null })\r\n );\r\n updatePayload.seoId = (seo as { id: number }).id;\r\n }\r\n }\r\n sanitizeBodyForEntity(repo, updatePayload);\r\n await repo.update(numericId, updatePayload as object);\r\n if (Array.isArray(rawBody.tags)) {\r\n const tagNames = (rawBody.tags as unknown[]).map((t) => String(t).trim()).filter(Boolean);\r\n const tagRepo = dataSource.getRepository(entityMap.tags);\r\n const tagEntities: import('typeorm').ObjectLiteral[] = [];\r\n for (const name of tagNames) {\r\n let tag = await tagRepo.findOne({ where: { name } });\r\n if (!tag) tag = await tagRepo.save(tagRepo.create({ name }));\r\n tagEntities.push(tag);\r\n }\r\n const blog = await repo.findOne({ where: { id: numericId }, relations: ['tags'] });\r\n if (blog) {\r\n (blog as Record<string, unknown>).tags = tagEntities;\r\n await repo.save(blog);\r\n }\r\n }\r\n const updated = await repo.findOne({ where: { id: numericId }, relations: ['tags', 'category', 'seo'] });\r\n return updated ? json(updated) : json({ message: 'Not found' }, { status: 404 });\r\n }\r\n\r\n if (entityHasSoftDelete(repo)) {\r\n const cur = await repo.findOne({\r\n where: { id: numericId, deleted: false } as import('typeorm').ObjectLiteral,\r\n relations: resource === 'orders' ? (['items'] as const) : [],\r\n });\r\n if (!cur) return json({ message: 'Not found' }, { status: 404 });\r\n if (resource === 'orders') {\r\n orderInvPrev = orderInventorySnapshotFromRow(\r\n cur as { status?: string; items?: { productId: number; quantity: unknown }[] }\r\n );\r\n }\r\n }\r\n\r\n if (resource === 'orders' && rawBody && typeof rawBody === 'object' && Array.isArray(rawBody.orderLines)) {\r\n const orderLinesNorm = normalizeOrderLinesInput(rawBody.orderLines);\r\n if (orderLinesNorm !== null) {\r\n const orderItemRepo = dataSource.getRepository(entityMap.order_items);\r\n const productRepo = dataSource.getRepository(entityMap.products);\r\n const scalarUpdateForCurrency = pickColumnUpdates(repo, rawBody);\r\n const existingOrderForCurrency = await repo.findOne({ where: { id: numericId } as import('typeorm').ObjectLiteral });\r\n const savedCurrency = String((existingOrderForCurrency as Record<string, unknown> | null)?.currency ?? 'INR').trim().toUpperCase();\r\n const effectiveCurrency = String(scalarUpdateForCurrency.currency ?? savedCurrency).trim().toUpperCase();\r\n\r\n // [Step 5+6] Forward discountId on PUT as well\r\n const putDiscountId = rawBody.discountId ? Number(rawBody.discountId) : null;\r\n const putOrderVendorId = Number(\r\n (existingOrderForCurrency as { vendorId?: number } | null)?.vendorId\r\n );\r\n\r\n const { subtotal, discount, tax, total, lines } =\r\n orderLinesNorm.length === 0\r\n ? { subtotal: 0, discount: 0, tax: 0, total: 0, lines: [] as OrderTotalsLine[] }\r\n : await calculateOrderTotalsFromLines(\r\n dataSource,\r\n entityMap,\r\n orderLinesNorm,\r\n effectiveCurrency,\r\n putDiscountId,\r\n Number.isFinite(putOrderVendorId) ? putOrderVendorId : null\r\n );\r\n\r\n const scalarUpdate = pickColumnUpdates(repo, rawBody);\r\n const nextStatus =\r\n typeof scalarUpdate.status === 'string' && scalarUpdate.status\r\n ? String(scalarUpdate.status)\r\n : orderInvPrev?.status ?? 'pending';\r\n\r\n if (nextStatus === ORDER_STATUS_CONFIRMED && lines.length > 0) {\r\n const verr = await validateInventoryForOrderBecomingConfirmed(\r\n dataSource, entityMap, orderInvPrev,\r\n lines.filter((l) => l.found && l.productId != null).map((l) => ({ productId: l.productId as number, quantity: l.quantity }))\r\n );\r\n if (verr) return json({ error: verr }, { status: 400 });\r\n }\r\n\r\n if (Object.keys(scalarUpdate).length > 0) {\r\n sanitizeBodyForEntity(repo, scalarUpdate);\r\n await repo.update(numericId, scalarUpdate as object);\r\n }\r\n\r\n await orderItemRepo.delete({ orderId: numericId } as import('typeorm').ObjectLiteral);\r\n\r\n for (const line of lines) {\r\n if (!line.found || !line.productId) continue;\r\n const prod = await productRepo.findOne({\r\n where: { id: line.productId, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n const pr = prod as { hsn?: string | null; uom?: string | null; type?: string | null } | null;\r\n await orderItemRepo.save(\r\n orderItemRepo.create({\r\n orderId: numericId,\r\n productId: line.productId,\r\n quantity: line.quantity,\r\n unitPrice: line.unitPrice,\r\n subTotal: line.subtotal,\r\n discount: line.discount ?? 0,\r\n discountedAmount: line.subtotal - (line.discount ?? 0),\r\n taxRate: line.taxRate,\r\n taxCode: line.taxCode,\r\n tax: line.tax,\r\n total: line.total,\r\n hsn: pr?.hsn ?? null,\r\n uom: pr?.uom ?? null,\r\n productType: pr?.type ?? null,\r\n })\r\n );\r\n }\r\n\r\n await repo.update(numericId, { subtotal, discount, tax, total } as import('typeorm').ObjectLiteral);\r\n\r\n const addressRawPut = String((rawBody as Record<string, unknown>)?.['contact.address'] ?? '').trim();\r\n if (addressRawPut && entityMap['order_addresses']) {\r\n const orderAddressRepo = dataSource.getRepository(entityMap['order_addresses']);\r\n const orderForCid = await repo.findOne({ where: { id: numericId } as import('typeorm').ObjectLiteral });\r\n const cid = (orderForCid as { contactId?: number } | null)?.contactId;\r\n if (cid) {\r\n const existing = await orderAddressRepo.findOne({ where: { contactId: cid, addressType: 'shipping_address' } as import('typeorm').ObjectLiteral });\r\n if (existing) {\r\n await orderAddressRepo.update((existing as { id: number }).id, { line1: addressRawPut } as import('typeorm').ObjectLiteral);\r\n } else {\r\n await orderAddressRepo.save(orderAddressRepo.create({\r\n contactId: cid, addressType: 'shipping_address',\r\n line1: addressRawPut, line2: null, city: '', state: '', postalCode: '', country: '',\r\n }));\r\n }\r\n }\r\n }\r\n\r\n const updatedOrder = await repo.findOne({\r\n where: { id: numericId, deleted: false } as import('typeorm').ObjectLiteral,\r\n relations: ['contact', 'billingAddress', 'shippingAddress', 'items', 'items.product', 'items.product.collection', 'payments'],\r\n });\r\n if (!updatedOrder) return json({ message: 'Not found' }, { status: 404 });\r\n\r\n if (orderInvPrev) {\r\n const invErr = await reconcileOrderInventoryBetweenSnapshots(\r\n dataSource, entityMap, orderInvPrev,\r\n orderInventorySnapshotFromRow(updatedOrder as { status?: string; items?: { productId: number; quantity: unknown }[] })\r\n );\r\n if (invErr) return json({ error: invErr }, { status: 409 });\r\n }\r\n\r\n {\r\n const orderForContact = await repo.findOne({ where: { id: numericId } as import('typeorm').ObjectLiteral });\r\n const cid = (orderForContact as { contactId?: number } | null)?.contactId;\r\n if (cid) {\r\n const wasConfirmed = orderInvPrev?.status === ORDER_STATUS_CONFIRMED;\r\n const isNowConfirmed = nextStatus === ORDER_STATUS_CONFIRMED;\r\n\r\n // Get existing order_discount record\r\n const existingOd = entityMap['order_discounts']\r\n ? await dataSource.getRepository(entityMap['order_discounts']).findOne({\r\n where: { orderId: numericId } as import('typeorm').ObjectLiteral,\r\n })\r\n : null;\r\n const existingDiscountId = existingOd\r\n ? (existingOd as { discountId: number }).discountId\r\n : null;\r\n\r\n // Case 1: discount removed\r\n if (!putDiscountId && existingDiscountId && wasConfirmed) {\r\n await decrementDiscountUsage(dataSource, entityMap, existingDiscountId, numericId);\r\n if (entityMap['order_discounts'] && existingOd) {\r\n await dataSource.getRepository(entityMap['order_discounts']).delete(\r\n (existingOd as { id: number }).id\r\n );\r\n }\r\n }\r\n\r\n // Case 2: discount changed\r\n if (putDiscountId && existingDiscountId && putDiscountId !== existingDiscountId) {\r\n // Decrement old discount if was confirmed\r\n if (wasConfirmed) {\r\n await decrementDiscountUsage(dataSource, entityMap, existingDiscountId, numericId);\r\n }\r\n // Increment new discount if now confirmed\r\n if (isNowConfirmed) {\r\n const usageErr = await checkAndIncrementDiscountUsage(dataSource, entityMap, putDiscountId, cid);\r\n if (usageErr) return json({ error: usageErr }, { status: 400 });\r\n }\r\n // Update order_discounts record\r\n if (existingOd && entityMap['order_discounts']) {\r\n await dataSource.getRepository(entityMap['order_discounts']).update(\r\n (existingOd as { id: number }).id,\r\n { discountId: putDiscountId, discountAmount: discount } as import('typeorm').ObjectLiteral\r\n );\r\n } else {\r\n await recordDiscountUsage(dataSource, entityMap, numericId, putDiscountId, cid, discount);\r\n }\r\n } \r\n\r\n // Case 3: same discount, status changed\r\n if (putDiscountId && existingDiscountId && putDiscountId === existingDiscountId) {\r\n // pending → confirmed: increment\r\n if (!wasConfirmed && isNowConfirmed) {\r\n const usageErr = await checkAndIncrementDiscountUsage(dataSource, entityMap, putDiscountId, cid);\r\n if (usageErr) return json({ error: usageErr }, { status: 400 });\r\n }\r\n // confirmed → not confirmed: decrement\r\n if (wasConfirmed && !isNowConfirmed) {\r\n await decrementDiscountUsage(dataSource, entityMap, putDiscountId, numericId);\r\n }\r\n // Update discount amount in case lines changed\r\n if (existingOd && entityMap['order_discounts']) {\r\n await dataSource.getRepository(entityMap['order_discounts']).update(\r\n (existingOd as { id: number }).id,\r\n { discountAmount: discount } as import('typeorm').ObjectLiteral\r\n );\r\n }\r\n }\r\n\r\n // Case 4: new discount applied (no existing)\r\n if (putDiscountId && !existingDiscountId) {\r\n if (isNowConfirmed) {\r\n const usageErr = await checkAndIncrementDiscountUsage(dataSource, entityMap, putDiscountId, cid);\r\n if (usageErr) return json({ error: usageErr }, { status: 400 });\r\n }\r\n await recordDiscountUsage(dataSource, entityMap, numericId, putDiscountId, cid, discount);\r\n }\r\n }\r\n }\r\n\r\n return json(updatedOrder);\r\n }\r\n }\r\n\r\n if (resource === 'discounts' && rawBody && typeof rawBody === 'object') {\r\n const scopePut = await resolveScopeById();\r\n const existing = await repo.findOne({\r\n where: { id: numericId } as import('typeorm').ObjectLiteral,\r\n });\r\n const discountPutDenied = vendorScopeAccessJson(existing as Record<string, unknown>, scopePut, resource);\r\n if (discountPutDenied) return discountPutDenied;\r\n const updatePayload = pickColumnUpdates(repo, rawBody);\r\n delete updatePayload.vendorId;\r\n if (!rawBody.isAutomatic && rawBody.couponCode != null && String(rawBody.couponCode).trim() !== '') {\r\n const code = String(rawBody.couponCode).trim().toUpperCase();\r\n const vid = Number((existing as { vendorId: number }).vendorId);\r\n const isUnique = await assertDiscountCouponCodeUnique(repo, code, vid, numericId);\r\n if (!isUnique) {\r\n return json(\r\n { error: 'Coupon code already exists for this store. Please use a unique coupon code.' },\r\n { status: 400 }\r\n );\r\n }\r\n updatePayload.couponCode = code;\r\n }\r\n const validationErr = validateDiscountBody({ ...(existing as object), ...updatePayload });\r\n if (validationErr) return json({ error: validationErr }, { status: 400 });\r\n if (Object.keys(updatePayload).length > 0) {\r\n sanitizeBodyForEntity(repo, updatePayload);\r\n await repo.update(numericId, updatePayload as object);\r\n }\r\n if (Array.isArray(rawBody.rules)) {\r\n await persistDiscountRules(dataSource, entityMap, numericId, rawBody.rules as unknown[]);\r\n }\r\n const reloaded = await repo.findOne({\r\n where: { id: numericId } as import('typeorm').ObjectLiteral,\r\n relations: ['rules'],\r\n });\r\n return reloaded ? json(reloaded) : json({ message: 'Not found' }, { status: 404 });\r\n }\r\n\r\n const scopePut = await resolveScopeById();\r\n if (resourceUsesVendorScope(resource)) {\r\n const idWhereCheck: import('typeorm').ObjectLiteral = entityHasSoftDelete(repo)\r\n ? ({ id: numericId, deleted: false } as import('typeorm').ObjectLiteral)\r\n : ({ id: numericId } as import('typeorm').ObjectLiteral);\r\n const existingScope = await repo.findOne({ where: idWhereCheck });\r\n const scopePutDenied = vendorScopeAccessJson(\r\n existingScope as Record<string, unknown>,\r\n scopePut,\r\n resource\r\n );\r\n if (scopePutDenied) return scopePutDenied;\r\n }\r\n\r\n const updatePayload = rawBody && typeof rawBody === 'object' ? pickColumnUpdates(repo, rawBody) : {};\r\n if (resourceUsesVendorScope(resource)) {\r\n delete updatePayload.vendorId;\r\n }\r\n if (resource === 'contacts' && 'type' in updatePayload) {\r\n const t = updatePayload.type;\r\n if (t === '' || t === 'none' || t == null) updatePayload.type = null;\r\n }\r\n if (resource === 'llm_agents' && 'scope' in updatePayload) {\r\n const scopeErr = await validateLlmAgentScopeForWrite(\r\n dataSource,\r\n entityMap,\r\n updatePayload.scope,\r\n numericId\r\n );\r\n if (scopeErr) return json({ error: scopeErr }, { status: 400 });\r\n }\r\n if (\r\n (resource === 'orders' || resource === 'payments') &&\r\n 'contactId' in updatePayload &&\r\n updatePayload.contactId != null &&\r\n entityMap.vendor_customers\r\n ) {\r\n const existingRow = await repo.findOne({\r\n where: { id: numericId } as import('typeorm').ObjectLiteral,\r\n });\r\n const vendorId = resolveVendorIdForContactCheck(\r\n scopePut,\r\n (existingRow as Record<string, unknown> | null) ?? {}\r\n );\r\n const contactErr = await assertContactAllowedForVendorOrder(\r\n dataSource,\r\n entityMap,\r\n vendorId ?? NaN,\r\n Number(updatePayload.contactId)\r\n );\r\n if (contactErr) {\r\n return json({ error: contactErr }, { status: 400 });\r\n }\r\n }\r\n if (resource === 'media') {\r\n const u = updatePayload as Record<string, unknown>;\r\n delete u.kind;\r\n if (rawBody && typeof rawBody === 'object' && 'parentId' in rawBody) {\r\n let pid: number | null = null;\r\n const p = (rawBody as Record<string, unknown>).parentId;\r\n if (p != null && p !== '') {\r\n const n = Number(p);\r\n if (!Number.isFinite(n)) return json({ error: 'Invalid parentId' }, { status: 400 });\r\n pid = n;\r\n }\r\n if (pid != null) {\r\n const parent = await repo.findOne({ where: { id: pid, deleted: false } as import('typeorm').ObjectLiteral });\r\n if (!parent || (parent as { kind: string }).kind !== 'folder') {\r\n return json({ error: 'parent must be a folder' }, { status: 400 });\r\n }\r\n }\r\n const row = await repo.findOne({ where: { id: numericId, deleted: false } as import('typeorm').ObjectLiteral });\r\n if (!row) return json({ message: 'Not found' }, { status: 404 });\r\n if (pid === numericId) return json({ error: 'Invalid parentId' }, { status: 400 });\r\n if ((row as { kind: string }).kind === 'folder' && pid != null) {\r\n let walk: number | null = pid;\r\n const seen = new Set<number>();\r\n while (walk != null) {\r\n if (walk === numericId) return json({ error: 'Cannot move a folder into itself or a descendant folder' }, { status: 400 });\r\n if (seen.has(walk)) break;\r\n seen.add(walk);\r\n const anc = await repo.findOne({ where: { id: walk, deleted: false } as import('typeorm').ObjectLiteral });\r\n walk = anc ? ((anc as { parentId: number | null }).parentId ?? null) : null;\r\n }\r\n }\r\n u.parentId = pid;\r\n } else {\r\n delete u.parentId;\r\n }\r\n }\r\n if (resource === 'products') {\r\n const currentRow = await repo.findOne({ where: { id: numericId, deleted: false } as import('typeorm').ObjectLiteral });\r\n if (!currentRow) return json({ message: 'Not found' }, { status: 404 });\r\n const merged: Record<string, unknown> = { ...(currentRow as Record<string, unknown>), ...updatePayload };\r\n const effSku = normalizeProductSku(merged.sku);\r\n if (effSku) {\r\n const ok = await assertProductSkuUnique(repo, effSku, numericId);\r\n if (!ok) return json({ error: 'SKU already exists. Please use a unique SKU.' }, { status: 400 });\r\n }\r\n if ('sku' in updatePayload) updatePayload.sku = effSku;\r\n }\r\n if (resource === 'addresses' && Object.keys(updatePayload).length > 0) {\r\n const currentRow = await repo.findOne({ where: { id: numericId } as import('typeorm').ObjectLiteral });\r\n if (!currentRow) return json({ message: 'Not found' }, { status: 404 });\r\n const merged: Record<string, unknown> = { ...(currentRow as Record<string, unknown>), ...updatePayload };\r\n if (merged.tag === '') merged.tag = null;\r\n const addrErr = validateAndNormalizeAddressRow(merged);\r\n if (addrErr) return json({ error: addrErr }, { status: 400 });\r\n for (const k of Object.keys(updatePayload)) {\r\n if (k in merged) (updatePayload as Record<string, unknown>)[k] = merged[k];\r\n }\r\n }\r\n if (resource === 'orders' && orderInvPrev) {\r\n const nextSt =\r\n typeof updatePayload.status === 'string' && updatePayload.status\r\n ? String(updatePayload.status)\r\n : orderInvPrev.status;\r\n if (nextSt === ORDER_STATUS_CONFIRMED && orderInvPrev.lines.length > 0) {\r\n const verr = await validateInventoryForOrderBecomingConfirmed(dataSource, entityMap, orderInvPrev, orderInvPrev.lines);\r\n if (verr) return json({ error: verr }, { status: 400 });\r\n }\r\n }\r\n if (Object.keys(updatePayload).length > 0) {\r\n sanitizeBodyForEntity(repo, updatePayload);\r\n await repo.update(numericId, updatePayload as object);\r\n }\r\n\r\n if (resource === 'orders' && rawBody && entityMap['order_addresses']) {\r\n const addressRawScalar = String((rawBody as Record<string, unknown>)['contact.address'] ?? '').trim();\r\n if (addressRawScalar) {\r\n const orderAddressRepo = dataSource.getRepository(entityMap['order_addresses']);\r\n const orderForCid = await repo.findOne({ where: { id: numericId } as import('typeorm').ObjectLiteral });\r\n const cid = (orderForCid as { contactId?: number } | null)?.contactId;\r\n if (cid) {\r\n const existingAddr = await orderAddressRepo.findOne({ where: { contactId: cid, addressType: 'shipping_address' } as import('typeorm').ObjectLiteral });\r\n if (existingAddr) {\r\n await orderAddressRepo.update((existingAddr as { id: number }).id, { line1: addressRawScalar } as import('typeorm').ObjectLiteral);\r\n } else {\r\n await orderAddressRepo.save(orderAddressRepo.create({\r\n contactId: cid, addressType: 'shipping_address',\r\n line1: addressRawScalar, line2: null, city: '', state: '', postalCode: '', country: '',\r\n }));\r\n }\r\n }\r\n }\r\n }\r\n\r\n const updated =\r\n resource === 'orders'\r\n ? await repo.findOne({ where: { id: numericId, deleted: false } as import('typeorm').ObjectLiteral, relations: ['items'] })\r\n : await repo.findOne({ where: { id: numericId } });\r\n\r\n if (resource === 'orders' && orderInvPrev && updated) {\r\n const invErr = await reconcileOrderInventoryBetweenSnapshots(\r\n dataSource, entityMap, orderInvPrev,\r\n orderInventorySnapshotFromRow(updated as { status?: string; items?: { productId: number; quantity: unknown }[] })\r\n );\r\n if (invErr) return json({ error: invErr }, { status: 409 });\r\n }\r\n if (resource === 'contacts' && updated) {\r\n await syncContactRowToErp(updated as import('typeorm').ObjectLiteral);\r\n }\r\n if (resource === 'products' && updated && getCms) {\r\n const cms = await getCms();\r\n await queueErpProductUpsertIfEnabled(cms, dataSource, entityMap, updated as import('typeorm').ObjectLiteral);\r\n }\r\n return updated ? json(updated) : json({ message: 'Not found' }, { status: 404 });\r\n },\r\n\r\n async DELETE(req: Request, resource: string, id: string) {\r\n const authError = await authz(req, resource, 'delete');\r\n if (authError) return authError;\r\n const entity = entityMap[resource];\r\n if (!entity) {\r\n logCrudClientError('DELETE by id', { reason: 'invalid_resource', resource, id });\r\n return json({ error: 'Invalid resource' }, { status: 400 });\r\n }\r\n const repo = dataSource.getRepository(entity);\r\n const numericId = Number(id);\r\n const scopeDelete = await resolveScopeById();\r\n if (entityHasSoftDelete(repo)) {\r\n const existing = await repo.findOne({\r\n where: { id: numericId, deleted: false } as import('typeorm').ObjectLiteral,\r\n });\r\n if (resourceUsesVendorScope(resource)) {\r\n const deleteDenied = vendorScopeAccessJson(existing as Record<string, unknown>, scopeDelete, resource);\r\n if (deleteDenied) return deleteDenied;\r\n } else if (!existing) {\r\n return json({ message: 'Not found' }, { status: 404 });\r\n }\r\n if (resource === 'contacts') {\r\n const result = await repo.delete(numericId);\r\n if (result.affected === 0) return json({ message: 'Not found' }, { status: 404 });\r\n return json({ message: 'Deleted successfully' }, { status: 200 });\r\n }\r\n\r\n // If deleting a confirmed order that had a discount, decrement usage\r\n if (resource === 'orders') {\r\n const existingOrder = existing as { status?: string; contactId?: number };\r\n if (existingOrder.status === ORDER_STATUS_CONFIRMED && entityMap['order_discounts']) {\r\n const odRepo = dataSource.getRepository(entityMap['order_discounts']);\r\n const od = await odRepo.findOne({\r\n where: { orderId: numericId } as import('typeorm').ObjectLiteral,\r\n });\r\n if (od) {\r\n const odRow = od as { discountId: number; contactId: number };\r\n await decrementDiscountUsage(\r\n dataSource, entityMap,\r\n odRow.discountId,\r\n numericId\r\n );\r\n }\r\n }\r\n }\r\n\r\n let deletedBy: number | null = null;\r\n if (getDeletedByUserId) {\r\n try { deletedBy = await getDeletedByUserId(req); } catch { deletedBy = null; }\r\n }\r\n await repo.update(numericId, buildSoftDeletePayload(repo.metadata, deletedBy) as object);\r\n return json({ message: 'Deleted successfully' }, { status: 200 });\r\n }\r\n if (resourceUsesVendorScope(resource)) {\r\n const existingHard = await repo.findOne({\r\n where: { id: numericId } as import('typeorm').ObjectLiteral,\r\n });\r\n const hardDeleteDenied = vendorScopeAccessJson(\r\n existingHard as Record<string, unknown>,\r\n scopeDelete,\r\n resource\r\n );\r\n if (hardDeleteDenied) return hardDeleteDenied;\r\n }\r\n const result = await repo.delete(numericId);\r\n if (result.affected === 0) return json({ message: 'Not found' }, { status: 404 });\r\n return json({ message: 'Deleted successfully' }, { status: 200 });\r\n },\r\n };\r\n}","import { In, type Repository, type SelectQueryBuilder } from 'typeorm';\r\nimport type { VendorScope } from '../auth/vendor-scope';\r\nimport { VENDOR_SCOPED_STORE_ENTITIES } from '../auth/vendor-scope';\r\nimport type { SessionUser } from '../auth/helpers';\r\nimport { getDefaultVendorId } from '../lib/default-vendor-id';\r\n\r\nexport type SessionVendorHints = Pick<SessionUser, 'activeVendorId' | 'groupId' | 'isRBACAdmin' | 'vendorIds'>;\r\n\r\nexport type VendorScopedCreateContext = {\r\n rawBody?: Record<string, unknown>;\r\n session?: SessionVendorHints | null;\r\n};\r\n\r\nexport function repoHasVendorIdColumn(repo: Repository<import('typeorm').ObjectLiteral>): boolean {\r\n return repo.metadata.columns.some((c) => c.propertyName === 'vendorId');\r\n}\r\n\r\nexport function resourceUsesVendorScope(resource: string): boolean {\r\n return resource === 'vendors' || VENDOR_SCOPED_STORE_ENTITIES.has(resource);\r\n}\r\n\r\nexport function mergeVendorScopeIntoWhere(\r\n where: Record<string, unknown>[] | Record<string, unknown>,\r\n scope: VendorScope,\r\n resource: string\r\n): Record<string, unknown>[] | Record<string, unknown> {\r\n if (scope.type === 'all') return where;\r\n if (scope.type === 'deny') {\r\n if (resource === 'vendors') {\r\n return { id: -1 };\r\n }\r\n return { vendorId: -1 };\r\n }\r\n if (resource === 'vendors') {\r\n return mergeWhereClause(where, { id: In(scope.vendorIds) });\r\n }\r\n return mergeWhereClause(where, { vendorId: scope.vendorId });\r\n}\r\n\r\nfunction mergeWhereClause(\r\n where: Record<string, unknown>[] | Record<string, unknown>,\r\n extra: Record<string, unknown>\r\n): Record<string, unknown>[] | Record<string, unknown> {\r\n if (Array.isArray(where)) {\r\n return where.map((w) => ({ ...w, ...extra }));\r\n }\r\n if (where && typeof where === 'object' && Object.keys(where).length > 0) {\r\n return { ...where, ...extra };\r\n }\r\n return extra;\r\n}\r\n\r\nexport function applyVendorScopeToQueryBuilder(\r\n qb: SelectQueryBuilder<import('typeorm').ObjectLiteral>,\r\n alias: string,\r\n scope: VendorScope\r\n): void {\r\n if (scope.type === 'all') return;\r\n if (scope.type === 'deny') {\r\n qb.andWhere('1 = 0');\r\n return;\r\n }\r\n // Always double-quote the alias — TypeORM aliases like \"order\" are reserved\r\n // SQL keywords in PostgreSQL and must be quoted to avoid syntax errors.\r\n qb.andWhere(`\"${alias}\".\"vendorId\" = :vendorScopeId`, { vendorScopeId: scope.vendorId });\r\n}\r\n\r\nexport function rowMatchesVendorScope(\r\n row: Record<string, unknown> | null | undefined,\r\n scope: VendorScope,\r\n resource: string\r\n): boolean {\r\n if (!row) return false;\r\n if (scope.type === 'all') return true;\r\n if (scope.type === 'deny') return false;\r\n if (resource === 'vendors') {\r\n const id = Number(row.id);\r\n return scope.vendorIds.includes(id);\r\n }\r\n return Number(row.vendorId) === scope.vendorId;\r\n}\r\n\r\n/** Vendor staff accessing another vendor's row → 403; missing row → 404. */\r\nexport function vendorScopeRowAccess(\r\n row: Record<string, unknown> | null | undefined,\r\n scope: VendorScope,\r\n resource: string\r\n): 'ok' | 'not_found' | 'forbidden' {\r\n if (!row) return 'not_found';\r\n if (rowMatchesVendorScope(row, scope, resource)) return 'ok';\r\n return scope.type === 'vendor' ? 'forbidden' : 'not_found';\r\n}\r\n\r\nexport function enforceVendorIdOnCreateBody(\r\n body: Record<string, unknown>,\r\n scope: VendorScope,\r\n repo: Repository<import('typeorm').ObjectLiteral>\r\n): void {\r\n if (!repoHasVendorIdColumn(repo)) return;\r\n if (scope.type === 'vendor') {\r\n delete body.vendorId;\r\n body.vendorId = scope.vendorId;\r\n }\r\n}\r\n\r\n/** Resolve vendorId for writes; vendor scope always uses session vendor, never the client body. */\r\nexport function resolveVendorIdForWrite(\r\n scope: VendorScope,\r\n session: SessionVendorHints | null | undefined,\r\n rawBody?: Record<string, unknown> | null\r\n): number | null {\r\n if (scope.type === 'vendor') return scope.vendorId;\r\n if (scope.type === 'deny') return null;\r\n\r\n if (rawBody) {\r\n const fromBody = Number(rawBody.vendorId);\r\n if (Number.isFinite(fromBody) && fromBody > 0) return fromBody;\r\n }\r\n\r\n const active = session?.activeVendorId;\r\n if (active != null && Number.isFinite(Number(active)) && Number(active) > 0) {\r\n return Number(active);\r\n }\r\n\r\n return getDefaultVendorId();\r\n}\r\n\r\n/** Apply vendor scope to create payloads; returns an error when vendorId cannot be resolved. */\r\nexport function requireVendorIdForScopedCreate(\r\n resource: string,\r\n persistBody: Record<string, unknown>,\r\n scope: VendorScope,\r\n repo: Repository<import('typeorm').ObjectLiteral>,\r\n context?: VendorScopedCreateContext | Record<string, unknown>\r\n): { ok: true } | { ok: false; error: string; status: number } {\r\n if (!resourceUsesVendorScope(resource) || !repoHasVendorIdColumn(repo)) {\r\n return { ok: true };\r\n }\r\n\r\n const ctx: VendorScopedCreateContext =\r\n context && ('session' in context || 'rawBody' in context)\r\n ? (context as VendorScopedCreateContext)\r\n : { rawBody: context as Record<string, unknown> | undefined };\r\n\r\n enforceVendorIdOnCreateBody(persistBody, scope, repo);\r\n\r\n if (scope.type === 'vendor') {\r\n return { ok: true };\r\n }\r\n\r\n if (scope.type === 'deny') {\r\n return {\r\n ok: false,\r\n error: 'Your account is not linked to a vendor store. Ask an administrator to assign you to a vendor.',\r\n status: 403,\r\n };\r\n }\r\n\r\n const vid = Number(persistBody.vendorId);\r\n if (Number.isFinite(vid) && vid > 0) return { ok: true };\r\n\r\n const resolved = resolveVendorIdForWrite(scope, ctx.session ?? null, ctx.rawBody ?? persistBody);\r\n if (resolved != null && resolved > 0) {\r\n persistBody.vendorId = resolved;\r\n return { ok: true };\r\n }\r\n\r\n return { ok: false, error: 'vendorId is required', status: 400 };\r\n}\r\n","/** Platform-admin fallback vendor when session has no activeVendorId. Override via DEFAULT_VENDOR_ID. */\r\nexport function getDefaultVendorId(): number {\r\n const raw = process.env.DEFAULT_VENDOR_ID;\r\n if (raw != null && String(raw).trim() !== '') {\r\n const n = Number(raw);\r\n if (Number.isFinite(n) && n > 0) return Math.floor(n);\r\n }\r\n return 1;\r\n}\r\n","import { Country, State, City } from 'country-state-city';\r\nimport type { ICity, ICountry, IState } from 'country-state-city';\r\n\r\nfunction norm(s: unknown): string {\r\n return typeof s === 'string' ? s.trim() : '';\r\n}\r\n\r\nfunction resolveCountry(input: string): ICountry | undefined {\r\n const t = input.trim();\r\n if (!t) return undefined;\r\n if (t.length === 2) {\r\n const byCode = Country.getCountryByCode(t.toUpperCase());\r\n if (byCode) return byCode;\r\n }\r\n const lower = t.toLowerCase();\r\n return Country.getAllCountries().find((c) => c.name.toLowerCase() === lower);\r\n}\r\n\r\nfunction resolveState(countryIso: string, input: string): IState | undefined {\r\n const t = input.trim();\r\n if (!t || !countryIso) return undefined;\r\n const states = State.getStatesOfCountry(countryIso);\r\n const lower = t.toLowerCase();\r\n return states.find((s) => s.isoCode.toLowerCase() === t.toLowerCase() || s.name.toLowerCase() === lower);\r\n}\r\n\r\nfunction resolveCity(countryIso: string, stateIso: string, input: string): ICity | undefined {\r\n const t = input.trim();\r\n if (!t || !countryIso || !stateIso) return undefined;\r\n const lower = t.toLowerCase();\r\n const cities = City.getCitiesOfState(countryIso, stateIso);\r\n return cities.find((c) => c.name.toLowerCase() === lower);\r\n}\r\n\r\n/** Validates required address fields and country → state → city hierarchy; returns canonical display names. */\r\nexport function assertValidAddressHierarchy(\r\n country: string,\r\n state: string,\r\n city: string\r\n): { ok: true; country: string; state: string; city: string } | { ok: false; error: string } {\r\n const c = resolveCountry(country);\r\n if (!c) return { ok: false, error: 'Invalid or unknown country.' };\r\n const st = resolveState(c.isoCode, state);\r\n if (!st) return { ok: false, error: 'State or province does not match the selected country.' };\r\n const ct = resolveCity(c.isoCode, st.isoCode, city);\r\n if (!ct) return { ok: false, error: 'City does not match the selected state.' };\r\n return { ok: true, country: c.name, state: st.name, city: ct.name };\r\n}\r\n\r\nexport type AddressScalarFields = {\r\n line1: unknown;\r\n line2?: unknown;\r\n postalCode: unknown;\r\n country: unknown;\r\n state: unknown;\r\n city: unknown;\r\n};\r\n\r\n/**\r\n * Ensures required address parts are present and geo data is consistent.\r\n * On success, mutates `row` with trimmed line1/line2/postalCode and canonical country/state/city names.\r\n */\r\nexport function validateAndNormalizeAddressRow(\r\n row: Record<string, unknown>\r\n): string | null {\r\n const line1 = norm(row.line1);\r\n const postalCode = norm(row.postalCode);\r\n const countryIn = norm(row.country);\r\n const stateIn = norm(row.state);\r\n const cityIn = norm(row.city);\r\n\r\n if (!line1) return 'Street address (line 1) is required.';\r\n if (!postalCode) return 'Postal code is required.';\r\n if (!countryIn || !stateIn || !cityIn) return 'Country, state, and city are required.';\r\n\r\n const geo = assertValidAddressHierarchy(countryIn, stateIn, cityIn);\r\n if (!geo.ok) return geo.error;\r\n\r\n row.line1 = line1;\r\n row.line2 = norm(row.line2) || null;\r\n row.postalCode = postalCode;\r\n row.country = geo.country;\r\n row.state = geo.state;\r\n row.city = geo.city;\r\n return null;\r\n}\r\n","import type { DataSource, EntityTarget } from 'typeorm';\r\nimport type { EntityMap } from '../../api/crud';\r\nimport type { LlmAgent } from '../../entities/llm-agent.entity';\r\nimport { isLlmAgentScope } from './llm-agent-scope';\r\n\r\n/** Returns an error message when scope is invalid or already used by another active row. */\r\nexport async function validateLlmAgentScopeForWrite(\r\n dataSource: DataSource,\r\n entityMap: EntityMap,\r\n scope: unknown,\r\n excludeId?: number\r\n): Promise<string | null> {\r\n if (scope == null || scope === '') return null;\r\n if (typeof scope !== 'string' || !isLlmAgentScope(scope)) {\r\n return `Invalid agent scope. Allowed: chatbot, blog_creation, social_media_post, email_intent_chatbot, blog_metadata.`;\r\n }\r\n\r\n const entity = entityMap.llm_agents;\r\n if (!entity) return null;\r\n\r\n const repo = dataSource.getRepository(entity as EntityTarget<LlmAgent>);\r\n const existing = await repo.findOne({\r\n where: { scope, deleted: false } as object,\r\n });\r\n if (!existing) return null;\r\n if (excludeId != null && existing.id === excludeId) return null;\r\n return `An active agent already uses scope \"${scope}\".`;\r\n}\r\n","/**\r\n * Auth API handler factories. Inject dataSource + entityMap, sendEmail, hash/compare; optional hooks to customize.\r\n */\r\nimport type { DataSource } from 'typeorm';\r\nimport { linkUnclaimedContactToUser } from '../lib/link-contact-to-user';\r\nimport type { EntityMap } from './crud';\r\n\r\nexport interface AuthHandlersConfig {\r\n json: (body: unknown, init?: { status?: number }) => Response;\r\n baseUrl: string;\r\n hashPassword: (plain: string) => Promise<string>;\r\n comparePassword: (plain: string, hash: string) => Promise<boolean>;\r\n}\r\n\r\nexport interface ForgotPasswordConfig extends AuthHandlersConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n sendEmail?: (opts: {\r\n to: string;\r\n subject: string;\r\n html: string;\r\n text?: string;\r\n /** Plain reset URL for templated emails (preferred over parsing html). */\r\n resetLink?: string;\r\n }) => Promise<void>;\r\n resetExpiryHours?: number;\r\n afterCreateToken?: (email: string, resetLink: string) => Promise<void>;\r\n}\r\n\r\nexport function createForgotPasswordHandler(config: ForgotPasswordConfig) {\r\n const { dataSource, entityMap, json, baseUrl, sendEmail, resetExpiryHours = 1, afterCreateToken } = config;\r\n return async function POST(request: Request): Promise<Response> {\r\n try {\r\n const body = await request.json().catch(() => ({})) as { email?: string };\r\n const email = typeof body?.email === 'string' ? body.email.trim().toLowerCase() : '';\r\n if (!email) return json({ error: 'Email is required' }, { status: 400 });\r\n\r\n const userRepo = dataSource.getRepository(entityMap.users);\r\n const user = await userRepo.findOne({ where: { email }, select: ['email'] });\r\n const msg = 'If an account exists with this email, you will receive a reset link shortly.';\r\n if (!user) return json({ message: msg }, { status: 200 });\r\n\r\n const crypto = await import('crypto');\r\n const token = crypto.randomBytes(32).toString('hex');\r\n const expiresAt = new Date(Date.now() + (resetExpiryHours * 60 * 60 * 1000));\r\n const tokenRepo = dataSource.getRepository(entityMap.password_reset_tokens);\r\n await tokenRepo.save(tokenRepo.create({ email: user.email, token, expiresAt }));\r\n const resetLink = `${baseUrl}/admin/reset-password?token=${token}`;\r\n\r\n if (sendEmail)\r\n await sendEmail({\r\n to: user.email,\r\n subject: 'Password reset',\r\n html: `<a href=\"${resetLink}\">Reset password</a>`,\r\n text: resetLink,\r\n resetLink,\r\n });\r\n if (afterCreateToken) await afterCreateToken(user.email, resetLink);\r\n return json({ message: msg }, { status: 200 });\r\n } catch (err) {\r\n return json({ error: 'Something went wrong. Please try again.' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nexport interface SetPasswordConfig extends AuthHandlersConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n minPasswordLength?: number;\r\n beforeUpdate?: (email: string, userId: number) => Promise<void>;\r\n}\r\n\r\nexport function createSetPasswordHandler(config: SetPasswordConfig) {\r\n const { dataSource, entityMap, json, hashPassword, minPasswordLength = 6, beforeUpdate } = config;\r\n return async function POST(request: Request): Promise<Response> {\r\n try {\r\n const body = await request.json().catch(() => ({})) as { token?: string; newPassword?: string };\r\n const { token, newPassword } = body;\r\n if (!token || !newPassword) return json({ error: 'Token and new password are required' }, { status: 400 });\r\n if (newPassword.length < minPasswordLength) return json({ error: 'Password must be at least 6 characters' }, { status: 400 });\r\n\r\n const tokenRepo = dataSource.getRepository(entityMap.password_reset_tokens);\r\n const record = await tokenRepo.findOne({ where: { token } });\r\n if (!record || record.expiresAt < new Date()) return json({ error: 'Invalid or expired reset link. Please request a new one.' }, { status: 400 });\r\n\r\n const userRepo = dataSource.getRepository(entityMap.users);\r\n const user = await userRepo.findOne({ where: { email: record.email }, select: ['id'] });\r\n if (!user) return json({ error: 'User not found' }, { status: 400 });\r\n\r\n if (beforeUpdate) await beforeUpdate(record.email, user.id);\r\n const hashedPassword = await hashPassword(newPassword);\r\n await userRepo.update(user.id, { password: hashedPassword, updatedAt: new Date() });\r\n await tokenRepo.delete({ email: record.email });\r\n return json({ message: 'Password updated successfully. You can now sign in.' });\r\n } catch {\r\n return json({ error: 'Something went wrong. Please try again.' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nexport interface InviteAcceptConfig extends AuthHandlersConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n beforeActivate?: (email: string, userId: number) => Promise<void>;\r\n}\r\n\r\n/** Decode invite token (base64 email) and set password + unblock user */\r\nexport function createInviteAcceptHandler(config: InviteAcceptConfig) {\r\n const { dataSource, entityMap, json, hashPassword, beforeActivate } = config;\r\n return async function POST(request: Request): Promise<Response> {\r\n try {\r\n const body = await request.json().catch(() => ({})) as { token?: string; password?: string };\r\n const { token, password } = body;\r\n if (!token || !password) return json({ error: 'Missing required fields: token, password' }, { status: 400 });\r\n\r\n let email: string;\r\n try {\r\n email = Buffer.from(token, 'base64').toString('utf8');\r\n } catch {\r\n return json({ error: 'Invalid or expired invite token' }, { status: 400 });\r\n }\r\n\r\n const userRepo = dataSource.getRepository(entityMap.users);\r\n const user = await userRepo.findOne({ where: { email }, select: ['id', 'blocked', 'password'] });\r\n if (!user) return json({ error: 'User not found' }, { status: 400 });\r\n const hasPassword = !!(user as { password?: string | null }).password;\r\n if (!user.blocked && hasPassword) {\r\n return json({ error: 'User is already active' }, { status: 400 });\r\n }\r\n\r\n if (entityMap.contacts) {\r\n await linkUnclaimedContactToUser(dataSource, entityMap.contacts, user.id, email);\r\n }\r\n if (beforeActivate) await beforeActivate(email, user.id);\r\n const hashedPassword = await hashPassword(password);\r\n await userRepo.update(user.id, { password: hashedPassword, blocked: false });\r\n return json({ message: 'User account activated successfully' }, { status: 200 });\r\n } catch (err) {\r\n return json({ error: 'Server Error' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nexport interface ChangePasswordConfig extends AuthHandlersConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n getSession: () => Promise<{ user?: { email?: string | null } } | null>;\r\n minPasswordLength?: number;\r\n beforeUpdate?: (email: string) => Promise<void>;\r\n}\r\n\r\nexport function createChangePasswordHandler(config: ChangePasswordConfig) {\r\n const { dataSource, entityMap, json, comparePassword, hashPassword, getSession, minPasswordLength = 6, beforeUpdate } = config;\r\n return async function POST(request: Request): Promise<Response> {\r\n try {\r\n const session = await getSession();\r\n if (!session?.user?.email) return json({ error: 'Unauthorized' }, { status: 401 });\r\n\r\n const body = await request.json().catch(() => ({})) as { currentPassword?: string; newPassword?: string };\r\n const { currentPassword, newPassword } = body;\r\n if (!currentPassword || !newPassword) return json({ error: 'Current password and new password are required' }, { status: 400 });\r\n if (newPassword.length < minPasswordLength) return json({ error: 'New password must be at least 6 characters long' }, { status: 400 });\r\n\r\n const userRepo = dataSource.getRepository(entityMap.users);\r\n const user = await userRepo.findOne({ where: { email: session.user.email }, select: ['password'] });\r\n if (!user) return json({ error: 'User not found' }, { status: 404 });\r\n if (!user.password) return json({ error: 'Current password is incorrect' }, { status: 400 });\r\n const valid = await comparePassword(currentPassword, user.password);\r\n if (!valid) return json({ error: 'Current password is incorrect' }, { status: 400 });\r\n\r\n if (beforeUpdate) await beforeUpdate(session.user.email);\r\n const hashedPassword = await hashPassword(newPassword);\r\n await userRepo.update({ email: session.user.email }, { password: hashedPassword, updatedAt: new Date() });\r\n return json({ message: 'Password updated successfully' });\r\n } catch {\r\n return json({ error: 'Internal server error' }, { status: 500 });\r\n }\r\n };\r\n}\r\n\r\nexport interface UserAuthApiConfig\r\n extends ForgotPasswordConfig,\r\n Omit<SetPasswordConfig, 'dataSource' | 'entityMap' | 'json' | 'baseUrl' | 'hashPassword' | 'comparePassword'>,\r\n Omit<InviteAcceptConfig, 'dataSource' | 'entityMap' | 'json' | 'baseUrl' | 'hashPassword' | 'comparePassword'>,\r\n Omit<ChangePasswordConfig, 'dataSource' | 'entityMap' | 'json' | 'baseUrl' | 'hashPassword' | 'comparePassword' | 'beforeUpdate' | 'getSession'> {\r\n getSession?: () => Promise<{ user?: { email?: string | null } } | null>;\r\n beforeChangePasswordUpdate?: (email: string) => Promise<void>;\r\n}\r\n\r\nconst USER_AUTH_PATHS = ['forgot-password', 'invite', 'set-password', 'reset-password'] as const;\r\n\r\n/**\r\n * Single router for all user-auth APIs. Mount in the app once.\r\n * Use when you have no users/[id] route (else Next.js gives [id] precedence and \"forgot-password\" would match as id).\r\n * Path is the segment after the mount (e.g. \"forgot-password\"). Returns 404 for unknown paths.\r\n */\r\nexport function createUserAuthApiRouter(config: UserAuthApiConfig) {\r\n const forgot = createForgotPasswordHandler(config);\r\n const setPass = createSetPasswordHandler(config);\r\n const invite = createInviteAcceptHandler(config);\r\n const changePass = config.getSession\r\n ? createChangePasswordHandler({\r\n ...config,\r\n getSession: config.getSession,\r\n beforeUpdate: config.beforeChangePasswordUpdate,\r\n })\r\n : null;\r\n\r\n return {\r\n async POST(req: Request, pathname: string): Promise<Response> {\r\n const path = pathname.replace(/\\/$/, '');\r\n if (!USER_AUTH_PATHS.includes(path as (typeof USER_AUTH_PATHS)[number])) {\r\n return config.json({ error: 'Not found' }, { status: 404 });\r\n }\r\n if (path === 'forgot-password') return forgot(req);\r\n if (path === 'set-password') return setPass(req);\r\n if (path === 'invite') return invite(req);\r\n if (path === 'reset-password' && changePass) return changePass(req);\r\n return config.json({ error: 'Not found' }, { status: 404 });\r\n },\r\n };\r\n}\r\n","/**\n * Admin API: attach knowledge base documents to an LLM agent, ingest text into chunks + embeddings.\n * Routes: GET/POST /api/llm_agents/:slug/knowledge, DELETE /api/llm_agents/:slug/knowledge/:documentId\n *\n * Pipeline logs (grep `[llm-agent-knowledge] pipeline`):\n * - 01_request — incoming POST, content-type preview\n * - 02_agent_loaded — agent id for slug\n * - 03_body_parsed — JSON vs multipart, sizes / documentId\n * - 04_* — file decode or PDF extract (multipart)\n * - 05_branch — link_existing_document | new_upload_ingest\n * - 06_* — KB row + junction (link create / exists)\n * - 06b_chunks_existing_count — link path: existing chunk rows\n * - 06_knowledge_document_saved — new ingest: document row id\n * - 07_chunk_split — split stats\n * - 07b_chunks_persisted — chunk rows saved\n * - 07_query_chunks_missing_embedding — link path: rows with NULL embedding\n * - 08_* — resolve LLM plugin, embed availability or skip\n * - 09_embedding_workers_start / 10_embedding_workers_finished — concurrent embed+DB update\n * - 11_response — final outcome summary\n * - 99_pipeline_error — uncaught exception\n */\nimport type { DataSource, EntityTarget, ObjectLiteral } from 'typeorm';\nimport { In } from 'typeorm';\nimport type { EntityMap } from './crud';\nimport type { RequireEntityPermissionFn } from './cms-handlers';\nimport type { LlmAgent } from '../entities/llm-agent.entity';\n\nconst INGEST_CHUNK_CHARS = 900;\n/** Avoid serverless / DB timeouts on huge uploads; ~400 × 900 ≈ 360k chars. */\nconst MAX_CHUNKS_PER_UPLOAD = 400;\nconst EMBED_CONCURRENCY = 5;\n/** Limit PDF buffer size before parsing (memory / CPU). */\nconst MAX_PDF_BYTES = 25 * 1024 * 1024;\n\nconst TEXT_FILE_TYPES = new Set(['text/plain', 'text/markdown', 'application/json']);\n\nconst KB_LOG = '[llm-agent-knowledge]';\n\n/** Ordered pipeline logs: upload → KB document → chunks → junction → embeddings. */\nfunction logKbPipeline(step: string, meta?: Record<string, unknown>): void {\n console.info(`${KB_LOG} pipeline`, { step, ...meta });\n}\n\nfunction llmEmbedDebug(): boolean {\n const v = process.env.LLM_EMBED_DEBUG?.toLowerCase();\n return v === '1' || v === 'true' || v === 'yes';\n}\n\nfunction isPdfUpload(mime: string, fileName: string): boolean {\n if (mime === 'application/pdf') return true;\n const n = fileName.toLowerCase();\n return n.endsWith('.pdf');\n}\n\nasync function extractTextFromPdf(buffer: Buffer): Promise<string> {\n const pdfParse = (await import('pdf-parse')) as unknown as (\n data: Buffer\n ) => Promise<{ text?: string }>;\n const data = await pdfParse(buffer);\n return (data?.text ?? '').trim();\n}\n\n/** Chunks that still need vectors (e.g. after a failed embed pass or CRUD-created documents). */\nasync function loadChunksMissingEmbeddings(\n dataSource: DataSource,\n documentId: number,\n slug: string\n): Promise<Array<{ id: number; content: string }>> {\n const rows = (await dataSource.query(\n `SELECT id, content FROM knowledge_base_chunks WHERE \"documentId\" = $1 AND embedding IS NULL ORDER BY \"chunkIndex\" ASC`,\n [documentId]\n )) as Array<{ id: number; content: string }>;\n const list = rows ?? [];\n logKbPipeline('07_query_chunks_missing_embedding', {\n slug,\n documentId,\n missingEmbeddingCount: list.length,\n });\n return list;\n}\n\nasync function writeEmbeddingsConcurrent(\n dataSource: DataSource,\n embed: (t: string) => Promise<number[]>,\n chunks: Array<{ id: number; content: string }>,\n concurrency: number,\n slug: string\n): Promise<{ written: number; failed: number }> {\n let next = 0;\n let written = 0;\n let failed = 0;\n let skippedEmpty = 0;\n\n logKbPipeline('09_embedding_workers_start', {\n slug,\n chunkCount: chunks.length,\n concurrency: Math.max(1, Math.min(concurrency, chunks.length)),\n });\n\n async function worker() {\n for (;;) {\n const i = next++;\n if (i >= chunks.length) return;\n const c = chunks[i]!;\n try {\n const emb = await embed(c.content);\n if (emb?.length) {\n const vectorStr = '[' + emb.join(',') + ']';\n await dataSource.query(\n `UPDATE knowledge_base_chunks SET embedding = $1::vector WHERE id = $2`,\n [vectorStr, c.id]\n );\n written++;\n } else {\n skippedEmpty++;\n if (llmEmbedDebug()) {\n console.warn(`${KB_LOG} embed() returned empty vector`, { chunkId: c.id });\n }\n }\n } catch (err) {\n failed++;\n console.error(`${KB_LOG} embedding DB update failed`, {\n chunkId: c.id,\n err: err instanceof Error ? err.message : String(err),\n });\n }\n }\n }\n\n const n = Math.max(1, Math.min(concurrency, chunks.length));\n await Promise.all(Array.from({ length: n }, () => worker()));\n const summary: Record<string, unknown> = {\n chunkCount: chunks.length,\n written,\n failed,\n skippedEmpty,\n };\n if (skippedEmpty > 0 && written === 0) {\n summary.hint =\n 'embed() returned empty vectors — see [LLM embed] / [LLM embed HF] logs (OpenAI gateway vs @huggingface/inference + legacy HTTP).';\n }\n logKbPipeline('10_embedding_workers_finished', { slug, ...summary });\n if (failed > 0 || (skippedEmpty > 0 && written === 0)) {\n console.error(`${KB_LOG} embedding pass finished with issues`, summary);\n }\n return { written, failed };\n}\n\nexport interface LlmAgentKnowledgeApiConfig {\n dataSource: DataSource;\n entityMap: EntityMap;\n getCms: () => Promise<{ getPlugin: (name: string) => unknown }>;\n json: (body: unknown, init?: { status?: number }) => Response;\n requireAuth: (req: Request) => Promise<Response | null>;\n requireEntityPermission?: RequireEntityPermissionFn;\n}\n\nfunction splitIntoChunks(text: string, maxLen: number): string[] {\n const t = text.trim();\n if (!t) return [];\n const chunks: string[] = [];\n for (let i = 0; i < t.length; i += maxLen) {\n chunks.push(t.slice(i, i + maxLen));\n }\n return chunks;\n}\n\nasync function findAgentBySlug(\n dataSource: DataSource,\n llmAgents: EntityTarget<ObjectLiteral>,\n slug: string\n): Promise<LlmAgent | null> {\n const repo = dataSource.getRepository(llmAgents as EntityTarget<LlmAgent>);\n return repo.findOne({\n where: { slug, deleted: false } as object,\n });\n}\n\nexport function createLlmAgentKnowledgeHandlers(config: LlmAgentKnowledgeApiConfig) {\n const { dataSource, entityMap, getCms, json, requireAuth, requireEntityPermission } = config;\n\n const kbDoc = entityMap.knowledge_base_documents;\n const kbChunk = entityMap.knowledge_base_chunks;\n const llmAgents = entityMap.llm_agents;\n const junction = entityMap.llm_agent_knowledge_documents;\n\n if (!kbDoc || !kbChunk || !llmAgents || !junction) {\n return null;\n }\n\n async function gate(req: Request, action: 'read' | 'update'): Promise<Response | null> {\n const a = await requireAuth(req);\n if (a) return a;\n if (requireEntityPermission) {\n const pe = await requireEntityPermission(req, 'llm_agents', action);\n if (pe) return pe;\n }\n return null;\n }\n\n async function runEmbeddingPass(\n slug: string,\n savedChunks: Array<{ id: number; content: string }>\n ): Promise<{ embeddingsWritten: number; embeddingsFailed: number; embedError?: string }> {\n let embeddingsWritten = 0;\n let embeddingsFailed = 0;\n try {\n logKbPipeline('08_resolve_llm_plugin', { slug, chunkCount: savedChunks.length });\n const cms = await getCms();\n const llm = cms.getPlugin('llm') as { embed?: (t: string) => Promise<number[]> } | undefined;\n if (llm?.embed && savedChunks.length > 0) {\n logKbPipeline('08b_embed_fn_available', {\n slug,\n chunkCount: savedChunks.length,\n firstChunkId: savedChunks[0]?.id,\n lastChunkId: savedChunks[savedChunks.length - 1]?.id,\n });\n const embedBound = (text: string) => llm.embed!(text);\n const { written, failed } = await writeEmbeddingsConcurrent(\n dataSource,\n embedBound,\n savedChunks,\n EMBED_CONCURRENCY,\n slug\n );\n embeddingsWritten = written;\n embeddingsFailed = failed;\n } else {\n logKbPipeline('08c_embed_skipped', {\n slug,\n hasLlmPlugin: !!llm,\n hasEmbed: typeof llm?.embed === 'function',\n chunkCount: savedChunks.length,\n reason: savedChunks.length === 0 ? 'no_chunks' : !llm ? 'no_llm_plugin' : 'no_embed_method',\n });\n console.error(`${KB_LOG} embeddings skipped`, {\n slug,\n hasLlmPlugin: !!llm,\n hasEmbed: typeof llm?.embed === 'function',\n chunkCount: savedChunks.length,\n hint:\n !llm || typeof llm.embed !== 'function'\n ? 'LLM plugin missing or no embed(); check LLM_GATEWAY_URL + LLM_API_KEY so llm plugin initializes.'\n : undefined,\n });\n }\n } catch (embErr) {\n const detail = embErr instanceof Error ? embErr.message : String(embErr);\n logKbPipeline('08d_embed_pass_exception', { slug, detail });\n console.error(`${KB_LOG} embedding step threw before/during batch`, { slug, detail, embErr });\n return {\n embeddingsWritten: 0,\n embeddingsFailed: savedChunks.length,\n embedError: detail,\n };\n }\n return { embeddingsWritten, embeddingsFailed };\n }\n\n return {\n async list(req: Request, slug: string): Promise<Response> {\n const denied = await gate(req, 'read');\n if (denied) return denied;\n try {\n const agent = await findAgentBySlug(dataSource, llmAgents, slug);\n if (!agent) return json({ error: 'Agent not found' }, { status: 404 });\n const linkRepo = dataSource.getRepository(junction);\n const links = await linkRepo.find({ where: { agentId: agent.id } as object });\n const docIds = [...new Set((links as Array<{ documentId: number }>).map((l) => l.documentId))];\n if (docIds.length === 0) return json({ documents: [] });\n const docRepo = dataSource.getRepository(kbDoc);\n const docs = await docRepo.find({ where: { id: In(docIds) } as object });\n const byId = new Map((docs as Array<{ id: number; name: string }>).map((d) => [d.id, d]));\n const documents = docIds\n .map((id) => {\n const d = byId.get(id);\n return d ? { id: d.id, name: d.name } : null;\n })\n .filter(Boolean);\n return json({ documents });\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'Failed to list knowledge';\n return json({ error: msg }, { status: 500 });\n }\n },\n\n async post(req: Request, slug: string): Promise<Response> {\n const denied = await gate(req, 'update');\n if (denied) return denied;\n try {\n const ct0 = req.headers.get('content-type') || '';\n logKbPipeline('01_request', { slug, contentType: ct0.slice(0, 80) });\n\n const agent = await findAgentBySlug(dataSource, llmAgents, slug);\n if (!agent) return json({ error: 'Agent not found' }, { status: 404 });\n logKbPipeline('02_agent_loaded', { slug, agentId: agent.id });\n\n let name = '';\n let text = '';\n let sourceUrl: string | null = null;\n let existingDocumentId: number | null = null;\n\n const ct = req.headers.get('content-type') || '';\n if (ct.includes('application/json')) {\n const body = (await req.json()) as {\n name?: string;\n text?: string;\n sourceUrl?: string | null;\n documentId?: number;\n };\n existingDocumentId =\n typeof body?.documentId === 'number' && Number.isFinite(body.documentId) ? body.documentId : null;\n name = (body?.name ?? '').trim();\n text = (body?.text ?? '').trim();\n sourceUrl =\n typeof body?.sourceUrl === 'string' && body.sourceUrl.trim() ? body.sourceUrl.trim() : null;\n logKbPipeline('03_body_parsed', {\n slug,\n mode: 'json',\n existingDocumentId,\n nameLen: name.length,\n textChars: text.length,\n hasSourceUrl: !!sourceUrl,\n });\n } else if (ct.includes('multipart/form-data')) {\n const form = await req.formData();\n name = (form.get('name') as string | null)?.trim() ?? '';\n text = (form.get('text') as string | null)?.trim() ?? '';\n const file = form.get('file');\n if (file && typeof file !== 'string' && 'arrayBuffer' in file) {\n const f = file as File;\n const mime = (f.type || '').split(';')[0]!.trim().toLowerCase();\n const buf = Buffer.from(await f.arrayBuffer());\n logKbPipeline('03_body_parsed', {\n slug,\n mode: 'multipart',\n fileName: f.name || '(no name)',\n mime,\n fileBytes: buf.length,\n });\n if (TEXT_FILE_TYPES.has(mime)) {\n const decoded = buf.toString('utf8');\n if (!text) text = decoded;\n logKbPipeline('04_file_decoded_text', { slug, mime, textChars: text.length });\n } else if (isPdfUpload(mime, f.name || '')) {\n if (buf.length > MAX_PDF_BYTES) {\n return json(\n { error: `PDF too large (max ${Math.floor(MAX_PDF_BYTES / (1024 * 1024))}MB)` },\n { status: 413 }\n );\n }\n try {\n logKbPipeline('04_pdf_extract_start', { slug, fileBytes: buf.length });\n const extracted = await extractTextFromPdf(buf);\n if (!text) text = extracted;\n logKbPipeline('04_pdf_extract_done', { slug, textChars: text.length });\n } catch {\n return json(\n { error: 'Could not read PDF text (file may be encrypted, corrupt, or image-only)' },\n { status: 422 }\n );\n }\n } else {\n return json(\n {\n error:\n 'Unsupported file type; use text/plain, text/markdown, application/json, or application/pdf',\n },\n { status: 415 }\n );\n }\n if (!name && f.name) name = f.name.replace(/\\.[^/.]+$/, '') || f.name;\n } else {\n logKbPipeline('03_body_parsed', { slug, mode: 'multipart', hasFile: false, textChars: text.length });\n }\n } else {\n return json({ error: 'Use application/json or multipart/form-data' }, { status: 400 });\n }\n\n const linkRepo = dataSource.getRepository(junction);\n\n if (existingDocumentId != null) {\n logKbPipeline('05_branch', { slug, branch: 'link_existing_document', documentId: existingDocumentId });\n const docRepo = dataSource.getRepository(kbDoc);\n const existing = await docRepo.findOne({ where: { id: existingDocumentId } as object });\n if (!existing) return json({ error: 'documentId not found' }, { status: 404 });\n const dup = await linkRepo.findOne({\n where: { agentId: agent.id, documentId: existingDocumentId } as object,\n });\n if (!dup) {\n await linkRepo.save(linkRepo.create({ agentId: agent.id, documentId: existingDocumentId } as object));\n logKbPipeline('06_junction_link_created', {\n slug,\n agentId: agent.id,\n documentId: existingDocumentId,\n });\n } else {\n logKbPipeline('06_junction_link_exists', {\n slug,\n agentId: agent.id,\n documentId: existingDocumentId,\n });\n }\n\n const chunkRepo = dataSource.getRepository(kbChunk);\n const docRow = existing as { id: number; content: string };\n const chunkCount = await chunkRepo.count({ where: { documentId: existingDocumentId } as object });\n logKbPipeline('06b_chunks_existing_count', {\n slug,\n documentId: existingDocumentId,\n chunkCount,\n });\n\n let chunksToEmbed: Array<{ id: number; content: string }> = [];\n let chunksCreated = 0;\n\n if (chunkCount === 0) {\n const text = (docRow.content ?? '').trim();\n if (!text) {\n logKbPipeline('07_ingest_aborted_empty_document', { slug, documentId: existingDocumentId });\n return json({\n documentId: existingDocumentId,\n linked: true,\n created: false,\n chunkCount: 0,\n embeddingsWritten: 0,\n embeddingsFailed: 0,\n warning: 'Document has no text content; add content then attach again to build chunks and embeddings.',\n });\n }\n const parts = splitIntoChunks(text, INGEST_CHUNK_CHARS);\n if (parts.length > MAX_CHUNKS_PER_UPLOAD) {\n return json(\n {\n error: `Document is too large for one ingest (${parts.length} chunks; max ${MAX_CHUNKS_PER_UPLOAD}). Split into smaller files.`,\n },\n { status: 413 }\n );\n }\n logKbPipeline('07_chunk_split', {\n slug,\n documentId: existingDocumentId,\n partCount: parts.length,\n maxChunkChars: INGEST_CHUNK_CHARS,\n totalChars: text.length,\n });\n const now = new Date();\n const chunkRows = parts.map((content, i) =>\n chunkRepo.create({\n documentId: existingDocumentId,\n content,\n chunkIndex: i,\n createdAt: now,\n } as object)\n );\n const savedList = await chunkRepo.save(chunkRows);\n chunksCreated = savedList.length;\n chunksToEmbed = (savedList as Array<{ id: number }>).map((row, i) => ({\n id: row.id,\n content: parts[i]!,\n }));\n logKbPipeline('07b_chunks_persisted', {\n slug,\n documentId: existingDocumentId,\n rowsInserted: chunksCreated,\n });\n } else {\n chunksToEmbed = await loadChunksMissingEmbeddings(dataSource, existingDocumentId, slug);\n if (chunksToEmbed.length === 0) {\n logKbPipeline('08_skip_embed_all_chunks_have_vectors', {\n slug,\n documentId: existingDocumentId,\n existingChunkCount: chunkCount,\n });\n }\n }\n\n const embedResult =\n chunksToEmbed.length > 0\n ? await runEmbeddingPass(slug, chunksToEmbed)\n : { embeddingsWritten: 0, embeddingsFailed: 0 };\n if (embedResult.embedError) {\n logKbPipeline('11_response', {\n slug,\n branch: 'link',\n documentId: existingDocumentId,\n ok: false,\n embeddingError: true,\n });\n return json(\n {\n documentId: existingDocumentId,\n linked: true,\n created: false,\n chunkCount: chunkCount + chunksCreated,\n chunksCreated,\n embeddingAttempted: true,\n embeddingsWritten: 0,\n embeddingsFailed: chunksToEmbed.length,\n warning: 'Document linked; embedding step failed. Fix LLM/embed config and attach again (or unlink and re-attach) to retry NULL embeddings.',\n detail: embedResult.embedError,\n },\n { status: 201 }\n );\n }\n\n logKbPipeline('11_response', {\n slug,\n branch: 'link',\n documentId: existingDocumentId,\n ok: true,\n chunkCount: chunkCount + chunksCreated,\n chunksCreated,\n chunksQueuedForEmbedding: chunksToEmbed.length,\n embeddingsWritten: embedResult.embeddingsWritten,\n embeddingsFailed: embedResult.embeddingsFailed,\n });\n return json({\n documentId: existingDocumentId,\n linked: true,\n created: false,\n chunkCount: chunkCount + chunksCreated,\n chunksCreated: chunksCreated || undefined,\n chunksQueuedForEmbedding: chunksToEmbed.length,\n embeddingAttempted: chunksToEmbed.length > 0,\n embeddingsWritten: embedResult.embeddingsWritten,\n embeddingsFailed: embedResult.embeddingsFailed,\n });\n }\n\n logKbPipeline('05_branch', { slug, branch: 'new_upload_ingest' });\n\n if (!text) return json({ error: 'text or file with text content is required' }, { status: 400 });\n if (!name) name = 'Untitled';\n\n const parts = splitIntoChunks(text, INGEST_CHUNK_CHARS);\n if (parts.length === 0) {\n return json({ error: 'text or file with text content is required' }, { status: 400 });\n }\n if (parts.length > MAX_CHUNKS_PER_UPLOAD) {\n return json(\n {\n error: `Document is too large for one upload (${parts.length} chunks; max ${MAX_CHUNKS_PER_UPLOAD}). Split into smaller files.`,\n },\n { status: 413 }\n );\n }\n logKbPipeline('07_chunk_split', {\n slug,\n partCount: parts.length,\n maxChunkChars: INGEST_CHUNK_CHARS,\n totalChars: text.length,\n documentName: name,\n });\n\n const docRepo = dataSource.getRepository(kbDoc);\n const chunkRepo = dataSource.getRepository(kbChunk);\n const now = new Date();\n const doc = await docRepo.save(\n docRepo.create({ name, content: text, sourceUrl, createdAt: now, updatedAt: now } as object)\n );\n const docId = (doc as { id: number }).id;\n logKbPipeline('06_knowledge_document_saved', {\n slug,\n documentId: docId,\n name,\n contentChars: text.length,\n hasSourceUrl: !!sourceUrl,\n });\n\n const chunkRows = parts.map((content, i) =>\n chunkRepo.create({ documentId: docId, content, chunkIndex: i, createdAt: now } as object)\n );\n const savedList = await chunkRepo.save(chunkRows);\n const savedChunks: Array<{ id: number; content: string }> = (savedList as Array<{ id: number }>).map(\n (row, i) => ({\n id: row.id,\n content: parts[i]!,\n })\n );\n logKbPipeline('07b_chunks_persisted', {\n slug,\n documentId: docId,\n rowsInserted: savedChunks.length,\n firstChunkId: savedChunks[0]?.id,\n lastChunkId: savedChunks[savedChunks.length - 1]?.id,\n });\n\n const dup = await linkRepo.findOne({ where: { agentId: agent.id, documentId: docId } as object });\n if (!dup) {\n await linkRepo.save(linkRepo.create({ agentId: agent.id, documentId: docId } as object));\n logKbPipeline('06c_junction_link_created', { slug, agentId: agent.id, documentId: docId });\n } else {\n logKbPipeline('06c_junction_link_exists', { slug, agentId: agent.id, documentId: docId });\n }\n\n const embedResult = await runEmbeddingPass(slug, savedChunks);\n if (embedResult.embedError) {\n logKbPipeline('11_response', {\n slug,\n branch: 'ingest',\n documentId: docId,\n ok: false,\n embeddingError: true,\n });\n return json(\n {\n documentId: docId,\n chunkCount: savedChunks.length,\n embeddingAttempted: true,\n created: true,\n linked: true,\n embeddingsWritten: 0,\n embeddingsFailed: savedChunks.length,\n warning: 'Document saved and linked; embedding step failed.',\n detail: embedResult.embedError,\n },\n { status: 201 }\n );\n }\n\n logKbPipeline('11_response', {\n slug,\n branch: 'ingest',\n documentId: docId,\n ok: true,\n chunkCount: savedChunks.length,\n embeddingsWritten: embedResult.embeddingsWritten,\n embeddingsFailed: embedResult.embeddingsFailed,\n });\n return json({\n documentId: docId,\n chunkCount: savedChunks.length,\n embeddingAttempted: savedChunks.length > 0,\n created: true,\n linked: true,\n embeddingsWritten: embedResult.embeddingsWritten,\n embeddingsFailed: embedResult.embeddingsFailed,\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'Failed to ingest knowledge';\n const name = err instanceof Error ? err.name : '';\n logKbPipeline('99_pipeline_error', { slug, errorName: name, message: msg });\n return json({ error: msg, errorName: name || undefined }, { status: 500 });\n }\n },\n\n async unlink(req: Request, slug: string, documentIdStr: string): Promise<Response> {\n const denied = await gate(req, 'update');\n if (denied) return denied;\n const documentId = parseInt(documentIdStr, 10);\n if (!Number.isFinite(documentId)) return json({ error: 'Invalid document id' }, { status: 400 });\n try {\n const agent = await findAgentBySlug(dataSource, llmAgents, slug);\n if (!agent) return json({ error: 'Agent not found' }, { status: 404 });\n logKbPipeline('unlink_junction', { slug, agentId: agent.id, documentId });\n const linkRepo = dataSource.getRepository(junction);\n await linkRepo.delete({ agentId: agent.id, documentId } as object);\n return json({ ok: true });\n } catch (err) {\n const msg = err instanceof Error ? err.message : 'Failed to unlink';\n return json({ error: msg }, { status: 500 });\n }\n },\n };\n}\n","import type { DataSource } from 'typeorm';\r\nimport type { EntityMap } from './crud';\r\nimport { SMS_MESSAGE_TEMPLATE_DEFAULTS, getSmsTemplateDefault } from '../message-templates/sms-defaults';\r\nimport type { RequireEntityPermissionFn } from './cms-handlers';\r\n\r\nexport interface MessageTemplateAdminHandlersConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n json: (body: unknown, init?: { status?: number }) => Response;\r\n requireAuth: (req: Request) => Promise<Response | null>;\r\n requireEntityPermission?: RequireEntityPermissionFn;\r\n}\r\n\r\nexport function createSmsMessageTemplateHandlers(config: MessageTemplateAdminHandlersConfig) {\r\n const { dataSource, entityMap, json, requireAuth, requireEntityPermission } = config;\r\n\r\n const repo = () => dataSource.getRepository(entityMap.message_templates);\r\n\r\n async function requireSettingsRead(req: Request): Promise<Response | null> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'settings', 'read');\r\n if (pe) return pe;\r\n }\r\n return null;\r\n }\r\n\r\n async function requireSettingsUpdate(req: Request): Promise<Response | null> {\r\n const a = await requireAuth(req);\r\n if (a) return a;\r\n if (requireEntityPermission) {\r\n const pe = await requireEntityPermission(req, 'settings', 'update');\r\n if (pe) return pe;\r\n }\r\n return null;\r\n }\r\n\r\n return {\r\n async GET(req: Request): Promise<Response> {\r\n const err = await requireSettingsRead(req);\r\n if (err) return err;\r\n try {\r\n const rows = await repo().find({ where: { channel: 'sms', deleted: false } as object });\r\n const byKey = new Map(rows.map((r) => [r.templateKey, r]));\r\n const items = SMS_MESSAGE_TEMPLATE_DEFAULTS.map((def) => {\r\n const row = byKey.get(def.templateKey);\r\n return {\r\n templateKey: def.templateKey,\r\n name: def.name,\r\n defaultBody: def.body,\r\n body: row?.body?.trim() ? row.body : def.body,\r\n externalTemplateRef: row?.externalTemplateRef?.trim() ?? '',\r\n otpVarKey:\r\n row?.providerMeta && typeof row.providerMeta.otpVarKey === 'string'\r\n ? String(row.providerMeta.otpVarKey)\r\n : def.providerMeta?.otpVarKey ?? 'var1',\r\n enabled: row ? row.enabled : false,\r\n dbId: row?.id ?? null,\r\n };\r\n });\r\n return json({ items });\r\n } catch {\r\n return json({ error: 'Failed to load templates' }, { status: 500 });\r\n }\r\n },\r\n\r\n async PUT(req: Request): Promise<Response> {\r\n const err = await requireSettingsUpdate(req);\r\n if (err) return err;\r\n try {\r\n const raw = (await req.json().catch(() => null)) as {\r\n items?: Array<{\r\n templateKey?: string;\r\n body?: string;\r\n externalTemplateRef?: string;\r\n otpVarKey?: string;\r\n enabled?: boolean;\r\n }>;\r\n } | null;\r\n if (!raw?.items || !Array.isArray(raw.items)) {\r\n return json({ error: 'Invalid payload' }, { status: 400 });\r\n }\r\n\r\n for (const item of raw.items) {\r\n const templateKey = typeof item.templateKey === 'string' ? item.templateKey.trim() : '';\r\n if (!getSmsTemplateDefault(templateKey)) continue;\r\n\r\n const body = typeof item.body === 'string' ? item.body : '';\r\n const externalTemplateRef =\r\n typeof item.externalTemplateRef === 'string' ? item.externalTemplateRef.trim() : '';\r\n const otpVarKey =\r\n typeof item.otpVarKey === 'string' && item.otpVarKey.trim()\r\n ? item.otpVarKey.trim()\r\n : 'var1';\r\n const enabled = item.enabled !== false;\r\n\r\n const existing = await repo().findOne({\r\n where: { channel: 'sms', templateKey, deleted: false } as object,\r\n });\r\n const def = getSmsTemplateDefault(templateKey)!;\r\n const providerMeta = { otpVarKey };\r\n\r\n if (existing) {\r\n await repo().update(existing.id, {\r\n name: def.name,\r\n body,\r\n externalTemplateRef: externalTemplateRef || null,\r\n providerMeta,\r\n enabled,\r\n updatedAt: new Date(),\r\n } as object);\r\n } else {\r\n await repo().save(\r\n repo().create({\r\n channel: 'sms',\r\n templateKey,\r\n name: def.name,\r\n subject: null,\r\n body,\r\n externalTemplateRef: externalTemplateRef || null,\r\n providerMeta,\r\n enabled,\r\n deleted: false,\r\n } as object)\r\n );\r\n }\r\n }\r\n return json({ ok: true });\r\n } catch {\r\n return json({ error: 'Failed to save templates' }, { status: 500 });\r\n }\r\n },\r\n };\r\n}\r\n","/**\r\n * Single CMS API handler: dashboard, analytics, upload, media zip extract, blog/form by slug, users API, user auth, CRUD. Mount once (e.g. app/api/[[...path]]/route.ts).\r\n */\r\nimport type { DataSource, EntityTarget } from 'typeorm';\r\nimport {\r\n createCrudHandler,\r\n createCrudByIdHandler,\r\n calculateOrderTotals,\r\n calculateOrderTotalsFromLines,\r\n normalizeOrderLinesInput,\r\n validateCoupon,\r\n} from './crud';\r\nimport type { CrudHandlerOptions, EntityMap } from './crud';\r\nimport { createUserAuthApiRouter } from './auth-handlers';\r\nimport type { UserAuthApiConfig } from './auth-handlers';\r\nimport {\r\n createDashboardStatsHandler,\r\n createAnalyticsHandlers,\r\n createEcommerceAnalyticsHandler,\r\n createUploadHandler,\r\n createMediaZipExtractHandler,\r\n createBlogBySlugHandler,\r\n createFormBySlugHandler,\r\n createFormSaveHandlers,\r\n createFormSubmissionHandler,\r\n createFormSubmissionGetByIdHandler,\r\n createFormSubmissionListHandler,\r\n createUsersApiHandlers,\r\n createUserAvatarHandler,\r\n createUserProfileHandler,\r\n createSettingsApiHandlers,\r\n createChatHandlers,\r\n} from './cms-handlers';\r\nimport { createLlmAgentKnowledgeHandlers } from './llm-agent-knowledge-handlers';\r\nimport type { LlmAgentKnowledgeApiConfig } from './llm-agent-knowledge-handlers';\r\nimport { createSmsMessageTemplateHandlers } from './message-template-admin-handlers';\r\nimport type {\r\n DashboardStatsConfig,\r\n AnalyticsHandlerConfig,\r\n EcommerceAnalyticsConfig,\r\n UploadHandlerConfig,\r\n BlogBySlugConfig,\r\n FormBySlugConfig,\r\n FormSaveHandlersConfig,\r\n FormSubmissionHandlerConfig,\r\n FormSubmissionGetByIdConfig,\r\n UsersApiConfig,\r\n UserAvatarConfig,\r\n UserProfileConfig,\r\n SettingsApiConfig,\r\n ChatApiConfig,\r\n} from './cms-handlers';\r\nimport type { EntityCrudAction } from '../auth/permission-entities';\r\nimport { sessionHasEntityAccess, type SessionUser } from '../auth/helpers';\r\nimport { explainSessionEntityAccess, logEntityAccessDecision, logRbac } from '../auth/rbac-debug';\r\nimport type { CompanyDetails } from '../plugins/email/templates/types';\r\nimport { createAdminRolesHandlers } from './admin-roles-handlers';\r\nimport { createVendorOnboardHandlers } from './vendor-handlers';\r\nimport { resolveVendorScopeFromSessionUser } from '../auth/vendor-scope';\r\nimport { hydrateVendorSessionUser } from '../lib/hydrate-vendor-session-user';\r\nimport { CMS_ENTITY_MAP } from '../entities';\r\nimport { LlmAgent, llmAgentToChatAgentOptions } from '../entities/llm-agent.entity';\r\nimport type { LlmService } from '../plugins/llm/llm-service';\r\nimport { BlogGeneratorService, resolveBlogCategoryIdByName } from '../plugins/blog-generator/blog-generator-service';\r\nimport { persistAllGeneratedBlogDrafts } from '../plugins/blog-generator/blog-generator-persist';\r\nimport { findLlmAgentByScope } from '../plugins/llm/find-llm-agent-by-scope';\r\nimport {\r\n LLM_AGENT_SCOPE_BLOG_CREATION,\r\n LLM_AGENT_SCOPE_BLOG_METADATA,\r\n LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST,\r\n} from '../plugins/llm/llm-agent-scope';\r\nimport { Category } from '../entities/category.entity';\r\nimport { Tag } from '../entities/tag.entity';\r\nimport type { User } from '../entities/user.entity';\r\nimport type { RssFeed } from '../entities/rss-feed.entity';\r\nimport type { RssArticle } from '../entities/rss-article.entity';\r\nimport { recordRssFetchSuccess, serializeRssFeed, upsertRssFeedRow } from './rss-feed-blog-api';\r\nimport { createSocialMediaHandlers } from '../plugins/social-media/social-media-api-handlers';\r\nimport { createJobScheduleHandlers } from './job-schedule-handlers';\r\nimport { error } from 'console';\r\n\r\n/** CMS instance with getPlugin; when provided, analytics and userAuth.sendEmail can be resolved from plugins when not passed. */\r\nexport type CmsGetter = () => Promise<{ getPlugin: (name: string) => unknown }>;\r\n\r\nconst KNOWLEDGE_SUFFIX = 'knowledge';\r\nconst CMS_API_LOG = '[cms-api]';\r\n\r\n/**\r\n * Some apps pass a subset of {@link CMS_ENTITY_MAP}. LLM plugins + knowledge CRUD need these keys;\r\n * merge missing ones from the core map so `/api/llm_agents` and knowledge routes do not return \"Invalid resource\".\r\n */\r\nfunction withLlmKnowledgeEntityFallbacks(base: EntityMap): EntityMap {\r\n const keys = [\r\n 'llm_agents',\r\n 'llm_agent_knowledge_documents',\r\n 'knowledge_base_documents',\r\n 'knowledge_base_chunks',\r\n 'rss_feeds',\r\n 'rss_articles',\r\n ] as const;\r\n const patch: Partial<EntityMap> = {};\r\n for (const key of keys) {\r\n if (!(key in base) || base[key as keyof EntityMap] == null) {\r\n const fallback = CMS_ENTITY_MAP[key as keyof typeof CMS_ENTITY_MAP] as EntityMap[string] | undefined;\r\n if (fallback) (patch as Record<string, EntityMap[string]>)[key] = fallback;\r\n }\r\n }\r\n const merged = Object.keys(patch).length > 0 ? ({ ...base, ...patch } as EntityMap) : base;\r\n // Direct class fallback so POST/GET /api/llm_agents never loses the entity (e.g. odd bundling of CMS_ENTITY_MAP).\r\n if (!merged.llm_agents) {\r\n const agent = (CMS_ENTITY_MAP.llm_agents ?? LlmAgent) as EntityMap['llm_agents'];\r\n return { ...merged, llm_agents: agent };\r\n }\r\n return merged;\r\n}\r\n\r\n/**\r\n * Resolves LLM agent knowledge routes for {@link createCmsApiHandler}.\r\n * - Canonical: `llm_agents`, `:slug`, `knowledge` (optional 4th segment for DELETE).\r\n * - Some clients / path parsers merge slug + `knowledge` into one segment (`jm-assistantknowledge`); accept that shape too.\r\n */\r\nfunction matchLlmAgentKnowledgeRoute(path: string[]): { slug: string; documentId: string | undefined } | null {\r\n const p = path[0] === 'api' ? path.slice(1) : path;\r\n if (p[0] !== 'llm_agents' || p.length < 2) return null;\r\n const seg1 = p[1];\r\n if (!seg1) return null;\r\n\r\n if (p[2] === KNOWLEDGE_SUFFIX) {\r\n return {\r\n slug: seg1,\r\n documentId: p.length >= 4 ? p[3] : undefined,\r\n };\r\n }\r\n\r\n if (seg1.endsWith(KNOWLEDGE_SUFFIX) && seg1.length > KNOWLEDGE_SUFFIX.length) {\r\n const slug = seg1.slice(0, -KNOWLEDGE_SUFFIX.length);\r\n if (!slug) return null;\r\n if (p.length === 2) return { slug, documentId: undefined };\r\n if (p.length === 3) return { slug, documentId: p[2] };\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport interface CmsApiHandlerConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n requireAuth: (req: Request) => Promise<Response | null>;\r\n json: (body: unknown, init?: { status?: number }) => Response;\r\n pathToModel?: (segment: string) => string;\r\n crudResources?: string[];\r\n /** When set, analytics and userAuth.sendEmail can be derived from getPlugin('analytics') and getPlugin('email') when not provided. */\r\n getCms?: CmsGetter;\r\n /** Optional: used when deriving userAuth.sendEmail to pass company details into email templates (e.g. from settings). */\r\n getCompanyDetails?: () => Promise<CompanyDetails>;\r\n /** Optional: used for form submission and other channel-based email recipients (from settings group \"email\"). */\r\n getRecipientForChannel?: (channel: 'crm' | 'sales' | 'fulfilment') => Promise<string | null>;\r\n userAuth?: UserAuthApiConfig;\r\n /** GET /api/dashboard/stats */\r\n dashboard?: DashboardStatsConfig;\r\n /** GET /api/dashboard/ecommerce */\r\n ecommerceAnalytics?: EcommerceAnalyticsConfig;\r\n /** GET /api/analytics. If omitted and getCms is set, uses getCms().getPlugin('analytics'). */\r\n analytics?: AnalyticsHandlerConfig;\r\n /** POST /api/upload (S3 or local) */\r\n upload?: UploadHandlerConfig;\r\n /** GET /api/blogs/slug/:slug (public) */\r\n blogBySlug?: BlogBySlugConfig;\r\n /** GET /api/forms/slug/:slug (public) */\r\n formBySlug?: FormBySlugConfig;\r\n /** POST/PUT /api/forms (save form + fields; when set, overrides CRUD for forms) */\r\n formSave?: FormSaveHandlersConfig;\r\n /** POST /api/form-submissions (public, no auth) */\r\n formSubmission?: FormSubmissionHandlerConfig;\r\n /** GET /api/form-submissions/:id (auth) with form + contact relations */\r\n formSubmissionGetById?: FormSubmissionGetByIdConfig;\r\n /** GET/POST /api/users, GET/PUT/DELETE /api/users/:id, POST /api/users/:id/regenerate-invite */\r\n usersApi?: UsersApiConfig;\r\n /** POST /api/users/avatar */\r\n userAvatar?: UserAvatarConfig;\r\n /** GET/PUT /api/users/profile (current session user) */\r\n userProfile?: UserProfileConfig;\r\n /** GET/PUT /api/settings/:group */\r\n settings?: SettingsApiConfig;\r\n /** GET /api/chat/config (public); POST /api/chat/identify; GET /api/chat/conversations/:id/messages; POST /api/chat/messages */\r\n chat?: ChatApiConfig;\r\n /**\r\n * GET/POST /api/llm_agents/:slug/knowledge; DELETE …/knowledge/:documentId — agent KB ingest + links.\r\n * When omitted but `chat` is set, the same dataSource / entityMap / getCms / json / requireAuth are reused automatically.\r\n */\r\n llmAgentKnowledge?: LlmAgentKnowledgeApiConfig;\r\n /**\r\n * Entity-level RBAC (session `entityPerms` / Administrator). When omitted, admin routes that need it respond with 403\r\n * (`entity_rbac_required`) so CRUD cannot run as auth-only. Pass `createAuthHelpers(...).requireEntityPermission` from the app.\r\n */\r\n requireEntityPermission?: (req: Request, entity: string, action: EntityCrudAction) => Promise<Response | null>;\r\n /** Required for vendor store RBAC + scoping. Alias: `getAuthenticatedUser`. */\r\n getSessionUser?: () => Promise<SessionUser | null>;\r\n /** Same as `getSessionUser` (from `createAuthHelpers().getAuthenticatedUser`). */\r\n getAuthenticatedUser?: () => Promise<SessionUser | null>;\r\n}\r\n\r\nconst DEFAULT_EXCLUDE = new Set([\r\n 'users',\r\n 'password_reset_tokens',\r\n 'user_groups',\r\n 'permissions',\r\n 'comments',\r\n 'form_fields',\r\n 'configs',\r\n 'carts',\r\n 'cart_items',\r\n 'wishlists',\r\n 'wishlist_items',\r\n 'message_templates',\r\n 'llm_agent_knowledge_documents',\r\n 'currency',\r\n 'currency_exchange',\r\n 'rss_feeds',\r\n 'rss_articles',\r\n 'job_schedules',\r\n 'job_schedule_runs',\r\n]);\r\n\r\nexport function createCmsApiHandler(config: CmsApiHandlerConfig) {\r\n const {\r\n dataSource,\r\n entityMap: rawEntityMap,\r\n pathToModel = (s) => s,\r\n crudResources: crudResourcesOverride,\r\n getCms,\r\n userAuth: userAuthConfig,\r\n dashboard,\r\n ecommerceAnalytics,\r\n analytics: analyticsConfig,\r\n upload,\r\n blogBySlug,\r\n formBySlug,\r\n formSave: formSaveConfig,\r\n formSubmission: formSubmissionConfig,\r\n formSubmissionGetById: formSubmissionGetByIdConfig,\r\n usersApi,\r\n userAvatar,\r\n userProfile,\r\n settings: settingsConfig,\r\n chat: chatConfig,\r\n llmAgentKnowledge: llmAgentKnowledgeConfig,\r\n requireEntityPermission: userRequireEntityPermission,\r\n getSessionUser,\r\n getAuthenticatedUser,\r\n } = config;\r\n\r\n const resolveSessionUser = getSessionUser ?? getAuthenticatedUser;\r\n\r\n const entityMap = withLlmKnowledgeEntityFallbacks(rawEntityMap);\r\n const baseCrudResources =\r\n crudResourcesOverride ?? Object.keys(entityMap).filter((k) => !DEFAULT_EXCLUDE.has(k));\r\n /** Plugins + dedicated routes use `llm_agents` even when the host app passes a narrow `crudResources` allowlist. */\r\n const crudResources =\r\n entityMap.llm_agents && !baseCrudResources.includes('llm_agents')\r\n ? [...baseCrudResources, 'llm_agents']\r\n : baseCrudResources;\r\n\r\n /**\r\n * When `getSessionUser` / `getAuthenticatedUser` is set, uses DB-hydrated vendor context only\r\n * (do not fall back to JWT `entityPerms` from the app's `requireEntityPermission`).\r\n */\r\n const requireEntityPermissionEffective = async (\r\n _req: Request,\r\n entity: string,\r\n action: EntityCrudAction\r\n ): Promise<Response | null> => {\r\n if (!resolveSessionUser) {\r\n logRbac('requireEntityPermission: getSessionUser not passed — vendor store APIs may 403', {\r\n entity,\r\n action,\r\n hint: 'Pass getSessionUser: auth.getAuthenticatedUser from createCmsAuthBundle()',\r\n });\r\n }\r\n\r\n if (resolveSessionUser) {\r\n const raw = await resolveSessionUser();\r\n const u = await hydrateVendorSessionUser(dataSource, raw);\r\n if (!u?.email) {\r\n logRbac('requireEntityPermission: no session user', { entity, action });\r\n return config.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n const allowed = sessionHasEntityAccess(u, entity, action);\r\n await logEntityAccessDecision(dataSource, 'cmsApi.requireEntityPermission', u, entity, action, {\r\n allowed,\r\n resolvePath: 'hydrated_session',\r\n });\r\n if (allowed) return null;\r\n const { reason } = explainSessionEntityAccess(u, entity, action);\r\n return config.json({ error: 'Forbidden', entity, action, reason }, { status: 403 });\r\n }\r\n if (userRequireEntityPermission) {\r\n logRbac('requireEntityPermission: using app callback only (no getSessionUser)', { entity, action });\r\n return userRequireEntityPermission(_req, entity, action);\r\n }\r\n return config.json({ error: 'Forbidden', reason: 'entity_rbac_required', entity, action }, { status: 403 });\r\n };\r\n\r\n const analytics: AnalyticsHandlerConfig | undefined =\r\n analyticsConfig ??\r\n (getCms\r\n ? {\r\n json: config.json,\r\n requireAuth: async () => null,\r\n getAnalyticsData: async (days) => {\r\n const cms = await getCms();\r\n const a = cms.getPlugin('analytics') as { getAnalyticsData?: (days: number) => Promise<unknown> } | undefined;\r\n if (!a?.getAnalyticsData) throw new Error('Analytics not configured');\r\n return a.getAnalyticsData(days);\r\n },\r\n getPropertyId: () => ({ currentViewId: process.env.GOOGLE_ANALYTICS_VIEW_ID }),\r\n getPermissions: () => ({\r\n serviceAccountEmail: process.env.GOOGLE_ANALYTICS_CLIENT_EMAIL,\r\n currentViewId: process.env.GOOGLE_ANALYTICS_VIEW_ID,\r\n }),\r\n }\r\n : undefined);\r\n\r\n const userAuth: UserAuthApiConfig | undefined =\r\n userAuthConfig && getCms && userAuthConfig.sendEmail === undefined\r\n ? {\r\n ...userAuthConfig,\r\n sendEmail: async (opts) => {\r\n const cms = await getCms();\r\n const queue = cms.getPlugin('queue') as { add: (name: string, data: object) => Promise<void> } | undefined;\r\n const companyDetails = config.getCompanyDetails ? await config.getCompanyDetails() : {};\r\n const resetLink =\r\n (typeof opts.resetLink === 'string' && opts.resetLink.trim()) ||\r\n (typeof opts.text === 'string' && opts.text.trim()) ||\r\n (typeof opts.html === 'string' ? (opts.html.match(/href\\s*=\\s*[\"']([^\"']+)[\"']/)?.[1] ?? '') : '');\r\n const ctx = { resetLink, companyDetails };\r\n if (queue) {\r\n const { queueEmail } = await import('../plugins/email/email-queue');\r\n await queueEmail(cms as { getPlugin: (name: string) => unknown }, { to: opts.to, templateName: 'passwordReset', ctx });\r\n return;\r\n }\r\n const email = cms.getPlugin('email') as { send: (data: { subject: string; html: string; text?: string; to?: string }) => Promise<boolean>; renderTemplate: (name: string, ctx: unknown) => { subject: string; html: string; text?: string } } | undefined;\r\n if (!email?.send) return;\r\n const rendered = email.renderTemplate('passwordReset', ctx);\r\n await email.send({ subject: rendered.subject, html: rendered.html, text: rendered.text, to: opts.to });\r\n },\r\n }\r\n : userAuthConfig;\r\n\r\n if (userAuth?.dataSource && entityMap.vendors) {\r\n const ds = userAuth.dataSource;\r\n const vendorEntity = entityMap.vendors;\r\n const prevActivate = userAuth.beforeActivate;\r\n userAuth.beforeActivate = async (email, userId) => {\r\n if (prevActivate) await prevActivate(email, userId);\r\n const { markVendorInviteAcceptedForUser } = await import('../lib/vendor-invite-status');\r\n await markVendorInviteAcceptedForUser(ds, vendorEntity, userId);\r\n };\r\n }\r\n\r\n const crudOpts: CrudHandlerOptions = {\r\n requireAuth: config.requireAuth,\r\n json: config.json,\r\n requireEntityPermission: requireEntityPermissionEffective,\r\n getCms,\r\n ...(resolveSessionUser\r\n ? {\r\n getDeletedByUserId: async () => {\r\n const u = await resolveSessionUser();\r\n if (!u?.id) return null;\r\n const n = Number(u.id);\r\n return Number.isFinite(n) ? n : null;\r\n },\r\n getVendorScope: async () => {\r\n const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());\r\n return resolveVendorScopeFromSessionUser(u ?? null);\r\n },\r\n getHydratedSessionUser: async () => {\r\n const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());\r\n return u ?? null;\r\n },\r\n }\r\n : {}),\r\n };\r\n const crud = createCrudHandler(dataSource, entityMap, crudOpts);\r\n const crudById = createCrudByIdHandler(dataSource, entityMap, crudOpts);\r\n\r\n const mergePerm = <T extends object>(c: T | undefined): T | undefined =>\r\n !c ? undefined : ({ ...c, requireEntityPermission: requireEntityPermissionEffective } as T);\r\n\r\n const adminRoles =\r\n getSessionUser &&\r\n createAdminRolesHandlers({\r\n dataSource,\r\n entityMap,\r\n json: config.json,\r\n getSessionUser,\r\n });\r\n const vendorOnboardBaseUrl =\r\n usersApi?.baseUrl?.replace(/\\/$/, '') ||\r\n (typeof process !== 'undefined' ? process.env.NEXTAUTH_URL : undefined) ||\r\n 'http://localhost:3000';\r\n const vendorHandlers =\r\n getSessionUser &&\r\n createVendorOnboardHandlers({\r\n dataSource,\r\n entityMap,\r\n json: config.json,\r\n getSessionUser,\r\n baseUrl: vendorOnboardBaseUrl,\r\n getCms,\r\n hashPassword: userAuth?.hashPassword,\r\n minPasswordLength: 6,\r\n });\r\n const userAuthRouter = userAuth ? createUserAuthApiRouter(userAuth) : null;\r\n\r\n const dashboardGet = dashboard ? createDashboardStatsHandler(mergePerm(dashboard) ?? dashboard) : null;\r\n const ecommerceAnalyticsResolved: EcommerceAnalyticsConfig =\r\n mergePerm(\r\n ecommerceAnalytics ?? {\r\n dataSource,\r\n entityMap,\r\n json: config.json,\r\n requireAuth: config.requireAuth,\r\n }\r\n )!;\r\n const ecommerceAnalyticsGet = createEcommerceAnalyticsHandler(ecommerceAnalyticsResolved);\r\n const analyticsHandlers = analytics ? createAnalyticsHandlers(analytics) : null;\r\n const uploadMerged = upload\r\n ? {\r\n ...(mergePerm(upload) ?? upload),\r\n dataSource: upload.dataSource ?? dataSource,\r\n entityMap: upload.entityMap ?? entityMap,\r\n }\r\n : null;\r\n const uploadPost = uploadMerged ? createUploadHandler(uploadMerged) : null;\r\n const zipExtractPost = uploadMerged ? createMediaZipExtractHandler(uploadMerged) : null;\r\n const blogBySlugGet = blogBySlug ? createBlogBySlugHandler(blogBySlug) : null;\r\n const formBySlugGet = formBySlug ? createFormBySlugHandler(formBySlug) : null;\r\n const formSaveHandlers = formSaveConfig ? createFormSaveHandlers(mergePerm(formSaveConfig) ?? formSaveConfig) : null;\r\n const formSubmissionPost = formSubmissionConfig ? createFormSubmissionHandler(formSubmissionConfig) : null;\r\n const formSubmissionGetById = formSubmissionGetByIdConfig\r\n ? createFormSubmissionGetByIdHandler(mergePerm(formSubmissionGetByIdConfig) ?? formSubmissionGetByIdConfig)\r\n : null;\r\n const formSubmissionList = formSubmissionGetByIdConfig\r\n ? createFormSubmissionListHandler(mergePerm(formSubmissionGetByIdConfig) ?? formSubmissionGetByIdConfig)\r\n : null;\r\n const usersApiMerged =\r\n usersApi && getCms\r\n ? {\r\n ...usersApi,\r\n getCms: usersApi.getCms ?? getCms,\r\n getCompanyDetails: usersApi.getCompanyDetails ?? config.getCompanyDetails,\r\n ...(getSessionUser ? { getSessionUser: usersApi.getSessionUser ?? getSessionUser } : {}),\r\n }\r\n : usersApi\r\n ? {\r\n ...usersApi,\r\n ...(getSessionUser ? { getSessionUser: usersApi.getSessionUser ?? getSessionUser } : {}),\r\n }\r\n : usersApi;\r\n const usersHandlers = usersApiMerged ? createUsersApiHandlers(mergePerm(usersApiMerged) ?? usersApiMerged) : null;\r\n const avatarPost = userAvatar ? createUserAvatarHandler(userAvatar) : null;\r\n const profileHandlers = userProfile ? createUserProfileHandler(userProfile) : null;\r\n const settingsHandlers = settingsConfig ? createSettingsApiHandlers(settingsConfig) : null;\r\n\r\n function resolvePublicSiteUrlForSocial(): string | undefined {\r\n if (typeof process === 'undefined') return undefined;\r\n const u = (process.env.CMS_PUBLIC_URL || process.env.NEXT_PUBLIC_SITE_URL || '').trim();\r\n if (u) return u.replace(/\\/+$/, '');\r\n const v = (process.env.VERCEL_URL || '').trim();\r\n if (!v) return undefined;\r\n return v.startsWith('http') ? v.replace(/\\/+$/, '') : `https://${v.replace(/\\/+$/, '')}`;\r\n }\r\n\r\n const socialMediaHandlers =\r\n settingsConfig?.dataSource && entityMap.configs\r\n ? createSocialMediaHandlers({\r\n dataSource: settingsConfig.dataSource,\r\n entityMap,\r\n json: config.json,\r\n requireAuth: config.requireAuth,\r\n requireEntityPermission: requireEntityPermissionEffective,\r\n encryptionKey: settingsConfig.encryptionKey,\r\n publicSiteUrl: resolvePublicSiteUrlForSocial(),\r\n })\r\n : null;\r\n const smsMessageTemplateHandlers = createSmsMessageTemplateHandlers({\r\n dataSource,\r\n entityMap,\r\n json: config.json,\r\n requireAuth: config.requireAuth,\r\n requireEntityPermission: requireEntityPermissionEffective,\r\n });\r\n const chatHandlers = chatConfig ? createChatHandlers(chatConfig) : null;\r\n\r\n const llmAgentKnowledgeMerged: LlmAgentKnowledgeApiConfig | undefined =\r\n llmAgentKnowledgeConfig ??\r\n (chatConfig\r\n ? {\r\n dataSource: chatConfig.dataSource,\r\n entityMap: withLlmKnowledgeEntityFallbacks(chatConfig.entityMap ?? rawEntityMap),\r\n getCms: chatConfig.getCms,\r\n json: chatConfig.json,\r\n requireAuth: chatConfig.requireAuth,\r\n }\r\n : undefined);\r\n\r\n const llmAgentKnowledgeHandlers = llmAgentKnowledgeMerged\r\n ? createLlmAgentKnowledgeHandlers({\r\n ...llmAgentKnowledgeMerged,\r\n requireEntityPermission: requireEntityPermissionEffective,\r\n })\r\n : null;\r\n\r\n const jobScheduleHandlers = getCms\r\n ? createJobScheduleHandlers({\r\n dataSource,\r\n entityMap,\r\n json: config.json,\r\n requireAuth: config.requireAuth,\r\n requireEntityPermission: requireEntityPermissionEffective,\r\n getCms,\r\n config:\r\n typeof process !== 'undefined'\r\n ? (process.env as unknown as Record<string, string>)\r\n : {},\r\n })\r\n : null;\r\n\r\n function resolveResource(segment: string): string {\r\n const model = pathToModel(segment);\r\n return crudResources.includes(model) ? model : segment;\r\n }\r\n\r\n return {\r\n async handle(method: string, pathInput: string[], req: Request): Promise<Response> {\r\n const m = typeof method === 'string' ? method.toUpperCase() : 'GET';\r\n const path = pathInput.length > 0 && pathInput[0] === 'api' ? pathInput.slice(1) : pathInput;\r\n async function analyticsGate(): Promise<Response | null> {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n return requireEntityPermissionEffective(req, 'analytics', 'read');\r\n }\r\n\r\n // Admin roles: [\"admin\", \"roles\"], [\"admin\", \"roles\", id], [\"admin\", \"roles\", id, \"permissions\"]\r\n if (path[0] === 'admin' && path[1] === 'roles') {\r\n if (!adminRoles) return config.json({ error: 'Not found' }, { status: 404 });\r\n if (path.length === 2 && m === 'GET') return adminRoles.list();\r\n if (path.length === 2 && m === 'POST') return adminRoles.createGroup(req);\r\n if (path.length === 3 && m === 'PATCH') return adminRoles.patchGroup(req, path[2]!);\r\n if (path.length === 3 && m === 'DELETE') return adminRoles.deleteGroup(path[2]!);\r\n if (path.length === 4 && path[3] === 'permissions' && m === 'PUT') return adminRoles.putPermissions(req, path[2]!);\r\n return config.json({ error: 'Not found' }, { status: 404 });\r\n }\r\n\r\n if (path[0] === 'admin' && path[1] === 'vendors' && path[2] === 'onboard' && path.length === 3 && m === 'POST') {\r\n if (!vendorHandlers) return config.json({ error: 'Not found' }, { status: 404 });\r\n return vendorHandlers.onboard(req);\r\n }\r\n if (path[0] === 'admin' && path[1] === 'vendor' && path[2] === 'switch' && path.length === 3 && m === 'POST') {\r\n if (!vendorHandlers) return config.json({ error: 'Not found' }, { status: 404 });\r\n return vendorHandlers.switchVendor(req);\r\n }\r\n if (path[0] === 'admin' && path[1] === 'vendor' && path[2] === 'team' && vendorHandlers) {\r\n if (path.length === 3 && m === 'GET') return vendorHandlers.listTeam();\r\n if (path.length === 3 && m === 'POST') return vendorHandlers.addTeamMember(req);\r\n if (path.length === 4 && m === 'DELETE') return vendorHandlers.removeTeamMember(req, path[3]!);\r\n }\r\n\r\n // Dashboard: [\"dashboard\", \"stats\"]\r\n if (path[0] === 'dashboard' && path[1] === 'stats' && path.length === 2 && m === 'GET' && dashboardGet) {\r\n return dashboardGet(req);\r\n }\r\n if (path[0] === 'dashboard' && path[1] === 'ecommerce' && path.length === 2 && m === 'GET' && ecommerceAnalyticsGet) {\r\n const g = await analyticsGate();\r\n if (g) return g;\r\n return ecommerceAnalyticsGet(req);\r\n }\r\n // Job schedules (pg-boss)\r\n if (path[0] === 'job-schedules' && jobScheduleHandlers) {\r\n if (path.length === 2 && m === 'GET') {\r\n return jobScheduleHandlers.getById(req, path[1]!);\r\n }\r\n if (path.length === 2 && m === 'PATCH') {\r\n return jobScheduleHandlers.update(req, path[1]!);\r\n }\r\n if (path.length === 2 && m === 'DELETE') {\r\n return jobScheduleHandlers.remove(req, path[1]!);\r\n }\r\n if (path.length === 3 && path[2] === 'run-now' && m === 'POST') {\r\n return jobScheduleHandlers.runNow(req, path[1]!);\r\n }\r\n if (path.length === 3 && path[2] === 'runs' && m === 'GET') {\r\n return jobScheduleHandlers.listRuns(req, path[1]!);\r\n }\r\n if (path.length === 1 && m === 'GET') {\r\n return jobScheduleHandlers.list(req);\r\n }\r\n if (path.length === 1 && m === 'POST') {\r\n return jobScheduleHandlers.create(req);\r\n }\r\n return config.json({ error: 'Not found' }, { status: 404 });\r\n }\r\n\r\n // Blog generator — persisted RSS feeds (not generic CRUD: UUID ids)\r\n if (path[0] === 'blog-generator' && path[1] === 'feeds' && path.length === 3 && m === 'DELETE' && getCms) {\r\n const id = path[2]!;\r\n const uuidLooksValid =\r\n typeof id === 'string' &&\r\n /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(id);\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermissionEffective(req, 'blogs', 'read');\r\n if (pe) return pe;\r\n if (!entityMap.rss_feeds) {\r\n return config.json({ error: 'RSS feeds are not configured (missing entity map).' }, { status: 503 });\r\n }\r\n if (!uuidLooksValid) {\r\n return config.json({ error: 'Invalid feed id' }, { status: 400 });\r\n }\r\n try {\r\n await dataSource.getRepository(entityMap.rss_feeds as EntityTarget<RssFeed>).delete({ id });\r\n return config.json({ ok: true });\r\n } catch (e) {\r\n const message = e instanceof Error ? e.message : 'Delete failed';\r\n return config.json({ error: message }, { status: 500 });\r\n }\r\n }\r\n\r\n if (path[0] === 'blog-generator' && path[1] === 'feeds' && path.length === 2 && m === 'GET' && getCms) {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermissionEffective(req, 'blogs', 'read');\r\n if (pe) return pe;\r\n if (!entityMap.rss_feeds) {\r\n return config.json({ error: 'RSS feeds are not configured (missing entity map).' }, { status: 503 });\r\n }\r\n try {\r\n const list = await dataSource.getRepository(entityMap.rss_feeds as EntityTarget<RssFeed>).find({\r\n where: { isActive: true },\r\n order: { updatedAt: 'DESC' },\r\n });\r\n return config.json({ feeds: list.map(serializeRssFeed) });\r\n } catch (e) {\r\n const message = e instanceof Error ? e.message : 'Failed to list feeds';\r\n return config.json({ error: message }, { status: 500 });\r\n }\r\n }\r\n\r\n if (path[0] === 'blog-generator' && path[1] === 'feeds' && path.length === 2 && m === 'POST' && getCms) {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermissionEffective(req, 'blogs', 'read');\r\n if (pe) return pe;\r\n if (!entityMap.rss_feeds) {\r\n return config.json({ error: 'RSS feeds are not configured (missing entity map).' }, { status: 503 });\r\n }\r\n let body: { rows?: unknown };\r\n try {\r\n body = (await req.json()) as { rows?: unknown };\r\n } catch {\r\n return config.json({ error: 'Invalid JSON body' }, { status: 400 });\r\n }\r\n const rowsIn = Array.isArray(body.rows) ? body.rows : [];\r\n const rows = rowsIn\r\n .map((r) => r as Record<string, unknown>)\r\n .map((r) => {\r\n let websiteUrl: string | null | undefined;\r\n if ('websiteUrl' in r) {\r\n const w = r.websiteUrl;\r\n if (w === null || w === '') websiteUrl = null;\r\n else if (typeof w === 'string') websiteUrl = w;\r\n }\r\n return {\r\n rssUrl: typeof r.rssUrl === 'string' ? r.rssUrl.trim() : '',\r\n name: typeof r.name === 'string' ? r.name : undefined,\r\n websiteUrl,\r\n };\r\n })\r\n .filter((r) => r.rssUrl !== '');\r\n try {\r\n const Feed = entityMap.rss_feeds as EntityTarget<RssFeed>;\r\n for (const r of rows) {\r\n await upsertRssFeedRow(dataSource, Feed, r.rssUrl, {\r\n name: r.name,\r\n websiteUrl: r.websiteUrl,\r\n });\r\n }\r\n const list = await dataSource.getRepository(Feed).find({\r\n where: { isActive: true },\r\n order: { updatedAt: 'DESC' },\r\n });\r\n return config.json({ feeds: list.map(serializeRssFeed) });\r\n } catch (e) {\r\n const message = e instanceof Error ? e.message : 'Failed to save feeds';\r\n return config.json({ error: message }, { status: 500 });\r\n }\r\n }\r\n\r\n // Blog generator (admin): POST [\"blog-generator\", \"latest\"] body: { rssUrl } | { rssUrls: string[] }\r\n if (path[0] === 'blog-generator' && path[1] === 'latest' && path.length === 2 && m === 'POST' && getCms) {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermissionEffective(req, 'blogs', 'read');\r\n if (pe) return pe;\r\n const cms = await getCms();\r\n const svc = cms.getPlugin('blog_generator') as BlogGeneratorService | undefined;\r\n if (!svc) {\r\n return config.json({ error: 'Blog Generator plugin is not enabled' }, { status: 503 });\r\n }\r\n let body: { rssUrl?: unknown; rssUrls?: unknown };\r\n try {\r\n body = (await req.json()) as { rssUrl?: unknown; rssUrls?: unknown };\r\n } catch {\r\n return config.json({ error: 'Invalid JSON body' }, { status: 400 });\r\n }\r\n const rawUrls: string[] = [];\r\n if (Array.isArray(body.rssUrls)) {\r\n for (const u of body.rssUrls) {\r\n if (typeof u === 'string') {\r\n const t = u.trim();\r\n if (t) rawUrls.push(t);\r\n }\r\n }\r\n }\r\n if (rawUrls.length === 0 && typeof body.rssUrl === 'string' && body.rssUrl.trim()) {\r\n rawUrls.push(body.rssUrl.trim());\r\n }\r\n const seen = new Set<string>();\r\n const urls = rawUrls.filter((u) => {\r\n if (seen.has(u)) return false;\r\n seen.add(u);\r\n return true;\r\n });\r\n if (urls.length === 0) {\r\n return config.json({ error: 'Provide rssUrls (array) or rssUrl (string)' }, { status: 400 });\r\n }\r\n const results: Array<{\r\n rssUrl: string;\r\n article: {\r\n title?: string;\r\n link?: string;\r\n summary?: string;\r\n content?: string;\r\n date: string;\r\n } | null;\r\n error?: string;\r\n }> = [];\r\n for (const rssUrl of urls) {\r\n try {\r\n if (entityMap.rss_feeds) {\r\n await upsertRssFeedRow(dataSource, entityMap.rss_feeds as EntityTarget<RssFeed>, rssUrl);\r\n }\r\n const latest = await svc.getLatestArticleFromFeed(rssUrl);\r\n if (entityMap.rss_feeds) {\r\n await recordRssFetchSuccess(\r\n dataSource,\r\n entityMap.rss_feeds as EntityTarget<RssFeed>,\r\n entityMap.rss_articles as EntityTarget<RssArticle> | undefined,\r\n rssUrl,\r\n latest == null\r\n ? null\r\n : {\r\n title: latest.title,\r\n link: latest.link,\r\n summary: latest.summary,\r\n content: latest.content,\r\n creator: latest.creator,\r\n date: latest.date,\r\n }\r\n );\r\n }\r\n const article =\r\n latest == null\r\n ? null\r\n : {\r\n title: latest.title,\r\n link: latest.link,\r\n summary: latest.summary,\r\n content: latest.content,\r\n date: latest.date.toISOString(),\r\n };\r\n results.push({ rssUrl, article });\r\n } catch (e) {\r\n const message = e instanceof Error ? e.message : 'Failed to parse feed';\r\n results.push({ rssUrl, article: null, error: message });\r\n }\r\n }\r\n const singleArticle = results.length === 1 ? results[0]!.article : undefined;\r\n return config.json({ results, article: singleArticle });\r\n }\r\n // Blog generator (admin): POST [\"blog-generator\", \"generate\"] — RSS → LLM Markdown\r\n if (path[0] === 'blog-generator' && path[1] === 'generate' && path.length === 2 && m === 'POST' && getCms) {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermissionEffective(req, 'blogs', 'read');\r\n if (pe) return pe;\r\n const cms = await getCms();\r\n const svc = cms.getPlugin('blog_generator') as BlogGeneratorService | undefined;\r\n if (!svc) {\r\n return config.json({ error: 'Blog Generator plugin is not enabled' }, { status: 503 });\r\n }\r\n const llm = cms.getPlugin('llm') as LlmService | undefined;\r\n if (!llm) {\r\n return config.json({ error: 'LLM plugin is not enabled. Configure the LLM gateway to generate articles.' }, { status: 503 });\r\n }\r\n let body: {\r\n rssUrl?: unknown;\r\n rssUrls?: unknown;\r\n systemInstruction?: unknown;\r\n validationRules?: unknown;\r\n persistToCms?: unknown;\r\n };\r\n try {\r\n body = (await req.json()) as {\r\n rssUrl?: unknown;\r\n rssUrls?: unknown;\r\n systemInstruction?: unknown;\r\n validationRules?: unknown;\r\n persistToCms?: unknown;\r\n };\r\n } catch {\r\n return config.json({ error: 'Invalid JSON body' }, { status: 400 });\r\n }\r\n const rawUrls: string[] = [];\r\n if (Array.isArray(body.rssUrls)) {\r\n for (const u of body.rssUrls) {\r\n if (typeof u === 'string') {\r\n const t = u.trim();\r\n if (t) rawUrls.push(t);\r\n }\r\n }\r\n }\r\n if (rawUrls.length === 0 && typeof body.rssUrl === 'string' && body.rssUrl.trim()) {\r\n rawUrls.push(body.rssUrl.trim());\r\n }\r\n const seen = new Set<string>();\r\n const rssUrls = rawUrls.filter((u) => {\r\n if (seen.has(u)) return false;\r\n seen.add(u);\r\n return true;\r\n });\r\n if (rssUrls.length === 0) {\r\n return config.json({ error: 'Provide rssUrls (non-empty array) or rssUrl (string)' }, { status: 400 });\r\n }\r\n const systemInstruction = typeof body.systemInstruction === 'string' ? body.systemInstruction : undefined;\r\n const validationRules = typeof body.validationRules === 'string' ? body.validationRules : undefined;\r\n const persistToCms = body.persistToCms === true;\r\n\r\n let llmAgentChatOptions: { model?: string; temperature?: number; max_tokens?: number } | undefined;\r\n let llmAgentResolution: { slug: string; model: string | null; temperature: number | null; maxTokens: number | null } | null =\r\n null;\r\n let metadataLlmAgentChatOptions: { model?: string; temperature?: number; max_tokens?: number } | undefined;\r\n let metadataLlmAgentResolution: {\r\n slug: string;\r\n model: string | null;\r\n temperature: number | null;\r\n maxTokens: number | null;\r\n } | null = null;\r\n let socialLlmAgentChatOptions: { model?: string; temperature?: number; max_tokens?: number } | undefined;\r\n let socialLlmAgentResolution: {\r\n slug: string;\r\n model: string | null;\r\n temperature: number | null;\r\n maxTokens: number | null;\r\n } | null = null;\r\n let metadataRow: LlmAgent | null = null;\r\n let socialRow: LlmAgent | null = null;\r\n let blogCreationRow: LlmAgent | null = null;\r\n if (entityMap.llm_agents) {\r\n blogCreationRow = await findLlmAgentByScope(dataSource, entityMap, LLM_AGENT_SCOPE_BLOG_CREATION);\r\n if (blogCreationRow) {\r\n const o = llmAgentToChatAgentOptions(blogCreationRow);\r\n llmAgentChatOptions = {\r\n model: o.model,\r\n temperature: o.temperature,\r\n max_tokens: o.max_tokens,\r\n };\r\n llmAgentResolution = {\r\n slug: blogCreationRow.slug,\r\n model: blogCreationRow.model?.trim() || null,\r\n temperature: blogCreationRow.temperature ?? null,\r\n maxTokens: blogCreationRow.maxTokens ?? null,\r\n };\r\n }\r\n metadataRow = await findLlmAgentByScope(dataSource, entityMap, LLM_AGENT_SCOPE_BLOG_METADATA);\r\n if (metadataRow) {\r\n const mo = llmAgentToChatAgentOptions(metadataRow);\r\n metadataLlmAgentChatOptions = {\r\n model: mo.model,\r\n temperature: mo.temperature,\r\n max_tokens: mo.max_tokens,\r\n };\r\n metadataLlmAgentResolution = {\r\n slug: metadataRow.slug,\r\n model: metadataRow.model?.trim() || null,\r\n temperature: metadataRow.temperature ?? null,\r\n maxTokens: metadataRow.maxTokens ?? null,\r\n };\r\n }\r\n socialRow = await findLlmAgentByScope(dataSource, entityMap, LLM_AGENT_SCOPE_SOCIAL_MEDIA_POST);\r\n if (socialRow) {\r\n const so = llmAgentToChatAgentOptions(socialRow);\r\n socialLlmAgentChatOptions = {\r\n model: so.model,\r\n temperature: so.temperature,\r\n max_tokens: so.max_tokens,\r\n };\r\n socialLlmAgentResolution = {\r\n slug: socialRow.slug,\r\n model: socialRow.model?.trim() || null,\r\n temperature: socialRow.temperature ?? null,\r\n maxTokens: socialRow.maxTokens ?? null,\r\n };\r\n }\r\n }\r\n\r\n try {\r\n const categoryEntities =\r\n entityMap.categories\r\n ? await dataSource.getRepository(entityMap.categories as EntityTarget<Category>).find({\r\n where: { deleted: false } as object,\r\n select: ['id', 'name'],\r\n })\r\n : [];\r\n const categoryRows = categoryEntities\r\n .map((r) => ({\r\n id: Number((r as Category).id),\r\n name: String((r as Category).name ?? '').trim(),\r\n }))\r\n .filter((r) => Number.isFinite(r.id) && r.name !== '');\r\n\r\n const tagEntities =\r\n entityMap.tags\r\n ? await dataSource.getRepository(entityMap.tags as EntityTarget<Tag>).find({\r\n where: { deleted: false } as object,\r\n select: ['name'],\r\n })\r\n : [];\r\n const tagNames = tagEntities\r\n .map((r) => String((r as Tag).name ?? '').trim())\r\n .filter((n) => n !== '');\r\n\r\n const out = await svc.generateBlogMarkdownFromRss({\r\n llm,\r\n rssUrls,\r\n systemInstruction:\r\n systemInstruction ?? blogCreationRow?.systemInstruction?.trim() ?? undefined,\r\n validationRules:\r\n validationRules ?? blogCreationRow?.validationRules?.trim() ?? undefined,\r\n categoryNamesHint: categoryRows.map((c) => c.name),\r\n tagNamesHint: tagNames,\r\n llmAgentChatOptions,\r\n metadataSystemInstruction: metadataRow?.systemInstruction,\r\n metadataValidationRules: metadataRow?.validationRules ?? undefined,\r\n metadataLlmAgentChatOptions,\r\n socialSystemInstruction: socialRow?.systemInstruction,\r\n socialValidationRules: socialRow?.validationRules ?? undefined,\r\n socialLlmAgentChatOptions,\r\n });\r\n\r\n let savedBlogs:\r\n | Array<{ blogId: number; slug: string; categoryId: number | null; seoId: number; tagIds: number[] }>\r\n | undefined;\r\n if (persistToCms) {\r\n const pCreate = await requireEntityPermissionEffective(req, 'blogs', 'create');\r\n if (pCreate) return pCreate;\r\n if (!entityMap.blogs || !entityMap.tags || !entityMap.categories || !entityMap.seos) {\r\n return config.json(\r\n { error: 'persistToCms requires blogs, tags, categories, and seos in the entity map.' },\r\n { status: 503 }\r\n );\r\n }\r\n let authorId: number | null = null;\r\n if (getSessionUser) {\r\n const su = await getSessionUser();\r\n if (su?.id) {\r\n const n = Number(su.id);\r\n if (Number.isFinite(n)) authorId = n;\r\n }\r\n if (authorId == null && su?.email?.trim() && entityMap.users) {\r\n const ur = await dataSource.getRepository(entityMap.users as EntityTarget<User>).findOne({\r\n where: { email: su.email.trim(), deleted: false } as object,\r\n select: ['id'],\r\n });\r\n if (ur) authorId = Number((ur as User).id);\r\n }\r\n }\r\n if (authorId == null || !Number.isFinite(authorId)) {\r\n return config.json(\r\n {\r\n error:\r\n 'persistToCms requires a logged-in user with id in session or a users row matching session email.',\r\n },\r\n { status: 400 }\r\n );\r\n }\r\n savedBlogs = await persistAllGeneratedBlogDrafts(\r\n dataSource,\r\n {\r\n blogs: entityMap.blogs,\r\n tags: entityMap.tags,\r\n categories: entityMap.categories,\r\n seos: entityMap.seos,\r\n },\r\n { drafts: out.blogDrafts, authorId }\r\n );\r\n }\r\n\r\n const blogs = out.blogDrafts.map((draft) => {\r\n const { categoryId, matched: categoryMatched } = resolveBlogCategoryIdByName(\r\n draft.categoryName,\r\n categoryRows\r\n );\r\n return {\r\n title: draft.title,\r\n slug: draft.slug ?? null,\r\n markdown: draft.markdown,\r\n socialMediaContent: draft.socialMediaContent ?? null,\r\n categoryName: draft.categoryName,\r\n categoryId,\r\n categoryMatched,\r\n seo: draft.seo,\r\n tags: draft.tags,\r\n parseMode: draft.parseMode,\r\n };\r\n });\r\n const firstArticle = out.article;\r\n return config.json({\r\n agentName: out.agentName,\r\n blogMarkdown: out.blogMarkdown,\r\n blogs,\r\n blog: blogs[0] ?? null,\r\n feedArticles: out.feedArticles.map((f) => ({\r\n rssUrl: f.rssUrl,\r\n article: {\r\n title: f.article.title,\r\n link: f.article.link,\r\n summary: f.article.summary,\r\n content: f.article.content,\r\n date: f.article.date.toISOString(),\r\n },\r\n })),\r\n llmAgent: llmAgentResolution,\r\n metadataLlmAgent: metadataLlmAgentResolution,\r\n socialLlmAgent: socialLlmAgentResolution,\r\n article: {\r\n title: firstArticle.title,\r\n link: firstArticle.link,\r\n summary: firstArticle.summary,\r\n content: firstArticle.content,\r\n date: firstArticle.date.toISOString(),\r\n },\r\n ...(savedBlogs != null ? { savedBlogs } : {}),\r\n });\r\n } catch (e) {\r\n const message = e instanceof Error ? e.message : 'Failed to generate blog';\r\n const status = /No items found|LLM returned empty/i.test(message) ? 400 : 502;\r\n return config.json({ error: message }, { status });\r\n }\r\n }\r\n // Analytics: [\"analytics\"], [\"analytics\", \"property-id\"], [\"analytics\", \"permissions\"]\r\n if (path[0] === 'analytics' && analyticsHandlers) {\r\n if (path.length === 1 && m === 'GET') {\r\n const g = await analyticsGate();\r\n if (g) return g;\r\n return analyticsHandlers.GET(req);\r\n }\r\n if (path.length === 2 && path[1] === 'property-id' && m === 'GET') {\r\n const g = await analyticsGate();\r\n if (g) return g;\r\n return analyticsHandlers.propertyId();\r\n }\r\n if (path.length === 2 && path[1] === 'permissions' && m === 'GET') {\r\n const g = await analyticsGate();\r\n if (g) return g;\r\n return analyticsHandlers.permissions();\r\n }\r\n }\r\n // Upload: [\"upload\"]\r\n if (path[0] === 'upload' && path.length === 1 && m === 'POST' && uploadPost) return uploadPost(req);\r\n // Media zip extract: [\"media\", \"extract\", id] POST\r\n if (path[0] === 'media' && path[1] === 'extract' && path.length === 3 && m === 'POST' && zipExtractPost) {\r\n return zipExtractPost(req, path[2]!);\r\n }\r\n // Blog by slug: [\"blogs\", \"slug\", slug] (public)\r\n if (path[0] === 'blogs' && path[1] === 'slug' && path.length === 3 && m === 'GET' && blogBySlugGet) {\r\n return blogBySlugGet(req, path[2]);\r\n }\r\n // Form by slug: [\"forms\", \"slug\", slug] (public)\r\n if (path[0] === 'forms' && path[1] === 'slug' && path.length === 3 && m === 'GET' && formBySlugGet) {\r\n return formBySlugGet(req, path[2]);\r\n }\r\n // Form submission: [\"form-submissions\"] GET (auth, list with relations) or POST (public); [\"form-submissions\", id] GET (auth, with relations)\r\n if (path[0] === 'form-submissions') {\r\n if (path.length === 1) {\r\n if (m === 'GET' && formSubmissionList) return formSubmissionList(req);\r\n if (m === 'POST' && formSubmissionPost) return formSubmissionPost(req);\r\n }\r\n if (path.length === 2 && m === 'GET' && formSubmissionGetById) return formSubmissionGetById(req, path[1]);\r\n }\r\n // Form save: [\"forms\"] POST; [\"forms\", id] GET (with fields) or PUT/PATCH (saves form + fields)\r\n if (path[0] === 'forms' && formSaveHandlers) {\r\n if (path.length === 1 && m === 'POST') return formSaveHandlers.POST(req);\r\n if (path.length === 2) {\r\n if (m === 'GET') return formSaveHandlers.GET(req, path[1]);\r\n if (m === 'PUT' || m === 'PATCH') return formSaveHandlers.PUT(req, path[1]);\r\n }\r\n }\r\n // Users API\r\n if (path[0] === 'users' && usersHandlers) {\r\n if (path.length === 1) {\r\n if (m === 'GET') return usersHandlers.list(req);\r\n if (m === 'POST') return usersHandlers.create(req);\r\n }\r\n if (path.length === 2) {\r\n if (path[1] === 'avatar' && m === 'POST' && avatarPost) return avatarPost(req);\r\n if (path[1] === 'profile' && profileHandlers) {\r\n if (m === 'GET') return profileHandlers.GET(req);\r\n if (m === 'PUT') return profileHandlers.PUT(req);\r\n }\r\n // users/:id\r\n const id = path[1];\r\n if (m === 'GET') return usersHandlers.getById(req, id);\r\n if (m === 'PUT' || m === 'PATCH') return usersHandlers.update(req, id);\r\n if (m === 'DELETE') return usersHandlers.delete(req, id);\r\n }\r\n if (path.length === 3 && path[2] === 'regenerate-invite' && m === 'POST') {\r\n return usersHandlers.regenerateInvite(req, path[1]);\r\n }\r\n }\r\n // User auth: [\"users\", \"forgot-password\"] etc.\r\n if (path[0] === 'users' && path.length === 2 && userAuthRouter && m === 'POST') {\r\n return userAuthRouter.POST(req, path[1]);\r\n }\r\n // Social media (LinkedIn): [\"social-media\", \"linkedin\", \"status\"|\"sync-profile\"|\"publish-blog\"]\r\n if (path[0] === 'social-media' && path[1] === 'linkedin' && socialMediaHandlers && path.length === 3) {\r\n const tail = path[2];\r\n if (tail === 'status' && m === 'GET') {\r\n return socialMediaHandlers.getLinkedInStatus(req);\r\n }\r\n if (tail === 'sync-profile' && m === 'POST') {\r\n return socialMediaHandlers.syncLinkedInProfile(req);\r\n }\r\n if (tail === 'fetch-organizations' && m === 'POST') {\r\n return socialMediaHandlers.fetchLinkedInOrganizations(req);\r\n }\r\n if (tail === 'publish-blog' && m === 'POST') {\r\n let body: { blogId?: unknown };\r\n try {\r\n body = (await req.json()) as { blogId?: unknown };\r\n } catch {\r\n return config.json({ error: 'Invalid JSON body' }, { status: 400 });\r\n }\r\n const id = Number(body?.blogId);\r\n return socialMediaHandlers.publishBlogToLinkedIn(req, id);\r\n }\r\n }\r\n // Social media (Facebook / Meta): [\"social-media\", \"facebook\", \"fetch-pages\"|\"status\"|\"publish-blog\"]\r\n if (path[0] === 'social-media' && path[1] === 'facebook' && socialMediaHandlers && path.length === 3) {\r\n const tail = path[2];\r\n if (tail === 'fetch-pages' && m === 'POST') {\r\n return socialMediaHandlers.fetchFacebookManagedPages(req);\r\n }\r\n if (tail === 'status' && m === 'GET') {\r\n return socialMediaHandlers.getFacebookStatus(req);\r\n }\r\n if (tail === 'publish-blog' && m === 'POST') {\r\n let body: { blogId?: unknown };\r\n try {\r\n body = (await req.json()) as { blogId?: unknown };\r\n } catch {\r\n return config.json({ error: 'Invalid JSON body' }, { status: 400 });\r\n }\r\n const id = Number(body?.blogId);\r\n return socialMediaHandlers.publishBlogToFacebook(req, id);\r\n }\r\n }\r\n // Settings: [\"settings\", group]\r\n if (path[0] === 'settings' && path.length === 2 && settingsHandlers) {\r\n const group = path[1]!;\r\n const isPublic = settingsConfig?.publicGetGroups?.includes(group);\r\n if (m === 'GET') {\r\n if (!isPublic) {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n // Admin shell UI prefs (nav/layout) — any signed-in admin user, not full settings RBAC.\r\n if (group !== 'admin_view') {\r\n const pe = await requireEntityPermissionEffective(req, 'settings', 'read');\r\n if (pe) return pe;\r\n }\r\n }\r\n return settingsHandlers.GET(req, group);\r\n }\r\n if (m === 'PUT') {\r\n const pe = await requireEntityPermissionEffective(req, 'settings', 'update');\r\n if (pe) return pe;\r\n return settingsHandlers.PUT(req, group);\r\n }\r\n }\r\n // Currency list: GET /api/currencies\r\nif (path[0] === 'currencies' && path.length === 1 && m === 'GET') {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const repo = dataSource.getRepository(entityMap.currency as any);\r\n const currencies = await repo.find({ where: { isActive: true }, order: { code: 'ASC' } });\r\n return config.json(currencies);\r\n}\r\n\r\n// Add currency: POST /api/currencies\r\nif (path[0] === 'currencies' && path.length === 1 && m === 'POST') {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const body = await req.json() as { code?: string; name?: string; symbol?: string };\r\n if (!body.code || !body.name || !body.symbol) {\r\n return config.json({ error: 'code, name and symbol are required' }, { status: 400 });\r\n }\r\n const repo = dataSource.getRepository(entityMap.currency as any);\r\n const existing = await repo.findOne({ where: { code: body.code.toUpperCase() } });\r\n if (existing) return config.json({ error: 'Currency with this code already exists' }, { status: 409 });\r\n const created = repo.create({ code: body.code.toUpperCase(), name: body.name, symbol: body.symbol, isActive: true, isBaseCurrency: false });\r\n await repo.save(created);\r\n return config.json(created);\r\n}\r\n\r\n// Exchange rates GET: /api/currencies/exchange-rates\r\nif (path[0] === 'currencies' && path[1] === 'exchange-rates' && path.length === 2 && m === 'GET') {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const repo = dataSource.getRepository(entityMap.currency_exchange as any);\r\n const rates = await repo.find();\r\n return config.json(rates);\r\n}\r\n\r\n// Single exchange rate lookup: GET /api/exchange-rate?from=INR&to=USD\r\nif (path[0] === 'exchange-rate' && path.length === 1 && m === 'GET') {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const url = new URL(req.url);\r\n const from = url.searchParams.get('from')?.toUpperCase();\r\n const to = url.searchParams.get('to')?.toUpperCase();\r\n if (!from || !to) {\r\n return config.json({ error: 'from and to query params are required' }, { status: 400 });\r\n }\r\n if (from === to) {\r\n return config.json({ from, to, rate: 1 });\r\n }\r\n if (!entityMap.currency_exchange) {\r\n return config.json({ error: 'currency_exchange entity not configured' }, { status: 503 });\r\n }\r\n try {\r\n const repo = dataSource.getRepository(entityMap.currency_exchange as any);\r\n const direct = await repo.findOne({\r\n where: { fromCurrency: from, toCurrency: to } as import('typeorm').ObjectLiteral,\r\n });\r\n if (direct) {\r\n return config.json({ from, to, rate: Number((direct as { rate: number }).rate) });\r\n }\r\n const inverse = await repo.findOne({\r\n where: { fromCurrency: to, toCurrency: from } as import('typeorm').ObjectLiteral,\r\n });\r\n if (inverse) {\r\n return config.json({ from, to, rate: 1 / Number((inverse as { rate: number }).rate) });\r\n }\r\n return config.json({ from, to, rate: 1 });\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n return config.json({ error: message }, { status: 500 });\r\n }\r\n}\r\n\r\n// Exchange rates PUT: /api/currencies/exchange-rates (bulk replace)\r\nif (path[0] === 'currencies' && path[1] === 'exchange-rates' && path.length === 2 && m === 'PUT') {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const body = await req.json() as { fromCurrency: string; toCurrency: string; rate: number }[];\r\n if (!Array.isArray(body)) return config.json({ error: 'Expected an array' }, { status: 400 });\r\n const repo = dataSource.getRepository(entityMap.currency_exchange as any);\r\n await repo.clear();\r\n const entries = body.map((e) => repo.create({ fromCurrency: e.fromCurrency, toCurrency: e.toCurrency, rate: e.rate }));\r\n await repo.save(entries);\r\n return config.json({ ok: true });\r\n}\r\n// Set base currency: PUT /api/currencies/base\r\nif (path[0] === 'currencies' && path[1] === 'base' && path.length === 2 && m === 'PUT') {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const body = await req.json() as { code?: string };\r\n if (!body.code) return config.json({ error: 'code is required' }, { status: 400 });\r\n const code = body.code.toUpperCase();\r\n const repo = dataSource.getRepository(entityMap.currency as any);\r\n // Unset all\r\n await dataSource.query(`UPDATE currency SET \"isBaseCurrency\" = false`);\r\n // Set the selected one\r\n const result = await dataSource.query(\r\n `UPDATE currency SET \"isBaseCurrency\" = true WHERE code = $1`,\r\n [code]\r\n );\r\n if (!result || result[1] === 0) return config.json({ error: 'Currency not found' }, { status: 404 });\r\n return config.json({ ok: true });\r\n}\r\n // SMS message templates (plugins page only): [\"message-templates\", \"sms\"]\r\n if (path[0] === 'message-templates' && path[1] === 'sms' && path.length === 2) {\r\n if (m === 'GET') return smsMessageTemplateHandlers.GET(req);\r\n if (m === 'PUT') return smsMessageTemplateHandlers.PUT(req);\r\n }\r\n // LLM agents CRUD: [\"llm_agents\"] GET/POST, [\"llm_agents\", id] GET/PUT/PATCH/DELETE\r\n // Handled before generic CRUD so it works even when crudResources is customised by the consuming app.\r\n if (path[0] === 'llm_agents') {\r\n if (!entityMap.llm_agents) {\r\n console.error(CMS_API_LOG, 'llm_agents route: entity missing after merge', {\r\n method: m,\r\n pathJoined: path.join('/'),\r\n entityMapKeyCount: Object.keys(entityMap).length,\r\n });\r\n return config.json(\r\n { error: 'LlmAgent entity is not registered', hint: 'Ensure migrations ran and entities include LlmAgent.' },\r\n { status: 503 }\r\n );\r\n }\r\n if (path.length === 1) {\r\n if (m === 'GET') return crud.GET(req, 'llm_agents');\r\n if (m === 'POST') return crud.POST(req, 'llm_agents');\r\n }\r\n if (path.length === 2 && !path[1]?.includes('knowledge')) {\r\n const id = path[1]!;\r\n if (m === 'GET') return crudById.GET(req, 'llm_agents', id);\r\n if (m === 'PUT' || m === 'PATCH') return crudById.PUT(req, 'llm_agents', id);\r\n if (m === 'DELETE') return crudById.DELETE(req, 'llm_agents', id);\r\n }\r\n }\r\n // LLM agent knowledge: canonical + merged-segment variants (see matchLlmAgentKnowledgeRoute)\r\n {\r\n const kbMatch = matchLlmAgentKnowledgeRoute(path);\r\n if (kbMatch) {\r\n if (!llmAgentKnowledgeHandlers) {\r\n return config.json(\r\n {\r\n error: 'LLM agent knowledge is not available',\r\n hint:\r\n 'With chat enabled, routes usually work automatically. Otherwise pass llmAgentKnowledge. If this persists, ensure entityMap includes knowledge_base_documents, knowledge_base_chunks, llm_agent_knowledge_documents, and run migrations.',\r\n },\r\n { status: 503 }\r\n );\r\n }\r\n const { slug, documentId } = kbMatch;\r\n if (m === 'DELETE' && documentId != null && documentId !== '') {\r\n return llmAgentKnowledgeHandlers.unlink(req, slug, documentId);\r\n }\r\n if (m === 'GET' && (documentId == null || documentId === '')) {\r\n return llmAgentKnowledgeHandlers.list(req, slug);\r\n }\r\n if (m === 'POST' && (documentId == null || documentId === '')) {\r\n return llmAgentKnowledgeHandlers.post(req, slug);\r\n }\r\n }\r\n }\r\n // Chat: [\"chat\", \"identify\"] POST; [\"chat\", \"conversations\", id, \"messages\"] GET; [\"chat\", \"messages\"] POST\r\n if (path[0] === 'chat' && chatHandlers) {\r\n if (path.length === 2 && path[1] === 'config' && m === 'GET') return chatHandlers.publicConfig(req);\r\n if (path.length === 2 && path[1] === 'identify' && m === 'POST') return chatHandlers.identify(req);\r\n if (path.length === 4 && path[1] === 'conversations' && path[3] === 'messages' && m === 'GET') return chatHandlers.getMessages(req, path[2]);\r\n if (path.length === 2 && path[1] === 'messages' && m === 'POST') return chatHandlers.postMessage(req);\r\n }\r\n\r\n // Invoice PDF: [\"orders\", id, \"invoice\"] (admin auth + orders:read)\r\n if (path[0] === 'orders' && path.length === 3 && path[2] === 'invoice' && m === 'GET' && getCms) {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermissionEffective(req, 'orders', 'read');\r\n if (pe) return pe;\r\n const cms = await getCms();\r\n const { streamOrderInvoicePdf } = await import('../plugins/erp/erp-order-invoice');\r\n const oid = Number(path[1]);\r\n if (!Number.isFinite(oid)) return config.json({ error: 'Invalid id' }, { status: 400 });\r\n return streamOrderInvoicePdf(cms, dataSource, entityMap, oid, {});\r\n }\r\n // ERP repost: [\"orders\", id, \"repost-erp\"] (admin auth + orders:update)\r\n if (path[0] === 'orders' && path.length === 3 && path[2] === 'repost-erp' && getCms) {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermissionEffective(req, 'orders', m === 'GET' ? 'read' : 'update');\r\n if (pe) return pe;\r\n const oid = Number(path[1]);\r\n if (!Number.isFinite(oid)) return config.json({ error: 'Invalid id' }, { status: 400 });\r\n const cms = await getCms();\r\n const { isErpIntegrationEnabled } = await import('../plugins/erp/erp-config-enabled');\r\n const enabled = await isErpIntegrationEnabled(cms, dataSource, entityMap);\r\n if (m === 'GET') {\r\n return config.json({ enabled });\r\n }\r\n if (m === 'POST') {\r\n if (!enabled) return config.json({ error: 'ERP integration is disabled' }, { status: 409 });\r\n const { queueErpPaidOrderForOrderId } = await import('../plugins/erp/paid-order-erp');\r\n await queueErpPaidOrderForOrderId(cms, dataSource, entityMap, oid);\r\n return config.json({ ok: true });\r\n }\r\n return config.json({ error: 'Method not allowed' }, { status: 405 });\r\n }\r\n\r\n // POST /api/discounts/validate-coupon\r\n if (path[0] === 'discounts' && path[1] === 'validate-coupon' && path.length === 2 && m === 'POST'){\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n try {\r\n const body = await req.json() as {\r\n couponCode?: string;\r\n discountId: number;\r\n orderLines?: unknown;\r\n currency?: string;\r\n contactId?: number;\r\n isAutomatic?: boolean;\r\n };\r\n const couponCode = typeof body.couponCode === 'string' ? body.couponCode.trim() : '';\r\n const isAutomatic = body.isAutomatic === true;\r\n const discountId = body.discountId ? Number(body.discountId) : null;\r\n if (!isAutomatic && !couponCode && !discountId){\r\n return config.json({ valid: false, error: 'Coupon code is required' }, { status: 400 });\r\n }\r\n const orderLinesNorm = normalizeOrderLinesInput(body.orderLines) ?? [];\r\n const currency = typeof body.currency === 'string' ? body.currency.trim().toUpperCase() : 'INR';\r\n const contactId = body.contactId ? Number(body.contactId) : null;\r\n let vendorId: number | null = null;\r\n if (resolveSessionUser) {\r\n const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());\r\n const scope = resolveVendorScopeFromSessionUser(u ?? null);\r\n if (scope.type === 'vendor') vendorId = scope.vendorId;\r\n }\r\n const result = await validateCoupon(\r\n dataSource,\r\n entityMap,\r\n couponCode,\r\n orderLinesNorm,\r\n currency,\r\n contactId,\r\n isAutomatic,\r\n discountId ?? undefined,\r\n vendorId\r\n );\r\n return config.json(result, { status: result.valid ? 200 : 400 });\r\n } catch (err){\r\n const message = err instanceof Error ? err.message : String(err);\r\n return config.json({ valid: false, error: message }, { status: 500 });\r\n }\r\n }\r\n\r\n // POST /api/orders/calculate — returns subtotal/tax/total preview without saving\r\n if (path[0] === 'orders' && path[1] === 'calculate' && path.length === 2 && m === 'POST') {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermissionEffective(req, 'orders', 'read');\r\n if (pe) return pe;\r\n try {\r\n const body = await req.json() as { itemsSummary?: string; orderLines?: unknown; discountId?: number; currency?: string };\r\n const discountId = body?.discountId ? Number(body.discountId) : null;\r\n const currency = typeof body?.currency === 'string' ? body.currency.trim().toUpperCase() : 'INR';\r\n let vendorId: number | null = null;\r\n if (resolveSessionUser) {\r\n const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());\r\n const scope = resolveVendorScopeFromSessionUser(u ?? null);\r\n if (scope.type === 'vendor') vendorId = scope.vendorId;\r\n }\r\n const orderLinesNorm = normalizeOrderLinesInput(body?.orderLines);\r\n if (orderLinesNorm && orderLinesNorm.length > 0) {\r\n const result = await calculateOrderTotalsFromLines(\r\n dataSource,\r\n entityMap,\r\n orderLinesNorm,\r\n currency,\r\n discountId,\r\n vendorId\r\n );\r\n return config.json(result);\r\n }\r\n const itemsSummary = String(body?.itemsSummary ?? '').trim();\r\n if (!itemsSummary) {\r\n return config.json({ subtotal: 0, discount: 0, tax: 0, total: 0, lines: [] });\r\n }\r\n const result = await calculateOrderTotals(dataSource, entityMap, itemsSummary, discountId, vendorId);\r\n return config.json(result);\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n return config.json({ error: message }, { status: 500 });\r\n }\r\n }\r\n\r\n // Public order tracking: GET /api/track/:token\r\n if (path[0] === 'track' && path.length === 2 && m === 'GET') {\r\n const token = path[1];\r\n if (!token) return config.json({ error: 'Token required' }, { status: 400 });\r\n try {\r\n const orderRepo = dataSource.getRepository(entityMap.orders);\r\n const order = await orderRepo.findOne({\r\n where: { qrToken: token, deleted: false } as import('typeorm').ObjectLiteral,\r\n relations: ['contact', 'items', 'items.product', 'items.product.collection'],\r\n });\r\n if (!order) return new Response(\r\n `<html><body style=\"font-family:sans-serif;text-align:center;padding:60px\"><h2>Order not found</h2><p style=\"color:#6b7280\">This QR code is invalid or the order has been removed.</p></body></html>`,\r\n { status: 404, headers: { 'Content-Type': 'text/html; charset=utf-8' } }\r\n );\r\n const { renderOrderTrackingPage } = await import('../admin/pages/OrderTrackPage');\r\n const html = renderOrderTrackingPage(order as Record<string, unknown>);\r\n return new Response(html, {\r\n status: 200,\r\n headers: { 'Content-Type': 'text/html; charset=utf-8' },\r\n });\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : String(err);\r\n return new Response(\r\n `<html><body style=\"font-family:sans-serif;text-align:center;padding:60px\"><h2>Something went wrong</h2><p style=\"color:#6b7280\">${message}</p></body></html>`,\r\n { status: 500, headers: { 'Content-Type': 'text/html; charset=utf-8' } }\r\n );\r\n }\r\n }\r\n\r\n // customer_contacts: GET (list by customerId) and POST (create link)\r\n if (path[0] === 'customer_contacts' && entityMap['customer_contacts']) {\r\n const a = await config.requireAuth(req);\r\n if (a) return a;\r\n const pe = await requireEntityPermissionEffective(req, 'vendor_customers', 'read');\r\n if (pe) return pe;\r\n if (path.length === 1 && m === 'GET') {\r\n const { searchParams } = new URL(req.url);\r\n const customerId = searchParams.get('customerId');\r\n const limit = Math.min(Number(searchParams.get('limit') || '200'), 500);\r\n if (!customerId || !Number.isFinite(Number(customerId))) {\r\n return config.json({ error: 'customerId is required' }, { status: 400 });\r\n }\r\n const repo = dataSource.getRepository(entityMap['customer_contacts']);\r\n const rows = await repo.find({\r\n where: { customerId: Number(customerId) } as import('typeorm').ObjectLiteral,\r\n relations: ['contact'],\r\n take: limit,\r\n order: { id: 'ASC' } as import('typeorm').ObjectLiteral,\r\n });\r\n return config.json({ data: rows, total: rows.length });\r\n }\r\n \r\n if (path.length === 1 && m === 'POST') {\r\n const pe2 = await requireEntityPermissionEffective(req, 'vendor_customers', 'create');\r\n if (pe2) return pe2;\r\n const body = await req.json() as { customerId?: unknown; contactId?: unknown };\r\n const customerId = Number(body.customerId);\r\n const contactId = Number(body.contactId);\r\n if (!Number.isFinite(customerId) || customerId <= 0) {\r\n return config.json({ error: 'customerId is required' }, { status: 400 });\r\n }\r\n if (!Number.isFinite(contactId) || contactId <= 0) {\r\n return config.json({ error: 'contactId is required' }, { status: 400 });\r\n }\r\n const repo = dataSource.getRepository(entityMap['customer_contacts']);\r\n const existing = await repo.findOne({\r\n where: { customerId, contactId } as import('typeorm').ObjectLiteral,\r\n });\r\n if (existing) {\r\n return config.json(existing, { status: 200 });\r\n }\r\n const created = await repo.save(\r\n repo.create({ customerId, contactId } as import('typeorm').ObjectLiteral)\r\n );\r\n return config.json(created, { status: 201 });\r\n }\r\n\r\n return config.json({ error: 'Method not allowed' }, { status: 405 });\r\n }\r\n \r\n // CRUD: [\"blogs\"] or [\"blogs\", \"123\"]\r\n if (path.length === 0) return config.json({ error: 'Not found' }, { status: 404 });\r\n const resource = resolveResource(path[0]);\r\n if (!crudResources.includes(resource)) {\r\n console.warn(CMS_API_LOG, 'generic CRUD gate: Invalid resource (not in crudResources)', {\r\n method: m,\r\n pathJoined: path.join('/'),\r\n pathSegments: path,\r\n resource,\r\n hasLlmAgentsEntity: Boolean(entityMap.llm_agents),\r\n crudResourcesHasResource: crudResources.includes(resource),\r\n crudResourcesLength: crudResources.length,\r\n });\r\n return config.json({ error: 'Invalid resource' }, { status: 400 });\r\n }\r\n\r\n // Bulk operations: [\"products\", \"metadata\"], [\"products\", \"bulk\"], [\"products\", \"export\"]\r\n if (path.length === 2) {\r\n if (path[1] === 'metadata' && m === 'GET') {\r\n return crud.GET_METADATA(req, resource);\r\n }\r\n if (path[1] === 'bulk' && m === 'POST') {\r\n return crud.BULK_POST(req, resource);\r\n }\r\n if (path[1] === 'export' && m === 'GET') {\r\n return crud.GET_EXPORT(req, resource);\r\n }\r\n }\r\n\r\n if (path.length === 1) {\r\n if (m === 'GET') return crud.GET(req, resource);\r\n if (m === 'POST') return crud.POST(req, resource);\r\n return config.json({ error: 'Method not allowed' }, { status: 405 });\r\n }\r\n if (path.length === 2) {\r\n const id = path[1];\r\n if (m === 'GET') return crudById.GET(req, resource, id);\r\n if (m === 'PUT' || m === 'PATCH') return crudById.PUT(req, resource, id);\r\n if (m === 'DELETE') return crudById.DELETE(req, resource, id);\r\n return config.json({ error: 'Method not allowed' }, { status: 405 });\r\n }\r\n return config.json({ error: 'Not found' }, { status: 404 });\r\n },\r\n };\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport type { EntityMap } from './crud';\r\nimport { getPermissionableEntityKeys, isSuperAdminGroupName } from '../auth/permission-entities';\r\nimport type { SessionUser } from '../auth/helpers';\r\nimport { canManageRoles } from '../auth/helpers';\r\nimport {\r\n canManageVendorRoles,\r\n VENDOR_STORE_RBAC_ENTITIES,\r\n} from '../auth/vendor-scope';\r\n\r\nexport type GetSessionUser = () => Promise<SessionUser | null>;\r\n\r\nexport interface AdminRolesHandlersConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n json: (body: unknown, init?: { status?: number }) => Response;\r\n getSessionUser: GetSessionUser;\r\n}\r\n\r\nexport function createAdminRolesHandlers(config: AdminRolesHandlersConfig) {\r\n const { dataSource, entityMap, json, getSessionUser } = config;\r\n const baseEntities = getPermissionableEntityKeys(entityMap as Record<string, unknown>);\r\n const allowEntities = new Set([...baseEntities, 'users']);\r\n const groupRepo = () => dataSource.getRepository(entityMap.user_groups);\r\n const permRepo = () => dataSource.getRepository(entityMap.permissions);\r\n const userRepo = () => dataSource.getRepository(entityMap.users);\r\n\r\n async function gate(): Promise<Response | SessionUser> {\r\n const u = await getSessionUser();\r\n if (!u?.email) return json({ error: 'Unauthorized' }, { status: 401 });\r\n if (!canManageRoles(u) && !canManageVendorRoles(u)) {\r\n return json({ error: 'Forbidden' }, { status: 403 });\r\n }\r\n return u;\r\n }\r\n\r\n function isVendorRolesOnly(u: SessionUser): boolean {\r\n return canManageVendorRoles(u) && !canManageRoles(u);\r\n }\r\n\r\n const vendorRoleEntities = [...VENDOR_STORE_RBAC_ENTITIES, 'dashboard', 'settings'].sort();\r\n\r\n return {\r\n async list(): Promise<Response> {\r\n const gated = await gate();\r\n if (gated instanceof Response) return gated;\r\n const u = gated;\r\n if (isVendorRolesOnly(u)) {\r\n const groupId = u.groupId;\r\n if (!groupId) return json({ error: 'No role group on your account' }, { status: 400 });\r\n const g = await groupRepo().findOne({\r\n where: { id: groupId, deleted: false },\r\n relations: ['permissions'],\r\n });\r\n if (!g) return json({ error: 'Role group not found' }, { status: 404 });\r\n return json({\r\n entities: vendorRoleEntities,\r\n vendorScoped: true,\r\n groups: [\r\n {\r\n id: g.id,\r\n name: g.name,\r\n permissions: (g.permissions ?? [])\r\n .filter((p) => !p.deleted)\r\n .map((p) => ({\r\n entity: p.entity,\r\n canCreate: p.canCreate,\r\n canRead: p.canRead,\r\n canUpdate: p.canUpdate,\r\n canDelete: p.canDelete,\r\n })),\r\n },\r\n ],\r\n });\r\n }\r\n const groups = await groupRepo().find({\r\n where: { deleted: false },\r\n order: { id: 'ASC' },\r\n relations: ['permissions'],\r\n });\r\n const entities = [...allowEntities].sort();\r\n return json({\r\n entities,\r\n vendorScoped: false,\r\n groups: groups.map((g) => ({\r\n id: g.id,\r\n name: g.name,\r\n permissions: (g.permissions ?? [])\r\n .filter((p) => !p.deleted)\r\n .map((p) => ({\r\n entity: p.entity,\r\n canCreate: p.canCreate,\r\n canRead: p.canRead,\r\n canUpdate: p.canUpdate,\r\n canDelete: p.canDelete,\r\n })),\r\n })),\r\n });\r\n },\r\n\r\n async createGroup(req: Request): Promise<Response> {\r\n const gated = await gate();\r\n if (gated instanceof Response) return gated;\r\n if (isVendorRolesOnly(gated)) return json({ error: 'Forbidden' }, { status: 403 });\r\n try {\r\n const body = (await req.json()) as { name?: string };\r\n const name = body?.name?.trim();\r\n if (!name) return json({ error: 'Name is required' }, { status: 400 });\r\n const repo = groupRepo();\r\n const existing = await repo.findOne({ where: { name } });\r\n if (existing) return json({ error: 'Group name already exists' }, { status: 400 });\r\n const g = await repo.save(repo.create({ name }));\r\n return json({ id: g.id, name: g.name, permissions: [] }, { status: 201 });\r\n } catch {\r\n return json({ error: 'Server error' }, { status: 500 });\r\n }\r\n },\r\n\r\n async patchGroup(req: Request, idStr: string): Promise<Response> {\r\n const gated = await gate();\r\n if (gated instanceof Response) return gated;\r\n if (isVendorRolesOnly(gated)) return json({ error: 'Forbidden' }, { status: 403 });\r\n const id = parseInt(idStr, 10);\r\n if (!Number.isFinite(id)) return json({ error: 'Invalid id' }, { status: 400 });\r\n try {\r\n const body = (await req.json()) as { name?: string };\r\n const name = body?.name?.trim();\r\n if (!name) return json({ error: 'Name is required' }, { status: 400 });\r\n const repo = groupRepo();\r\n const g = await repo.findOne({ where: { id, deleted: false } });\r\n if (!g) return json({ error: 'Not found' }, { status: 404 });\r\n if (isSuperAdminGroupName(g.name) && !isSuperAdminGroupName(name)) {\r\n return json({ error: 'Cannot rename the administrator group' }, { status: 400 });\r\n }\r\n const dup = await repo.findOne({ where: { name } });\r\n if (dup && dup.id !== id) return json({ error: 'Name already in use' }, { status: 400 });\r\n g.name = name;\r\n await repo.save(g);\r\n return json({ id: g.id, name: g.name });\r\n } catch {\r\n return json({ error: 'Server error' }, { status: 500 });\r\n }\r\n },\r\n\r\n async deleteGroup(idStr: string): Promise<Response> {\r\n const gated = await gate();\r\n if (gated instanceof Response) return gated;\r\n if (isVendorRolesOnly(gated)) return json({ error: 'Forbidden' }, { status: 403 });\r\n const id = parseInt(idStr, 10);\r\n if (!Number.isFinite(id)) return json({ error: 'Invalid id' }, { status: 400 });\r\n const repo = groupRepo();\r\n const g = await repo.findOne({ where: { id, deleted: false } });\r\n if (!g) return json({ error: 'Not found' }, { status: 404 });\r\n if (isSuperAdminGroupName(g.name)) return json({ error: 'Cannot delete the administrator group' }, { status: 400 });\r\n const userCount = await userRepo().count({ where: { groupId: id } });\r\n if (userCount > 0) return json({ error: 'Reassign users before deleting this group' }, { status: 409 });\r\n await permRepo().delete({ groupId: id });\r\n await repo.update(id, { deleted: true, deletedAt: new Date() } as object);\r\n return json({ ok: true });\r\n },\r\n\r\n async putPermissions(req: Request, idStr: string): Promise<Response> {\r\n const gated = await gate();\r\n if (gated instanceof Response) return gated;\r\n const groupId = parseInt(idStr, 10);\r\n if (!Number.isFinite(groupId)) return json({ error: 'Invalid id' }, { status: 400 });\r\n if (isVendorRolesOnly(gated) && gated.groupId !== groupId) {\r\n return json({ error: 'Forbidden' }, { status: 403 });\r\n }\r\n const groupRepository = groupRepo();\r\n const g = await groupRepository.findOne({ where: { id: groupId, deleted: false } });\r\n if (!g) return json({ error: 'Group not found' }, { status: 404 });\r\n const entityAllow = isVendorRolesOnly(gated)\r\n ? new Set(vendorRoleEntities)\r\n : allowEntities;\r\n try {\r\n const body = (await req.json()) as {\r\n permissions?: Array<{\r\n entity: string;\r\n canCreate?: boolean;\r\n canRead?: boolean;\r\n canUpdate?: boolean;\r\n canDelete?: boolean;\r\n }>;\r\n };\r\n const rows = body?.permissions;\r\n if (!Array.isArray(rows)) return json({ error: 'permissions array required' }, { status: 400 });\r\n for (const r of rows) {\r\n if (!r?.entity || !entityAllow.has(r.entity)) {\r\n return json({ error: `Invalid entity: ${r?.entity ?? ''}` }, { status: 400 });\r\n }\r\n }\r\n await dataSource.transaction(async (em) => {\r\n await em.getRepository(entityMap.permissions).delete({ groupId });\r\n for (const r of rows) {\r\n await em.getRepository(entityMap.permissions).save(\r\n em.getRepository(entityMap.permissions).create({\r\n groupId,\r\n entity: r.entity,\r\n canCreate: !!r.canCreate,\r\n canRead: !!r.canRead,\r\n canUpdate: !!r.canUpdate,\r\n canDelete: !!r.canDelete,\r\n })\r\n );\r\n }\r\n });\r\n const updated = await groupRepository.findOne({\r\n where: { id: groupId },\r\n relations: ['permissions'],\r\n });\r\n return json({\r\n id: groupId,\r\n permissions: (updated?.permissions ?? []).map((p) => ({\r\n entity: p.entity,\r\n canCreate: p.canCreate,\r\n canRead: p.canRead,\r\n canUpdate: p.canUpdate,\r\n canDelete: p.canDelete,\r\n })),\r\n });\r\n } catch {\r\n return json({ error: 'Server error' }, { status: 500 });\r\n }\r\n },\r\n };\r\n}\r\n","import { In, type DataSource } from 'typeorm';\r\nimport type { EntityMap } from './crud';\r\nimport type { SessionUser } from '../auth/helpers';\r\nimport {\r\n canManageVendorTeam,\r\n isPlatformAdministrator,\r\n resolveVendorScopeFromSessionUser,\r\n VENDOR_OWNER_GROUP_NAME,\r\n} from '../auth/vendor-scope';\r\nimport { inviteStatusForActivation } from '../lib/vendor-invite-status';\r\nimport { sendVendorOnboardEmails } from '../lib/send-vendor-onboard-emails';\r\n\r\nexport type VendorOwnerActivation = 'invite' | 'password';\r\n\r\nexport interface VendorOnboardHandlersConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n json: (body: unknown, init?: { status?: number }) => Response;\r\n getSessionUser: () => Promise<SessionUser | null>;\r\n baseUrl: string;\r\n getCms?: () => Promise<{ getPlugin: (name: string) => unknown }>;\r\n hashPassword?: (plain: string) => Promise<string>;\r\n minPasswordLength?: number;\r\n}\r\n\r\nfunction slugify(input: string): string {\r\n return input\r\n .trim()\r\n .toLowerCase()\r\n .replace(/[^a-z0-9]+/g, '-')\r\n .replace(/^-+|-+$/g, '')\r\n .slice(0, 80);\r\n}\r\n\r\nexport function createVendorOnboardHandlers(config: VendorOnboardHandlersConfig) {\r\n const {\r\n dataSource,\r\n entityMap,\r\n json,\r\n getSessionUser,\r\n baseUrl,\r\n getCms,\r\n hashPassword,\r\n minPasswordLength = 6,\r\n } = config;\r\n\r\n async function gateAdmin(): Promise<Response | null> {\r\n const u = await getSessionUser();\r\n if (!u?.email) return json({ error: 'Unauthorized' }, { status: 401 });\r\n if (!isPlatformAdministrator(u)) return json({ error: 'Forbidden', reason: 'admin_only' }, { status: 403 });\r\n return null;\r\n }\r\n\r\n async function resolveActiveVendorId(u: SessionUser): Promise<number | null> {\r\n const scope = resolveVendorScopeFromSessionUser(u);\r\n if (scope.type === 'vendor') return scope.vendorId;\r\n if (scope.type === 'all') {\r\n const id = u.activeVendorId ?? u.vendorIds?.[0];\r\n return id != null && Number.isFinite(id) ? id : null;\r\n }\r\n return null;\r\n }\r\n\r\n async function gateVendorTeam(): Promise<\r\n { user: SessionUser; vendorId: number } | Response\r\n > {\r\n const u = await getSessionUser();\r\n if (!u?.email) return json({ error: 'Unauthorized' }, { status: 401 });\r\n if (!canManageVendorTeam(u)) return json({ error: 'Forbidden' }, { status: 403 });\r\n const vendorId = await resolveActiveVendorId(u);\r\n if (vendorId == null) {\r\n return json({ error: 'No vendor store linked to this account' }, { status: 400 });\r\n }\r\n return { user: u, vendorId };\r\n }\r\n\r\n async function trySendVendorOnboardEmails(input: {\r\n vendorName: string;\r\n vendorSlug: string;\r\n ownerName: string;\r\n ownerEmail: string;\r\n activation: VendorOwnerActivation;\r\n inviteLink?: string;\r\n kind?: 'vendor_onboard' | 'team_invite';\r\n sendToOwner: boolean;\r\n }): Promise<boolean> {\r\n if (!getCms) return false;\r\n try {\r\n const { ownerEmailSent } = await sendVendorOnboardEmails(\r\n {\r\n vendorName: input.vendorName,\r\n vendorSlug: input.vendorSlug,\r\n ownerName: input.ownerName,\r\n ownerEmail: input.ownerEmail,\r\n activation: input.activation,\r\n inviteLink: input.inviteLink,\r\n signInLink: `${baseUrl.replace(/\\/$/, '')}/admin`,\r\n kind: input.kind ?? 'vendor_onboard',\r\n sendToOwner: input.sendToOwner,\r\n },\r\n {\r\n getDataSource: async () => dataSource,\r\n entityMap: { configs: entityMap.configs },\r\n getCms,\r\n }\r\n );\r\n return ownerEmailSent;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n return {\r\n /** POST /api/admin/vendors/onboard — create vendor + owner user + vendor_users + invite */\r\n async onboard(req: Request): Promise<Response> {\r\n const err = await gateAdmin();\r\n if (err) return err;\r\n if (!entityMap.vendors || !entityMap.users || !entityMap.vendor_users || !entityMap.user_groups) {\r\n return json({ error: 'Vendor entities not configured' }, { status: 500 });\r\n }\r\n try {\r\n const body = (await req.json()) as {\r\n vendor?: { name?: string; slug?: string; email?: string; phone?: string; active?: boolean };\r\n user?: { name?: string; email?: string; password?: string };\r\n activation?: VendorOwnerActivation;\r\n sendInviteEmail?: boolean;\r\n sendOwnerEmail?: boolean;\r\n };\r\n const vendorName = body.vendor?.name?.trim();\r\n const userName = body.user?.name?.trim();\r\n const userEmail = body.user?.email?.trim().toLowerCase();\r\n if (!vendorName || !userName || !userEmail) {\r\n return json({ error: 'vendor.name, user.name, and user.email are required' }, { status: 400 });\r\n }\r\n const activation: VendorOwnerActivation = body.activation === 'password' ? 'password' : 'invite';\r\n const sendOwnerEmail = body.sendOwnerEmail !== false && body.sendInviteEmail !== false;\r\n let ownerPasswordHash: string | null = null;\r\n if (activation === 'password') {\r\n const plain = body.user?.password?.trim();\r\n if (!plain) {\r\n return json({ error: 'Password is required when activating with a set password' }, { status: 400 });\r\n }\r\n if (plain.length < minPasswordLength) {\r\n return json(\r\n { error: `Password must be at least ${minPasswordLength} characters` },\r\n { status: 400 }\r\n );\r\n }\r\n if (!hashPassword) {\r\n return json({ error: 'Password hashing is not configured on the server' }, { status: 501 });\r\n }\r\n ownerPasswordHash = await hashPassword(plain);\r\n }\r\n const slug = (body.vendor?.slug?.trim() || slugify(vendorName)) || slugify(vendorName);\r\n if (!slug) return json({ error: 'Could not derive vendor slug' }, { status: 400 });\r\n\r\n const result = await dataSource.transaction(async (em) => {\r\n const vendorRepo = em.getRepository(entityMap.vendors);\r\n const userRepo = em.getRepository(entityMap.users);\r\n const vuRepo = em.getRepository(entityMap.vendor_users);\r\n const groupRepo = em.getRepository(entityMap.user_groups);\r\n\r\n const dupVendor = await vendorRepo.findOne({ where: { slug, deleted: false } });\r\n if (dupVendor) throw new Error('VENDOR_SLUG_EXISTS');\r\n\r\n const ownerGroup = await groupRepo.findOne({ where: { name: VENDOR_OWNER_GROUP_NAME, deleted: false } });\r\n if (!ownerGroup) throw new Error('VENDOR_OWNER_GROUP_MISSING');\r\n\r\n const existingUser = await userRepo.findOne({ where: { email: userEmail } });\r\n if (existingUser && !existingUser.deleted) throw new Error('USER_EMAIL_EXISTS');\r\n\r\n const newUser = existingUser?.deleted\r\n ? await (async () => {\r\n await userRepo.update(existingUser.id, {\r\n deleted: false,\r\n deletedAt: null,\r\n deletedBy: null,\r\n name: userName,\r\n email: userEmail,\r\n password: ownerPasswordHash,\r\n blocked: activation === 'invite',\r\n groupId: ownerGroup.id,\r\n adminAccess: true,\r\n updatedAt: new Date(),\r\n } as object);\r\n const row = await userRepo.findOne({ where: { id: existingUser.id } });\r\n if (!row) throw new Error('user missing after restore');\r\n return row;\r\n })()\r\n : await userRepo.save(\r\n userRepo.create({\r\n name: userName,\r\n email: userEmail,\r\n password: ownerPasswordHash,\r\n blocked: activation === 'invite',\r\n groupId: ownerGroup.id,\r\n adminAccess: true,\r\n })\r\n );\r\n\r\n const vendor = await vendorRepo.save(\r\n vendorRepo.create({\r\n name: vendorName,\r\n slug,\r\n email: body.vendor?.email?.trim() || null,\r\n phone: body.vendor?.phone?.trim() || null,\r\n active: body.vendor?.active !== false,\r\n deleted: false,\r\n userId: newUser.id,\r\n inviteStatus: inviteStatusForActivation(activation),\r\n })\r\n );\r\n\r\n const existingLink = await vuRepo.findOne({\r\n where: { vendorId: vendor.id, userId: newUser.id },\r\n });\r\n if (!existingLink) {\r\n await vuRepo.save(\r\n vuRepo.create({\r\n vendorId: vendor.id,\r\n userId: newUser.id,\r\n role: 'owner',\r\n })\r\n );\r\n }\r\n\r\n return { vendor, user: newUser };\r\n });\r\n\r\n let inviteLink: string | undefined;\r\n let emailSent = false;\r\n if (activation === 'invite') {\r\n const emailToken = Buffer.from(result.user.email as string).toString('base64');\r\n inviteLink = `${baseUrl}/admin/invite?token=${emailToken}`;\r\n }\r\n if (sendOwnerEmail) {\r\n emailSent = await trySendVendorOnboardEmails({\r\n vendorName,\r\n vendorSlug: slug,\r\n ownerName: userName,\r\n ownerEmail: userEmail,\r\n activation,\r\n inviteLink,\r\n sendToOwner: true,\r\n });\r\n } else if (getCms) {\r\n await trySendVendorOnboardEmails({\r\n vendorName,\r\n vendorSlug: slug,\r\n ownerName: userName,\r\n ownerEmail: userEmail,\r\n activation,\r\n inviteLink,\r\n sendToOwner: false,\r\n });\r\n }\r\n\r\n const message =\r\n activation === 'password'\r\n ? emailSent\r\n ? 'Vendor onboarded successfully. Welcome email sent to the owner.'\r\n : sendOwnerEmail\r\n ? 'Vendor onboarded successfully. Owner can sign in with the password you set (welcome email may not have been sent — check email plugin).'\r\n : 'Vendor onboarded successfully. Owner can sign in with the password you set.'\r\n : emailSent\r\n ? 'Vendor onboarded successfully. Invite email sent.'\r\n : sendOwnerEmail\r\n ? 'Vendor onboarded successfully. Invite link created (email may not have been sent — check email plugin).'\r\n : 'Vendor onboarded successfully. Share the invite link with the owner.';\r\n\r\n return json(\r\n {\r\n message,\r\n activation,\r\n emailSent,\r\n vendor: result.vendor,\r\n user: { id: result.user.id, name: result.user.name, email: result.user.email },\r\n inviteLink,\r\n },\r\n { status: 201 }\r\n );\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n if (msg === 'VENDOR_SLUG_EXISTS') return json({ error: 'Vendor slug already exists' }, { status: 400 });\r\n if (msg === 'USER_EMAIL_EXISTS') return json({ error: 'User with this email already exists' }, { status: 400 });\r\n if (msg === 'VENDOR_OWNER_GROUP_MISSING') {\r\n return json({ error: 'Vendor Owner group not found. Run migrations.' }, { status: 500 });\r\n }\r\n return json({ error: 'Server error' }, { status: 500 });\r\n }\r\n },\r\n\r\n /** POST /api/admin/vendor/switch — set active vendor in session (JWT update via client) */\r\n async switchVendor(req: Request): Promise<Response> {\r\n const u = await getSessionUser();\r\n if (!u?.email) return json({ error: 'Unauthorized' }, { status: 401 });\r\n const body = (await req.json()) as { vendorId?: number };\r\n const vendorId = Number(body.vendorId);\r\n if (!Number.isFinite(vendorId)) return json({ error: 'vendorId required' }, { status: 400 });\r\n if (u.isRBACAdmin) {\r\n return json({ activeVendorId: vendorId, vendorIds: u.vendorIds ?? [] });\r\n }\r\n const ids = u.vendorIds ?? [];\r\n if (!ids.includes(vendorId)) return json({ error: 'Forbidden' }, { status: 403 });\r\n return json({ activeVendorId: vendorId, vendorIds: ids });\r\n },\r\n\r\n /** GET /api/admin/vendor/team */\r\n async listTeam(): Promise<Response> {\r\n const gated = await gateVendorTeam();\r\n if (gated instanceof Response) return gated;\r\n const { vendorId } = gated;\r\n if (!entityMap.vendor_users || !entityMap.users) {\r\n return json({ error: 'Vendor entities not configured' }, { status: 500 });\r\n }\r\n const vuRepo = dataSource.getRepository(entityMap.vendor_users);\r\n const userRepo = dataSource.getRepository(entityMap.users);\r\n const links = await vuRepo.find({ where: { vendorId }, order: { id: 'ASC' } });\r\n if (links.length === 0) return json({ vendorId, members: [] });\r\n const users = await userRepo.find({\r\n where: { id: In(links.map((l) => l.userId)) },\r\n relations: ['group'],\r\n });\r\n const userById = new Map(users.map((u) => [u.id as number, u]));\r\n const members = links.map((l) => {\r\n const u = userById.get(l.userId);\r\n return {\r\n vendorUserId: l.id,\r\n userId: l.userId,\r\n role: l.role,\r\n name: u?.name ?? null,\r\n email: u?.email ?? null,\r\n blocked: u?.blocked ?? false,\r\n groupName: (u as { group?: { name?: string } })?.group?.name ?? null,\r\n };\r\n });\r\n return json({ vendorId, members });\r\n },\r\n\r\n /** POST /api/admin/vendor/team — add staff to vendor */\r\n async addTeamMember(req: Request): Promise<Response> {\r\n const gated = await gateVendorTeam();\r\n if (gated instanceof Response) return gated;\r\n const { vendorId, user: actor } = gated;\r\n if (!entityMap.users || !entityMap.vendor_users || !entityMap.user_groups || !entityMap.vendors) {\r\n return json({ error: 'Vendor entities not configured' }, { status: 500 });\r\n }\r\n try {\r\n const body = (await req.json()) as {\r\n name?: string;\r\n email?: string;\r\n activation?: VendorOwnerActivation;\r\n sendInviteEmail?: boolean;\r\n sendOwnerEmail?: boolean;\r\n user?: { password?: string };\r\n };\r\n const userName = body.name?.trim();\r\n const userEmail = body.email?.trim().toLowerCase();\r\n if (!userName || !userEmail) {\r\n return json({ error: 'name and email are required' }, { status: 400 });\r\n }\r\n const activation: VendorOwnerActivation = body.activation === 'password' ? 'password' : 'invite';\r\n const sendOwnerEmail = body.sendOwnerEmail !== false && body.sendInviteEmail !== false;\r\n let ownerPasswordHash: string | null = null;\r\n if (activation === 'password') {\r\n const plain = body.user?.password?.trim();\r\n if (!plain) return json({ error: 'Password is required' }, { status: 400 });\r\n if (plain.length < minPasswordLength) {\r\n return json(\r\n { error: `Password must be at least ${minPasswordLength} characters` },\r\n { status: 400 }\r\n );\r\n }\r\n if (!hashPassword) return json({ error: 'Password hashing not configured' }, { status: 501 });\r\n ownerPasswordHash = await hashPassword(plain);\r\n }\r\n\r\n const staffGroupId = actor.groupId;\r\n const result = await dataSource.transaction(async (em) => {\r\n const userRepo = em.getRepository(entityMap.users);\r\n const vuRepo = em.getRepository(entityMap.vendor_users);\r\n const groupRepo = em.getRepository(entityMap.user_groups);\r\n\r\n let groupId = staffGroupId ?? null;\r\n if (!groupId) {\r\n const g = await groupRepo.findOne({\r\n where: { name: VENDOR_OWNER_GROUP_NAME, deleted: false },\r\n });\r\n groupId = g?.id ?? null;\r\n }\r\n if (!groupId) throw new Error('VENDOR_OWNER_GROUP_MISSING');\r\n\r\n const existingUser = await userRepo.findOne({ where: { email: userEmail } });\r\n if (existingUser && !existingUser.deleted) {\r\n const link = await vuRepo.findOne({\r\n where: { vendorId, userId: existingUser.id },\r\n });\r\n if (link) throw new Error('USER_ALREADY_ON_TEAM');\r\n }\r\n let newUser = existingUser;\r\n if (existingUser?.deleted) {\r\n await userRepo.update(existingUser.id, {\r\n deleted: false,\r\n deletedAt: null,\r\n deletedBy: null,\r\n name: userName,\r\n email: userEmail,\r\n password: ownerPasswordHash,\r\n blocked: activation === 'invite',\r\n groupId,\r\n adminAccess: true,\r\n updatedAt: new Date(),\r\n } as object);\r\n newUser = await userRepo.findOne({ where: { id: existingUser.id } });\r\n if (!newUser) throw new Error('user missing after restore');\r\n } else if (existingUser && !existingUser.deleted) {\r\n await userRepo.update(existingUser.id, {\r\n name: userName,\r\n groupId,\r\n adminAccess: true,\r\n ...(ownerPasswordHash\r\n ? { password: ownerPasswordHash, blocked: false }\r\n : activation === 'invite'\r\n ? { password: null, blocked: true }\r\n : {}),\r\n } as object);\r\n newUser = await userRepo.findOne({ where: { id: existingUser.id } });\r\n if (!newUser) throw new Error('user missing after update');\r\n } else if (!existingUser) {\r\n newUser = await userRepo.save(\r\n userRepo.create({\r\n name: userName,\r\n email: userEmail,\r\n password: ownerPasswordHash,\r\n blocked: activation === 'invite',\r\n groupId,\r\n adminAccess: true,\r\n })\r\n );\r\n }\r\n if (!newUser) throw new Error('user missing');\r\n\r\n const existingLink = await vuRepo.findOne({\r\n where: { vendorId, userId: newUser.id },\r\n });\r\n if (!existingLink) {\r\n await vuRepo.save(\r\n vuRepo.create({\r\n vendorId,\r\n userId: newUser.id,\r\n role: 'staff',\r\n })\r\n );\r\n }\r\n\r\n return newUser;\r\n });\r\n\r\n const vendorRow = await dataSource.getRepository(entityMap.vendors).findOne({\r\n where: { id: vendorId, deleted: false } as object,\r\n });\r\n const vendorName = String((vendorRow as { name?: string } | null)?.name ?? 'Vendor store');\r\n const vendorSlug = String((vendorRow as { slug?: string } | null)?.slug ?? '');\r\n\r\n let inviteLink: string | undefined;\r\n let emailSent = false;\r\n if (activation === 'invite') {\r\n const emailToken = Buffer.from(result.email as string).toString('base64');\r\n inviteLink = `${baseUrl}/admin/invite?token=${emailToken}`;\r\n }\r\n if (sendOwnerEmail || getCms) {\r\n emailSent = await trySendVendorOnboardEmails({\r\n vendorName,\r\n vendorSlug,\r\n ownerName: userName,\r\n ownerEmail: userEmail,\r\n activation,\r\n inviteLink,\r\n kind: 'team_invite',\r\n sendToOwner: sendOwnerEmail,\r\n });\r\n }\r\n\r\n return json(\r\n {\r\n message: emailSent\r\n ? 'Team member added. Invitation email sent.'\r\n : sendOwnerEmail\r\n ? 'Team member added (email may not have been sent — check email plugin).'\r\n : 'Team member added',\r\n emailSent,\r\n user: { id: result.id, name: result.name, email: result.email },\r\n inviteLink,\r\n },\r\n { status: 201 }\r\n );\r\n } catch (e) {\r\n const msg = e instanceof Error ? e.message : String(e);\r\n if (msg === 'USER_ALREADY_ON_TEAM') {\r\n return json({ error: 'User is already on this vendor team' }, { status: 400 });\r\n }\r\n if (msg === 'VENDOR_OWNER_GROUP_MISSING') {\r\n return json({ error: 'Vendor role group not found. Run migrations.' }, { status: 500 });\r\n }\r\n return json({ error: 'Server error' }, { status: 500 });\r\n }\r\n },\r\n\r\n /** DELETE /api/admin/vendor/team/:userId */\r\n async removeTeamMember(_req: Request, userIdStr: string): Promise<Response> {\r\n const gated = await gateVendorTeam();\r\n if (gated instanceof Response) return gated;\r\n const { vendorId, user: actor } = gated;\r\n const userId = parseInt(userIdStr, 10);\r\n if (!Number.isFinite(userId)) return json({ error: 'Invalid user id' }, { status: 400 });\r\n if (!entityMap.vendor_users) return json({ error: 'Vendor entities not configured' }, { status: 500 });\r\n const vuRepo = dataSource.getRepository(entityMap.vendor_users);\r\n const link = await vuRepo.findOne({ where: { vendorId, userId } });\r\n if (!link) return json({ error: 'Not found' }, { status: 404 });\r\n if (link.role === 'owner' && Number(actor.id) !== userId) {\r\n return json({ error: 'Cannot remove the store owner' }, { status: 400 });\r\n }\r\n await vuRepo.delete(link.id);\r\n return json({ message: 'Removed from team' });\r\n },\r\n };\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport type { EntityTarget, ObjectLiteral } from 'typeorm';\r\nimport { In, IsNull } from 'typeorm';\r\nimport type { SessionUser } from '../auth/helpers';\r\nimport type { EntityMap } from './crud';\r\nimport { linkUnclaimedContactToUser } from '../lib/link-contact-to-user';\r\nimport { isValidSignupEmail } from '../lib/is-valid-signup-email';\r\nimport { queueEmail } from '../plugins/email/email-queue';\r\nimport { queueErpCreateContactIfEnabled } from '../plugins/erp/erp-contact-sync';\r\nimport { buildCanonicalOrderNumber, temporaryOrderNumberPlaceholder } from '../lib/order-number';\r\nimport { tryRefreshOrderFromErpForStorefront } from '../plugins/erp/erp-order-sync';\r\nimport { streamOrderInvoicePdf } from '../plugins/erp/erp-order-invoice';\r\nimport type { CompanyDetails } from '../plugins/email/templates/types';\r\nimport { assertCaptchaOk } from '../plugins/captcha/assert';\r\nimport { validateAndNormalizeAddressRow } from '../lib/address-geo-validation';\r\nimport { queueSms } from '../plugins/sms/sms-queue';\r\nimport {\r\n createOtpChallenge,\r\n verifyAndConsumeOtpChallenge,\r\n generateNumericOtp,\r\n normalizePhoneE164,\r\n type OtpPurpose,\r\n} from '../lib/otp-challenge';\r\nconst GUEST_COOKIE = 'guest_id';\r\nconst ONE_YEAR = 60 * 60 * 24 * 365;\r\n\r\nexport interface StorefrontOtpFlags {\r\n login?: boolean;\r\n verifyEmail?: boolean;\r\n verifyPhone?: boolean;\r\n}\r\n\r\nfunction parseCookies(header: string | null): Record<string, string> {\r\n const out: Record<string, string> = {};\r\n if (!header) return out;\r\n for (const part of header.split(';')) {\r\n const i = part.indexOf('=');\r\n if (i === -1) continue;\r\n const k = part.slice(0, i).trim();\r\n const v = part.slice(i + 1).trim();\r\n out[k] = decodeURIComponent(v);\r\n }\r\n return out;\r\n}\r\n\r\nfunction guestCookieHeader(name: string, token: string): string {\r\n return `${name}=${encodeURIComponent(token)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${ONE_YEAR}`;\r\n}\r\n\r\nexport interface StorefrontApiConfig {\r\n dataSource: DataSource;\r\n entityMap: EntityMap;\r\n json: (body: unknown, init?: { status?: number; headers?: HeadersInit }) => Response;\r\n getSessionUser: () => Promise<SessionUser | null>;\r\n guestCookieName?: string;\r\n /** Required for POST storefront/register */\r\n hashPassword?: (plain: string) => Promise<string>;\r\n /** When set, new registrations are blocked until email is verified and a signup email is sent. */\r\n getCms?: () => Promise<{ getPlugin: (name: string) => unknown }>;\r\n getCompanyDetails?: () => Promise<CompanyDetails>;\r\n /** Origin for verify links (e.g. process.env.NEXTAUTH_URL). Required with getCms for verification URLs. */\r\n publicSiteUrl?: string;\r\n /** When a flag is true, the corresponding OTP storefront route is enabled. */\r\n otpFlags?: StorefrontOtpFlags;\r\n /** Defaults to OTP_PEPPER or NEXTAUTH_SECRET. */\r\n otpPepper?: string;\r\n defaultPhoneCountryCode?: string;\r\n /** When false, login OTP send accepts email only (no phone). Default true. */\r\n otpAllowPhoneLogin?: boolean;\r\n}\r\n\r\nconst SIGNUP_VERIFY_EXPIRY_HOURS = 72;\r\n\r\nexport function createStorefrontApiHandler(config: StorefrontApiConfig) {\r\n const { dataSource, entityMap, json, getSessionUser, getCms, getCompanyDetails, publicSiteUrl } = config;\r\n const cookieName = config.guestCookieName ?? GUEST_COOKIE;\r\n const otpFlags = config.otpFlags;\r\n const otpPepper = config.otpPepper;\r\n const defaultPhoneCc = config.defaultPhoneCountryCode;\r\n const otpAllowPhoneLogin = config.otpAllowPhoneLogin !== false;\r\n\r\n function otpOff(key: keyof StorefrontOtpFlags) {\r\n return !otpFlags || otpFlags[key] !== true;\r\n }\r\n\r\n const cartRepo = () => dataSource.getRepository(entityMap.carts);\r\n const cartItemRepo = () => dataSource.getRepository(entityMap.cart_items);\r\n const productRepo = () => dataSource.getRepository(entityMap.products);\r\n const contactRepo = () => dataSource.getRepository(entityMap.contacts);\r\n const addressRepo = () => dataSource.getRepository(entityMap.addresses);\r\n const orderRepo = () => dataSource.getRepository(entityMap.orders);\r\n const orderItemRepo = () => dataSource.getRepository(entityMap.order_items);\r\n const wishlistRepo = () => dataSource.getRepository(entityMap.wishlists);\r\n const wishlistItemRepo = () => dataSource.getRepository(entityMap.wishlist_items);\r\n const userRepo = () => dataSource.getRepository(entityMap.users);\r\n const tokenRepo = () => dataSource.getRepository(entityMap.password_reset_tokens);\r\n const collectionRepo = () => dataSource.getRepository(entityMap.collections);\r\n const groupRepo = () => dataSource.getRepository(entityMap.user_groups);\r\n const configRepo = () => dataSource.getRepository(entityMap.configs);\r\n const customerRepo = () => dataSource.getRepository(entityMap.customer);\r\n const customerContactsRepo = () => dataSource.getRepository(entityMap.customer_contacts);\r\n\r\n const CART_CHECKOUT_RELATIONS = ['items', 'items.product', 'items.product.taxes', 'items.product.taxes.tax'] as const;\r\n\r\n /** Single-vendor cart required until multi-vendor checkout split is implemented. */\r\n function resolveSingleVendorIdFromCart(\r\n cart: ObjectLiteral\r\n ): { vendorId: number } | { error: string; status: number } {\r\n const vendorIds = new Set<number>();\r\n for (const it of (cart.items as ObjectLiteral[]) || []) {\r\n const p = it.product as ObjectLiteral | undefined;\r\n if (!p || p.deleted || p.status !== 'available') continue;\r\n const vid = Number(p.vendorId);\r\n if (Number.isInteger(vid) && vid > 0) vendorIds.add(vid);\r\n }\r\n if (vendorIds.size === 0) return { error: 'Cart has no valid products', status: 400 };\r\n if (vendorIds.size > 1) {\r\n return {\r\n error: 'Cart contains products from multiple vendors. Please checkout one vendor at a time.',\r\n status: 400,\r\n };\r\n }\r\n return { vendorId: [...vendorIds][0]! };\r\n }\r\n\r\n function roundMoney(n: number): number {\r\n return Math.round(n * 100) / 100;\r\n }\r\n\r\n type CheckoutDraftLine = {\r\n productId: number;\r\n quantity: number;\r\n unitPrice: number;\r\n tax: number;\r\n total: number;\r\n hsn: string | null;\r\n uom: string | null;\r\n productType: string | null;\r\n taxRate: number | null;\r\n taxCode: string | null;\r\n };\r\n\r\n async function getStoreDefaultTaxRate(): Promise<number | null> {\r\n const rows = await configRepo().find({ where: { settings: 'store', deleted: false } as ObjectLiteral });\r\n for (const row of rows) {\r\n const r = row as { key: string; value: string };\r\n if (r.key === 'defaultTaxRate') {\r\n const n = parseFloat(String(r.value ?? '').trim());\r\n return Number.isFinite(n) && n >= 0 ? n : null;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n function computeTaxForProductLine(\r\n p: ObjectLiteral,\r\n lineSubtotal: number,\r\n defaultRate: number | null\r\n ): { tax: number; taxRate: number | null; taxCode: string | null } {\r\n const pts = (p.taxes as ObjectLiteral[] | undefined) ?? [];\r\n const activePts = pts.filter((pt) => {\r\n const t = pt.tax as ObjectLiteral | undefined;\r\n return t != null && t.active !== false;\r\n });\r\n if (activePts.length) {\r\n let sumRate = 0;\r\n const slugs: string[] = [];\r\n for (const pt of activePts) {\r\n const t = pt.tax as ObjectLiteral;\r\n const r = Number(pt.rate != null && pt.rate !== '' ? pt.rate : (t.rate ?? 0));\r\n if (Number.isFinite(r)) sumRate += r;\r\n const slug = String(t.slug ?? '').trim();\r\n if (slug) slugs.push(slug);\r\n }\r\n const tax = roundMoney((lineSubtotal * sumRate) / 100);\r\n return {\r\n tax,\r\n taxRate: sumRate > 0 ? roundMoney(sumRate) : null,\r\n taxCode: slugs.length ? [...new Set(slugs)].sort().join(',') : null,\r\n };\r\n }\r\n if (defaultRate != null && defaultRate > 0) {\r\n return {\r\n tax: roundMoney((lineSubtotal * defaultRate) / 100),\r\n taxRate: roundMoney(defaultRate),\r\n taxCode: null,\r\n };\r\n }\r\n return { tax: 0, taxRate: null, taxCode: null };\r\n }\r\n\r\n function parseInlineAddress(raw: unknown): Record<string, string> | null {\r\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) return null;\r\n const o = raw as Record<string, unknown>;\r\n const line1 = String(o.line1 ?? '').trim();\r\n if (!line1) return null;\r\n return {\r\n line1,\r\n line2: o.line2 != null ? String(o.line2) : '',\r\n city: o.city != null ? String(o.city) : '',\r\n state: o.state != null ? String(o.state) : '',\r\n postalCode: o.postalCode != null ? String(o.postalCode) : '',\r\n country: o.country != null ? String(o.country) : '',\r\n };\r\n }\r\n\r\n function intFromBody(v: unknown): number | undefined {\r\n if (typeof v === 'number' && Number.isInteger(v)) return v;\r\n if (typeof v === 'string' && /^\\d+$/.test(v)) return parseInt(v, 10);\r\n return undefined;\r\n }\r\n\r\n async function resolveCheckoutAddress(\r\n contactId: number,\r\n idVal: unknown,\r\n inlineVal: unknown\r\n ): Promise<{ id: number | null; error?: string }> {\r\n const aid = intFromBody(idVal);\r\n if (aid != null) {\r\n const existing = await addressRepo().findOne({\r\n where: { id: aid, contactId } as ObjectLiteral,\r\n });\r\n if (!existing) return { id: null, error: 'Address not found' };\r\n return { id: aid };\r\n }\r\n const addr = parseInlineAddress(inlineVal);\r\n if (addr) {\r\n const saved = await addressRepo().save(\r\n addressRepo().create({\r\n contactId,\r\n line1: addr.line1,\r\n line2: addr.line2?.trim() ? addr.line2 : null,\r\n city: addr.city?.trim() ? addr.city : null,\r\n state: addr.state?.trim() ? addr.state : null,\r\n postalCode: addr.postalCode?.trim() ? addr.postalCode : null,\r\n country: addr.country?.trim() ? addr.country : null,\r\n } as ObjectLiteral)\r\n );\r\n return { id: (saved as { id: number }).id };\r\n }\r\n return { id: null };\r\n }\r\n\r\n async function prepareCheckoutFromCart(\r\n b: Record<string, unknown>,\r\n cart: ObjectLiteral,\r\n contactId: number\r\n ): Promise<\r\n | {\r\n ok: true;\r\n lines: CheckoutDraftLine[];\r\n subtotal: number;\r\n orderTax: number;\r\n orderTotal: number;\r\n billingAddressId: number;\r\n shippingAddressId: number | null;\r\n }\r\n | { ok: false; status: number; message: string }\r\n > {\r\n const defaultRate = await getStoreDefaultTaxRate();\r\n const lines: CheckoutDraftLine[] = [];\r\n let subtotal = 0;\r\n let orderTax = 0;\r\n let needsShipping = false;\r\n\r\n for (const it of (cart.items as ObjectLiteral[]) || []) {\r\n const p = it.product as ObjectLiteral | undefined;\r\n if (!p || p.deleted || p.status !== 'available') continue;\r\n const unit = Number(p.price);\r\n const qty = (it.quantity as number) || 1;\r\n const lineSubtotal = unit * qty;\r\n const pType = p.type === 'service' ? 'service' : 'product';\r\n if (pType === 'product') needsShipping = true;\r\n\r\n const { tax, taxRate, taxCode } = computeTaxForProductLine(p, lineSubtotal, defaultRate);\r\n const lineTotal = roundMoney(lineSubtotal + tax);\r\n subtotal = roundMoney(subtotal + lineSubtotal);\r\n orderTax = roundMoney(orderTax + tax);\r\n\r\n lines.push({\r\n productId: p.id as number,\r\n quantity: qty,\r\n unitPrice: unit,\r\n tax,\r\n total: lineTotal,\r\n hsn: (p.hsn as string | null) ?? null,\r\n uom: (p.uom as string | null) ?? null,\r\n productType: pType,\r\n taxRate,\r\n taxCode,\r\n });\r\n }\r\n\r\n if (!lines.length) return { ok: false, status: 400, message: 'No available items in cart' };\r\n\r\n const bill = await resolveCheckoutAddress(contactId, b.billingAddressId, b.billingAddress);\r\n if (bill.error) return { ok: false, status: 400, message: bill.error };\r\n if (bill.id == null) return { ok: false, status: 400, message: 'Billing address required' };\r\n\r\n const ship = await resolveCheckoutAddress(contactId, b.shippingAddressId, b.shippingAddress);\r\n if (ship.error) return { ok: false, status: 400, message: ship.error };\r\n\r\n let shippingAddressId: number | null = ship.id;\r\n if (needsShipping && shippingAddressId == null) shippingAddressId = bill.id;\r\n if (needsShipping && shippingAddressId == null) {\r\n return { ok: false, status: 400, message: 'Shipping address required' };\r\n }\r\n\r\n const orderTotal = roundMoney(subtotal + orderTax);\r\n\r\n return {\r\n ok: true,\r\n lines,\r\n subtotal,\r\n orderTax,\r\n orderTotal,\r\n billingAddressId: bill.id,\r\n shippingAddressId,\r\n };\r\n }\r\n\r\n async function syncContactToErp(contact: ObjectLiteral): Promise<void> {\r\n if (!getCms) return;\r\n try {\r\n const cms = await getCms();\r\n await queueErpCreateContactIfEnabled(cms, dataSource, entityMap, {\r\n name: String((contact as { name: string }).name ?? ''),\r\n email: String((contact as { email: string }).email ?? '').trim(),\r\n phone: (contact as { phone: string | null }).phone,\r\n type: (contact as { type: string | null }).type,\r\n company: (contact as { company: string | null }).company,\r\n notes: (contact as { notes: string | null }).notes,\r\n });\r\n } catch {\r\n /* ignore */\r\n }\r\n }\r\n\r\n async function ensureContactForUser(userId: number): Promise<{ id: number } | null> {\r\n let c = await contactRepo().findOne({ where: { userId, deleted: false } as ObjectLiteral });\r\n if (c) return c as { id: number };\r\n const u = await userRepo().findOne({ where: { id: userId } });\r\n if (!u) return null;\r\n const unclaimed = await contactRepo().findOne({\r\n where: { email: u.email, userId: IsNull(), deleted: false } as ObjectLiteral,\r\n });\r\n if (unclaimed) {\r\n await contactRepo().update((unclaimed as { id: number }).id, { userId });\r\n return { id: (unclaimed as { id: number }).id };\r\n }\r\n const created = await contactRepo().save(\r\n contactRepo().create({\r\n name: u.name,\r\n email: u.email,\r\n phone: null,\r\n userId,\r\n deleted: false,\r\n } as ObjectLiteral)\r\n );\r\n await syncContactToErp(created as ObjectLiteral);\r\n return { id: (created as { id: number }).id };\r\n }\r\n\r\n function parseCheckoutContactDetails(\r\n b: Record<string, unknown>\r\n ): { name: string; email: string; phone: string | null } | null {\r\n const src =\r\n b.contact && typeof b.contact === 'object' && !Array.isArray(b.contact)\r\n ? (b.contact as Record<string, unknown>)\r\n : b;\r\n const name = String(src.name ?? '').trim();\r\n const email = String(src.email ?? '').trim().toLowerCase();\r\n const phone = src.phone != null && src.phone !== '' ? String(src.phone).trim() : null;\r\n if (!name || !email) return null;\r\n return { name, email, phone };\r\n }\r\n\r\n async function ensureCustomerContactLink(customerId: number, contactId: number): Promise<void> {\r\n if (!entityMap.customer_contacts) return;\r\n const existing = await customerContactsRepo().findOne({\r\n where: { customerId, contactId } as ObjectLiteral,\r\n });\r\n if (!existing) {\r\n await customerContactsRepo().save(\r\n customerContactsRepo().create({ customerId, contactId } as ObjectLiteral)\r\n );\r\n }\r\n }\r\n\r\n async function resolveCustomerCheckoutContact(\r\n b: Record<string, unknown>,\r\n sessionUserId: number\r\n ): Promise<\r\n | { ok: true; contactId: number; customerId: number }\r\n | { ok: false; status: number; message: string }\r\n > {\r\n if (!entityMap.customer) {\r\n return { ok: false, status: 503, message: 'Customer not configured' };\r\n }\r\n const payloadUserId = intFromBody(b.userId) ?? sessionUserId;\r\n if (payloadUserId !== sessionUserId) {\r\n return { ok: false, status: 401, message: 'Unauthorized' };\r\n }\r\n const details = parseCheckoutContactDetails(b);\r\n if (!details) {\r\n return { ok: false, status: 400, message: 'contact name and email required' };\r\n }\r\n const customer = await customerRepo().findOne({\r\n where: { userId: payloadUserId, deleted: false } as ObjectLiteral,\r\n });\r\n if (!customer) {\r\n return { ok: false, status: 404, message: 'Customer not found' };\r\n }\r\n const customerId = (customer as { id: number }).id;\r\n\r\n let contact = await contactRepo().findOne({\r\n where: { email: details.email, deleted: false } as ObjectLiteral,\r\n });\r\n if (!contact) {\r\n contact = await contactRepo().save(\r\n contactRepo().create({\r\n name: details.name,\r\n email: details.email,\r\n phone: details.phone,\r\n type: 'customer',\r\n userId: null,\r\n deleted: false,\r\n } as ObjectLiteral)\r\n );\r\n await syncContactToErp(contact as ObjectLiteral);\r\n } else {\r\n await contactRepo().update((contact as { id: number }).id, {\r\n name: details.name,\r\n phone: details.phone ?? (contact as { phone: string | null }).phone,\r\n } as ObjectLiteral);\r\n }\r\n const contactId = (contact as { id: number }).id;\r\n await ensureCustomerContactLink(customerId, contactId);\r\n return { ok: true, contactId, customerId };\r\n }\r\n\r\n async function loadBuyerCart(sessionUserId: number): Promise<ObjectLiteral | null> {\r\n const buyerContact = await ensureContactForUser(sessionUserId);\r\n if (!buyerContact) return null;\r\n return cartRepo().findOne({\r\n where: { contactId: buyerContact.id } as ObjectLiteral,\r\n relations: [...CART_CHECKOUT_RELATIONS],\r\n });\r\n }\r\n\r\n async function resolveCheckoutContactAndCart(\r\n b: Record<string, unknown>,\r\n req: Request,\r\n sessionUid: number\r\n ): Promise<\r\n | { ok: true; contactId: number; cart: ObjectLiteral | null }\r\n | { ok: false; response: Response }\r\n > {\r\n if (Number.isFinite(sessionUid)) {\r\n const useCustomerFlow =\r\n Boolean(entityMap.customer && entityMap.customer_contacts) && parseCheckoutContactDetails(b) != null;\r\n\r\n if (useCustomerFlow) {\r\n const resolved = await resolveCustomerCheckoutContact(b, sessionUid);\r\n if (!resolved.ok) {\r\n return { ok: false, response: json({ error: resolved.message }, { status: resolved.status }) };\r\n }\r\n const cart = await loadBuyerCart(sessionUid);\r\n return { ok: true, contactId: resolved.contactId, cart };\r\n }\r\n\r\n const contact = await ensureContactForUser(sessionUid);\r\n if (!contact) {\r\n return { ok: false, response: json({ error: 'Contact required' }, { status: 400 }) };\r\n }\r\n const cart = await cartRepo().findOne({\r\n where: { contactId: contact.id } as ObjectLiteral,\r\n relations: [...CART_CHECKOUT_RELATIONS],\r\n });\r\n return { ok: true, contactId: contact.id, cart };\r\n }\r\n\r\n const details = parseCheckoutContactDetails(b);\r\n const email = details?.email ?? String(b.email ?? '').trim().toLowerCase();\r\n const name = details?.name ?? String(b.name ?? '').trim();\r\n const phone =\r\n details?.phone ?? (b.phone != null && b.phone !== '' ? String(b.phone).trim() : null);\r\n if (!email || !name) {\r\n return {\r\n ok: false,\r\n response: json({ error: 'name and email required for guest checkout' }, { status: 400 }),\r\n };\r\n }\r\n let contact = await contactRepo().findOne({ where: { email, deleted: false } as ObjectLiteral });\r\n if (contact && (contact as { userId: number | null }).userId != null) {\r\n return { ok: false, response: json({ error: 'Please sign in to complete checkout' }, { status: 400 }) };\r\n }\r\n if (!contact) {\r\n contact = await contactRepo().save(\r\n contactRepo().create({\r\n name,\r\n email,\r\n phone,\r\n userId: null,\r\n deleted: false,\r\n } as ObjectLiteral)\r\n );\r\n } else {\r\n await contactRepo().update((contact as { id: number }).id, {\r\n name,\r\n phone: phone ?? (contact as { phone: string | null }).phone,\r\n } as ObjectLiteral);\r\n }\r\n const contactId = (contact as { id: number }).id;\r\n const guestForErp = await contactRepo().findOne({ where: { id: contactId } as ObjectLiteral });\r\n if (guestForErp) await syncContactToErp(guestForErp);\r\n const cookies = parseCookies(req.headers.get('cookie'));\r\n const guestToken = cookies[cookieName];\r\n if (!guestToken) {\r\n return { ok: false, response: json({ error: 'Cart not found' }, { status: 400 }) };\r\n }\r\n const cart = await cartRepo().findOne({\r\n where: { guestToken } as ObjectLiteral,\r\n relations: [...CART_CHECKOUT_RELATIONS],\r\n });\r\n return { ok: true, contactId, cart };\r\n }\r\n\r\n async function getOrCreateCart(req: Request): Promise<{ cart: ObjectLiteral; setCookie: string | null; err: Response | null }> {\r\n const u = await getSessionUser();\r\n const uid = u?.id ? parseInt(String(u.id), 10) : NaN;\r\n if (Number.isFinite(uid)) {\r\n const contact = await ensureContactForUser(uid);\r\n if (!contact) return { cart: {} as ObjectLiteral, setCookie: null, err: json({ error: 'User not found' }, { status: 400 }) };\r\n let cart = await cartRepo().findOne({\r\n where: { contactId: contact.id } as ObjectLiteral,\r\n relations: ['items', 'items.product'],\r\n });\r\n if (!cart) {\r\n cart = await cartRepo().save(\r\n cartRepo().create({ contactId: contact.id, guestToken: null, currency: 'INR' } as ObjectLiteral)\r\n );\r\n cart = await cartRepo().findOne({\r\n where: { id: (cart as { id: number }).id },\r\n relations: ['items', 'items.product'],\r\n });\r\n }\r\n return { cart: cart!, setCookie: null, err: null };\r\n }\r\n const cookies = parseCookies(req.headers.get('cookie'));\r\n let token = cookies[cookieName] || '';\r\n if (!token) {\r\n token = crypto.randomUUID();\r\n let cart = await cartRepo().findOne({\r\n where: { guestToken: token } as ObjectLiteral,\r\n relations: ['items', 'items.product'],\r\n });\r\n if (!cart) {\r\n cart = await cartRepo().save(\r\n cartRepo().create({ guestToken: token, contactId: null, currency: 'INR' } as ObjectLiteral)\r\n );\r\n cart = await cartRepo().findOne({\r\n where: { id: (cart as { id: number }).id },\r\n relations: ['items', 'items.product'],\r\n });\r\n }\r\n return { cart: cart!, setCookie: guestCookieHeader(cookieName, token), err: null };\r\n }\r\n let cart = await cartRepo().findOne({\r\n where: { guestToken: token } as ObjectLiteral,\r\n relations: ['items', 'items.product'],\r\n });\r\n if (!cart) {\r\n cart = await cartRepo().save(\r\n cartRepo().create({ guestToken: token, contactId: null, currency: 'INR' } as ObjectLiteral)\r\n );\r\n cart = await cartRepo().findOne({\r\n where: { id: (cart as { id: number }).id },\r\n relations: ['items', 'items.product'],\r\n });\r\n }\r\n return { cart: cart!, setCookie: null, err: null };\r\n }\r\n\r\n function primaryProductImageUrl(metadata: unknown): string | null {\r\n const meta = metadata as { images?: Array<{ url?: string; isDefault?: boolean }> } | null;\r\n const images = meta?.images;\r\n if (!Array.isArray(images) || !images.length) return null;\r\n const sorted = images.filter((i) => i?.url) as Array<{ url: string; isDefault?: boolean }>;\r\n if (!sorted.length) return null;\r\n const di = sorted.findIndex((i) => i.isDefault);\r\n if (di > 0) {\r\n const [d] = sorted.splice(di, 1);\r\n sorted.unshift(d!);\r\n }\r\n return sorted[0]!.url;\r\n }\r\n\r\n function serializeCart(cart: ObjectLiteral) {\r\n const items = (cart.items as ObjectLiteral[]) || [];\r\n return {\r\n id: cart.id,\r\n currency: cart.currency,\r\n items: items.map((it) => {\r\n const p = it.product as ObjectLiteral | undefined;\r\n return {\r\n id: it.id,\r\n productId: it.productId,\r\n quantity: it.quantity,\r\n metadata: it.metadata,\r\n product: p\r\n ? {\r\n id: p.id,\r\n name: p.name,\r\n slug: p.slug,\r\n price: p.price,\r\n sku: p.sku,\r\n type: p.type === 'service' ? 'service' : 'product',\r\n image: primaryProductImageUrl(p.metadata),\r\n }\r\n : null,\r\n };\r\n }),\r\n };\r\n }\r\n\r\n function serializeSeo(seo: unknown): ObjectLiteral | undefined {\r\n if (!seo || typeof seo !== 'object') return undefined;\r\n const s = seo as ObjectLiteral;\r\n return {\r\n title: s.title ?? null,\r\n description: s.description ?? null,\r\n keywords: s.keywords ?? null,\r\n ogTitle: s.ogTitle ?? null,\r\n ogDescription: s.ogDescription ?? null,\r\n ogImage: s.ogImage ?? null,\r\n slug: s.slug ?? null,\r\n };\r\n }\r\n\r\n function serializeProduct(p: ObjectLiteral) {\r\n const seo = serializeSeo(p.seo);\r\n return {\r\n id: p.id,\r\n name: p.name,\r\n slug: p.slug,\r\n sku: p.sku,\r\n hsn: p.hsn,\r\n uom: p.uom ?? null,\r\n type: p.type === 'service' ? 'service' : 'product',\r\n price: p.price,\r\n compareAtPrice: p.compareAtPrice,\r\n status: p.status,\r\n collectionId: p.collectionId,\r\n metadata: p.metadata,\r\n ...(seo ? { seo } : {}),\r\n };\r\n }\r\n\r\n return {\r\n async handle(method: string, path: string[], req: Request): Promise<Response> {\r\n try {\r\n // --- products GET list ---\r\n if (path[0] === 'products' && path.length === 1 && method === 'GET') {\r\n const url = new URL(req.url || '', 'http://localhost');\r\n const collectionSlug = url.searchParams.get('collection')?.trim();\r\n const collectionId = url.searchParams.get('collectionId');\r\n const limit = Math.min(100, Math.max(1, parseInt(url.searchParams.get('limit') || '20', 10)));\r\n const offset = Math.max(0, parseInt(url.searchParams.get('offset') || '0', 10));\r\n const where: ObjectLiteral = { status: 'available', deleted: false };\r\n let collectionFilter: { name: string | null; slug: string | null } | null = null;\r\n if (collectionSlug) {\r\n let col: ObjectLiteral | null = null;\r\n if (/^\\d+$/.test(collectionSlug)) {\r\n col = (await collectionRepo().findOne({\r\n where: {\r\n id: parseInt(collectionSlug, 10),\r\n active: true,\r\n deleted: false,\r\n } as ObjectLiteral,\r\n })) as ObjectLiteral | null;\r\n } else {\r\n col = (await collectionRepo()\r\n .createQueryBuilder('c')\r\n .where('LOWER(c.slug) = LOWER(:slug)', { slug: collectionSlug })\r\n .andWhere('c.active = :a', { a: true })\r\n .andWhere('c.deleted = :d', { d: false })\r\n .getOne()) as ObjectLiteral | null;\r\n }\r\n if (!col) {\r\n return json({ products: [], total: 0, collection: null });\r\n }\r\n where.collectionId = col.id;\r\n collectionFilter = { name: col.name as string | null, slug: col.slug as string | null };\r\n } else if (collectionId) {\r\n const cid = parseInt(collectionId, 10);\r\n if (Number.isFinite(cid)) where.collectionId = cid;\r\n }\r\n const [items, total] = await productRepo().findAndCount({\r\n where,\r\n order: { id: 'ASC' },\r\n take: limit,\r\n skip: offset,\r\n });\r\n return json({\r\n products: items.map(serializeProduct),\r\n total,\r\n ...(collectionFilter && { collection: collectionFilter }),\r\n });\r\n }\r\n\r\n // --- products GET by id or slug ---\r\n if (path[0] === 'products' && path.length === 2 && method === 'GET') {\r\n const idOrSlug = path[1]!;\r\n const byId = /^\\d+$/.test(idOrSlug);\r\n const product = await productRepo().findOne({\r\n where: byId\r\n ? { id: parseInt(idOrSlug, 10), status: 'available', deleted: false }\r\n : { slug: idOrSlug, status: 'available', deleted: false },\r\n relations: ['attributes', 'attributes.attribute', 'seo'],\r\n } as ObjectLiteral);\r\n if (!product) return json({ error: 'Not found' }, { status: 404 });\r\n const p = product as ObjectLiteral;\r\n const attrRows = (p.attributes as ObjectLiteral[] | undefined) ?? [];\r\n const attributeTags = attrRows.map((pa) => ({\r\n name: ((pa.attribute as ObjectLiteral)?.name as string) ?? '',\r\n value: String(pa.value ?? ''),\r\n })).filter((t) => t.name || t.value);\r\n return json({ ...serializeProduct(p), attributes: attributeTags });\r\n }\r\n\r\n // --- collections GET list ---\r\n if (path[0] === 'collections' && path.length === 1 && method === 'GET') {\r\n const items = await collectionRepo().find({\r\n where: { active: true, deleted: false } as ObjectLiteral,\r\n order: { sortOrder: 'ASC', id: 'ASC' },\r\n });\r\n const ids = items.map((c) => (c as ObjectLiteral).id as number);\r\n const countByCollection: Record<number, number> = {};\r\n if (ids.length > 0) {\r\n const rows = await productRepo()\r\n .createQueryBuilder('p')\r\n .select('p.collectionId', 'collectionId')\r\n .addSelect('COUNT(p.id)', 'cnt')\r\n .where('p.collectionId IN (:...ids)', { ids })\r\n .andWhere('p.status = :status', { status: 'available' })\r\n .andWhere('p.deleted = :del', { del: false })\r\n .groupBy('p.collectionId')\r\n .getRawMany();\r\n for (const r of rows) {\r\n const cid = (r as ObjectLiteral).collectionId;\r\n if (cid != null) countByCollection[Number(cid)] = parseInt(String((r as ObjectLiteral).cnt), 10);\r\n }\r\n }\r\n return json({\r\n collections: items.map((c) => {\r\n const col = c as ObjectLiteral;\r\n const id = col.id as number;\r\n return {\r\n id,\r\n name: col.name,\r\n slug: col.slug,\r\n description: col.description,\r\n image: col.image,\r\n productCount: countByCollection[id] ?? 0,\r\n };\r\n }),\r\n });\r\n }\r\n\r\n // --- collections GET by id or slug ---\r\n if (path[0] === 'collections' && path.length === 2 && method === 'GET') {\r\n const idOrSlug = path[1]!;\r\n const byId = /^\\d+$/.test(idOrSlug);\r\n const collection = await collectionRepo().findOne({\r\n where: byId\r\n ? { id: parseInt(idOrSlug, 10), active: true, deleted: false }\r\n : { slug: idOrSlug, active: true, deleted: false },\r\n relations: ['seo'],\r\n } as ObjectLiteral);\r\n if (!collection) return json({ error: 'Not found' }, { status: 404 });\r\n const col = collection as ObjectLiteral;\r\n const products = await productRepo().find({\r\n where: { collectionId: col.id, status: 'available', deleted: false } as ObjectLiteral,\r\n order: { id: 'ASC' },\r\n });\r\n const colSeo = serializeSeo(col.seo);\r\n return json({\r\n id: col.id,\r\n name: col.name,\r\n slug: col.slug,\r\n description: col.description,\r\n image: col.image,\r\n ...(colSeo ? { seo: colSeo } : {}),\r\n products: products.map((p) => serializeProduct(p as ObjectLiteral)),\r\n });\r\n }\r\n\r\n // --- profile GET (auth) ---\r\n if (path[0] === 'profile' && path.length === 1 && method === 'GET') {\r\n const u = await getSessionUser();\r\n const uid = u?.id ? parseInt(String(u.id), 10) : NaN;\r\n if (!Number.isFinite(uid)) return json({ error: 'Unauthorized' }, { status: 401 });\r\n const user = await userRepo().findOne({ where: { id: uid }, select: ['id', 'name', 'email'] });\r\n if (!user) return json({ error: 'Not found' }, { status: 404 });\r\n const contact = await contactRepo().findOne({ where: { userId: uid, deleted: false } as ObjectLiteral });\r\n return json({\r\n user: { id: (user as ObjectLiteral).id, name: (user as ObjectLiteral).name, email: (user as ObjectLiteral).email },\r\n contact: contact\r\n ? {\r\n id: (contact as ObjectLiteral).id,\r\n name: (contact as ObjectLiteral).name,\r\n email: (contact as ObjectLiteral).email,\r\n phone: (contact as ObjectLiteral).phone,\r\n }\r\n : null,\r\n });\r\n }\r\n\r\n // --- profile PUT (auth) ---\r\n if (path[0] === 'profile' && path.length === 1 && method === 'PUT') {\r\n const u = await getSessionUser();\r\n const uid = u?.id ? parseInt(String(u.id), 10) : NaN;\r\n if (!Number.isFinite(uid)) return json({ error: 'Unauthorized' }, { status: 401 });\r\n const b = (await req.json().catch(() => ({}))) as { name?: string; phone?: string };\r\n const contact = await contactRepo().findOne({ where: { userId: uid, deleted: false } as ObjectLiteral });\r\n if (contact) {\r\n const updates: ObjectLiteral = {};\r\n if (typeof b.name === 'string' && b.name.trim()) updates.name = b.name.trim();\r\n if (b.phone !== undefined) updates.phone = b.phone === null || b.phone === '' ? null : String(b.phone);\r\n if (Object.keys(updates).length) await contactRepo().update((contact as { id: number }).id, updates);\r\n }\r\n const user = await userRepo().findOne({ where: { id: uid }, select: ['id', 'name', 'email'] });\r\n if (user && typeof b.name === 'string' && b.name.trim()) {\r\n await userRepo().update(uid, { name: b.name.trim() });\r\n }\r\n const updatedContact = await contactRepo().findOne({ where: { userId: uid, deleted: false } as ObjectLiteral });\r\n if (updatedContact) await syncContactToErp(updatedContact as ObjectLiteral);\r\n const updatedUser = await userRepo().findOne({ where: { id: uid }, select: ['id', 'name', 'email'] });\r\n return json({\r\n user: updatedUser ? { id: (updatedUser as ObjectLiteral).id, name: (updatedUser as ObjectLiteral).name, email: (updatedUser as ObjectLiteral).email } : null,\r\n contact: updatedContact\r\n ? {\r\n id: (updatedContact as ObjectLiteral).id,\r\n name: (updatedContact as ObjectLiteral).name,\r\n email: (updatedContact as ObjectLiteral).email,\r\n phone: (updatedContact as ObjectLiteral).phone,\r\n }\r\n : null,\r\n });\r\n }\r\n\r\n // --- addresses (auth: contact's addresses) ---\r\n async function getContactForAddresses(): Promise<{ contactId: number } | Response> {\r\n const u = await getSessionUser();\r\n const uid = u?.id ? parseInt(String(u.id), 10) : NaN;\r\n if (!Number.isFinite(uid)) return json({ error: 'Unauthorized' }, { status: 401 });\r\n const contact = await contactRepo().findOne({ where: { userId: uid, deleted: false } as ObjectLiteral });\r\n if (!contact) return json({ error: 'Contact not found' }, { status: 404 });\r\n return { contactId: (contact as { id: number }).id };\r\n }\r\n function serializeAddress(a: ObjectLiteral) {\r\n return {\r\n id: a.id,\r\n contactId: a.contactId,\r\n tag: a.tag,\r\n line1: a.line1,\r\n line2: a.line2,\r\n city: a.city,\r\n state: a.state,\r\n postalCode: a.postalCode,\r\n country: a.country,\r\n };\r\n }\r\n if (path[0] === 'addresses' && path.length === 1 && method === 'GET') {\r\n const contactOrErr = await getContactForAddresses();\r\n if (contactOrErr instanceof Response) return contactOrErr;\r\n const list = await addressRepo().find({\r\n where: { contactId: contactOrErr.contactId },\r\n order: { id: 'ASC' },\r\n });\r\n return json({ addresses: list.map((a) => serializeAddress(a as ObjectLiteral)) });\r\n }\r\n if (path[0] === 'addresses' && path.length === 1 && method === 'POST') {\r\n const contactOrErr = await getContactForAddresses();\r\n if (contactOrErr instanceof Response) return contactOrErr;\r\n const b = (await req.json().catch(() => ({}))) as Record<string, unknown>;\r\n const row: Record<string, unknown> = {\r\n contactId: contactOrErr.contactId,\r\n tag: typeof b.tag === 'string' ? b.tag.trim() || null : null,\r\n line1: typeof b.line1 === 'string' ? b.line1 : '',\r\n line2: typeof b.line2 === 'string' ? b.line2.trim() || null : null,\r\n city: typeof b.city === 'string' ? b.city : '',\r\n state: typeof b.state === 'string' ? b.state : '',\r\n postalCode: typeof b.postalCode === 'string' ? b.postalCode : '',\r\n country: typeof b.country === 'string' ? b.country : '',\r\n };\r\n const addrErr = validateAndNormalizeAddressRow(row);\r\n if (addrErr) return json({ error: addrErr }, { status: 400 });\r\n const created = await addressRepo().save(addressRepo().create(row as ObjectLiteral));\r\n return json(serializeAddress(created as ObjectLiteral));\r\n }\r\n if (path[0] === 'addresses' && path.length === 2 && (method === 'PATCH' || method === 'PUT')) {\r\n const contactOrErr = await getContactForAddresses();\r\n if (contactOrErr instanceof Response) return contactOrErr;\r\n const id = parseInt(path[1]!, 10);\r\n if (!Number.isFinite(id)) return json({ error: 'Invalid id' }, { status: 400 });\r\n const existing = await addressRepo().findOne({ where: { id, contactId: contactOrErr.contactId } as ObjectLiteral });\r\n if (!existing) return json({ error: 'Not found' }, { status: 404 });\r\n const b = (await req.json().catch(() => ({}))) as Record<string, unknown>;\r\n const updates: ObjectLiteral = {};\r\n if (b.tag !== undefined) updates.tag = typeof b.tag === 'string' ? b.tag.trim() || null : null;\r\n if (b.line1 !== undefined) updates.line1 = typeof b.line1 === 'string' ? b.line1.trim() || null : null;\r\n if (b.line2 !== undefined) updates.line2 = typeof b.line2 === 'string' ? b.line2.trim() || null : null;\r\n if (b.city !== undefined) updates.city = typeof b.city === 'string' ? b.city.trim() || null : null;\r\n if (b.state !== undefined) updates.state = typeof b.state === 'string' ? b.state.trim() || null : null;\r\n if (b.postalCode !== undefined) updates.postalCode = typeof b.postalCode === 'string' ? b.postalCode.trim() || null : null;\r\n if (b.country !== undefined) updates.country = typeof b.country === 'string' ? b.country.trim() || null : null;\r\n if (Object.keys(updates).length) {\r\n const merged: Record<string, unknown> = { ...(existing as Record<string, unknown>), ...updates };\r\n if (merged.tag === '') merged.tag = null;\r\n const addrErr = validateAndNormalizeAddressRow(merged);\r\n if (addrErr) return json({ error: addrErr }, { status: 400 });\r\n for (const k of Object.keys(updates)) {\r\n if (k in merged) (updates as Record<string, unknown>)[k] = merged[k];\r\n }\r\n await addressRepo().update(id, updates);\r\n }\r\n const updated = await addressRepo().findOne({ where: { id } as ObjectLiteral });\r\n return json(serializeAddress(updated as ObjectLiteral));\r\n }\r\n if (path[0] === 'addresses' && path.length === 2 && method === 'DELETE') {\r\n const contactOrErr = await getContactForAddresses();\r\n if (contactOrErr instanceof Response) return contactOrErr;\r\n const id = parseInt(path[1]!, 10);\r\n if (!Number.isFinite(id)) return json({ error: 'Invalid id' }, { status: 400 });\r\n const existing = await addressRepo().findOne({ where: { id, contactId: contactOrErr.contactId } as ObjectLiteral });\r\n if (!existing) return json({ error: 'Not found' }, { status: 404 });\r\n await addressRepo().delete(id);\r\n return json({ deleted: true });\r\n }\r\n\r\n // --- verify-email POST (public) ---\r\n if (path[0] === 'verify-email' && path.length === 1 && method === 'POST') {\r\n const b = (await req.json().catch(() => ({}))) as { token?: string };\r\n const token = typeof b.token === 'string' ? b.token.trim() : '';\r\n if (!token) return json({ error: 'token is required' }, { status: 400 });\r\n const record = await tokenRepo().findOne({ where: { token } as ObjectLiteral });\r\n if (!record || (record as { expiresAt: Date }).expiresAt < new Date()) {\r\n return json({ error: 'Invalid or expired link. Please sign up again or contact support.' }, { status: 400 });\r\n }\r\n const email = (record as { email: string }).email;\r\n const user = await userRepo().findOne({ where: { email }, select: ['id', 'blocked'] });\r\n if (!user) return json({ error: 'User not found' }, { status: 400 });\r\n await userRepo().update((user as { id: number }).id, {\r\n blocked: false,\r\n emailVerifiedAt: new Date(),\r\n updatedAt: new Date(),\r\n } as ObjectLiteral);\r\n await tokenRepo().delete({ email } as ObjectLiteral);\r\n return json({ success: true, message: 'Email verified. You can sign in.' });\r\n }\r\n\r\n // --- auth/otp/send POST ---\r\n if (path[0] === 'auth' && path[1] === 'otp' && path[2] === 'send' && path.length === 3 && method === 'POST') {\r\n const b = (await req.json().catch(() => ({}))) as Record<string, unknown>;\r\n const purposeRaw = typeof b.purpose === 'string' ? b.purpose.trim() : '';\r\n const purpose = (purposeRaw === 'login' || purposeRaw === 'verify_email' || purposeRaw === 'verify_phone'\r\n ? purposeRaw\r\n : '') as OtpPurpose | '';\r\n if (!purpose) return json({ error: 'purpose must be login, verify_email, or verify_phone' }, { status: 400 });\r\n if (purpose === 'login' && otpOff('login')) return json({ error: 'otp_disabled' }, { status: 403 });\r\n if (purpose === 'verify_email' && otpOff('verifyEmail')) return json({ error: 'otp_disabled' }, { status: 403 });\r\n if (purpose === 'verify_phone' && otpOff('verifyPhone')) return json({ error: 'otp_disabled' }, { status: 403 });\r\n\r\n const capOtp = await assertCaptchaOk(getCms, b, req, json);\r\n if (capOtp) return capOtp;\r\n\r\n const emailIn = typeof b.email === 'string' ? b.email.trim().toLowerCase() : '';\r\n const phoneIn = typeof b.phone === 'string' ? b.phone.trim() : '';\r\n let identifier: string;\r\n let channel: 'email' | 'sms';\r\n\r\n if (purpose === 'login') {\r\n if (emailIn) {\r\n identifier = emailIn;\r\n channel = 'email';\r\n } else if (phoneIn) {\r\n if (!otpAllowPhoneLogin) {\r\n return json({ error: 'Phone sign-in is not enabled' }, { status: 403 });\r\n }\r\n const p = normalizePhoneE164(phoneIn, defaultPhoneCc);\r\n if (!p) return json({ error: 'Invalid phone' }, { status: 400 });\r\n identifier = p;\r\n channel = 'sms';\r\n } else {\r\n return json({ error: 'email or phone required' }, { status: 400 });\r\n }\r\n const user =\r\n channel === 'email'\r\n ? await userRepo().findOne({ where: { email: identifier } as ObjectLiteral })\r\n : await userRepo().findOne({ where: { phone: identifier } as ObjectLiteral });\r\n if (!user || (user as { deleted?: boolean }).deleted || (user as { blocked?: boolean }).blocked) {\r\n return json({ ok: true });\r\n }\r\n } else if (purpose === 'verify_email') {\r\n if (!emailIn || !isValidSignupEmail(emailIn)) return json({ error: 'Valid email required' }, { status: 400 });\r\n identifier = emailIn;\r\n channel = 'email';\r\n const user = await userRepo().findOne({ where: { email: identifier } as ObjectLiteral });\r\n if (!user || (user as { deleted?: boolean }).deleted) return json({ ok: true });\r\n } else {\r\n const su = await getSessionUser();\r\n const uid = su?.id ? parseInt(String(su.id), 10) : NaN;\r\n if (!Number.isFinite(uid)) return json({ error: 'Unauthorized' }, { status: 401 });\r\n const p = normalizePhoneE164(phoneIn, defaultPhoneCc);\r\n if (!p) return json({ error: 'Valid phone required' }, { status: 400 });\r\n identifier = p;\r\n channel = 'sms';\r\n const taken = await userRepo().findOne({\r\n where: { phone: identifier } as ObjectLiteral,\r\n select: ['id'],\r\n });\r\n if (taken && (taken as { id: number }).id !== uid) {\r\n return json({ error: 'Phone already in use' }, { status: 400 });\r\n }\r\n }\r\n\r\n const code = generateNumericOtp(6);\r\n const created = await createOtpChallenge(dataSource, entityMap, {\r\n purpose,\r\n channel,\r\n identifier,\r\n code,\r\n pepper: otpPepper,\r\n });\r\n if (!created.ok) return json({ error: created.error }, { status: created.status });\r\n\r\n if (!getCms) return json({ error: 'OTP delivery not configured' }, { status: 503 });\r\n\r\n try {\r\n const cms = await getCms();\r\n if (channel === 'email') {\r\n if (!cms.getPlugin('email')) return json({ error: 'Email not configured' }, { status: 503 });\r\n const companyDetails = getCompanyDetails ? await getCompanyDetails() : {};\r\n await queueEmail(cms, {\r\n to: identifier,\r\n templateName: 'otp',\r\n ctx: { code, companyDetails: companyDetails ?? {} },\r\n });\r\n } else {\r\n if (!cms.getPlugin('sms')) return json({ error: 'SMS not configured' }, { status: 503 });\r\n const templateKey = purpose === 'verify_phone' ? 'auth.otp_verify_phone' : 'auth.otp_login';\r\n await queueSms(cms, { to: identifier, templateKey, variables: { code } });\r\n }\r\n } catch {\r\n return json({ error: 'Failed to send code' }, { status: 500 });\r\n }\r\n return json({ ok: true });\r\n }\r\n\r\n // --- auth/otp/verify-email POST ---\r\n if (path[0] === 'auth' && path[1] === 'otp' && path[2] === 'verify-email' && path.length === 3 && method === 'POST') {\r\n if (otpOff('verifyEmail')) return json({ error: 'otp_disabled' }, { status: 403 });\r\n const b = (await req.json().catch(() => ({}))) as { email?: string; code?: string };\r\n const email = typeof b.email === 'string' ? b.email.trim().toLowerCase() : '';\r\n const code = typeof b.code === 'string' ? b.code.trim() : '';\r\n if (!email || !code) return json({ error: 'email and code required' }, { status: 400 });\r\n const v = await verifyAndConsumeOtpChallenge(dataSource, entityMap, {\r\n purpose: 'verify_email',\r\n identifier: email,\r\n code,\r\n pepper: otpPepper,\r\n });\r\n if (!v.ok) return json({ error: v.error }, { status: v.status });\r\n const user = await userRepo().findOne({ where: { email } as ObjectLiteral });\r\n if (!user) return json({ error: 'User not found' }, { status: 400 });\r\n await userRepo().update((user as { id: number }).id, {\r\n blocked: false,\r\n emailVerifiedAt: new Date(),\r\n updatedAt: new Date(),\r\n } as ObjectLiteral);\r\n await tokenRepo().delete({ email } as ObjectLiteral);\r\n return json({ success: true, message: 'Email verified. You can sign in.' });\r\n }\r\n\r\n // --- auth/otp/verify-phone POST ---\r\n if (path[0] === 'auth' && path[1] === 'otp' && path[2] === 'verify-phone' && path.length === 3 && method === 'POST') {\r\n if (otpOff('verifyPhone')) return json({ error: 'otp_disabled' }, { status: 403 });\r\n const su = await getSessionUser();\r\n const uid = su?.id ? parseInt(String(su.id), 10) : NaN;\r\n if (!Number.isFinite(uid)) return json({ error: 'Unauthorized' }, { status: 401 });\r\n const b = (await req.json().catch(() => ({}))) as { phone?: string; code?: string };\r\n const phoneRaw = typeof b.phone === 'string' ? b.phone.trim() : '';\r\n const code = typeof b.code === 'string' ? b.code.trim() : '';\r\n const phone = normalizePhoneE164(phoneRaw, defaultPhoneCc);\r\n if (!phone || !code) return json({ error: 'phone and code required' }, { status: 400 });\r\n const v = await verifyAndConsumeOtpChallenge(dataSource, entityMap, {\r\n purpose: 'verify_phone',\r\n identifier: phone,\r\n code,\r\n pepper: otpPepper,\r\n });\r\n if (!v.ok) return json({ error: v.error }, { status: v.status });\r\n const taken = await userRepo().findOne({ where: { phone } as ObjectLiteral, select: ['id'] });\r\n if (taken && (taken as { id: number }).id !== uid) {\r\n return json({ error: 'Phone already in use' }, { status: 400 });\r\n }\r\n await userRepo().update(uid, { phone, phoneVerifiedAt: new Date(), updatedAt: new Date() } as ObjectLiteral);\r\n const contact = await ensureContactForUser(uid);\r\n if (contact) {\r\n await contactRepo().update(contact.id, { phone } as ObjectLiteral);\r\n }\r\n return json({ success: true });\r\n }\r\n\r\n // --- register POST ---\r\n if (path[0] === 'register' && path.length === 1 && method === 'POST') {\r\n if (!config.hashPassword) return json({ error: 'Registration not configured' }, { status: 501 });\r\n const b = (await req.json().catch(() => ({}))) as Record<string, unknown>;\r\n const capReg = await assertCaptchaOk(getCms, b, req, json);\r\n if (capReg) return capReg;\r\n const name = typeof b.name === 'string' ? b.name.trim() : '';\r\n const email = typeof b.email === 'string' ? b.email.trim().toLowerCase() : '';\r\n const password = typeof b.password === 'string' ? b.password : '';\r\n if (!name || !email || !password) return json({ error: 'name, email and password are required' }, { status: 400 });\r\n if (!isValidSignupEmail(email)) return json({ error: 'Invalid email address' }, { status: 400 });\r\n const existing = await userRepo().findOne({ where: { email } });\r\n if (existing) return json({ error: 'User with this email already exists' }, { status: 400 });\r\n const customerG = await groupRepo().findOne({ where: { name: 'Customer', deleted: false } as ObjectLiteral });\r\n const groupId = customerG ? (customerG as { id: number }).id : null;\r\n const hashed = await config.hashPassword(password);\r\n const requireEmailVerification = Boolean(getCms);\r\n const newUser = await userRepo().save(\r\n userRepo().create({\r\n name,\r\n email,\r\n password: hashed,\r\n blocked: requireEmailVerification,\r\n groupId,\r\n adminAccess: false,\r\n } as ObjectLiteral)\r\n );\r\n const userId = (newUser as { id: number }).id;\r\n await linkUnclaimedContactToUser(dataSource, entityMap.contacts, userId, email);\r\n\r\n let emailVerificationSent = false;\r\n if (requireEmailVerification && getCms) {\r\n try {\r\n const crypto = await import('crypto');\r\n const rawToken = crypto.randomBytes(32).toString('hex');\r\n const expiresAt = new Date(Date.now() + SIGNUP_VERIFY_EXPIRY_HOURS * 60 * 60 * 1000);\r\n await tokenRepo().save(\r\n tokenRepo().create({ email, token: rawToken, expiresAt } as ObjectLiteral)\r\n );\r\n const cms = await getCms();\r\n const companyDetails = getCompanyDetails ? await getCompanyDetails() : {};\r\n const base = (publicSiteUrl || '').replace(/\\/$/, '').trim() || 'http://localhost:3000';\r\n const verifyEmailUrl = `${base}/verify-email?token=${encodeURIComponent(rawToken)}`;\r\n await queueEmail(cms, {\r\n to: email,\r\n templateName: 'signup',\r\n ctx: { name, verifyEmailUrl, companyDetails: companyDetails ?? {} },\r\n });\r\n emailVerificationSent = true;\r\n } catch {\r\n await userRepo().update(userId, { blocked: false, updatedAt: new Date() } as ObjectLiteral);\r\n }\r\n }\r\n\r\n return json({\r\n success: true,\r\n userId,\r\n emailVerificationSent,\r\n });\r\n }\r\n\r\n // --- cart GET ---\r\n if (path[0] === 'cart' && path.length === 1 && method === 'GET') {\r\n const { cart, setCookie, err } = await getOrCreateCart(req);\r\n if (err) return err;\r\n const body = serializeCart(cart);\r\n if (setCookie) return json(body, { headers: { 'Set-Cookie': setCookie } });\r\n return json(body);\r\n }\r\n\r\n // --- cart/items POST ---\r\n if (path[0] === 'cart' && path[1] === 'items' && path.length === 2 && method === 'POST') {\r\n const body = (await req.json().catch(() => ({}))) as Record<string, unknown>;\r\n const capCart = await assertCaptchaOk(getCms, body, req, json);\r\n if (capCart) return capCart;\r\n const productId = Number(body.productId);\r\n const quantity = Math.max(1, Number(body.quantity) || 1);\r\n if (!Number.isFinite(productId)) return json({ error: 'productId required' }, { status: 400 });\r\n const product = await productRepo().findOne({ where: { id: productId, deleted: false } as ObjectLiteral });\r\n if (!product) return json({ error: 'Product not found' }, { status: 404 });\r\n const { cart, setCookie, err } = await getOrCreateCart(req);\r\n if (err) return err;\r\n const cartId = (cart as { id: number }).id;\r\n const existing = await cartItemRepo().findOne({ where: { cartId, productId } as ObjectLiteral });\r\n if (existing) {\r\n await cartItemRepo().update((existing as { id: number }).id, {\r\n quantity: (existing as { quantity: number }).quantity + quantity,\r\n });\r\n } else {\r\n await cartItemRepo().save(\r\n cartItemRepo().create({ cartId, productId, quantity } as ObjectLiteral)\r\n );\r\n }\r\n await cartRepo().update(cartId, { updatedAt: new Date() });\r\n const fresh = await cartRepo().findOne({\r\n where: { id: cartId },\r\n relations: ['items', 'items.product'],\r\n });\r\n const out = serializeCart(fresh!);\r\n if (setCookie) return json(out, { headers: { 'Set-Cookie': setCookie } });\r\n return json(out);\r\n }\r\n\r\n // --- cart/items/:id PATCH DELETE ---\r\n if (path[0] === 'cart' && path[1] === 'items' && path.length === 3) {\r\n const itemId = parseInt(path[2]!, 10);\r\n if (!Number.isFinite(itemId)) return json({ error: 'Invalid item id' }, { status: 400 });\r\n const { cart, setCookie, err } = await getOrCreateCart(req);\r\n if (err) return err;\r\n const cartId = (cart as { id: number }).id;\r\n const item = await cartItemRepo().findOne({ where: { id: itemId, cartId } as ObjectLiteral });\r\n if (!item) return json({ error: 'Not found' }, { status: 404 });\r\n if (method === 'DELETE') {\r\n await cartItemRepo().delete(itemId);\r\n await cartRepo().update(cartId, { updatedAt: new Date() });\r\n const fresh = await cartRepo().findOne({\r\n where: { id: cartId },\r\n relations: ['items', 'items.product'],\r\n });\r\n const out = serializeCart(fresh!);\r\n if (setCookie) return json(out, { headers: { 'Set-Cookie': setCookie } });\r\n return json(out);\r\n }\r\n if (method === 'PATCH') {\r\n const b = (await req.json().catch(() => ({}))) as { quantity?: number };\r\n const q = Math.max(0, Number(b.quantity) || 0);\r\n if (q === 0) await cartItemRepo().delete(itemId);\r\n else await cartItemRepo().update(itemId, { quantity: q });\r\n await cartRepo().update(cartId, { updatedAt: new Date() });\r\n const fresh = await cartRepo().findOne({\r\n where: { id: cartId },\r\n relations: ['items', 'items.product'],\r\n });\r\n const out = serializeCart(fresh!);\r\n if (setCookie) return json(out, { headers: { 'Set-Cookie': setCookie } });\r\n return json(out);\r\n }\r\n }\r\n\r\n // --- cart/merge POST (auth) ---\r\n if (path[0] === 'cart' && path[1] === 'merge' && method === 'POST') {\r\n const u = await getSessionUser();\r\n const uid = u?.id ? parseInt(String(u.id), 10) : NaN;\r\n if (!Number.isFinite(uid)) return json({ error: 'Unauthorized' }, { status: 401 });\r\n const contact = await ensureContactForUser(uid);\r\n if (!contact) return json({ error: 'Contact not found' }, { status: 400 });\r\n const cookies = parseCookies(req.headers.get('cookie'));\r\n const guestToken = cookies[cookieName];\r\n if (!guestToken) return json({ merged: false, message: 'No guest cart' });\r\n const guestCart = await cartRepo().findOne({\r\n where: { guestToken } as ObjectLiteral,\r\n relations: ['items'],\r\n });\r\n if (!guestCart || !((guestCart as { items?: unknown[] }).items || []).length) {\r\n let uc = await cartRepo().findOne({\r\n where: { contactId: contact.id } as ObjectLiteral,\r\n relations: ['items', 'items.product'],\r\n });\r\n if (!uc) uc = { items: [] } as ObjectLiteral;\r\n return json(\r\n { merged: false, cart: serializeCart(uc) },\r\n { headers: { 'Set-Cookie': `${cookieName}=; Path=/; Max-Age=0` } }\r\n );\r\n }\r\n let userCart = await cartRepo().findOne({ where: { contactId: contact.id } as ObjectLiteral });\r\n if (!userCart) {\r\n userCart = await cartRepo().save(\r\n cartRepo().create({ contactId: contact.id, guestToken: null, currency: (guestCart as { currency: string }).currency } as ObjectLiteral)\r\n );\r\n }\r\n const uidCart = (userCart as { id: number }).id;\r\n const gItems = ((guestCart as { items: ObjectLiteral[] }).items) || [];\r\n for (const gi of gItems) {\r\n const existing = await cartItemRepo().findOne({\r\n where: { cartId: uidCart, productId: (gi as { productId: number }).productId } as ObjectLiteral,\r\n });\r\n if (existing) {\r\n await cartItemRepo().update((existing as { id: number }).id, {\r\n quantity: (existing as { quantity: number }).quantity + (gi as { quantity: number }).quantity,\r\n });\r\n } else {\r\n await cartItemRepo().save(\r\n cartItemRepo().create({\r\n cartId: uidCart,\r\n productId: (gi as { productId: number }).productId,\r\n quantity: (gi as { quantity: number }).quantity,\r\n metadata: (gi as { metadata: unknown }).metadata,\r\n } as ObjectLiteral)\r\n );\r\n }\r\n }\r\n await cartRepo().delete((guestCart as { id: number }).id);\r\n await cartRepo().update(uidCart, { updatedAt: new Date() });\r\n const fresh = await cartRepo().findOne({\r\n where: { id: uidCart },\r\n relations: ['items', 'items.product'],\r\n });\r\n // Merge guest wishlist into contact wishlist (same guestId cookie)\r\n const guestWishlist = await wishlistRepo().findOne({\r\n where: { guestId: guestToken } as ObjectLiteral,\r\n relations: ['items'],\r\n });\r\n if (guestWishlist && ((guestWishlist as { items?: unknown[] }).items || []).length > 0) {\r\n const userWishlist = await getDefaultWishlist(contact.id);\r\n const gItems = ((guestWishlist as { items: ObjectLiteral[] }).items) || [];\r\n for (const gi of gItems) {\r\n const pid = (gi as { productId: number }).productId;\r\n const ex = await wishlistItemRepo().findOne({ where: { wishlistId: userWishlist.id, productId: pid } as ObjectLiteral });\r\n if (!ex) await wishlistItemRepo().save(wishlistItemRepo().create({ wishlistId: userWishlist.id, productId: pid } as ObjectLiteral));\r\n }\r\n await wishlistRepo().delete((guestWishlist as { id: number }).id);\r\n }\r\n return json({ merged: true, cart: serializeCart(fresh!) }, { headers: { 'Set-Cookie': `${cookieName}=; Path=/; Max-Age=0` } });\r\n }\r\n\r\n // --- wishlist (guest or auth: same guestId cookie as cart) ---\r\n async function getDefaultWishlist(contactId: number) {\r\n let w = await wishlistRepo().findOne({ where: { contactId, name: 'default' } as ObjectLiteral });\r\n if (!w) {\r\n w = await wishlistRepo().save(wishlistRepo().create({ contactId, guestId: null, name: 'default' } as ObjectLiteral));\r\n }\r\n return w as { id: number };\r\n }\r\n\r\n async function getOrCreateWishlist(req: Request): Promise<{ wishlist: ObjectLiteral; setCookie: string | null; err: Response | null }> {\r\n const u = await getSessionUser();\r\n const uid = u?.id ? parseInt(String(u.id), 10) : NaN;\r\n if (Number.isFinite(uid)) {\r\n const contact = await ensureContactForUser(uid);\r\n if (!contact) return { wishlist: {} as ObjectLiteral, setCookie: null, err: json({ error: 'User not found' }, { status: 400 }) };\r\n const w = await getDefaultWishlist(contact.id);\r\n const wishlist = await wishlistRepo().findOne({ where: { id: w.id } as ObjectLiteral });\r\n return { wishlist: wishlist!, setCookie: null, err: null };\r\n }\r\n const cookies = parseCookies(req.headers.get('cookie'));\r\n let token = cookies[cookieName] || '';\r\n if (!token) {\r\n token = crypto.randomUUID();\r\n let w = await wishlistRepo().findOne({ where: { guestId: token } as ObjectLiteral });\r\n if (!w) {\r\n w = await wishlistRepo().save(wishlistRepo().create({ guestId: token, contactId: null, name: 'default' } as ObjectLiteral));\r\n }\r\n return { wishlist: w!, setCookie: guestCookieHeader(cookieName, token), err: null };\r\n }\r\n let w = await wishlistRepo().findOne({ where: { guestId: token } as ObjectLiteral });\r\n if (!w) {\r\n w = await wishlistRepo().save(wishlistRepo().create({ guestId: token, contactId: null, name: 'default' } as ObjectLiteral));\r\n }\r\n return { wishlist: w!, setCookie: null, err: null };\r\n }\r\n\r\n if (path[0] === 'wishlist' && path.length === 1 && method === 'GET') {\r\n const { wishlist, setCookie, err } = await getOrCreateWishlist(req);\r\n if (err) return err;\r\n const items = await wishlistItemRepo().find({\r\n where: { wishlistId: (wishlist as { id: number }).id } as ObjectLiteral,\r\n relations: ['product'],\r\n });\r\n const body = {\r\n wishlistId: (wishlist as { id: number }).id,\r\n items: items.map((it) => {\r\n const p = (it as ObjectLiteral).product as ObjectLiteral | undefined;\r\n return {\r\n id: (it as ObjectLiteral).id,\r\n productId: (it as ObjectLiteral).productId,\r\n product: p\r\n ? {\r\n id: p.id,\r\n name: p.name,\r\n slug: p.slug,\r\n price: p.price,\r\n sku: p.sku,\r\n image: primaryProductImageUrl(p.metadata),\r\n }\r\n : null,\r\n };\r\n }),\r\n };\r\n if (setCookie) return json(body, { headers: { 'Set-Cookie': setCookie } });\r\n return json(body);\r\n }\r\n\r\n if (path[0] === 'wishlist' && path[1] === 'items' && path.length === 2 && method === 'POST') {\r\n const { wishlist, setCookie, err } = await getOrCreateWishlist(req);\r\n if (err) return err;\r\n const b = (await req.json().catch(() => ({}))) as Record<string, unknown>;\r\n const capWl = await assertCaptchaOk(getCms, b, req, json);\r\n if (capWl) return capWl;\r\n const productId = Number(b.productId);\r\n if (!Number.isFinite(productId)) return json({ error: 'productId required' }, { status: 400 });\r\n const wid = (wishlist as { id: number }).id;\r\n const ex = await wishlistItemRepo().findOne({ where: { wishlistId: wid, productId } as ObjectLiteral });\r\n if (!ex) await wishlistItemRepo().save(wishlistItemRepo().create({ wishlistId: wid, productId } as ObjectLiteral));\r\n if (setCookie) return json({ ok: true }, { headers: { 'Set-Cookie': setCookie } });\r\n return json({ ok: true });\r\n }\r\n\r\n if (path[0] === 'wishlist' && path[1] === 'items' && path.length === 3 && method === 'DELETE') {\r\n const { wishlist, setCookie, err } = await getOrCreateWishlist(req);\r\n if (err) return err;\r\n const productId = parseInt(path[2]!, 10);\r\n await wishlistItemRepo().delete({ wishlistId: (wishlist as { id: number }).id, productId } as ObjectLiteral);\r\n if (setCookie) return json({ ok: true }, { headers: { 'Set-Cookie': setCookie } });\r\n return json({ ok: true });\r\n }\r\n\r\n // --- checkout/order POST (create order only, for Razorpay; do not clear cart) ---\r\n if (path[0] === 'checkout' && path[1] === 'order' && path.length === 2 && method === 'POST') {\r\n const b = (await req.json().catch(() => ({}))) as Record<string, unknown>;\r\n const capOrd = await assertCaptchaOk(getCms, b, req, json);\r\n if (capOrd) return capOrd;\r\n const u = await getSessionUser();\r\n const uid = u?.id ? parseInt(String(u.id), 10) : NaN;\r\n const checkoutIdentity = await resolveCheckoutContactAndCart(b, req, uid);\r\n if (!checkoutIdentity.ok) return checkoutIdentity.response;\r\n const { contactId, cart } = checkoutIdentity;\r\n if (!cart || !((cart.items as ObjectLiteral[]) || []).length) {\r\n return json({ error: 'Cart is empty' }, { status: 400 });\r\n }\r\n const prepOrd = await prepareCheckoutFromCart(b, cart, contactId);\r\n if (!prepOrd.ok) return json({ error: prepOrd.message }, { status: prepOrd.status });\r\n const vendorRes = resolveSingleVendorIdFromCart(cart);\r\n if ('error' in vendorRes) return json({ error: vendorRes.error }, { status: vendorRes.status });\r\n const cartId = (cart as { id: number }).id;\r\n const ord = await orderRepo().save(\r\n orderRepo().create({\r\n vendorId: vendorRes.vendorId,\r\n orderNumber: temporaryOrderNumberPlaceholder(),\r\n orderKind: 'sale',\r\n parentOrderId: null,\r\n contactId,\r\n billingAddressId: prepOrd.billingAddressId,\r\n shippingAddressId: prepOrd.shippingAddressId,\r\n status: 'pending',\r\n subtotal: prepOrd.subtotal,\r\n tax: prepOrd.orderTax,\r\n discount: 0,\r\n total: prepOrd.orderTotal,\r\n currency: (cart.currency as string) || 'INR',\r\n metadata: { cartId },\r\n } as ObjectLiteral)\r\n );\r\n const oid = (ord as { id: number }).id;\r\n await orderRepo().update(oid, {\r\n orderNumber: buildCanonicalOrderNumber('sale', oid, (ord as { createdAt?: Date }).createdAt ?? new Date()),\r\n } as ObjectLiteral);\r\n for (const line of prepOrd.lines) {\r\n await orderItemRepo().save(\r\n orderItemRepo().create({\r\n orderId: oid,\r\n productId: line.productId,\r\n quantity: line.quantity,\r\n unitPrice: line.unitPrice,\r\n tax: line.tax,\r\n total: line.total,\r\n hsn: line.hsn,\r\n uom: line.uom,\r\n productType: line.productType,\r\n taxRate: line.taxRate,\r\n taxCode: line.taxCode,\r\n } as ObjectLiteral)\r\n );\r\n }\r\n return json({\r\n orderId: oid,\r\n orderNumber: (ord as { orderNumber: string }).orderNumber,\r\n subtotal: prepOrd.subtotal,\r\n tax: prepOrd.orderTax,\r\n total: prepOrd.orderTotal,\r\n currency: (cart.currency as string) || 'INR',\r\n });\r\n }\r\n\r\n // --- checkout POST ---\r\n if (path[0] === 'checkout' && path.length === 1 && method === 'POST') {\r\n const b = (await req.json().catch(() => ({}))) as Record<string, unknown>;\r\n const capChk = await assertCaptchaOk(getCms, b, req, json);\r\n if (capChk) return capChk;\r\n const u = await getSessionUser();\r\n const uid = u?.id ? parseInt(String(u.id), 10) : NaN;\r\n const checkoutIdentity = await resolveCheckoutContactAndCart(b, req, uid);\r\n if (!checkoutIdentity.ok) return checkoutIdentity.response;\r\n const { contactId, cart } = checkoutIdentity;\r\n if (!cart || !((cart.items as ObjectLiteral[]) || []).length) {\r\n return json({ error: 'Cart is empty' }, { status: 400 });\r\n }\r\n const prepChk = await prepareCheckoutFromCart(b, cart, contactId);\r\n if (!prepChk.ok) return json({ error: prepChk.message }, { status: prepChk.status });\r\n const vendorResChk = resolveSingleVendorIdFromCart(cart);\r\n if ('error' in vendorResChk) return json({ error: vendorResChk.error }, { status: vendorResChk.status });\r\n const ord = await orderRepo().save(\r\n orderRepo().create({\r\n vendorId: vendorResChk.vendorId,\r\n orderNumber: temporaryOrderNumberPlaceholder(),\r\n orderKind: 'sale',\r\n parentOrderId: null,\r\n contactId,\r\n billingAddressId: prepChk.billingAddressId,\r\n shippingAddressId: prepChk.shippingAddressId,\r\n status: 'pending',\r\n subtotal: prepChk.subtotal,\r\n tax: prepChk.orderTax,\r\n discount: 0,\r\n total: prepChk.orderTotal,\r\n currency: (cart.currency as string) || 'INR',\r\n } as ObjectLiteral)\r\n );\r\n const oid = (ord as { id: number }).id;\r\n await orderRepo().update(oid, {\r\n orderNumber: buildCanonicalOrderNumber('sale', oid, (ord as { createdAt?: Date }).createdAt ?? new Date()),\r\n } as ObjectLiteral);\r\n for (const line of prepChk.lines) {\r\n await orderItemRepo().save(\r\n orderItemRepo().create({\r\n orderId: oid,\r\n productId: line.productId,\r\n quantity: line.quantity,\r\n unitPrice: line.unitPrice,\r\n tax: line.tax,\r\n total: line.total,\r\n hsn: line.hsn,\r\n uom: line.uom,\r\n productType: line.productType,\r\n taxRate: line.taxRate,\r\n taxCode: line.taxCode,\r\n } as ObjectLiteral)\r\n );\r\n }\r\n await cartItemRepo().delete({ cartId: (cart as { id: number }).id } as ObjectLiteral);\r\n await cartRepo().delete((cart as { id: number }).id);\r\n return json({\r\n orderId: oid,\r\n orderNumber: (ord as { orderNumber: string }).orderNumber,\r\n subtotal: prepChk.subtotal,\r\n tax: prepChk.orderTax,\r\n total: prepChk.orderTotal,\r\n });\r\n }\r\n\r\n // --- orders GET ---\r\n if (path[0] === 'orders' && path.length === 1 && method === 'GET') {\r\n const u = await getSessionUser();\r\n const uid = u?.id ? parseInt(String(u.id), 10) : NaN;\r\n if (!Number.isFinite(uid)) return json({ error: 'Unauthorized' }, { status: 401 });\r\n const contact = await contactRepo().findOne({ where: { userId: uid, deleted: false } as ObjectLiteral });\r\n if (!contact) return json({ orders: [] });\r\n const orders = await orderRepo().find({\r\n where: { contactId: (contact as { id: number }).id, deleted: false, orderKind: 'sale' } as ObjectLiteral,\r\n order: { createdAt: 'DESC' },\r\n take: 50,\r\n });\r\n const orderIds = orders.map((o) => (o as ObjectLiteral).id as number);\r\n const previewByOrder: Record<number, string[]> = {};\r\n if (orderIds.length) {\r\n const oItems = await orderItemRepo().find({\r\n where: { orderId: In(orderIds) },\r\n relations: ['product'],\r\n order: { id: 'ASC' },\r\n });\r\n for (const oi of oItems) {\r\n const oid = (oi as ObjectLiteral).orderId as number;\r\n if (!previewByOrder[oid]) previewByOrder[oid] = [];\r\n if (previewByOrder[oid].length >= 4) continue;\r\n const url = primaryProductImageUrl(((oi as ObjectLiteral).product as ObjectLiteral)?.metadata);\r\n if (url && !previewByOrder[oid].includes(url)) previewByOrder[oid].push(url);\r\n }\r\n }\r\n return json({\r\n orders: orders.map((o) => {\r\n const ol = o as ObjectLiteral;\r\n return {\r\n id: ol.id,\r\n orderNumber: ol.orderNumber,\r\n status: ol.status,\r\n total: ol.total,\r\n currency: ol.currency,\r\n createdAt: ol.createdAt,\r\n previewImages: previewByOrder[ol.id as number] ?? [],\r\n };\r\n }),\r\n });\r\n }\r\n\r\n if (path[0] === 'orders' && path.length === 3 && path[2] === 'invoice' && method === 'GET') {\r\n const u = await getSessionUser();\r\n const uid = u?.id ? parseInt(String(u.id), 10) : NaN;\r\n if (!Number.isFinite(uid)) return json({ error: 'Unauthorized' }, { status: 401 });\r\n if (!getCms) return json({ error: 'Not found' }, { status: 404 });\r\n const contact = await contactRepo().findOne({ where: { userId: uid, deleted: false } as ObjectLiteral });\r\n if (!contact) return json({ error: 'Not found' }, { status: 404 });\r\n const orderId = parseInt(path[1]!, 10);\r\n if (!Number.isFinite(orderId)) return json({ error: 'Invalid id' }, { status: 400 });\r\n const cms = await getCms();\r\n return streamOrderInvoicePdf(cms, dataSource, entityMap, orderId, {\r\n ownerContactId: (contact as { id: number }).id,\r\n });\r\n }\r\n\r\n if (path[0] === 'orders' && path.length === 2 && method === 'GET') {\r\n const u = await getSessionUser();\r\n const uid = u?.id ? parseInt(String(u.id), 10) : NaN;\r\n if (!Number.isFinite(uid)) return json({ error: 'Unauthorized' }, { status: 401 });\r\n const contact = await contactRepo().findOne({ where: { userId: uid, deleted: false } as ObjectLiteral });\r\n if (!contact) return json({ error: 'Not found' }, { status: 404 });\r\n const orderId = parseInt(path[1]!, 10);\r\n let order = await orderRepo().findOne({\r\n where: { id: orderId, contactId: (contact as { id: number }).id, deleted: false } as ObjectLiteral,\r\n relations: ['items', 'items.product'],\r\n });\r\n if (!order) return json({ error: 'Not found' }, { status: 404 });\r\n if (getCms) {\r\n const cms = await getCms();\r\n await tryRefreshOrderFromErpForStorefront(cms, dataSource, entityMap, order as ObjectLiteral);\r\n order = await orderRepo().findOne({\r\n where: { id: orderId, contactId: (contact as { id: number }).id, deleted: false } as ObjectLiteral,\r\n relations: ['items', 'items.product'],\r\n });\r\n }\r\n if (!order) return json({ error: 'Not found' }, { status: 404 });\r\n const o = order as ObjectLiteral;\r\n const lines = ((o.items as ObjectLiteral[]) || []).map((line) => {\r\n const p = line.product as ObjectLiteral | undefined;\r\n return {\r\n id: line.id,\r\n productId: line.productId,\r\n quantity: line.quantity,\r\n unitPrice: line.unitPrice,\r\n tax: line.tax,\r\n total: line.total,\r\n product: p\r\n ? {\r\n name: p.name,\r\n slug: p.slug,\r\n sku: p.sku,\r\n image: primaryProductImageUrl(p.metadata),\r\n }\r\n : null,\r\n };\r\n });\r\n const kind = (o.orderKind as string) || 'sale';\r\n let relatedOrders: ObjectLiteral[] = [];\r\n if (kind === 'sale') {\r\n relatedOrders = await orderRepo().find({\r\n where: { parentOrderId: orderId, deleted: false } as ObjectLiteral,\r\n order: { id: 'ASC' },\r\n });\r\n }\r\n const meta = o.metadata as Record<string, unknown> | null | undefined;\r\n const fulfillmentPreview =\r\n meta && typeof meta.fulfillment === 'object' && meta.fulfillment && 'status' in (meta.fulfillment as object)\r\n ? String((meta.fulfillment as { status?: string }).status ?? '')\r\n : '';\r\n return json({\r\n order: {\r\n id: o.id,\r\n orderNumber: o.orderNumber,\r\n orderKind: kind,\r\n parentOrderId: o.parentOrderId ?? null,\r\n status: o.status,\r\n subtotal: o.subtotal,\r\n tax: o.tax,\r\n discount: o.discount,\r\n total: o.total,\r\n currency: o.currency,\r\n createdAt: o.createdAt,\r\n metadata: o.metadata ?? null,\r\n items: lines,\r\n },\r\n relatedOrders: relatedOrders.map((r) => ({\r\n id: r.id,\r\n orderNumber: r.orderNumber,\r\n orderKind: r.orderKind ?? 'return',\r\n status: r.status,\r\n createdAt: r.createdAt,\r\n fulfillmentStatus:\r\n r.metadata &&\r\n typeof r.metadata === 'object' &&\r\n (r.metadata as { fulfillment?: { status?: string } }).fulfillment?.status,\r\n })),\r\n fulfillmentPreview: fulfillmentPreview || undefined,\r\n });\r\n }\r\n\r\n return json({ error: 'Not found' }, { status: 404 });\r\n } catch {\r\n return json({ error: 'Server error' }, { status: 500 });\r\n }\r\n },\r\n };\r\n}\r\n","/** Max lengths per RFC 5321 / 5322 (practical subset). */\r\nconst MAX_EMAIL = 254;\r\nconst MAX_LOCAL = 64;\r\n\r\n/**\r\n * Rejects obviously invalid signup addresses (format, length, missing TLD).\r\n * Used by storefront register so junk strings cannot create accounts.\r\n */\r\nexport function isValidSignupEmail(email: string): boolean {\r\n if (!email || email.length > MAX_EMAIL) return false;\r\n const at = email.indexOf('@');\r\n if (at <= 0 || at !== email.lastIndexOf('@')) return false;\r\n const local = email.slice(0, at);\r\n const domain = email.slice(at + 1);\r\n if (!local || local.length > MAX_LOCAL || !domain || domain.length > 253) return false;\r\n if (local.startsWith('.') || local.endsWith('.') || local.includes('..')) return false;\r\n if (domain.startsWith('.') || domain.endsWith('.') || domain.includes('..')) return false;\r\n if (!/^[a-z0-9._%+-]+$/i.test(local)) return false;\r\n if (!/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$/i.test(domain)) return false;\r\n const tld = domain.split('.').pop()!;\r\n return tld.length >= 2;\r\n}\r\n","export interface AdminNavItem {\r\n href: string;\r\n label: string;\r\n icon?: string;\r\n}\r\n\r\nexport const DEFAULT_ADMIN_NAV: AdminNavItem[] = [\r\n { href: '/admin/dashboard', label: 'Dashboard' },\r\n { href: '/admin/contacts', label: 'Contacts' },\r\n { href: '/admin/blogs', label: 'Blogs' },\r\n { href: '/admin/blog-generator', label: 'Blog generator' },\r\n { href: '/admin/users', label: 'Users' },\r\n { href: '/admin/roles', label: 'Roles' },\r\n { href: '/admin/forms', label: 'Forms' },\r\n { href: '/admin/submissions', label: 'Submissions' },\r\n { href: '/admin/pages', label: 'Pages' },\r\n];\r\n"],"mappings":"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AW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAMhB,GAAG,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["pickInvoiceId","Stripe","Razorpay","crypto","PgBoss","isVendorOwner","allowed","loadDbPermissionsForUser","formatMoney","formatDate","pick","escapeHtml","subject","escapeHtml","bodyHtml","text","html","render","escapeHtml","render","escapeHtml","escapeHtml","render","render","escapeHtml","render","escapeHtml","render","escapeHtml","render","escapeHtml","render","escapeHtml","render","escapeHtml","render","escapeHtml","render","render","nodemailer","norm","emailPlugin","resolveSmsTemplateForSend","applyTemplateVars","StripePaymentService","RazorpayPaymentService","fs","path","model","Redis","fastq","import_typeorm","import_typeorm","import_typeorm","JOB_RUNNER_QUEUE","import_crypto","import_typeorm","import_typeorm","import_typeorm","norm","fs","fs","path","isErpIntegrationEnabled","markVendorInvitePendingForUser","result","emailPlugin","Parser","s","title","path","fs","out","path","import_crypto","import_typeorm","import_ioredis","clientIp","Redis","addrToRecord","getSettingsGroup","import_typeorm","bcrypt","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","AddressType","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","fs","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","Type","SubType","ConditionType","ConditionOperator","ComparisonOperator","DiscountType","DiscountStatus","import_typeorm","import_typeorm","import_typeorm","import_typeorm","import_typeorm","NextResponse","LOG_PREFIX","isPublicMethod","_CredentialsProvider","isVendorOwner","path","import_typeorm","import_typeorm","norm","import_crypto","repo","sortField","typeFilter","total","data","sortParam","persistBody","vendorIdCheck","created","bcrypt","crypto","nestDiscountRules","scope","updatePayload","updated","scopePut","result","crypto","path","import_typeorm","docRepo","dup","chunkRepo","text","parts","now","chunkRows","savedList","embedResult","import_typeorm","path","queueEmail","markVendorInviteAcceptedForUser","streamOrderInvoicePdf","isErpIntegrationEnabled","queueErpPaidOrderForOrderId","result","renderOrderTrackingPage","import_typeorm","roundMoney","cart","contact","path","serializeAddress","crypto","gItems","req","w"]}
|