@open-mercato/core 0.10.1-develop.8004.1.a8a79ee43f → 0.10.1-develop.8022.1.b6753de892
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/.turbo/turbo-build.log +1 -1
- package/dist/modules/audit_logs/components/AuditLogsActions.js +80 -50
- package/dist/modules/audit_logs/components/AuditLogsActions.js.map +3 -3
- package/dist/modules/audit_logs/lib/rowPresentation.js +82 -0
- package/dist/modules/audit_logs/lib/rowPresentation.js.map +7 -0
- package/dist/modules/catalog/commands/variants.js +89 -16
- package/dist/modules/catalog/commands/variants.js.map +2 -2
- package/dist/modules/catalog/seed/examples.js +7 -0
- package/dist/modules/catalog/seed/examples.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +2 -2
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/components/detail/AssignRoleDialog.js +10 -21
- package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +2 -2
- package/dist/modules/customers/migrations/Migration20260825140000_customers.js +17 -10
- package/dist/modules/customers/migrations/Migration20260825140000_customers.js.map +2 -2
- package/dist/modules/entities/cli.js +138 -66
- package/dist/modules/entities/cli.js.map +3 -3
- package/dist/modules/promotions/commands/codes.js +18 -3
- package/dist/modules/promotions/commands/codes.js.map +2 -2
- package/dist/modules/query_index/cli.js +17 -1
- package/dist/modules/query_index/cli.js.map +2 -2
- package/dist/modules/query_index/lib/reindexer.js +23 -5
- package/dist/modules/query_index/lib/reindexer.js.map +2 -2
- package/dist/modules/sales/commands/configuration.js +30 -16
- package/dist/modules/sales/commands/configuration.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +36 -15
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/seed/examples.js +35 -6
- package/dist/modules/sales/seed/examples.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/audit_logs/components/AuditLogsActions.tsx +85 -48
- package/src/modules/audit_logs/i18n/de.json +16 -0
- package/src/modules/audit_logs/i18n/en.json +16 -0
- package/src/modules/audit_logs/i18n/es.json +16 -0
- package/src/modules/audit_logs/i18n/ko.json +16 -0
- package/src/modules/audit_logs/i18n/pl.json +16 -0
- package/src/modules/audit_logs/lib/rowPresentation.ts +92 -0
- package/src/modules/catalog/commands/variants.ts +96 -17
- package/src/modules/catalog/seed/examples.ts +7 -0
- package/src/modules/customers/api/interactions/route.ts +2 -2
- package/src/modules/customers/components/detail/AssignRoleDialog.tsx +9 -12
- package/src/modules/customers/i18n/de.json +2 -1
- package/src/modules/customers/i18n/en.json +2 -1
- package/src/modules/customers/i18n/es.json +2 -1
- package/src/modules/customers/i18n/ko.json +2 -1
- package/src/modules/customers/i18n/pl.json +2 -1
- package/src/modules/customers/migrations/Migration20260825140000_customers.ts +21 -10
- package/src/modules/entities/cli.ts +144 -65
- package/src/modules/promotions/commands/codes.ts +19 -4
- package/src/modules/query_index/cli.ts +17 -1
- package/src/modules/query_index/lib/reindexer.ts +55 -6
- package/src/modules/sales/commands/configuration.ts +35 -16
- package/src/modules/sales/components/documents/AddressesSection.tsx +51 -20
- package/src/modules/sales/i18n/de.json +3 -0
- package/src/modules/sales/i18n/en.json +3 -0
- package/src/modules/sales/i18n/es.json +3 -0
- package/src/modules/sales/i18n/ko.json +3 -0
- package/src/modules/sales/i18n/pl.json +4 -1
- package/src/modules/sales/seed/examples.ts +41 -6
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/catalog/seed/examples.ts"],
|
|
4
|
-
"sourcesContent": ["import { randomUUID } from \"node:crypto\";\nimport path from \"node:path\";\nimport { promises as fs } from \"node:fs\";\nimport type { EntityManager } from \"@mikro-orm/postgresql\";\nimport type { AwilixContainer } from \"awilix\";\nimport { SalesChannel } from \"@open-mercato/core/modules/sales/data/entities\";\nimport {\n CatalogOffer,\n CatalogPriceKind,\n CatalogProduct,\n CatalogProductCategory,\n CatalogProductCategoryAssignment,\n CatalogProductPrice,\n CatalogProductVariant,\n} from \"../data/entities\";\nimport { DefaultDataEngine } from \"@open-mercato/shared/lib/data/engine\";\nimport {\n ensureCustomFieldDefinitions,\n type FieldSetInput,\n} from \"@open-mercato/core/modules/entities/lib/field-definitions\";\nimport { CustomFieldEntityConfig } from \"@open-mercato/core/modules/entities/data/entities\";\nimport { rebuildCategoryHierarchyForOrganization } from \"../lib/categoryHierarchy\";\nimport { defineFields, cf } from \"@open-mercato/shared/modules/dsl\";\nimport { E } from \"#generated/entities.ids.generated\";\nimport { SalesTaxRate } from \"@open-mercato/core/modules/sales/data/entities\";\nimport {\n Attachment,\n AttachmentPartition,\n} from \"@open-mercato/core/modules/attachments/data/entities\";\nimport {\n ensureDefaultPartitions,\n resolveDefaultPartitionCode,\n} from \"@open-mercato/core/modules/attachments/lib/partitions\";\nimport { storePartitionFile } from \"@open-mercato/core/modules/attachments/lib/storage\";\nimport { mergeAttachmentMetadata } from \"@open-mercato/core/modules/attachments/lib/metadata\";\nimport {\n buildAttachmentFileUrl,\n buildAttachmentImageUrl,\n slugifyAttachmentFileName,\n} from \"@open-mercato/core/modules/attachments/lib/imageUrls\";\nimport { canonicalizeUnitCode } from \"../lib/unitCodes\";\nimport { createLogger } from '@open-mercato/shared/lib/logger';\n\nconst logger = createLogger('catalog');\n\ntype SeedScope = { tenantId: string; organizationId: string };\n\nconst EXAMPLES_MEDIA_ROOT = path.join(process.cwd(), \"public\", \"examples\");\n\nfunction detectMimeType(fileName: string): string {\n const ext = fileName.toLowerCase().split(\".\").pop() || \"\";\n if (ext === \"png\") return \"image/png\";\n if (ext === \"jpg\" || ext === \"jpeg\") return \"image/jpeg\";\n if (ext === \"webp\") return \"image/webp\";\n return \"application/octet-stream\";\n}\n\nasync function ensureAttachmentPartition(\n em: EntityManager,\n code: string,\n): Promise<AttachmentPartition> {\n let partition = await em.findOne(AttachmentPartition, { code });\n if (!partition) {\n await ensureDefaultPartitions(em);\n partition = await em.findOne(AttachmentPartition, { code });\n }\n if (!partition) {\n throw new Error(`Attachment partition \"${code}\" is not configured.`);\n }\n return partition;\n}\n\nasync function attachMediaFromExamples(\n em: EntityManager,\n scope: SeedScope,\n entityId: string,\n recordId: string,\n mediaSeeds?: MediaSeed[],\n): Promise<Array<{ id: string; imageUrl: string }>> {\n if (!mediaSeeds?.length) return [];\n const partitionCode = resolveDefaultPartitionCode(entityId);\n const partition = await ensureAttachmentPartition(em, partitionCode);\n const results: Array<{ id: string; imageUrl: string }> = [];\n for (const media of mediaSeeds) {\n const sourcePath = path.join(EXAMPLES_MEDIA_ROOT, media.file);\n let buffer: Buffer;\n try {\n buffer = await fs.readFile(sourcePath);\n } catch (error) {\n logger.warn('catalog.seed example media missing', { sourcePath });\n continue;\n }\n const stored = await storePartitionFile({\n partitionCode: partition.code,\n orgId: scope.organizationId,\n tenantId: scope.tenantId,\n fileName: media.file,\n buffer,\n });\n const attachmentId = randomUUID();\n const slug = slugifyAttachmentFileName(media.file, \"media\");\n const metadata = mergeAttachmentMetadata(null, {\n assignments: [{ type: entityId, id: recordId }],\n });\n const attachment = em.create(Attachment, {\n id: attachmentId,\n entityId,\n recordId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n partitionCode: partition.code,\n fileName: media.file,\n mimeType: detectMimeType(media.file),\n fileSize: buffer.length,\n storageDriver: partition.storageDriver || \"local\",\n storagePath: stored.storagePath,\n storageMetadata: metadata,\n url: buildAttachmentFileUrl(attachmentId),\n });\n em.persist(attachment);\n results.push({\n id: attachmentId,\n imageUrl: buildAttachmentImageUrl(attachmentId, { slug }),\n });\n }\n return results;\n}\n\nconst PRODUCT_FIELDSETS = [\n {\n code: \"fashion_mens_footwear\",\n label: \"Fashion \u00B7 Men \u00B7 Footwear\",\n icon: \"carbon:sneaker\",\n description:\n \"Material, construction, and care metadata for men\u2019s performance footwear.\",\n groups: [\n { code: \"identity\", title: \"Identity\" },\n { code: \"materials\", title: \"Materials & Build\" },\n { code: \"care\", title: \"Care instructions\" },\n ],\n },\n {\n code: \"fashion_womens_dresses\",\n label: \"Fashion \u00B7 Women \u00B7 Dresses & Jumpsuits\",\n icon: \"solar:dress-linear\",\n description: \"Silhouette, fabric, and care metadata for womenswear.\",\n groups: [\n { code: \"identity\", title: \"Identity\" },\n { code: \"materials\", title: \"Materials\" },\n { code: \"fit\", title: \"Fit & Length\" },\n { code: \"care\", title: \"Care instructions\" },\n ],\n },\n {\n code: \"service_schedule\",\n label: \"Services \u00B7 Scheduling\",\n icon: \"solar:calendar-linear\",\n description:\n \"Scheduling, preparation, and delivery metadata for service offerings.\",\n groups: [\n { code: \"identity\", title: \"Identity\" },\n { code: \"timing\", title: \"Timing rules\" },\n { code: \"resources\", title: \"Resources & Delivery\" },\n ],\n },\n] as const;\n\nconst VARIANT_FIELDSETS = [\n {\n code: \"fashion_mens_footwear\",\n label: \"Fashion \u00B7 Men \u00B7 Footwear\",\n icon: \"carbon:sneaker\",\n description: \"Variant-level sizing metadata for men\u2019s footwear.\",\n groups: [\n { code: \"fit\", title: \"Fit\" },\n { code: \"finish\", title: \"Finish\" },\n ],\n },\n {\n code: \"fashion_womens_dresses\",\n label: \"Fashion \u00B7 Women \u00B7 Dresses & Jumpsuits\",\n icon: \"solar:dress-linear\",\n description: \"Variant-level sizing metadata for womenswear.\",\n groups: [\n { code: \"fit\", title: \"Fit\" },\n { code: \"finish\", title: \"Finish\" },\n ],\n },\n {\n code: \"service_schedule\",\n label: \"Services \u00B7 Scheduling\",\n icon: \"solar:calendar-linear\",\n description:\n \"Provider, duration, and environment metadata for service slots.\",\n groups: [\n { code: \"provider\", title: \"Provider\" },\n { code: \"environment\", title: \"Environment\" },\n ],\n },\n] as const;\n\nconst CUSTOM_FIELD_SETS: FieldSetInput[] = [\n defineFields(E.catalog.catalog_product, [\n cf.text(\"style_code\", {\n label: \"Style code\",\n description: \"Reference code shared with merchandising teams.\",\n filterable: true,\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"identity\" },\n }),\n cf.select(\n \"upper_material\",\n [\"engineered_knit\", \"full_grain_leather\", \"recycled_mesh\"],\n {\n label: \"Upper material\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"materials\" },\n filterable: true,\n },\n ),\n cf.select(\"cushioning_profile\", [\"responsive\", \"plush\", \"stability\"], {\n label: \"Cushioning profile\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"materials\" },\n }),\n cf.multiline(\"care_notes\", {\n label: \"Care notes\",\n editor: \"markdown\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"care\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product, [\n cf.select(\"silhouette\", [\"wrap\", \"column\", \"fit_and_flare\", \"jumpsuit\"], {\n label: \"Silhouette\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"identity\" },\n filterable: true,\n }),\n cf.select(\"fabric_mix\", [\"silk_blend\", \"recycled_poly\", \"linen\", \"cupro\"], {\n label: \"Fabric mix\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"materials\" },\n }),\n cf.select(\"occasion_ready\", [\"daytime\", \"evening\", \"resort\"], {\n label: \"Occasion\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"fit\" },\n }),\n cf.multiline(\"finishing_details\", {\n label: \"Finishing details\",\n editor: \"markdown\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"care\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.integer(\"shoe_size\", {\n label: \"US size\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"fit\" },\n filterable: true,\n }),\n cf.select(\"shoe_width\", [\"B\", \"D\", \"EE\"], {\n label: \"Width\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"fit\" },\n }),\n cf.text(\"colorway\", {\n label: \"Colorway\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"finish\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.integer(\"numeric_size\", {\n label: \"Numeric size\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"fit\" },\n }),\n cf.select(\"length_profile\", [\"mini\", \"midi\", \"maxi\"], {\n label: \"Length\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"fit\" },\n }),\n cf.text(\"color_story\", {\n label: \"Color story\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"finish\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product, [\n cf.integer(\"service_duration_minutes\", {\n label: \"Duration (minutes)\",\n description: \"Length of a single service slot.\",\n fieldset: \"service_schedule\",\n group: { code: \"timing\" },\n filterable: true,\n required: true,\n }),\n cf.integer(\"service_buffer_minutes\", {\n label: \"Buffer between appointments\",\n description:\n \"Minimum downtime between consecutive service slots (minutes).\",\n fieldset: \"service_schedule\",\n group: { code: \"timing\" },\n }),\n cf.text(\"service_location\", {\n label: \"Location / Room\",\n description: \"Where the service is delivered.\",\n fieldset: \"service_schedule\",\n group: { code: \"identity\" },\n }),\n cf.select(\n \"service_resources\",\n [\"stylist\", \"therapist\", \"treatment_room\", \"wash_station\", \"steam_room\"],\n {\n label: \"Required resources\",\n description: \"Staff or rooms required to perform the service.\",\n fieldset: \"service_schedule\",\n group: { code: \"resources\" },\n multi: true,\n },\n ),\n cf.boolean(\"service_remote_available\", {\n label: \"Remote session available\",\n description:\n \"Indicates whether the service can be performed remotely or virtually.\",\n fieldset: \"service_schedule\",\n group: { code: \"resources\" },\n defaultValue: false,\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.select(\"provider_level\", [\"junior\", \"senior\", \"master\"], {\n label: \"Provider level\",\n description: \"Seniority of the assigned specialist.\",\n fieldset: \"service_schedule\",\n group: { code: \"provider\" },\n filterable: true,\n }),\n cf.text(\"staff_member\", {\n label: \"Staff member\",\n description:\n \"Optional name of the staff member who usually delivers this variant.\",\n fieldset: \"service_schedule\",\n group: { code: \"provider\" },\n }),\n cf.select(\"environment_type\", [\"studio\", \"suite\", \"on_site\"], {\n label: \"Environment\",\n description: \"Where the session is hosted.\",\n fieldset: \"service_schedule\",\n group: { code: \"environment\" },\n }),\n ]),\n];\n\ntype CategorySeed = {\n slug: string;\n name: string;\n description?: string;\n children?: CategorySeed[];\n};\n\nconst CATEGORY_TREE: CategorySeed[] = [\n {\n slug: \"fashion\",\n name: \"Fashion\",\n description: \"Seasonal assortments and vertical-specific collections.\",\n children: [\n {\n slug: \"fashion-men\",\n name: \"Men\",\n children: [\n {\n slug: \"fashion-men-footwear\",\n name: \"Footwear\",\n description: \"Premium sneakers, boots, and sandals.\",\n },\n ],\n },\n {\n slug: \"fashion-women\",\n name: \"Women\",\n children: [\n {\n slug: \"fashion-women-dresses-jumpsuits\",\n name: \"Dresses & Jumpsuits\",\n description: \"Occasion-ready dresses and tailored jumpsuits.\",\n },\n ],\n },\n ],\n },\n {\n slug: \"services\",\n name: \"Services\",\n description: \"Bookable in-person and virtual experiences.\",\n children: [\n {\n slug: \"services-hairdresser\",\n name: \"Hairdresser\",\n description:\n \"Salon services ranging from quick trims to signature looks.\",\n },\n {\n slug: \"services-massage\",\n name: \"Massage\",\n description: \"Wellness treatments and bodywork sessions.\",\n },\n ],\n },\n];\n\ntype MediaSeed = {\n file: string;\n title?: string;\n};\n\ntype VariantSeed = {\n name: string;\n sku: string;\n isDefault?: boolean;\n optionValues?: Record<string, string>;\n prices: {\n regular: number;\n sale?: number;\n };\n customFields?: Record<string, string | number | boolean | null>;\n media?: MediaSeed[];\n};\n\ntype ProductSeed = {\n title: string;\n handle: string;\n sku?: string;\n description: string;\n categorySlug: string;\n customFieldsetCode: string;\n variantFieldsetCode: string;\n unit: string;\n metadata?: Record<string, unknown>;\n customFields?: Record<string, string | number | boolean | null>;\n media?: MediaSeed[];\n variants: VariantSeed[];\n};\n\nconst PRODUCT_SEEDS: ProductSeed[] = [\n {\n title: \"Atlas Runner Sneaker\",\n handle: \"atlas-runner-sneaker\",\n sku: \"ATLAS-RUNNER\",\n description:\n \"Lightweight road sneaker engineered with a breathable knit upper, recycled TPU overlays, and a decoupled heel for smooth transitions.\",\n categorySlug: \"fashion-men-footwear\",\n customFieldsetCode: \"fashion_mens_footwear\",\n variantFieldsetCode: \"fashion_mens_footwear\",\n unit: \"pair\",\n metadata: { division: \"RunLab\", season: \"SS25\" },\n customFields: {\n style_code: \"AR-2025\",\n upper_material: \"engineered_knit\",\n cushioning_profile: \"responsive\",\n care_notes:\n \"Spot clean after each run and air dry. Avoid machine drying.\",\n },\n media: [{ file: \"atlas-runner-midnight-1.png\" }],\n variants: [\n {\n name: \"Midnight Navy \u00B7 US 8\",\n sku: \"ATLAS-RUN-NAVY-8\",\n isDefault: true,\n optionValues: { color: \"Midnight Navy\", size: \"US 8\" },\n prices: { regular: 168, sale: 148 },\n customFields: {\n shoe_size: 8,\n shoe_width: \"D\",\n colorway: \"Midnight Navy\",\n },\n media: [\n { file: \"atlas-runner-midnight-1.png\" },\n { file: \"atlas-runner-midnight-2.png\" },\n ],\n },\n {\n name: \"Glacier Grey \u00B7 US 10\",\n sku: \"ATLAS-RUN-GLACIER-10\",\n optionValues: { color: \"Glacier Grey\", size: \"US 10\" },\n prices: { regular: 168, sale: 138 },\n customFields: {\n shoe_size: 10,\n shoe_width: \"EE\",\n colorway: \"Glacier Grey\",\n },\n media: [\n { file: \"atlas-runner-glacier-1.png\" },\n { file: \"atlas-runner-glacier-2.png\" },\n ],\n },\n ],\n },\n {\n title: \"Aurora Wrap Dress\",\n handle: \"aurora-wrap-dress\",\n sku: \"AURORA-WRAP\",\n description:\n \"Bias-cut wrap dress with blouson sleeves, matte silk blend, and hidden interior snaps so the placket stays put at events.\",\n categorySlug: \"fashion-women-dresses-jumpsuits\",\n customFieldsetCode: \"fashion_womens_dresses\",\n variantFieldsetCode: \"fashion_womens_dresses\",\n unit: \"unit\",\n metadata: { capsule: \"Evening Atelier\", season: \"Resort 25\" },\n customFields: {\n silhouette: \"wrap\",\n fabric_mix: \"silk_blend\",\n occasion_ready: \"evening\",\n finishing_details:\n \"Hand-finished hem with subtle tonal beading along the wrap edge.\",\n },\n media: [{ file: \"aurora-wrap-rosewood.png\" }],\n variants: [\n {\n name: \"Rosewood \u00B7 Medium\",\n sku: \"AURORA-ROSE-M\",\n isDefault: true,\n optionValues: { color: \"Rosewood\", size: \"Medium\" },\n prices: { regular: 248, sale: 212 },\n customFields: {\n numeric_size: 6,\n length_profile: \"midi\",\n color_story: \"Rosewood\",\n },\n media: [{ file: \"aurora-wrap-rosewood.png\" }],\n },\n {\n name: \"Celestial \u00B7 Large\",\n sku: \"AURORA-CELESTIAL-L\",\n optionValues: { color: \"Celestial\", size: \"Large\" },\n prices: { regular: 248, sale: 198 },\n customFields: {\n numeric_size: 8,\n length_profile: \"maxi\",\n color_story: \"Celestial blue\",\n },\n media: [{ file: \"aurora-wrap-celestial.png\" }],\n },\n ],\n },\n {\n title: \"Signature Haircut & Finish\",\n handle: \"signature-haircut-service\",\n sku: \"SERV-HAIR-60\",\n description:\n \"Tailored haircut with relaxing wash, scalp massage, and styling finish. Designed for repeat visits in the demo portal.\",\n categorySlug: \"services-hairdresser\",\n customFieldsetCode: \"service_schedule\",\n variantFieldsetCode: \"service_schedule\",\n unit: \"hour\",\n metadata: { channel: \"salon\", serviceType: \"hairdresser\" },\n customFields: {\n service_duration_minutes: 60,\n service_buffer_minutes: 15,\n service_location: \"Salon Studio 3\",\n service_resources: \"stylist,wash_station\",\n service_remote_available: false,\n },\n media: [{ file: \"hairdresser-service.png\" }],\n variants: [\n {\n name: \"Senior Stylist \u00B7 60 min\",\n sku: \"SERV-HAIR-60-SENIOR\",\n isDefault: true,\n optionValues: { stylist: \"Senior\", duration: \"60\" },\n prices: { regular: 95, sale: 85 },\n customFields: {\n provider_level: \"senior\",\n staff_member: \"Amelia Hart\",\n environment_type: \"studio\",\n },\n media: [{ file: \"hairdresser-service.png\" }],\n },\n ],\n },\n {\n title: \"Restorative Massage Session\",\n handle: \"restorative-massage-service\",\n sku: \"SERV-MASSAGE-90\",\n description:\n \"Full-body massage with aromatherapy oils and guided breathing. Includes complimentary refreshments and studio amenities.\",\n categorySlug: \"services-massage\",\n customFieldsetCode: \"service_schedule\",\n variantFieldsetCode: \"service_schedule\",\n unit: \"hour\",\n metadata: { channel: \"wellness\", serviceType: \"massage\" },\n customFields: {\n service_duration_minutes: 90,\n service_buffer_minutes: 20,\n service_location: \"Wellness Suite B\",\n service_resources: \"therapist,treatment_room,steam_room\",\n service_remote_available: false,\n },\n media: [{ file: \"massage-service.png\" }],\n variants: [\n {\n name: \"Master Therapist \u00B7 90 min\",\n sku: \"SERV-MASSAGE-90-MASTER\",\n isDefault: true,\n optionValues: { therapist: \"Master\", duration: \"90\" },\n prices: { regular: 140, sale: 120 },\n customFields: {\n provider_level: \"master\",\n staff_member: \"Noah Li\",\n environment_type: \"suite\",\n },\n media: [{ file: \"massage-service.png\" }],\n },\n ],\n },\n];\n\nconst CHANNEL_DEFINITION = {\n code: \"fashion-online\",\n name: \"Mercato Fashion Online\",\n description: \"Direct-to-consumer storefront showcasing premium demos.\",\n websiteUrl: \"https://demo.open-mercato.com\",\n contactEmail: \"store@open-mercato.com\",\n};\n\nfunction formatMoney(value: number): string {\n return value.toFixed(2);\n}\n\nasync function resolveDefaultTaxRate(\n em: EntityManager,\n scope: SeedScope,\n): Promise<SalesTaxRate | null> {\n const [rate] = await em.find(\n SalesTaxRate,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n deletedAt: null,\n },\n {\n limit: 1,\n orderBy: {\n isDefault: \"DESC\",\n priority: \"ASC\",\n rate: \"DESC\",\n createdAt: \"ASC\",\n },\n },\n );\n return rate ?? null;\n}\n\nasync function ensureFieldsetConfig(\n em: EntityManager,\n scope: SeedScope,\n entityId: string,\n fieldsets: typeof PRODUCT_FIELDSETS | typeof VARIANT_FIELDSETS,\n): Promise<void> {\n const now = new Date();\n let config = await em.findOne(CustomFieldEntityConfig, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n });\n if (!config) {\n config = em.create(CustomFieldEntityConfig, {\n id: randomUUID(),\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n isActive: true,\n createdAt: now,\n updatedAt: now,\n });\n }\n config.configJson = {\n fieldsets,\n singleFieldsetPerRecord: true,\n };\n config.isActive = true;\n config.updatedAt = now;\n em.persist(config);\n}\n\nasync function ensureFieldsetsAndDefinitions(\n em: EntityManager,\n scope: SeedScope,\n): Promise<void> {\n await ensureFieldsetConfig(\n em,\n scope,\n E.catalog.catalog_product,\n PRODUCT_FIELDSETS,\n );\n await ensureFieldsetConfig(\n em,\n scope,\n E.catalog.catalog_product_variant,\n VARIANT_FIELDSETS,\n );\n await ensureCustomFieldDefinitions(em, CUSTOM_FIELD_SETS, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n });\n await em.flush();\n}\n\nasync function ensureCategories(\n em: EntityManager,\n scope: SeedScope,\n): Promise<Map<string, CatalogProductCategory>> {\n const map = new Map<string, CatalogProductCategory>();\n const now = new Date();\n\n const upsert = async (\n seed: CategorySeed,\n parent: CatalogProductCategory | null,\n ) => {\n let record = await em.findOne(CatalogProductCategory, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n slug: seed.slug,\n });\n if (!record) {\n record = em.create(CatalogProductCategory, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n name: seed.name,\n slug: seed.slug,\n description: seed.description ?? null,\n parentId: parent ? parent.id : null,\n rootId: parent ? (parent.rootId ?? parent.id) : null,\n treePath: null,\n depth: parent ? (parent.depth ?? 0) + 1 : 0,\n ancestorIds: [],\n childIds: [],\n descendantIds: [],\n metadata: null,\n isActive: true,\n createdAt: now,\n updatedAt: now,\n });\n em.persist(record);\n } else {\n record.name = seed.name;\n record.description = seed.description ?? null;\n record.parentId = parent ? parent.id : null;\n record.isActive = true;\n record.updatedAt = now;\n }\n map.set(seed.slug, record);\n if (Array.isArray(seed.children)) {\n for (const child of seed.children) {\n await upsert(child, record);\n }\n }\n };\n\n for (const seed of CATEGORY_TREE) {\n await upsert(seed, null);\n }\n\n await em.flush();\n await rebuildCategoryHierarchyForOrganization(\n em,\n scope.organizationId,\n scope.tenantId,\n );\n\n return map;\n}\n\nasync function ensureChannel(\n em: EntityManager,\n scope: SeedScope,\n): Promise<SalesChannel> {\n const now = new Date();\n let channel = await em.findOne(SalesChannel, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n code: CHANNEL_DEFINITION.code,\n deletedAt: null,\n });\n if (!channel) {\n channel = em.create(SalesChannel, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n code: CHANNEL_DEFINITION.code,\n name: CHANNEL_DEFINITION.name,\n description: CHANNEL_DEFINITION.description,\n websiteUrl: CHANNEL_DEFINITION.websiteUrl,\n contactEmail: CHANNEL_DEFINITION.contactEmail,\n status: \"active\",\n isActive: true,\n metadata: { locale: \"en-US\" },\n createdAt: now,\n updatedAt: now,\n });\n em.persist(channel);\n await em.flush();\n }\n return channel;\n}\n\nasync function loadPriceKinds(\n em: EntityManager,\n scope: SeedScope,\n): Promise<Map<string, CatalogPriceKind>> {\n const kinds = await em.find(CatalogPriceKind, {\n tenantId: scope.tenantId,\n code: { $in: [\"regular\", \"sale\"] },\n deletedAt: null,\n });\n const map = new Map<string, CatalogPriceKind>();\n for (const kind of kinds) {\n map.set(kind.code.toLowerCase(), kind);\n }\n return map;\n}\n\nexport async function seedCatalogExamples(\n em: EntityManager,\n container: AwilixContainer,\n scope: SeedScope,\n): Promise<boolean> {\n if (!em.getMetadata().has(SalesChannel)) return false;\n\n await ensureFieldsetsAndDefinitions(em, scope);\n await ensureDefaultPartitions(em);\n\n const handles = PRODUCT_SEEDS.map((seed) => seed.handle);\n const existingProducts = await em.find(CatalogProduct, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n handle: { $in: [...handles] },\n });\n const existingByHandle = new Map(\n existingProducts.map((product) => [product.handle?.toLowerCase(), product]),\n );\n\n const categoryMap = await ensureCategories(em, scope);\n const channel = await ensureChannel(em, scope);\n const priceKinds = await loadPriceKinds(em, scope);\n const regularKind = priceKinds.get(\"regular\");\n const saleKind = priceKinds.get(\"sale\");\n const defaultTaxRate = await resolveDefaultTaxRate(em, scope);\n const defaultTaxRateId = defaultTaxRate?.id ?? null;\n const defaultTaxRateValue = defaultTaxRate?.rate ?? null;\n if (!regularKind || !saleKind) {\n throw new Error(\n \"Missing catalog price kinds; run `mercato catalog seed-price-kinds` first.\",\n );\n }\n\n const dataEngine = new DefaultDataEngine(em, container);\n const customFieldAssignments: Array<() => Promise<void>> = [];\n let createdAny = false;\n\n for (const productSeed of PRODUCT_SEEDS) {\n const existing = existingByHandle.get(productSeed.handle.toLowerCase());\n if (existing) {\n continue;\n }\n createdAny = true;\n const product = em.create(CatalogProduct, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: productSeed.title,\n description: productSeed.description,\n sku: productSeed.sku ?? null,\n handle: productSeed.handle,\n productType: \"configurable\",\n primaryCurrencyCode: \"USD\",\n defaultUnit: canonicalizeUnitCode(productSeed.unit) ?? productSeed.unit,\n customFieldsetCode: productSeed.customFieldsetCode,\n metadata: productSeed.metadata ?? null,\n taxRateId: defaultTaxRateId,\n taxRate: defaultTaxRateValue,\n isConfigurable: true,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(product);\n\n const category = categoryMap.get(productSeed.categorySlug);\n if (category) {\n const assignment = em.create(CatalogProductCategoryAssignment, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n category,\n position: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(assignment);\n }\n\n const offer = em.create(CatalogOffer, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n channelId: channel.id,\n title: `${productSeed.title} \u00B7 Online`,\n description: \"Offer curated for the demo storefront channel.\",\n metadata: { channelCode: CHANNEL_DEFINITION.code },\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(offer);\n\n if (\n productSeed.customFields &&\n Object.keys(productSeed.customFields).length\n ) {\n const payload = { ...productSeed.customFields };\n customFieldAssignments.push(() =>\n dataEngine.setCustomFields({\n entityId: E.catalog.catalog_product,\n recordId: product.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: payload,\n }),\n );\n }\n\n const productMedia = await attachMediaFromExamples(\n em,\n scope,\n E.catalog.catalog_product,\n product.id,\n productSeed.media,\n );\n if (productMedia.length) {\n const hero = productMedia[0];\n product.defaultMediaId = hero.id;\n product.defaultMediaUrl = hero.imageUrl;\n offer.defaultMediaId = hero.id;\n offer.defaultMediaUrl = hero.imageUrl;\n }\n\n for (const variantSeed of productSeed.variants) {\n const variant = em.create(CatalogProductVariant, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n name: variantSeed.name,\n sku: variantSeed.sku,\n isDefault: variantSeed.isDefault ?? false,\n optionValues: variantSeed.optionValues ?? null,\n customFieldsetCode: productSeed.variantFieldsetCode,\n metadata: null,\n taxRateId: defaultTaxRateId,\n taxRate: defaultTaxRateValue,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(variant);\n\n const variantMedia = await attachMediaFromExamples(\n em,\n scope,\n E.catalog.catalog_product_variant,\n variant.id,\n variantSeed.media,\n );\n const regularPrice = em.create(CatalogProductPrice, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n variant,\n offer,\n priceKind: regularKind,\n currencyCode: \"USD\",\n kind: regularKind.code,\n minQuantity: 1,\n taxRate: defaultTaxRateValue,\n unitPriceGross: formatMoney(variantSeed.prices.regular),\n unitPriceNet: formatMoney(variantSeed.prices.regular),\n channelId: channel.id,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(regularPrice);\n\n if (variantSeed.prices.sale !== undefined) {\n const salePrice = em.create(CatalogProductPrice, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n variant,\n offer,\n priceKind: saleKind,\n currencyCode: \"USD\",\n kind: saleKind.code,\n minQuantity: 1,\n taxRate: defaultTaxRateValue,\n unitPriceGross: formatMoney(variantSeed.prices.sale),\n unitPriceNet: formatMoney(variantSeed.prices.sale),\n channelId: channel.id,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(salePrice);\n }\n\n if (\n variantSeed.customFields &&\n Object.keys(variantSeed.customFields).length\n ) {\n const payload = { ...variantSeed.customFields };\n customFieldAssignments.push(() =>\n dataEngine.setCustomFields({\n entityId: E.catalog.catalog_product_variant,\n recordId: variant.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: payload,\n }),\n );\n }\n }\n }\n\n if (!createdAny) {\n return false;\n }\n\n await em.flush();\n\n for (const assign of customFieldAssignments) {\n try {\n await assign();\n } catch (err) {\n logger.warn(\"catalog.seed failed to set example custom field values\", { err });\n }\n }\n\n return true;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { randomUUID } from \"node:crypto\";\nimport path from \"node:path\";\nimport { promises as fs } from \"node:fs\";\nimport type { EntityManager } from \"@mikro-orm/postgresql\";\nimport type { AwilixContainer } from \"awilix\";\nimport { SalesChannel } from \"@open-mercato/core/modules/sales/data/entities\";\nimport {\n CatalogOffer,\n CatalogPriceKind,\n CatalogProduct,\n CatalogProductCategory,\n CatalogProductCategoryAssignment,\n CatalogProductPrice,\n CatalogProductVariant,\n} from \"../data/entities\";\nimport { DefaultDataEngine } from \"@open-mercato/shared/lib/data/engine\";\nimport {\n ensureCustomFieldDefinitions,\n type FieldSetInput,\n} from \"@open-mercato/core/modules/entities/lib/field-definitions\";\nimport { CustomFieldEntityConfig } from \"@open-mercato/core/modules/entities/data/entities\";\nimport { rebuildCategoryHierarchyForOrganization } from \"../lib/categoryHierarchy\";\nimport { defineFields, cf } from \"@open-mercato/shared/modules/dsl\";\nimport { E } from \"#generated/entities.ids.generated\";\nimport { SalesTaxRate } from \"@open-mercato/core/modules/sales/data/entities\";\nimport {\n Attachment,\n AttachmentPartition,\n} from \"@open-mercato/core/modules/attachments/data/entities\";\nimport {\n ensureDefaultPartitions,\n resolveDefaultPartitionCode,\n} from \"@open-mercato/core/modules/attachments/lib/partitions\";\nimport { storePartitionFile } from \"@open-mercato/core/modules/attachments/lib/storage\";\nimport { mergeAttachmentMetadata } from \"@open-mercato/core/modules/attachments/lib/metadata\";\nimport {\n buildAttachmentFileUrl,\n buildAttachmentImageUrl,\n slugifyAttachmentFileName,\n} from \"@open-mercato/core/modules/attachments/lib/imageUrls\";\nimport { canonicalizeUnitCode } from \"../lib/unitCodes\";\nimport { createLogger } from '@open-mercato/shared/lib/logger';\n\nconst logger = createLogger('catalog');\n\ntype SeedScope = { tenantId: string; organizationId: string };\n\nconst EXAMPLES_MEDIA_ROOT = path.join(process.cwd(), \"public\", \"examples\");\n\nfunction detectMimeType(fileName: string): string {\n const ext = fileName.toLowerCase().split(\".\").pop() || \"\";\n if (ext === \"png\") return \"image/png\";\n if (ext === \"jpg\" || ext === \"jpeg\") return \"image/jpeg\";\n if (ext === \"webp\") return \"image/webp\";\n return \"application/octet-stream\";\n}\n\nasync function ensureAttachmentPartition(\n em: EntityManager,\n code: string,\n): Promise<AttachmentPartition> {\n let partition = await em.findOne(AttachmentPartition, { code });\n if (!partition) {\n await ensureDefaultPartitions(em);\n partition = await em.findOne(AttachmentPartition, { code });\n }\n if (!partition) {\n throw new Error(`Attachment partition \"${code}\" is not configured.`);\n }\n return partition;\n}\n\nasync function attachMediaFromExamples(\n em: EntityManager,\n scope: SeedScope,\n entityId: string,\n recordId: string,\n mediaSeeds?: MediaSeed[],\n): Promise<Array<{ id: string; imageUrl: string }>> {\n if (!mediaSeeds?.length) return [];\n const partitionCode = resolveDefaultPartitionCode(entityId);\n const partition = await ensureAttachmentPartition(em, partitionCode);\n const results: Array<{ id: string; imageUrl: string }> = [];\n for (const media of mediaSeeds) {\n const sourcePath = path.join(EXAMPLES_MEDIA_ROOT, media.file);\n let buffer: Buffer;\n try {\n buffer = await fs.readFile(sourcePath);\n } catch (error) {\n logger.warn('catalog.seed example media missing', { sourcePath });\n continue;\n }\n const stored = await storePartitionFile({\n partitionCode: partition.code,\n orgId: scope.organizationId,\n tenantId: scope.tenantId,\n fileName: media.file,\n buffer,\n });\n const attachmentId = randomUUID();\n const slug = slugifyAttachmentFileName(media.file, \"media\");\n const metadata = mergeAttachmentMetadata(null, {\n assignments: [{ type: entityId, id: recordId }],\n });\n const attachment = em.create(Attachment, {\n id: attachmentId,\n entityId,\n recordId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n partitionCode: partition.code,\n fileName: media.file,\n mimeType: detectMimeType(media.file),\n fileSize: buffer.length,\n storageDriver: partition.storageDriver || \"local\",\n storagePath: stored.storagePath,\n storageMetadata: metadata,\n url: buildAttachmentFileUrl(attachmentId),\n });\n em.persist(attachment);\n results.push({\n id: attachmentId,\n imageUrl: buildAttachmentImageUrl(attachmentId, { slug }),\n });\n }\n return results;\n}\n\nconst PRODUCT_FIELDSETS = [\n {\n code: \"fashion_mens_footwear\",\n label: \"Fashion \u00B7 Men \u00B7 Footwear\",\n icon: \"carbon:sneaker\",\n description:\n \"Material, construction, and care metadata for men\u2019s performance footwear.\",\n groups: [\n { code: \"identity\", title: \"Identity\" },\n { code: \"materials\", title: \"Materials & Build\" },\n { code: \"care\", title: \"Care instructions\" },\n ],\n },\n {\n code: \"fashion_womens_dresses\",\n label: \"Fashion \u00B7 Women \u00B7 Dresses & Jumpsuits\",\n icon: \"solar:dress-linear\",\n description: \"Silhouette, fabric, and care metadata for womenswear.\",\n groups: [\n { code: \"identity\", title: \"Identity\" },\n { code: \"materials\", title: \"Materials\" },\n { code: \"fit\", title: \"Fit & Length\" },\n { code: \"care\", title: \"Care instructions\" },\n ],\n },\n {\n code: \"service_schedule\",\n label: \"Services \u00B7 Scheduling\",\n icon: \"solar:calendar-linear\",\n description:\n \"Scheduling, preparation, and delivery metadata for service offerings.\",\n groups: [\n { code: \"identity\", title: \"Identity\" },\n { code: \"timing\", title: \"Timing rules\" },\n { code: \"resources\", title: \"Resources & Delivery\" },\n ],\n },\n] as const;\n\nconst VARIANT_FIELDSETS = [\n {\n code: \"fashion_mens_footwear\",\n label: \"Fashion \u00B7 Men \u00B7 Footwear\",\n icon: \"carbon:sneaker\",\n description: \"Variant-level sizing metadata for men\u2019s footwear.\",\n groups: [\n { code: \"fit\", title: \"Fit\" },\n { code: \"finish\", title: \"Finish\" },\n ],\n },\n {\n code: \"fashion_womens_dresses\",\n label: \"Fashion \u00B7 Women \u00B7 Dresses & Jumpsuits\",\n icon: \"solar:dress-linear\",\n description: \"Variant-level sizing metadata for womenswear.\",\n groups: [\n { code: \"fit\", title: \"Fit\" },\n { code: \"finish\", title: \"Finish\" },\n ],\n },\n {\n code: \"service_schedule\",\n label: \"Services \u00B7 Scheduling\",\n icon: \"solar:calendar-linear\",\n description:\n \"Provider, duration, and environment metadata for service slots.\",\n groups: [\n { code: \"provider\", title: \"Provider\" },\n { code: \"environment\", title: \"Environment\" },\n ],\n },\n] as const;\n\nconst CUSTOM_FIELD_SETS: FieldSetInput[] = [\n defineFields(E.catalog.catalog_product, [\n cf.text(\"style_code\", {\n label: \"Style code\",\n description: \"Reference code shared with merchandising teams.\",\n filterable: true,\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"identity\" },\n }),\n cf.select(\n \"upper_material\",\n [\"engineered_knit\", \"full_grain_leather\", \"recycled_mesh\"],\n {\n label: \"Upper material\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"materials\" },\n filterable: true,\n },\n ),\n cf.select(\"cushioning_profile\", [\"responsive\", \"plush\", \"stability\"], {\n label: \"Cushioning profile\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"materials\" },\n }),\n cf.multiline(\"care_notes\", {\n label: \"Care notes\",\n editor: \"markdown\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"care\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product, [\n cf.select(\"silhouette\", [\"wrap\", \"column\", \"fit_and_flare\", \"jumpsuit\"], {\n label: \"Silhouette\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"identity\" },\n filterable: true,\n }),\n cf.select(\"fabric_mix\", [\"silk_blend\", \"recycled_poly\", \"linen\", \"cupro\"], {\n label: \"Fabric mix\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"materials\" },\n }),\n cf.select(\"occasion_ready\", [\"daytime\", \"evening\", \"resort\"], {\n label: \"Occasion\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"fit\" },\n }),\n cf.multiline(\"finishing_details\", {\n label: \"Finishing details\",\n editor: \"markdown\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"care\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.integer(\"shoe_size\", {\n label: \"US size\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"fit\" },\n filterable: true,\n }),\n cf.select(\"shoe_width\", [\"B\", \"D\", \"EE\"], {\n label: \"Width\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"fit\" },\n }),\n cf.text(\"colorway\", {\n label: \"Colorway\",\n fieldset: \"fashion_mens_footwear\",\n group: { code: \"finish\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.integer(\"numeric_size\", {\n label: \"Numeric size\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"fit\" },\n }),\n cf.select(\"length_profile\", [\"mini\", \"midi\", \"maxi\"], {\n label: \"Length\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"fit\" },\n }),\n cf.text(\"color_story\", {\n label: \"Color story\",\n fieldset: \"fashion_womens_dresses\",\n group: { code: \"finish\" },\n }),\n ]),\n defineFields(E.catalog.catalog_product, [\n cf.integer(\"service_duration_minutes\", {\n label: \"Duration (minutes)\",\n description: \"Length of a single service slot.\",\n fieldset: \"service_schedule\",\n group: { code: \"timing\" },\n filterable: true,\n required: true,\n }),\n cf.integer(\"service_buffer_minutes\", {\n label: \"Buffer between appointments\",\n description:\n \"Minimum downtime between consecutive service slots (minutes).\",\n fieldset: \"service_schedule\",\n group: { code: \"timing\" },\n }),\n cf.text(\"service_location\", {\n label: \"Location / Room\",\n description: \"Where the service is delivered.\",\n fieldset: \"service_schedule\",\n group: { code: \"identity\" },\n }),\n cf.select(\n \"service_resources\",\n [\"stylist\", \"therapist\", \"treatment_room\", \"wash_station\", \"steam_room\"],\n {\n label: \"Required resources\",\n description: \"Staff or rooms required to perform the service.\",\n fieldset: \"service_schedule\",\n group: { code: \"resources\" },\n multi: true,\n },\n ),\n cf.boolean(\"service_remote_available\", {\n label: \"Remote session available\",\n description:\n \"Indicates whether the service can be performed remotely or virtually.\",\n fieldset: \"service_schedule\",\n group: { code: \"resources\" },\n defaultValue: false,\n }),\n ]),\n defineFields(E.catalog.catalog_product_variant, [\n cf.select(\"provider_level\", [\"junior\", \"senior\", \"master\"], {\n label: \"Provider level\",\n description: \"Seniority of the assigned specialist.\",\n fieldset: \"service_schedule\",\n group: { code: \"provider\" },\n filterable: true,\n }),\n cf.text(\"staff_member\", {\n label: \"Staff member\",\n description:\n \"Optional name of the staff member who usually delivers this variant.\",\n fieldset: \"service_schedule\",\n group: { code: \"provider\" },\n }),\n cf.select(\"environment_type\", [\"studio\", \"suite\", \"on_site\"], {\n label: \"Environment\",\n description: \"Where the session is hosted.\",\n fieldset: \"service_schedule\",\n group: { code: \"environment\" },\n }),\n ]),\n];\n\ntype CategorySeed = {\n slug: string;\n name: string;\n description?: string;\n children?: CategorySeed[];\n};\n\nconst CATEGORY_TREE: CategorySeed[] = [\n {\n slug: \"fashion\",\n name: \"Fashion\",\n description: \"Seasonal assortments and vertical-specific collections.\",\n children: [\n {\n slug: \"fashion-men\",\n name: \"Men\",\n children: [\n {\n slug: \"fashion-men-footwear\",\n name: \"Footwear\",\n description: \"Premium sneakers, boots, and sandals.\",\n },\n ],\n },\n {\n slug: \"fashion-women\",\n name: \"Women\",\n children: [\n {\n slug: \"fashion-women-dresses-jumpsuits\",\n name: \"Dresses & Jumpsuits\",\n description: \"Occasion-ready dresses and tailored jumpsuits.\",\n },\n ],\n },\n ],\n },\n {\n slug: \"services\",\n name: \"Services\",\n description: \"Bookable in-person and virtual experiences.\",\n children: [\n {\n slug: \"services-hairdresser\",\n name: \"Hairdresser\",\n description:\n \"Salon services ranging from quick trims to signature looks.\",\n },\n {\n slug: \"services-massage\",\n name: \"Massage\",\n description: \"Wellness treatments and bodywork sessions.\",\n },\n ],\n },\n];\n\ntype MediaSeed = {\n file: string;\n title?: string;\n};\n\ntype VariantSeed = {\n name: string;\n sku: string;\n isDefault?: boolean;\n optionValues?: Record<string, string>;\n prices: {\n regular: number;\n sale?: number;\n };\n customFields?: Record<string, string | number | boolean | null>;\n media?: MediaSeed[];\n};\n\ntype ProductSeed = {\n title: string;\n handle: string;\n sku?: string;\n description: string;\n categorySlug: string;\n customFieldsetCode: string;\n variantFieldsetCode: string;\n unit: string;\n metadata?: Record<string, unknown>;\n customFields?: Record<string, string | number | boolean | null>;\n media?: MediaSeed[];\n variants: VariantSeed[];\n};\n\nconst PRODUCT_SEEDS: ProductSeed[] = [\n {\n title: \"Atlas Runner Sneaker\",\n handle: \"atlas-runner-sneaker\",\n sku: \"ATLAS-RUNNER\",\n description:\n \"Lightweight road sneaker engineered with a breathable knit upper, recycled TPU overlays, and a decoupled heel for smooth transitions.\",\n categorySlug: \"fashion-men-footwear\",\n customFieldsetCode: \"fashion_mens_footwear\",\n variantFieldsetCode: \"fashion_mens_footwear\",\n unit: \"pair\",\n metadata: { division: \"RunLab\", season: \"SS25\" },\n customFields: {\n style_code: \"AR-2025\",\n upper_material: \"engineered_knit\",\n cushioning_profile: \"responsive\",\n care_notes:\n \"Spot clean after each run and air dry. Avoid machine drying.\",\n },\n media: [{ file: \"atlas-runner-midnight-1.png\" }],\n variants: [\n {\n name: \"Midnight Navy \u00B7 US 8\",\n sku: \"ATLAS-RUN-NAVY-8\",\n isDefault: true,\n optionValues: { color: \"Midnight Navy\", size: \"US 8\" },\n prices: { regular: 168, sale: 148 },\n customFields: {\n shoe_size: 8,\n shoe_width: \"D\",\n colorway: \"Midnight Navy\",\n },\n media: [\n { file: \"atlas-runner-midnight-1.png\" },\n { file: \"atlas-runner-midnight-2.png\" },\n ],\n },\n {\n name: \"Glacier Grey \u00B7 US 10\",\n sku: \"ATLAS-RUN-GLACIER-10\",\n optionValues: { color: \"Glacier Grey\", size: \"US 10\" },\n prices: { regular: 168, sale: 138 },\n customFields: {\n shoe_size: 10,\n shoe_width: \"EE\",\n colorway: \"Glacier Grey\",\n },\n media: [\n { file: \"atlas-runner-glacier-1.png\" },\n { file: \"atlas-runner-glacier-2.png\" },\n ],\n },\n ],\n },\n {\n title: \"Aurora Wrap Dress\",\n handle: \"aurora-wrap-dress\",\n sku: \"AURORA-WRAP\",\n description:\n \"Bias-cut wrap dress with blouson sleeves, matte silk blend, and hidden interior snaps so the placket stays put at events.\",\n categorySlug: \"fashion-women-dresses-jumpsuits\",\n customFieldsetCode: \"fashion_womens_dresses\",\n variantFieldsetCode: \"fashion_womens_dresses\",\n unit: \"unit\",\n metadata: { capsule: \"Evening Atelier\", season: \"Resort 25\" },\n customFields: {\n silhouette: \"wrap\",\n fabric_mix: \"silk_blend\",\n occasion_ready: \"evening\",\n finishing_details:\n \"Hand-finished hem with subtle tonal beading along the wrap edge.\",\n },\n media: [{ file: \"aurora-wrap-rosewood.png\" }],\n variants: [\n {\n name: \"Rosewood \u00B7 Medium\",\n sku: \"AURORA-ROSE-M\",\n isDefault: true,\n optionValues: { color: \"Rosewood\", size: \"Medium\" },\n prices: { regular: 248, sale: 212 },\n customFields: {\n numeric_size: 6,\n length_profile: \"midi\",\n color_story: \"Rosewood\",\n },\n media: [{ file: \"aurora-wrap-rosewood.png\" }],\n },\n {\n name: \"Celestial \u00B7 Large\",\n sku: \"AURORA-CELESTIAL-L\",\n optionValues: { color: \"Celestial\", size: \"Large\" },\n prices: { regular: 248, sale: 198 },\n customFields: {\n numeric_size: 8,\n length_profile: \"maxi\",\n color_story: \"Celestial blue\",\n },\n media: [{ file: \"aurora-wrap-celestial.png\" }],\n },\n ],\n },\n {\n title: \"Signature Haircut & Finish\",\n handle: \"signature-haircut-service\",\n sku: \"SERV-HAIR-60\",\n description:\n \"Tailored haircut with relaxing wash, scalp massage, and styling finish. Designed for repeat visits in the demo portal.\",\n categorySlug: \"services-hairdresser\",\n customFieldsetCode: \"service_schedule\",\n variantFieldsetCode: \"service_schedule\",\n unit: \"hour\",\n metadata: { channel: \"salon\", serviceType: \"hairdresser\" },\n customFields: {\n service_duration_minutes: 60,\n service_buffer_minutes: 15,\n service_location: \"Salon Studio 3\",\n service_resources: \"stylist,wash_station\",\n service_remote_available: false,\n },\n media: [{ file: \"hairdresser-service.png\" }],\n variants: [\n {\n name: \"Senior Stylist \u00B7 60 min\",\n sku: \"SERV-HAIR-60-SENIOR\",\n isDefault: true,\n optionValues: { stylist: \"Senior\", duration: \"60\" },\n prices: { regular: 95, sale: 85 },\n customFields: {\n provider_level: \"senior\",\n staff_member: \"Amelia Hart\",\n environment_type: \"studio\",\n },\n media: [{ file: \"hairdresser-service.png\" }],\n },\n ],\n },\n {\n title: \"Restorative Massage Session\",\n handle: \"restorative-massage-service\",\n sku: \"SERV-MASSAGE-90\",\n description:\n \"Full-body massage with aromatherapy oils and guided breathing. Includes complimentary refreshments and studio amenities.\",\n categorySlug: \"services-massage\",\n customFieldsetCode: \"service_schedule\",\n variantFieldsetCode: \"service_schedule\",\n unit: \"hour\",\n metadata: { channel: \"wellness\", serviceType: \"massage\" },\n customFields: {\n service_duration_minutes: 90,\n service_buffer_minutes: 20,\n service_location: \"Wellness Suite B\",\n service_resources: \"therapist,treatment_room,steam_room\",\n service_remote_available: false,\n },\n media: [{ file: \"massage-service.png\" }],\n variants: [\n {\n name: \"Master Therapist \u00B7 90 min\",\n sku: \"SERV-MASSAGE-90-MASTER\",\n isDefault: true,\n optionValues: { therapist: \"Master\", duration: \"90\" },\n prices: { regular: 140, sale: 120 },\n customFields: {\n provider_level: \"master\",\n staff_member: \"Noah Li\",\n environment_type: \"suite\",\n },\n media: [{ file: \"massage-service.png\" }],\n },\n ],\n },\n];\n\nconst CHANNEL_DEFINITION = {\n code: \"fashion-online\",\n name: \"Mercato Fashion Online\",\n description: \"Direct-to-consumer storefront showcasing premium demos.\",\n websiteUrl: \"https://demo.open-mercato.com\",\n contactEmail: \"store@open-mercato.com\",\n};\n\nfunction formatMoney(value: number): string {\n return value.toFixed(2);\n}\n\nasync function resolveDefaultTaxRate(\n em: EntityManager,\n scope: SeedScope,\n): Promise<SalesTaxRate | null> {\n const [rate] = await em.find(\n SalesTaxRate,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n deletedAt: null,\n },\n {\n limit: 1,\n orderBy: {\n isDefault: \"DESC\",\n priority: \"ASC\",\n rate: \"DESC\",\n createdAt: \"ASC\",\n },\n },\n );\n return rate ?? null;\n}\n\nasync function ensureFieldsetConfig(\n em: EntityManager,\n scope: SeedScope,\n entityId: string,\n fieldsets: typeof PRODUCT_FIELDSETS | typeof VARIANT_FIELDSETS,\n): Promise<void> {\n const now = new Date();\n let config = await em.findOne(CustomFieldEntityConfig, {\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n });\n if (!config) {\n config = em.create(CustomFieldEntityConfig, {\n id: randomUUID(),\n entityId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n isActive: true,\n createdAt: now,\n updatedAt: now,\n });\n }\n config.configJson = {\n fieldsets,\n singleFieldsetPerRecord: true,\n };\n config.isActive = true;\n config.updatedAt = now;\n em.persist(config);\n}\n\nasync function ensureFieldsetsAndDefinitions(\n em: EntityManager,\n scope: SeedScope,\n): Promise<void> {\n await ensureFieldsetConfig(\n em,\n scope,\n E.catalog.catalog_product,\n PRODUCT_FIELDSETS,\n );\n await ensureFieldsetConfig(\n em,\n scope,\n E.catalog.catalog_product_variant,\n VARIANT_FIELDSETS,\n );\n await ensureCustomFieldDefinitions(em, CUSTOM_FIELD_SETS, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n });\n await em.flush();\n}\n\nasync function ensureCategories(\n em: EntityManager,\n scope: SeedScope,\n): Promise<Map<string, CatalogProductCategory>> {\n const map = new Map<string, CatalogProductCategory>();\n const now = new Date();\n\n const upsert = async (\n seed: CategorySeed,\n parent: CatalogProductCategory | null,\n ) => {\n let record = await em.findOne(CatalogProductCategory, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n slug: seed.slug,\n });\n if (!record) {\n record = em.create(CatalogProductCategory, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n name: seed.name,\n slug: seed.slug,\n description: seed.description ?? null,\n parentId: parent ? parent.id : null,\n rootId: parent ? (parent.rootId ?? parent.id) : null,\n treePath: null,\n depth: parent ? (parent.depth ?? 0) + 1 : 0,\n ancestorIds: [],\n childIds: [],\n descendantIds: [],\n metadata: null,\n isActive: true,\n createdAt: now,\n updatedAt: now,\n });\n em.persist(record);\n } else {\n record.name = seed.name;\n record.description = seed.description ?? null;\n record.parentId = parent ? parent.id : null;\n record.isActive = true;\n record.updatedAt = now;\n }\n map.set(seed.slug, record);\n if (Array.isArray(seed.children)) {\n for (const child of seed.children) {\n await upsert(child, record);\n }\n }\n };\n\n for (const seed of CATEGORY_TREE) {\n await upsert(seed, null);\n }\n\n await em.flush();\n await rebuildCategoryHierarchyForOrganization(\n em,\n scope.organizationId,\n scope.tenantId,\n );\n\n return map;\n}\n\nasync function ensureChannel(\n em: EntityManager,\n scope: SeedScope,\n): Promise<SalesChannel> {\n const now = new Date();\n let channel = await em.findOne(SalesChannel, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n code: CHANNEL_DEFINITION.code,\n deletedAt: null,\n });\n if (!channel) {\n channel = em.create(SalesChannel, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n code: CHANNEL_DEFINITION.code,\n name: CHANNEL_DEFINITION.name,\n description: CHANNEL_DEFINITION.description,\n websiteUrl: CHANNEL_DEFINITION.websiteUrl,\n contactEmail: CHANNEL_DEFINITION.contactEmail,\n status: \"active\",\n isActive: true,\n metadata: { locale: \"en-US\" },\n createdAt: now,\n updatedAt: now,\n });\n em.persist(channel);\n await em.flush();\n }\n return channel;\n}\n\nasync function loadPriceKinds(\n em: EntityManager,\n scope: SeedScope,\n): Promise<Map<string, CatalogPriceKind>> {\n const kinds = await em.find(CatalogPriceKind, {\n tenantId: scope.tenantId,\n code: { $in: [\"regular\", \"sale\"] },\n deletedAt: null,\n });\n const map = new Map<string, CatalogPriceKind>();\n for (const kind of kinds) {\n map.set(kind.code.toLowerCase(), kind);\n }\n return map;\n}\n\nexport function listCatalogExampleKeys(): { productHandles: string[]; variantSkus: string[] } {\n return {\n productHandles: PRODUCT_SEEDS.map((seed) => seed.handle),\n variantSkus: PRODUCT_SEEDS.flatMap((seed) => seed.variants.map((variant) => variant.sku)),\n };\n}\n\nexport async function seedCatalogExamples(\n em: EntityManager,\n container: AwilixContainer,\n scope: SeedScope,\n): Promise<boolean> {\n if (!em.getMetadata().has(SalesChannel)) return false;\n\n await ensureFieldsetsAndDefinitions(em, scope);\n await ensureDefaultPartitions(em);\n\n const handles = PRODUCT_SEEDS.map((seed) => seed.handle);\n const existingProducts = await em.find(CatalogProduct, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n handle: { $in: [...handles] },\n });\n const existingByHandle = new Map(\n existingProducts.map((product) => [product.handle?.toLowerCase(), product]),\n );\n\n const categoryMap = await ensureCategories(em, scope);\n const channel = await ensureChannel(em, scope);\n const priceKinds = await loadPriceKinds(em, scope);\n const regularKind = priceKinds.get(\"regular\");\n const saleKind = priceKinds.get(\"sale\");\n const defaultTaxRate = await resolveDefaultTaxRate(em, scope);\n const defaultTaxRateId = defaultTaxRate?.id ?? null;\n const defaultTaxRateValue = defaultTaxRate?.rate ?? null;\n if (!regularKind || !saleKind) {\n throw new Error(\n \"Missing catalog price kinds; run `mercato catalog seed-price-kinds` first.\",\n );\n }\n\n const dataEngine = new DefaultDataEngine(em, container);\n const customFieldAssignments: Array<() => Promise<void>> = [];\n let createdAny = false;\n\n for (const productSeed of PRODUCT_SEEDS) {\n const existing = existingByHandle.get(productSeed.handle.toLowerCase());\n if (existing) {\n continue;\n }\n createdAny = true;\n const product = em.create(CatalogProduct, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n title: productSeed.title,\n description: productSeed.description,\n sku: productSeed.sku ?? null,\n handle: productSeed.handle,\n productType: \"configurable\",\n primaryCurrencyCode: \"USD\",\n defaultUnit: canonicalizeUnitCode(productSeed.unit) ?? productSeed.unit,\n customFieldsetCode: productSeed.customFieldsetCode,\n metadata: productSeed.metadata ?? null,\n taxRateId: defaultTaxRateId,\n taxRate: defaultTaxRateValue,\n isConfigurable: true,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(product);\n\n const category = categoryMap.get(productSeed.categorySlug);\n if (category) {\n const assignment = em.create(CatalogProductCategoryAssignment, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n category,\n position: 0,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(assignment);\n }\n\n const offer = em.create(CatalogOffer, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n channelId: channel.id,\n title: `${productSeed.title} \u00B7 Online`,\n description: \"Offer curated for the demo storefront channel.\",\n metadata: { channelCode: CHANNEL_DEFINITION.code },\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(offer);\n\n if (\n productSeed.customFields &&\n Object.keys(productSeed.customFields).length\n ) {\n const payload = { ...productSeed.customFields };\n customFieldAssignments.push(() =>\n dataEngine.setCustomFields({\n entityId: E.catalog.catalog_product,\n recordId: product.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: payload,\n }),\n );\n }\n\n const productMedia = await attachMediaFromExamples(\n em,\n scope,\n E.catalog.catalog_product,\n product.id,\n productSeed.media,\n );\n if (productMedia.length) {\n const hero = productMedia[0];\n product.defaultMediaId = hero.id;\n product.defaultMediaUrl = hero.imageUrl;\n offer.defaultMediaId = hero.id;\n offer.defaultMediaUrl = hero.imageUrl;\n }\n\n for (const variantSeed of productSeed.variants) {\n const variant = em.create(CatalogProductVariant, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n name: variantSeed.name,\n sku: variantSeed.sku,\n isDefault: variantSeed.isDefault ?? false,\n optionValues: variantSeed.optionValues ?? null,\n customFieldsetCode: productSeed.variantFieldsetCode,\n metadata: null,\n taxRateId: defaultTaxRateId,\n taxRate: defaultTaxRateValue,\n isActive: true,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(variant);\n\n const variantMedia = await attachMediaFromExamples(\n em,\n scope,\n E.catalog.catalog_product_variant,\n variant.id,\n variantSeed.media,\n );\n const regularPrice = em.create(CatalogProductPrice, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n variant,\n offer,\n priceKind: regularKind,\n currencyCode: \"USD\",\n kind: regularKind.code,\n minQuantity: 1,\n taxRate: defaultTaxRateValue,\n unitPriceGross: formatMoney(variantSeed.prices.regular),\n unitPriceNet: formatMoney(variantSeed.prices.regular),\n channelId: channel.id,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(regularPrice);\n\n if (variantSeed.prices.sale !== undefined) {\n const salePrice = em.create(CatalogProductPrice, {\n id: randomUUID(),\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n product,\n variant,\n offer,\n priceKind: saleKind,\n currencyCode: \"USD\",\n kind: saleKind.code,\n minQuantity: 1,\n taxRate: defaultTaxRateValue,\n unitPriceGross: formatMoney(variantSeed.prices.sale),\n unitPriceNet: formatMoney(variantSeed.prices.sale),\n channelId: channel.id,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n em.persist(salePrice);\n }\n\n if (\n variantSeed.customFields &&\n Object.keys(variantSeed.customFields).length\n ) {\n const payload = { ...variantSeed.customFields };\n customFieldAssignments.push(() =>\n dataEngine.setCustomFields({\n entityId: E.catalog.catalog_product_variant,\n recordId: variant.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n values: payload,\n }),\n );\n }\n }\n }\n\n if (!createdAny) {\n return false;\n }\n\n await em.flush();\n\n for (const assign of customFieldAssignments) {\n try {\n await assign();\n } catch (err) {\n logger.warn(\"catalog.seed failed to set example custom field values\", { err });\n }\n }\n\n return true;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -267,12 +267,12 @@ function applyInteractionListFilters(baseQuery, params) {
|
|
|
267
267
|
if (query.excludeInteractionType) q = q.where("interaction_type", "!=", query.excludeInteractionType);
|
|
268
268
|
if (query.search) {
|
|
269
269
|
const searchTerm = `%${escapeLikePattern(query.search)}%`;
|
|
270
|
-
q = q.where(sql`coalesce(title, '') ilike ${searchTerm} or coalesce(body, '') ilike ${searchTerm}`);
|
|
270
|
+
q = q.where(sql`(coalesce(title, '') ilike ${searchTerm} or coalesce(body, '') ilike ${searchTerm})`);
|
|
271
271
|
}
|
|
272
272
|
if (query.recurrenceMasters === "true") {
|
|
273
273
|
q = q.where("recurrence_rule", "is not", null);
|
|
274
274
|
if (query.from) {
|
|
275
|
-
q = q.where(sql`recurrence_end is null or recurrence_end >= ${query.from}`);
|
|
275
|
+
q = q.where(sql`(recurrence_end is null or recurrence_end >= ${query.from})`);
|
|
276
276
|
}
|
|
277
277
|
if (query.to) {
|
|
278
278
|
q = q.where(sql`coalesce(occurred_at, scheduled_at, created_at) <= ${query.to}`);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/api/interactions/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { sql } from 'kysely'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { normalizeCustomFieldResponse } from '@open-mercato/shared/lib/custom-fields/normalize'\nimport { applyResponseEnrichers } from '@open-mercato/shared/lib/crud/enricher-runner'\nimport type { EnricherContext } from '@open-mercato/shared/lib/crud/response-enricher'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTenantEncryptionService } from '@open-mercato/shared/lib/encryption/customFieldValues'\nimport { resolveEncryptedSortFields, resolveEncryptedSortMaxRows } from '@open-mercato/shared/lib/query/encrypted-sort'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { resolveOrganizationScopeFilter } from '@open-mercato/core/modules/directory/utils/organizationScopeFilter'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CustomerDeal, CustomerInteraction } from '../../data/entities'\nimport { interactionUserKey, loadInteractionAuthors } from '../../lib/interactionUsers'\nimport { interactionCreateSchema, interactionUpdateSchema } from '../../data/validators'\nimport { parseScopedCommandInput } from '../utils'\nimport {\n createCustomersCrudOpenApi,\n defaultOkResponseSchema,\n} from '../openapi'\nimport { CUSTOMER_INTERACTION_ENTITY_ID } from '../../lib/interactionCompatibility'\nimport { applyEmailVisibilityFilter } from '../../lib/visibilityFilter'\nimport { listGrantsForViewer, listSharedChannelIds } from '../../lib/conversationShares'\nimport { resolveEncryptedSortPage } from './encryptedSortPage'\nimport { applyDecryptedFields } from './decryptedFields'\nimport { resolveCanonicalActivityTargetId } from '../../lib/legacyActivityBridge'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst interactionSortFieldSchema = z.enum([\n 'scheduledAt',\n 'occurredAt',\n 'createdAt',\n 'updatedAt',\n 'status',\n 'priority',\n 'interactionType',\n 'title',\n])\n\nexport const listSchema = z\n .object({\n limit: z.coerce.number().min(1).max(100).default(25),\n cursor: z.string().optional(),\n entityId: z.string().uuid().optional(),\n dealId: z.string().uuid().optional(),\n status: z.string().optional(),\n interactionType: z.string().optional(),\n type: z.string().optional(),\n excludeInteractionType: z.string().optional(),\n search: z.string().trim().min(1).optional(),\n from: z.coerce.date().optional(),\n to: z.coerce.date().optional(),\n recurrenceMasters: z.enum(['true', 'false']).optional(),\n pinned: z.enum(['true', 'false']).optional(),\n sortField: interactionSortFieldSchema.optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.interactions.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.interactions.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.interactions.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.interactions.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CustomerInteraction,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n enrichers: { entityId: 'customers.interaction' },\n indexer: {\n entityType: 'customers:customer_interaction',\n },\n actions: {\n create: {\n commandId: 'customers.interactions.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(interactionCreateSchema, raw ?? {}, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.interactionId ?? result?.id ?? null }),\n status: 201,\n },\n update: {\n commandId: 'customers.interactions.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const parsed = parseScopedCommandInput(interactionUpdateSchema, raw ?? {}, ctx, translate)\n // Bridge legacy `customer_activities` rows into `customer_interactions`\n // before the canonical update runs so historical activities (#1807)\n // remain editable through the new dialog. No-op when the canonical\n // record already exists.\n const tenantId = ctx.auth?.tenantId ?? null\n if (typeof parsed.id === 'string' && tenantId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const commandContext: CommandRuntimeContext = {\n container: ctx.container,\n auth: ctx.auth ?? null,\n organizationScope: ctx.organizationScope ?? null,\n selectedOrganizationId: ctx.selectedOrganizationId ?? null,\n organizationIds: ctx.organizationIds ?? null,\n request: ctx.request,\n }\n await resolveCanonicalActivityTargetId(em, commandBus, commandContext, parsed.id, tenantId)\n } catch (err) {\n // Bridging is best-effort; downstream lookup will surface a 404\n // when neither canonical nor legacy rows exist.\n logger.warn('Legacy interaction bridge failed', { component: 'interactions.put', id: parsed.id, err })\n }\n }\n return parsed\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'customers.interactions.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id =\n parsed?.body?.id ??\n parsed?.id ??\n parsed?.query?.id ??\n (ctx.request ? new URL(ctx.request.url).searchParams.get('id') : null)\n if (!id) {\n throw new CrudHttpError(400, {\n error: translate('customers.errors.interaction_required', 'Interaction id is required'),\n })\n }\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nconst { POST, PUT, DELETE } = crud\n\nexport { POST, PUT, DELETE }\n\ntype InteractionListRow = {\n id: string\n entity_id: string\n deal_id: string | null\n interaction_type: string\n title: string | null\n body: string | null\n status: string\n scheduled_at: Date | null\n occurred_at: Date | null\n priority: number | null\n author_user_id: string | null\n owner_user_id: string | null\n external_message_id: string | null\n appearance_icon: string | null\n appearance_color: string | null\n source: string | null\n timezone: string | null\n duration_minutes: number | null\n location: string | null\n all_day: boolean | null\n recurrence_rule: string | null\n recurrence_end: Date | null\n participants: Array<{ userId?: string; name?: string; email?: string; status?: string }> | null\n reminder_minutes: number | null\n visibility: string | null\n /** Denormalized channel \u2014 the shared-team-mailbox arm keys on this, not on the author. */\n channel_id: string | null\n linked_entities: Array<{ id: string; type: string; label: string }> | null\n guest_permissions: { canInviteOthers?: boolean; canModify?: boolean; canSeeList?: boolean } | null\n pinned: boolean\n organization_id: string\n tenant_id: string\n created_at: Date\n updated_at: Date\n __sort_value: string | number | Date | null\n}\n\ntype CursorPayload = {\n id: string\n sortValue: string | number | null\n}\n\ntype RbacServiceLike = {\n getGrantedFeatures?: (userId: string, input: { tenantId: string | null; organizationId: string | null }) => Promise<string[]>\n}\n\nconst cursorSchema = z.object({\n id: z.string().uuid(),\n sortValue: z.union([z.string(), z.number(), z.null()]),\n})\n\nconst interactionSortConfig = {\n scheduledAt: { column: 'scheduled_at', type: 'date' as const, defaultDir: 'asc' as const },\n occurredAt: { column: 'occurred_at', type: 'date' as const, defaultDir: 'desc' as const },\n createdAt: { column: 'created_at', type: 'date' as const, defaultDir: 'desc' as const },\n updatedAt: { column: 'updated_at', type: 'date' as const, defaultDir: 'desc' as const },\n status: { column: 'status', type: 'text' as const, defaultDir: 'asc' as const },\n priority: { column: 'priority', type: 'number' as const, defaultDir: 'desc' as const },\n interactionType: { column: 'interaction_type', type: 'text' as const, defaultDir: 'asc' as const },\n title: { column: 'title', type: 'text' as const, defaultDir: 'asc' as const },\n} as const\n\nfunction toIsoString(value: unknown): string | null {\n if (value == null) return null\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? null : value.toISOString()\n }\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed.length) return null\n const parsed = new Date(trimmed)\n return Number.isNaN(parsed.getTime()) ? trimmed : parsed.toISOString()\n }\n return null\n}\n\nfunction normalizeCursorValue(\n value: string | number | Date | null,\n type: 'date' | 'number' | 'text',\n): string | number | null {\n if (value == null) return null\n if (type === 'number') {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n }\n if (type === 'date') {\n return toIsoString(value)\n }\n if (typeof value === 'string') return value\n if (value instanceof Date) return value.toISOString()\n return String(value)\n}\n\nfunction encodeCursor(payload: CursorPayload): string {\n return Buffer.from(JSON.stringify(payload), 'utf8').toString('base64')\n}\n\nfunction decodeCursor(token: string | undefined, type: 'date' | 'number' | 'text'): CursorPayload | null {\n if (!token) return null\n try {\n const decoded = Buffer.from(token, 'base64').toString('utf8')\n const parsed = cursorSchema.parse(JSON.parse(decoded))\n return {\n id: parsed.id,\n sortValue: normalizeCursorValue(parsed.sortValue, type),\n }\n } catch {\n return null\n }\n}\n\nfunction buildSortSql(\n sortField: keyof typeof interactionSortConfig,\n sortDir: 'asc' | 'desc',\n): string {\n const config = interactionSortConfig[sortField]\n if (config.type === 'date') {\n const sentinel =\n sortDir === 'asc'\n ? \"timestamp with time zone '9999-12-31T23:59:59.999Z'\"\n : \"timestamp with time zone '0001-01-01T00:00:00.000Z'\"\n return `coalesce(${config.column}, ${sentinel})`\n }\n if (config.type === 'number') {\n const sentinel = sortDir === 'asc' ? '2147483647' : '-2147483648'\n return `coalesce(${config.column}, ${sentinel})`\n }\n const sentinel = sortDir === 'asc' ? \"'~~~~~~~~~~'\" : \"''\"\n return `coalesce(${config.column}, ${sentinel})`\n}\n\nconst INTERACTION_LIST_COLUMNS = [\n 'id',\n 'entity_id',\n 'deal_id',\n 'interaction_type',\n 'title',\n 'body',\n 'status',\n 'scheduled_at',\n 'occurred_at',\n 'priority',\n 'author_user_id',\n 'owner_user_id',\n 'external_message_id',\n 'appearance_icon',\n 'appearance_color',\n 'source',\n 'timezone',\n 'duration_minutes',\n 'location',\n 'all_day',\n 'recurrence_rule',\n 'recurrence_end',\n 'participants',\n 'reminder_minutes',\n 'visibility',\n // Required by `interactionEmailCardEnricher`: without `channel_id` the\n // shared-team-mailbox arm of `isEmailHiddenFrom` can never match, so a teammate\n // silently loses the email-card actions on a mailbox they may legitimately read.\n 'channel_id',\n 'linked_entities',\n 'guest_permissions',\n 'pinned',\n 'organization_id',\n 'tenant_id',\n 'created_at',\n 'updated_at',\n] as const\n\n// Shared by both the SQL keyset path and the encrypted-sort candidate scan\n// so the two paths never drift on which rows are in scope.\nfunction applyInteractionListFilters(\n baseQuery: any,\n params: {\n tenantId: string\n organizationIds: string[] | undefined\n query: z.infer<typeof listSchema>\n },\n): any {\n let q = baseQuery.where('deleted_at', 'is', null).where('tenant_id', '=', params.tenantId)\n if (params.organizationIds !== undefined) q = q.where('organization_id', 'in', params.organizationIds)\n const { query } = params\n if (query.entityId) q = q.where('entity_id', '=', query.entityId)\n if (query.dealId) q = q.where('deal_id', '=', query.dealId)\n if (query.status) q = q.where('status', '=', query.status)\n if (query.interactionType) q = q.where('interaction_type', '=', query.interactionType)\n if (query.type) {\n const types = query.type.split(',').map((t) => t.trim()).filter(Boolean)\n if (types.length > 0) q = q.where('interaction_type', 'in', types)\n }\n if (query.pinned === 'true') {\n q = q.where('pinned', '=', true)\n } else if (query.pinned === 'false') {\n q = q.where('pinned', '=', false)\n }\n if (query.excludeInteractionType) q = q.where('interaction_type', '!=', query.excludeInteractionType)\n if (query.search) {\n // NOTE: for tenants with data encryption enabled, `title`/`body` are\n // ciphertext at rest (see encryption.ts), so this ILIKE matches encrypted\n // bytes and returns no rows \u2014 substring search over encrypted free-text\n // columns is unsupported, the same documented limitation as\n // customer_activity / customer_comment. The returned page's title/body are\n // still decrypted for display further below.\n const searchTerm = `%${escapeLikePattern(query.search)}%`\n q = q.where(sql<boolean>`coalesce(title, '') ilike ${searchTerm} or coalesce(body, '') ilike ${searchTerm}`)\n }\n if (query.recurrenceMasters === 'true') {\n q = q.where('recurrence_rule', 'is not', null)\n if (query.from) {\n q = q.where(sql<boolean>`recurrence_end is null or recurrence_end >= ${query.from}`)\n }\n if (query.to) {\n q = q.where(sql<boolean>`coalesce(occurred_at, scheduled_at, created_at) <= ${query.to}`)\n }\n } else {\n if (query.from) {\n q = q.where(sql<boolean>`coalesce(occurred_at, scheduled_at, created_at) >= ${query.from}`)\n }\n if (query.to) {\n q = q.where(sql<boolean>`coalesce(occurred_at, scheduled_at, created_at) <= ${query.to}`)\n }\n }\n return q\n}\n\nasync function resolveUserFeatures(\n container: { resolve: (name: string) => unknown },\n userId: string,\n tenantId: string | null,\n organizationId: string | null,\n): Promise<string[] | undefined> {\n try {\n const rbac = container.resolve('rbacService') as RbacServiceLike | undefined\n if (!rbac?.getGrantedFeatures) return undefined\n return await rbac.getGrantedFeatures(userId, { tenantId, organizationId })\n } catch {\n return undefined\n }\n}\n\nasync function buildEnricherContext(\n container: { resolve: (name: string) => unknown },\n auth: NonNullable<Awaited<ReturnType<typeof getAuthFromRequest>>>,\n organizationId: string | null,\n precomputedUserFeatures?: { userId: string; features: string[] | undefined },\n): Promise<EnricherContext> {\n const userId =\n (typeof auth.sub === 'string' && auth.sub.trim().length > 0\n ? auth.sub\n : typeof auth.userId === 'string' && auth.userId.trim().length > 0\n ? auth.userId\n : typeof auth.keyId === 'string' && auth.keyId.trim().length > 0\n ? auth.keyId\n : 'system')\n\n // Reuse features already resolved for this same user (the GET handler resolves\n // them once for the visibility filter) to avoid a second RBAC lookup per request.\n const userFeatures =\n precomputedUserFeatures && precomputedUserFeatures.userId === userId\n ? precomputedUserFeatures.features\n : await resolveUserFeatures(container, userId, auth.tenantId ?? null, organizationId)\n\n return {\n organizationId: organizationId ?? '',\n tenantId: auth.tenantId ?? '',\n userId,\n em: container.resolve('em'),\n container,\n userFeatures,\n }\n}\n\nexport async function GET(req: Request) {\n try {\n const queryUrl = new URL(req.url)\n const query = listSchema.parse(Object.fromEntries(queryUrl.searchParams))\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, {\n error: translate('customers.errors.unauthorized', 'Unauthorized'),\n })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const { organizationIds, rbacOrganizationId: selectedOrganizationId } = resolveOrganizationScopeFilter(scope, auth)\n\n const requestedSortField = query.sortField ?? 'scheduledAt'\n const sortConfig = interactionSortConfig[requestedSortField]\n const sortDir = query.sortDir ?? sortConfig.defaultDir\n const sortSql = buildSortSql(requestedSortField, sortDir)\n const cursor = decodeCursor(query.cursor, sortConfig.type)\n if (query.cursor && !cursor) {\n throw new CrudHttpError(400, {\n error: translate('customers.interactions.cursor.invalid', 'Invalid cursor'),\n })\n }\n if (organizationIds?.length === 0) {\n return NextResponse.json({ items: [] })\n }\n\n const em = (container.resolve('em') as EntityManager).fork()\n const db = em.getKysely<any>() as any\n\n // \u2500\u2500 Email visibility filter (2026-05-27) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Non-email interactions pass through; email rows with visibility='private'\n // are filtered out unless the caller is the author or has admin bypass.\n // API-key callers have no user identity (`auth.sub` undefined): resolve the\n // viewer to null so they never gain the author bypass and only see shared\n // emails (fail-closed). Mirrors counts/people/activities routes.\n const viewerUserId = auth.isApiKey ? null : (auth.sub ?? null)\n // Conversation shares that widen this caller's email access. Unscoped surface,\n // so this is the capped variant (see SHARE_ARM_MAX).\n const emailShareScope = {\n tenantId: auth.tenantId as string,\n organizationId: selectedOrganizationId,\n }\n const [emailShareGrants, emailSharedChannelIds] = await Promise.all([\n listGrantsForViewer(em, emailShareScope, viewerUserId),\n listSharedChannelIds(em, emailShareScope, viewerUserId),\n ])\n const encryptionService = resolveTenantEncryptionService(em)\n // Encrypted sort columns can't use SQL keyset ordering on ciphertext, so an\n // encrypted sort field takes a bounded candidate-scan + in-memory-sort path\n // instead of the SQL path below. Resolved alongside the independent\n // visibility-feature lookup rather than after it.\n const [callerUserFeatures, encryptedSortFields] = await Promise.all([\n viewerUserId\n ? resolveUserFeatures(container, viewerUserId, auth.tenantId ?? null, selectedOrganizationId)\n : Promise.resolve(undefined),\n resolveEncryptedSortFields(\n encryptionService,\n CUSTOMER_INTERACTION_ENTITY_ID,\n [sortConfig.column],\n auth.tenantId,\n selectedOrganizationId,\n ),\n ])\n const sortFieldIsEncrypted = encryptedSortFields.has(sortConfig.column)\n\n let pageRows: InteractionListRow[]\n let hasMore: boolean\n\n if (sortFieldIsEncrypted) {\n let candidateQuery = applyInteractionListFilters(\n db.selectFrom('customer_interactions').select(['id', sortConfig.column]),\n { tenantId: auth.tenantId, organizationIds, query },\n )\n candidateQuery = applyEmailVisibilityFilter(candidateQuery as any, {\n currentUserId: viewerUserId,\n userFeatures: callerUserFeatures,\n sharedConversations: emailShareGrants,\n sharedChannelIds: emailSharedChannelIds,\n })\n const cap = resolveEncryptedSortMaxRows()\n if (cap !== null) {\n candidateQuery = candidateQuery.limit(cap).orderBy('id', 'asc')\n }\n const candidateRows = await candidateQuery.execute() as Array<{ id: string } & Record<string, unknown>>\n if (cap !== null && candidateRows.length >= cap) {\n logger.warn('Encrypted sort candidate scan hit OM_ENCRYPTED_SORT_MAX_ROWS cap; results may be incomplete', {\n component: 'interactions.GET',\n cap,\n sortField: sortConfig.column,\n tenantId: auth.tenantId,\n })\n }\n\n const decryptPayload = encryptionService?.decryptEntityPayload?.bind(encryptionService)\n const { pageIds, hasMore: encryptedHasMore } = await resolveEncryptedSortPage({\n candidates: candidateRows,\n decryptRow: async (row) => {\n if (!decryptPayload) return row\n try {\n const decrypted = await decryptPayload(CUSTOMER_INTERACTION_ENTITY_ID, row, auth.tenantId, selectedOrganizationId)\n return { ...row, ...decrypted }\n } catch (err) {\n logger.error('error decrypting sort candidate', { component: 'interactions.GET', err })\n return row\n }\n },\n sortField: sortConfig.column,\n sortDir,\n cursorId: cursor?.id ?? null,\n limit: query.limit,\n })\n hasMore = encryptedHasMore\n\n if (pageIds.length === 0) {\n pageRows = []\n } else {\n let pageQuery = applyInteractionListFilters(\n db.selectFrom('customer_interactions').select([...INTERACTION_LIST_COLUMNS, sql`${sql.raw(sortSql)}`.as('__sort_value')]),\n { tenantId: auth.tenantId, organizationIds, query },\n )\n pageQuery = applyEmailVisibilityFilter(pageQuery as any, {\n currentUserId: viewerUserId,\n userFeatures: callerUserFeatures,\n sharedConversations: emailShareGrants,\n sharedChannelIds: emailSharedChannelIds,\n })\n pageQuery = pageQuery.where('id', 'in', pageIds)\n const rawPageRows = await pageQuery.execute() as InteractionListRow[]\n const byId = new Map(rawPageRows.map((row) => [row.id, row]))\n pageRows = pageIds\n .map((id) => byId.get(id))\n .filter((row): row is InteractionListRow => row != null)\n }\n } else {\n let rowsQuery = applyInteractionListFilters(\n db\n .selectFrom('customer_interactions')\n .select([...INTERACTION_LIST_COLUMNS, sql`${sql.raw(sortSql)}`.as('__sort_value')])\n .limit(query.limit + 1),\n { tenantId: auth.tenantId, organizationIds, query },\n )\n\n if (cursor) {\n const op = sortDir === 'asc' ? '>' : '<'\n const opRaw = sql.raw(op)\n const sortRaw = sql.raw(sortSql)\n rowsQuery = rowsQuery.where((eb: any) => eb.or([\n sql<boolean>`${sortRaw} ${opRaw} ${cursor.sortValue}`,\n eb.and([\n sql<boolean>`${sortRaw} = ${cursor.sortValue}`,\n eb('id', op, cursor.id),\n ]),\n ]))\n }\n\n rowsQuery = applyEmailVisibilityFilter(rowsQuery as any, {\n currentUserId: viewerUserId,\n userFeatures: callerUserFeatures,\n sharedConversations: emailShareGrants,\n sharedChannelIds: emailSharedChannelIds,\n })\n\n rowsQuery = rowsQuery.orderBy(sql`${sql.raw(sortSql)} ${sql.raw(sortDir)}`).orderBy('id', sortDir)\n\n const rows = await rowsQuery.execute() as InteractionListRow[]\n pageRows = rows.slice(0, query.limit)\n hasMore = rows.length > query.limit\n }\n\n const dealIds = Array.from(\n new Set(\n pageRows\n .map((row) => (typeof row.deal_id === 'string' ? row.deal_id : null))\n .filter((value): value is string => !!value),\n ),\n )\n const interactionIds = pageRows.map((row) => row.id)\n // A page can span the selected organization plus its descendants\n // (organizationScope.ts expands a concrete selection that way), and\n // encryption maps are resolved per organization with first-match-wins \u2014\n // an org-specific map replaces rather than merges with the tenant-wide\n // one. Resolving a single field set from `selectedOrganizationId` and\n // applying it to every row therefore missed descendant-org fields the\n // row's own map covers (#5945 follow-up). Each row's own\n // `organization_id` is resolved instead, one lookup per distinct\n // organization on the page \u2014 `getEncryptedFieldNames` memoizes per\n // (entity, tenant, organization), so this adds no query for the common\n // single-organization case.\n const pageOrganizationIds = Array.from(\n new Set(pageRows.map((row) => row.organization_id).filter((value): value is string => !!value)),\n )\n\n const [userMap, deals, customFieldValues, interactionRecords, encryptedFieldsByOrganization] = await Promise.all([\n loadInteractionAuthors(em, pageRows.map((row) => ({\n tenantId: row.tenant_id,\n organizationId: row.organization_id,\n authorUserId: row.author_user_id,\n }))),\n dealIds.length > 0 ? findWithDecryption(em, CustomerDeal, { id: { $in: dealIds } }, undefined, { tenantId: auth.tenantId, organizationId: selectedOrganizationId }) : Promise.resolve([]),\n interactionIds.length > 0\n ? loadCustomFieldValues({\n em,\n entityId: CUSTOMER_INTERACTION_ENTITY_ID,\n recordIds: interactionIds,\n tenantIdByRecord: Object.fromEntries(pageRows.map((row) => [row.id, row.tenant_id])),\n organizationIdByRecord: Object.fromEntries(pageRows.map((row) => [row.id, row.organization_id])),\n tenantFallbacks: [auth.tenantId].filter((value): value is string => !!value),\n })\n : Promise.resolve<Record<string, Record<string, unknown>>>({}),\n interactionIds.length > 0\n ? findWithDecryption(em, CustomerInteraction, { id: { $in: interactionIds } } as never, undefined, { tenantId: auth.tenantId, organizationId: selectedOrganizationId })\n : Promise.resolve([]),\n (async () => {\n const byOrganization = new Map<string, readonly string[]>()\n if (interactionIds.length === 0 || !encryptionService?.getEncryptedFieldNames || pageOrganizationIds.length === 0) {\n return byOrganization\n }\n await Promise.all(pageOrganizationIds.map(async (organizationId) => {\n const fields = await encryptionService.getEncryptedFieldNames(CUSTOMER_INTERACTION_ENTITY_ID, auth.tenantId, organizationId)\n byOrganization.set(organizationId, fields)\n }))\n return byOrganization\n })(),\n ])\n\n const dealMap = new Map(\n deals.map((deal) => [deal.id, deal.title]),\n )\n // The kysely rows above carry raw column values, so every field the entity's\n // encryption map covers arrives as ciphertext. findWithDecryption already\n // returned those fields in plaintext, so the response takes them from the\n // decrypted records. The covered set is read from each row's own\n // organization's resolved map rather than hard-coded or shared across the\n // page, so extending the map \u2014 or a page spanning several organizations \u2014\n // cannot leave a field passing through as ciphertext (#5945).\n const interactionRecordMap = new Map<string, CustomerInteraction>(\n (interactionRecords as CustomerInteraction[]).map((record) => [record.id, record]),\n )\n\n const baseItems = pageRows.map((row) => applyDecryptedFields({\n id: row.id,\n entityId: row.entity_id,\n dealId: row.deal_id ?? null,\n interactionType: row.interaction_type,\n title: row.title ?? null,\n body: row.body ?? null,\n status: row.status,\n scheduledAt: toIsoString(row.scheduled_at),\n occurredAt: toIsoString(row.occurred_at),\n priority: row.priority ?? null,\n authorUserId: row.author_user_id ?? null,\n ownerUserId: row.owner_user_id ?? null,\n externalMessageId: row.external_message_id ?? null,\n appearanceIcon: row.appearance_icon ?? null,\n appearanceColor: row.appearance_color ?? null,\n source: row.source ?? null,\n duration: row.duration_minutes ?? null,\n durationMinutes: row.duration_minutes ?? null,\n timezone: row.timezone ?? null,\n location: row.location ?? null,\n allDay: row.all_day ?? null,\n recurrenceRule: row.recurrence_rule ?? null,\n recurrenceEnd: toIsoString(row.recurrence_end),\n participants: row.participants ?? null,\n reminderMinutes: row.reminder_minutes ?? null,\n visibility: row.visibility ?? null,\n channelId: row.channel_id ?? null,\n linkedEntities: row.linked_entities ?? null,\n guestPermissions: row.guest_permissions ?? null,\n pinned: row.pinned ?? false,\n organizationId: row.organization_id,\n tenantId: row.tenant_id,\n createdAt: toIsoString(row.created_at) ?? new Date().toISOString(),\n updatedAt: toIsoString(row.updated_at) ?? new Date().toISOString(),\n authorName: row.author_user_id ? userMap.get(interactionUserKey({ tenantId: row.tenant_id, organizationId: row.organization_id }, row.author_user_id))?.name ?? null : null,\n authorEmail: row.author_user_id ? userMap.get(interactionUserKey({ tenantId: row.tenant_id, organizationId: row.organization_id }, row.author_user_id))?.email ?? null : null,\n dealTitle: row.deal_id ? dealMap.get(row.deal_id) ?? null : null,\n customValues: normalizeCustomFieldResponse(customFieldValues[row.id]) ?? null,\n }, interactionRecordMap.get(row.id), encryptedFieldsByOrganization.get(row.organization_id) ?? []))\n\n const enricherContext = await buildEnricherContext(\n container,\n auth,\n selectedOrganizationId,\n viewerUserId ? { userId: viewerUserId, features: callerUserFeatures } : undefined,\n )\n const enriched = await applyResponseEnrichers(baseItems, 'customers.interaction', enricherContext)\n\n let nextCursor: string | undefined\n if (hasMore && pageRows.length > 0) {\n const last = pageRows[pageRows.length - 1]\n nextCursor = encodeCursor({\n id: last.id,\n sortValue: normalizeCursorValue(last.__sort_value, sortConfig.type),\n })\n }\n\n return NextResponse.json({\n items: enriched.items,\n nextCursor,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n if (err instanceof z.ZodError) {\n return NextResponse.json(\n { error: 'Validation failed', details: err.issues },\n { status: 400 },\n )\n }\n logger.error('customers.interactions.get failed', { err })\n const { translate } = await resolveTranslations()\n return NextResponse.json(\n { error: translate('customers.interactions.load.error', 'Failed to load interactions.') },\n { status: 500 },\n )\n }\n}\n\nconst interactionListItemSchema = z\n .object({\n id: z.string().uuid(),\n entityId: z.string().uuid().nullable(),\n dealId: z.string().uuid().nullable(),\n interactionType: z.string(),\n title: z.string().nullable(),\n body: z.string().nullable(),\n status: z.string(),\n scheduledAt: z.string().nullable(),\n occurredAt: z.string().nullable(),\n priority: z.number().nullable(),\n authorUserId: z.string().uuid().nullable(),\n ownerUserId: z.string().uuid().nullable(),\n externalMessageId: z.string().uuid().nullable().optional(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n duration: z.number().nullable().optional(),\n durationMinutes: z.number().nullable().optional(),\n timezone: z.string().nullable().optional(),\n location: z.string().nullable().optional(),\n allDay: z.boolean().nullable().optional(),\n recurrenceRule: z.string().nullable().optional(),\n recurrenceEnd: z.string().nullable().optional(),\n participants: z.array(\n z.object({\n userId: z\n .string()\n .uuid()\n .optional()\n .describe(\n 'Absent for an external guest, who has no person/customer/staff record and is identified by email instead. Identify a participant by userId when present, otherwise by its normalized email.',\n ),\n name: z.string().optional(),\n email: z.string().optional(),\n status: z.string().optional(),\n }),\n ).nullable().optional(),\n reminderMinutes: z.number().nullable().optional(),\n visibility: z.string().nullable().optional(),\n linkedEntities: z.array(\n z.object({\n id: z.string().uuid(),\n type: z.string(),\n label: z.string(),\n }),\n ).nullable().optional(),\n guestPermissions: z\n .object({\n canInviteOthers: z.boolean().optional(),\n canModify: z.boolean().optional(),\n canSeeList: z.boolean().optional(),\n })\n .nullable()\n .optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n createdAt: z.string().nullable(),\n updatedAt: z.string().nullable(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealTitle: z.string().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n _integrations: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n\nconst interactionListResponseSchema = z.object({\n items: z.array(interactionListItemSchema),\n nextCursor: z.string().optional(),\n})\n\nconst interactionCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n})\n\nexport const openApi = createCustomersCrudOpenApi({\n resourceName: 'Interaction',\n querySchema: listSchema,\n listResponseSchema: interactionListResponseSchema,\n create: {\n schema: interactionCreateSchema,\n responseSchema: interactionCreateResponseSchema,\n description: 'Creates a new interaction linked to a customer entity or deal.',\n },\n update: {\n schema: interactionUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates fields for an existing interaction.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Soft-deletes an interaction identified by `id`. Accepts id via body or query string.',\n },\n})\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { sql } from 'kysely'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { normalizeCustomFieldResponse } from '@open-mercato/shared/lib/custom-fields/normalize'\nimport { applyResponseEnrichers } from '@open-mercato/shared/lib/crud/enricher-runner'\nimport type { EnricherContext } from '@open-mercato/shared/lib/crud/response-enricher'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTenantEncryptionService } from '@open-mercato/shared/lib/encryption/customFieldValues'\nimport { resolveEncryptedSortFields, resolveEncryptedSortMaxRows } from '@open-mercato/shared/lib/query/encrypted-sort'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { resolveOrganizationScopeFilter } from '@open-mercato/core/modules/directory/utils/organizationScopeFilter'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CustomerDeal, CustomerInteraction } from '../../data/entities'\nimport { interactionUserKey, loadInteractionAuthors } from '../../lib/interactionUsers'\nimport { interactionCreateSchema, interactionUpdateSchema } from '../../data/validators'\nimport { parseScopedCommandInput } from '../utils'\nimport {\n createCustomersCrudOpenApi,\n defaultOkResponseSchema,\n} from '../openapi'\nimport { CUSTOMER_INTERACTION_ENTITY_ID } from '../../lib/interactionCompatibility'\nimport { applyEmailVisibilityFilter } from '../../lib/visibilityFilter'\nimport { listGrantsForViewer, listSharedChannelIds } from '../../lib/conversationShares'\nimport { resolveEncryptedSortPage } from './encryptedSortPage'\nimport { applyDecryptedFields } from './decryptedFields'\nimport { resolveCanonicalActivityTargetId } from '../../lib/legacyActivityBridge'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst interactionSortFieldSchema = z.enum([\n 'scheduledAt',\n 'occurredAt',\n 'createdAt',\n 'updatedAt',\n 'status',\n 'priority',\n 'interactionType',\n 'title',\n])\n\nexport const listSchema = z\n .object({\n limit: z.coerce.number().min(1).max(100).default(25),\n cursor: z.string().optional(),\n entityId: z.string().uuid().optional(),\n dealId: z.string().uuid().optional(),\n status: z.string().optional(),\n interactionType: z.string().optional(),\n type: z.string().optional(),\n excludeInteractionType: z.string().optional(),\n search: z.string().trim().min(1).optional(),\n from: z.coerce.date().optional(),\n to: z.coerce.date().optional(),\n recurrenceMasters: z.enum(['true', 'false']).optional(),\n pinned: z.enum(['true', 'false']).optional(),\n sortField: interactionSortFieldSchema.optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.interactions.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.interactions.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.interactions.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.interactions.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CustomerInteraction,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n enrichers: { entityId: 'customers.interaction' },\n indexer: {\n entityType: 'customers:customer_interaction',\n },\n actions: {\n create: {\n commandId: 'customers.interactions.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(interactionCreateSchema, raw ?? {}, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.interactionId ?? result?.id ?? null }),\n status: 201,\n },\n update: {\n commandId: 'customers.interactions.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const parsed = parseScopedCommandInput(interactionUpdateSchema, raw ?? {}, ctx, translate)\n // Bridge legacy `customer_activities` rows into `customer_interactions`\n // before the canonical update runs so historical activities (#1807)\n // remain editable through the new dialog. No-op when the canonical\n // record already exists.\n const tenantId = ctx.auth?.tenantId ?? null\n if (typeof parsed.id === 'string' && tenantId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const commandBus = ctx.container.resolve('commandBus') as CommandBus\n const commandContext: CommandRuntimeContext = {\n container: ctx.container,\n auth: ctx.auth ?? null,\n organizationScope: ctx.organizationScope ?? null,\n selectedOrganizationId: ctx.selectedOrganizationId ?? null,\n organizationIds: ctx.organizationIds ?? null,\n request: ctx.request,\n }\n await resolveCanonicalActivityTargetId(em, commandBus, commandContext, parsed.id, tenantId)\n } catch (err) {\n // Bridging is best-effort; downstream lookup will surface a 404\n // when neither canonical nor legacy rows exist.\n logger.warn('Legacy interaction bridge failed', { component: 'interactions.put', id: parsed.id, err })\n }\n }\n return parsed\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'customers.interactions.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id =\n parsed?.body?.id ??\n parsed?.id ??\n parsed?.query?.id ??\n (ctx.request ? new URL(ctx.request.url).searchParams.get('id') : null)\n if (!id) {\n throw new CrudHttpError(400, {\n error: translate('customers.errors.interaction_required', 'Interaction id is required'),\n })\n }\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nconst { POST, PUT, DELETE } = crud\n\nexport { POST, PUT, DELETE }\n\ntype InteractionListRow = {\n id: string\n entity_id: string\n deal_id: string | null\n interaction_type: string\n title: string | null\n body: string | null\n status: string\n scheduled_at: Date | null\n occurred_at: Date | null\n priority: number | null\n author_user_id: string | null\n owner_user_id: string | null\n external_message_id: string | null\n appearance_icon: string | null\n appearance_color: string | null\n source: string | null\n timezone: string | null\n duration_minutes: number | null\n location: string | null\n all_day: boolean | null\n recurrence_rule: string | null\n recurrence_end: Date | null\n participants: Array<{ userId?: string; name?: string; email?: string; status?: string }> | null\n reminder_minutes: number | null\n visibility: string | null\n /** Denormalized channel \u2014 the shared-team-mailbox arm keys on this, not on the author. */\n channel_id: string | null\n linked_entities: Array<{ id: string; type: string; label: string }> | null\n guest_permissions: { canInviteOthers?: boolean; canModify?: boolean; canSeeList?: boolean } | null\n pinned: boolean\n organization_id: string\n tenant_id: string\n created_at: Date\n updated_at: Date\n __sort_value: string | number | Date | null\n}\n\ntype CursorPayload = {\n id: string\n sortValue: string | number | null\n}\n\ntype RbacServiceLike = {\n getGrantedFeatures?: (userId: string, input: { tenantId: string | null; organizationId: string | null }) => Promise<string[]>\n}\n\nconst cursorSchema = z.object({\n id: z.string().uuid(),\n sortValue: z.union([z.string(), z.number(), z.null()]),\n})\n\nconst interactionSortConfig = {\n scheduledAt: { column: 'scheduled_at', type: 'date' as const, defaultDir: 'asc' as const },\n occurredAt: { column: 'occurred_at', type: 'date' as const, defaultDir: 'desc' as const },\n createdAt: { column: 'created_at', type: 'date' as const, defaultDir: 'desc' as const },\n updatedAt: { column: 'updated_at', type: 'date' as const, defaultDir: 'desc' as const },\n status: { column: 'status', type: 'text' as const, defaultDir: 'asc' as const },\n priority: { column: 'priority', type: 'number' as const, defaultDir: 'desc' as const },\n interactionType: { column: 'interaction_type', type: 'text' as const, defaultDir: 'asc' as const },\n title: { column: 'title', type: 'text' as const, defaultDir: 'asc' as const },\n} as const\n\nfunction toIsoString(value: unknown): string | null {\n if (value == null) return null\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? null : value.toISOString()\n }\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed.length) return null\n const parsed = new Date(trimmed)\n return Number.isNaN(parsed.getTime()) ? trimmed : parsed.toISOString()\n }\n return null\n}\n\nfunction normalizeCursorValue(\n value: string | number | Date | null,\n type: 'date' | 'number' | 'text',\n): string | number | null {\n if (value == null) return null\n if (type === 'number') {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n }\n if (type === 'date') {\n return toIsoString(value)\n }\n if (typeof value === 'string') return value\n if (value instanceof Date) return value.toISOString()\n return String(value)\n}\n\nfunction encodeCursor(payload: CursorPayload): string {\n return Buffer.from(JSON.stringify(payload), 'utf8').toString('base64')\n}\n\nfunction decodeCursor(token: string | undefined, type: 'date' | 'number' | 'text'): CursorPayload | null {\n if (!token) return null\n try {\n const decoded = Buffer.from(token, 'base64').toString('utf8')\n const parsed = cursorSchema.parse(JSON.parse(decoded))\n return {\n id: parsed.id,\n sortValue: normalizeCursorValue(parsed.sortValue, type),\n }\n } catch {\n return null\n }\n}\n\nfunction buildSortSql(\n sortField: keyof typeof interactionSortConfig,\n sortDir: 'asc' | 'desc',\n): string {\n const config = interactionSortConfig[sortField]\n if (config.type === 'date') {\n const sentinel =\n sortDir === 'asc'\n ? \"timestamp with time zone '9999-12-31T23:59:59.999Z'\"\n : \"timestamp with time zone '0001-01-01T00:00:00.000Z'\"\n return `coalesce(${config.column}, ${sentinel})`\n }\n if (config.type === 'number') {\n const sentinel = sortDir === 'asc' ? '2147483647' : '-2147483648'\n return `coalesce(${config.column}, ${sentinel})`\n }\n const sentinel = sortDir === 'asc' ? \"'~~~~~~~~~~'\" : \"''\"\n return `coalesce(${config.column}, ${sentinel})`\n}\n\nconst INTERACTION_LIST_COLUMNS = [\n 'id',\n 'entity_id',\n 'deal_id',\n 'interaction_type',\n 'title',\n 'body',\n 'status',\n 'scheduled_at',\n 'occurred_at',\n 'priority',\n 'author_user_id',\n 'owner_user_id',\n 'external_message_id',\n 'appearance_icon',\n 'appearance_color',\n 'source',\n 'timezone',\n 'duration_minutes',\n 'location',\n 'all_day',\n 'recurrence_rule',\n 'recurrence_end',\n 'participants',\n 'reminder_minutes',\n 'visibility',\n // Required by `interactionEmailCardEnricher`: without `channel_id` the\n // shared-team-mailbox arm of `isEmailHiddenFrom` can never match, so a teammate\n // silently loses the email-card actions on a mailbox they may legitimately read.\n 'channel_id',\n 'linked_entities',\n 'guest_permissions',\n 'pinned',\n 'organization_id',\n 'tenant_id',\n 'created_at',\n 'updated_at',\n] as const\n\n// Shared by both the SQL keyset path and the encrypted-sort candidate scan\n// so the two paths never drift on which rows are in scope.\nfunction applyInteractionListFilters(\n baseQuery: any,\n params: {\n tenantId: string\n organizationIds: string[] | undefined\n query: z.infer<typeof listSchema>\n },\n): any {\n let q = baseQuery.where('deleted_at', 'is', null).where('tenant_id', '=', params.tenantId)\n if (params.organizationIds !== undefined) q = q.where('organization_id', 'in', params.organizationIds)\n const { query } = params\n if (query.entityId) q = q.where('entity_id', '=', query.entityId)\n if (query.dealId) q = q.where('deal_id', '=', query.dealId)\n if (query.status) q = q.where('status', '=', query.status)\n if (query.interactionType) q = q.where('interaction_type', '=', query.interactionType)\n if (query.type) {\n const types = query.type.split(',').map((t) => t.trim()).filter(Boolean)\n if (types.length > 0) q = q.where('interaction_type', 'in', types)\n }\n if (query.pinned === 'true') {\n q = q.where('pinned', '=', true)\n } else if (query.pinned === 'false') {\n q = q.where('pinned', '=', false)\n }\n if (query.excludeInteractionType) q = q.where('interaction_type', '!=', query.excludeInteractionType)\n if (query.search) {\n // NOTE: for tenants with data encryption enabled, `title`/`body` are\n // ciphertext at rest (see encryption.ts), so this ILIKE matches encrypted\n // bytes and returns no rows \u2014 substring search over encrypted free-text\n // columns is unsupported, the same documented limitation as\n // customer_activity / customer_comment. The returned page's title/body are\n // still decrypted for display further below.\n const searchTerm = `%${escapeLikePattern(query.search)}%`\n q = q.where(sql<boolean>`(coalesce(title, '') ilike ${searchTerm} or coalesce(body, '') ilike ${searchTerm})`)\n }\n if (query.recurrenceMasters === 'true') {\n q = q.where('recurrence_rule', 'is not', null)\n if (query.from) {\n q = q.where(sql<boolean>`(recurrence_end is null or recurrence_end >= ${query.from})`)\n }\n if (query.to) {\n q = q.where(sql<boolean>`coalesce(occurred_at, scheduled_at, created_at) <= ${query.to}`)\n }\n } else {\n if (query.from) {\n q = q.where(sql<boolean>`coalesce(occurred_at, scheduled_at, created_at) >= ${query.from}`)\n }\n if (query.to) {\n q = q.where(sql<boolean>`coalesce(occurred_at, scheduled_at, created_at) <= ${query.to}`)\n }\n }\n return q\n}\n\nasync function resolveUserFeatures(\n container: { resolve: (name: string) => unknown },\n userId: string,\n tenantId: string | null,\n organizationId: string | null,\n): Promise<string[] | undefined> {\n try {\n const rbac = container.resolve('rbacService') as RbacServiceLike | undefined\n if (!rbac?.getGrantedFeatures) return undefined\n return await rbac.getGrantedFeatures(userId, { tenantId, organizationId })\n } catch {\n return undefined\n }\n}\n\nasync function buildEnricherContext(\n container: { resolve: (name: string) => unknown },\n auth: NonNullable<Awaited<ReturnType<typeof getAuthFromRequest>>>,\n organizationId: string | null,\n precomputedUserFeatures?: { userId: string; features: string[] | undefined },\n): Promise<EnricherContext> {\n const userId =\n (typeof auth.sub === 'string' && auth.sub.trim().length > 0\n ? auth.sub\n : typeof auth.userId === 'string' && auth.userId.trim().length > 0\n ? auth.userId\n : typeof auth.keyId === 'string' && auth.keyId.trim().length > 0\n ? auth.keyId\n : 'system')\n\n // Reuse features already resolved for this same user (the GET handler resolves\n // them once for the visibility filter) to avoid a second RBAC lookup per request.\n const userFeatures =\n precomputedUserFeatures && precomputedUserFeatures.userId === userId\n ? precomputedUserFeatures.features\n : await resolveUserFeatures(container, userId, auth.tenantId ?? null, organizationId)\n\n return {\n organizationId: organizationId ?? '',\n tenantId: auth.tenantId ?? '',\n userId,\n em: container.resolve('em'),\n container,\n userFeatures,\n }\n}\n\nexport async function GET(req: Request) {\n try {\n const queryUrl = new URL(req.url)\n const query = listSchema.parse(Object.fromEntries(queryUrl.searchParams))\n const container = await createRequestContainer()\n const auth = await getAuthFromRequest(req)\n const { translate } = await resolveTranslations()\n\n if (!auth || !auth.tenantId) {\n throw new CrudHttpError(401, {\n error: translate('customers.errors.unauthorized', 'Unauthorized'),\n })\n }\n\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const { organizationIds, rbacOrganizationId: selectedOrganizationId } = resolveOrganizationScopeFilter(scope, auth)\n\n const requestedSortField = query.sortField ?? 'scheduledAt'\n const sortConfig = interactionSortConfig[requestedSortField]\n const sortDir = query.sortDir ?? sortConfig.defaultDir\n const sortSql = buildSortSql(requestedSortField, sortDir)\n const cursor = decodeCursor(query.cursor, sortConfig.type)\n if (query.cursor && !cursor) {\n throw new CrudHttpError(400, {\n error: translate('customers.interactions.cursor.invalid', 'Invalid cursor'),\n })\n }\n if (organizationIds?.length === 0) {\n return NextResponse.json({ items: [] })\n }\n\n const em = (container.resolve('em') as EntityManager).fork()\n const db = em.getKysely<any>() as any\n\n // \u2500\u2500 Email visibility filter (2026-05-27) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Non-email interactions pass through; email rows with visibility='private'\n // are filtered out unless the caller is the author or has admin bypass.\n // API-key callers have no user identity (`auth.sub` undefined): resolve the\n // viewer to null so they never gain the author bypass and only see shared\n // emails (fail-closed). Mirrors counts/people/activities routes.\n const viewerUserId = auth.isApiKey ? null : (auth.sub ?? null)\n // Conversation shares that widen this caller's email access. Unscoped surface,\n // so this is the capped variant (see SHARE_ARM_MAX).\n const emailShareScope = {\n tenantId: auth.tenantId as string,\n organizationId: selectedOrganizationId,\n }\n const [emailShareGrants, emailSharedChannelIds] = await Promise.all([\n listGrantsForViewer(em, emailShareScope, viewerUserId),\n listSharedChannelIds(em, emailShareScope, viewerUserId),\n ])\n const encryptionService = resolveTenantEncryptionService(em)\n // Encrypted sort columns can't use SQL keyset ordering on ciphertext, so an\n // encrypted sort field takes a bounded candidate-scan + in-memory-sort path\n // instead of the SQL path below. Resolved alongside the independent\n // visibility-feature lookup rather than after it.\n const [callerUserFeatures, encryptedSortFields] = await Promise.all([\n viewerUserId\n ? resolveUserFeatures(container, viewerUserId, auth.tenantId ?? null, selectedOrganizationId)\n : Promise.resolve(undefined),\n resolveEncryptedSortFields(\n encryptionService,\n CUSTOMER_INTERACTION_ENTITY_ID,\n [sortConfig.column],\n auth.tenantId,\n selectedOrganizationId,\n ),\n ])\n const sortFieldIsEncrypted = encryptedSortFields.has(sortConfig.column)\n\n let pageRows: InteractionListRow[]\n let hasMore: boolean\n\n if (sortFieldIsEncrypted) {\n let candidateQuery = applyInteractionListFilters(\n db.selectFrom('customer_interactions').select(['id', sortConfig.column]),\n { tenantId: auth.tenantId, organizationIds, query },\n )\n candidateQuery = applyEmailVisibilityFilter(candidateQuery as any, {\n currentUserId: viewerUserId,\n userFeatures: callerUserFeatures,\n sharedConversations: emailShareGrants,\n sharedChannelIds: emailSharedChannelIds,\n })\n const cap = resolveEncryptedSortMaxRows()\n if (cap !== null) {\n candidateQuery = candidateQuery.limit(cap).orderBy('id', 'asc')\n }\n const candidateRows = await candidateQuery.execute() as Array<{ id: string } & Record<string, unknown>>\n if (cap !== null && candidateRows.length >= cap) {\n logger.warn('Encrypted sort candidate scan hit OM_ENCRYPTED_SORT_MAX_ROWS cap; results may be incomplete', {\n component: 'interactions.GET',\n cap,\n sortField: sortConfig.column,\n tenantId: auth.tenantId,\n })\n }\n\n const decryptPayload = encryptionService?.decryptEntityPayload?.bind(encryptionService)\n const { pageIds, hasMore: encryptedHasMore } = await resolveEncryptedSortPage({\n candidates: candidateRows,\n decryptRow: async (row) => {\n if (!decryptPayload) return row\n try {\n const decrypted = await decryptPayload(CUSTOMER_INTERACTION_ENTITY_ID, row, auth.tenantId, selectedOrganizationId)\n return { ...row, ...decrypted }\n } catch (err) {\n logger.error('error decrypting sort candidate', { component: 'interactions.GET', err })\n return row\n }\n },\n sortField: sortConfig.column,\n sortDir,\n cursorId: cursor?.id ?? null,\n limit: query.limit,\n })\n hasMore = encryptedHasMore\n\n if (pageIds.length === 0) {\n pageRows = []\n } else {\n let pageQuery = applyInteractionListFilters(\n db.selectFrom('customer_interactions').select([...INTERACTION_LIST_COLUMNS, sql`${sql.raw(sortSql)}`.as('__sort_value')]),\n { tenantId: auth.tenantId, organizationIds, query },\n )\n pageQuery = applyEmailVisibilityFilter(pageQuery as any, {\n currentUserId: viewerUserId,\n userFeatures: callerUserFeatures,\n sharedConversations: emailShareGrants,\n sharedChannelIds: emailSharedChannelIds,\n })\n pageQuery = pageQuery.where('id', 'in', pageIds)\n const rawPageRows = await pageQuery.execute() as InteractionListRow[]\n const byId = new Map(rawPageRows.map((row) => [row.id, row]))\n pageRows = pageIds\n .map((id) => byId.get(id))\n .filter((row): row is InteractionListRow => row != null)\n }\n } else {\n let rowsQuery = applyInteractionListFilters(\n db\n .selectFrom('customer_interactions')\n .select([...INTERACTION_LIST_COLUMNS, sql`${sql.raw(sortSql)}`.as('__sort_value')])\n .limit(query.limit + 1),\n { tenantId: auth.tenantId, organizationIds, query },\n )\n\n if (cursor) {\n const op = sortDir === 'asc' ? '>' : '<'\n const opRaw = sql.raw(op)\n const sortRaw = sql.raw(sortSql)\n rowsQuery = rowsQuery.where((eb: any) => eb.or([\n sql<boolean>`${sortRaw} ${opRaw} ${cursor.sortValue}`,\n eb.and([\n sql<boolean>`${sortRaw} = ${cursor.sortValue}`,\n eb('id', op, cursor.id),\n ]),\n ]))\n }\n\n rowsQuery = applyEmailVisibilityFilter(rowsQuery as any, {\n currentUserId: viewerUserId,\n userFeatures: callerUserFeatures,\n sharedConversations: emailShareGrants,\n sharedChannelIds: emailSharedChannelIds,\n })\n\n rowsQuery = rowsQuery.orderBy(sql`${sql.raw(sortSql)} ${sql.raw(sortDir)}`).orderBy('id', sortDir)\n\n const rows = await rowsQuery.execute() as InteractionListRow[]\n pageRows = rows.slice(0, query.limit)\n hasMore = rows.length > query.limit\n }\n\n const dealIds = Array.from(\n new Set(\n pageRows\n .map((row) => (typeof row.deal_id === 'string' ? row.deal_id : null))\n .filter((value): value is string => !!value),\n ),\n )\n const interactionIds = pageRows.map((row) => row.id)\n // A page can span the selected organization plus its descendants\n // (organizationScope.ts expands a concrete selection that way), and\n // encryption maps are resolved per organization with first-match-wins \u2014\n // an org-specific map replaces rather than merges with the tenant-wide\n // one. Resolving a single field set from `selectedOrganizationId` and\n // applying it to every row therefore missed descendant-org fields the\n // row's own map covers (#5945 follow-up). Each row's own\n // `organization_id` is resolved instead, one lookup per distinct\n // organization on the page \u2014 `getEncryptedFieldNames` memoizes per\n // (entity, tenant, organization), so this adds no query for the common\n // single-organization case.\n const pageOrganizationIds = Array.from(\n new Set(pageRows.map((row) => row.organization_id).filter((value): value is string => !!value)),\n )\n\n const [userMap, deals, customFieldValues, interactionRecords, encryptedFieldsByOrganization] = await Promise.all([\n loadInteractionAuthors(em, pageRows.map((row) => ({\n tenantId: row.tenant_id,\n organizationId: row.organization_id,\n authorUserId: row.author_user_id,\n }))),\n dealIds.length > 0 ? findWithDecryption(em, CustomerDeal, { id: { $in: dealIds } }, undefined, { tenantId: auth.tenantId, organizationId: selectedOrganizationId }) : Promise.resolve([]),\n interactionIds.length > 0\n ? loadCustomFieldValues({\n em,\n entityId: CUSTOMER_INTERACTION_ENTITY_ID,\n recordIds: interactionIds,\n tenantIdByRecord: Object.fromEntries(pageRows.map((row) => [row.id, row.tenant_id])),\n organizationIdByRecord: Object.fromEntries(pageRows.map((row) => [row.id, row.organization_id])),\n tenantFallbacks: [auth.tenantId].filter((value): value is string => !!value),\n })\n : Promise.resolve<Record<string, Record<string, unknown>>>({}),\n interactionIds.length > 0\n ? findWithDecryption(em, CustomerInteraction, { id: { $in: interactionIds } } as never, undefined, { tenantId: auth.tenantId, organizationId: selectedOrganizationId })\n : Promise.resolve([]),\n (async () => {\n const byOrganization = new Map<string, readonly string[]>()\n if (interactionIds.length === 0 || !encryptionService?.getEncryptedFieldNames || pageOrganizationIds.length === 0) {\n return byOrganization\n }\n await Promise.all(pageOrganizationIds.map(async (organizationId) => {\n const fields = await encryptionService.getEncryptedFieldNames(CUSTOMER_INTERACTION_ENTITY_ID, auth.tenantId, organizationId)\n byOrganization.set(organizationId, fields)\n }))\n return byOrganization\n })(),\n ])\n\n const dealMap = new Map(\n deals.map((deal) => [deal.id, deal.title]),\n )\n // The kysely rows above carry raw column values, so every field the entity's\n // encryption map covers arrives as ciphertext. findWithDecryption already\n // returned those fields in plaintext, so the response takes them from the\n // decrypted records. The covered set is read from each row's own\n // organization's resolved map rather than hard-coded or shared across the\n // page, so extending the map \u2014 or a page spanning several organizations \u2014\n // cannot leave a field passing through as ciphertext (#5945).\n const interactionRecordMap = new Map<string, CustomerInteraction>(\n (interactionRecords as CustomerInteraction[]).map((record) => [record.id, record]),\n )\n\n const baseItems = pageRows.map((row) => applyDecryptedFields({\n id: row.id,\n entityId: row.entity_id,\n dealId: row.deal_id ?? null,\n interactionType: row.interaction_type,\n title: row.title ?? null,\n body: row.body ?? null,\n status: row.status,\n scheduledAt: toIsoString(row.scheduled_at),\n occurredAt: toIsoString(row.occurred_at),\n priority: row.priority ?? null,\n authorUserId: row.author_user_id ?? null,\n ownerUserId: row.owner_user_id ?? null,\n externalMessageId: row.external_message_id ?? null,\n appearanceIcon: row.appearance_icon ?? null,\n appearanceColor: row.appearance_color ?? null,\n source: row.source ?? null,\n duration: row.duration_minutes ?? null,\n durationMinutes: row.duration_minutes ?? null,\n timezone: row.timezone ?? null,\n location: row.location ?? null,\n allDay: row.all_day ?? null,\n recurrenceRule: row.recurrence_rule ?? null,\n recurrenceEnd: toIsoString(row.recurrence_end),\n participants: row.participants ?? null,\n reminderMinutes: row.reminder_minutes ?? null,\n visibility: row.visibility ?? null,\n channelId: row.channel_id ?? null,\n linkedEntities: row.linked_entities ?? null,\n guestPermissions: row.guest_permissions ?? null,\n pinned: row.pinned ?? false,\n organizationId: row.organization_id,\n tenantId: row.tenant_id,\n createdAt: toIsoString(row.created_at) ?? new Date().toISOString(),\n updatedAt: toIsoString(row.updated_at) ?? new Date().toISOString(),\n authorName: row.author_user_id ? userMap.get(interactionUserKey({ tenantId: row.tenant_id, organizationId: row.organization_id }, row.author_user_id))?.name ?? null : null,\n authorEmail: row.author_user_id ? userMap.get(interactionUserKey({ tenantId: row.tenant_id, organizationId: row.organization_id }, row.author_user_id))?.email ?? null : null,\n dealTitle: row.deal_id ? dealMap.get(row.deal_id) ?? null : null,\n customValues: normalizeCustomFieldResponse(customFieldValues[row.id]) ?? null,\n }, interactionRecordMap.get(row.id), encryptedFieldsByOrganization.get(row.organization_id) ?? []))\n\n const enricherContext = await buildEnricherContext(\n container,\n auth,\n selectedOrganizationId,\n viewerUserId ? { userId: viewerUserId, features: callerUserFeatures } : undefined,\n )\n const enriched = await applyResponseEnrichers(baseItems, 'customers.interaction', enricherContext)\n\n let nextCursor: string | undefined\n if (hasMore && pageRows.length > 0) {\n const last = pageRows[pageRows.length - 1]\n nextCursor = encodeCursor({\n id: last.id,\n sortValue: normalizeCursorValue(last.__sort_value, sortConfig.type),\n })\n }\n\n return NextResponse.json({\n items: enriched.items,\n nextCursor,\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n if (err instanceof z.ZodError) {\n return NextResponse.json(\n { error: 'Validation failed', details: err.issues },\n { status: 400 },\n )\n }\n logger.error('customers.interactions.get failed', { err })\n const { translate } = await resolveTranslations()\n return NextResponse.json(\n { error: translate('customers.interactions.load.error', 'Failed to load interactions.') },\n { status: 500 },\n )\n }\n}\n\nconst interactionListItemSchema = z\n .object({\n id: z.string().uuid(),\n entityId: z.string().uuid().nullable(),\n dealId: z.string().uuid().nullable(),\n interactionType: z.string(),\n title: z.string().nullable(),\n body: z.string().nullable(),\n status: z.string(),\n scheduledAt: z.string().nullable(),\n occurredAt: z.string().nullable(),\n priority: z.number().nullable(),\n authorUserId: z.string().uuid().nullable(),\n ownerUserId: z.string().uuid().nullable(),\n externalMessageId: z.string().uuid().nullable().optional(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n duration: z.number().nullable().optional(),\n durationMinutes: z.number().nullable().optional(),\n timezone: z.string().nullable().optional(),\n location: z.string().nullable().optional(),\n allDay: z.boolean().nullable().optional(),\n recurrenceRule: z.string().nullable().optional(),\n recurrenceEnd: z.string().nullable().optional(),\n participants: z.array(\n z.object({\n userId: z\n .string()\n .uuid()\n .optional()\n .describe(\n 'Absent for an external guest, who has no person/customer/staff record and is identified by email instead. Identify a participant by userId when present, otherwise by its normalized email.',\n ),\n name: z.string().optional(),\n email: z.string().optional(),\n status: z.string().optional(),\n }),\n ).nullable().optional(),\n reminderMinutes: z.number().nullable().optional(),\n visibility: z.string().nullable().optional(),\n linkedEntities: z.array(\n z.object({\n id: z.string().uuid(),\n type: z.string(),\n label: z.string(),\n }),\n ).nullable().optional(),\n guestPermissions: z\n .object({\n canInviteOthers: z.boolean().optional(),\n canModify: z.boolean().optional(),\n canSeeList: z.boolean().optional(),\n })\n .nullable()\n .optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n createdAt: z.string().nullable(),\n updatedAt: z.string().nullable(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealTitle: z.string().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n _integrations: z.record(z.string(), z.unknown()).optional(),\n })\n .passthrough()\n\nconst interactionListResponseSchema = z.object({\n items: z.array(interactionListItemSchema),\n nextCursor: z.string().optional(),\n})\n\nconst interactionCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n})\n\nexport const openApi = createCustomersCrudOpenApi({\n resourceName: 'Interaction',\n querySchema: listSchema,\n listResponseSchema: interactionListResponseSchema,\n create: {\n schema: interactionCreateSchema,\n responseSchema: interactionCreateResponseSchema,\n description: 'Creates a new interaction linked to a customer entity or deal.',\n },\n update: {\n schema: interactionUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates fields for an existing interaction.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Soft-deletes an interaction identified by `id`. Accepts id via body or query string.',\n },\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["sentinel"]
|
|
7
7
|
}
|