@aglyn/plugins-crm 1.0.0-beta.221 → 1.0.0-beta.223
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/package.json +13 -13
- package/src/lib/components/activity-list.js +12 -5
- package/src/lib/components/activity-list.js.map +1 -1
- package/src/lib/components/companies-bulk-bar.d.ts +1 -4
- package/src/lib/components/companies-bulk-bar.js +7 -20
- package/src/lib/components/companies-bulk-bar.js.map +1 -1
- package/src/lib/components/companies-section.d.ts +3 -3
- package/src/lib/components/companies-section.js +149 -46
- package/src/lib/components/companies-section.js.map +1 -1
- package/src/lib/components/company-edit-drawer.js +281 -20
- package/src/lib/components/company-edit-drawer.js.map +1 -1
- package/src/lib/components/company-properties-card.js +99 -8
- package/src/lib/components/company-properties-card.js.map +1 -1
- package/src/lib/components/contact-detail-page.js +3 -1
- package/src/lib/components/contact-detail-page.js.map +1 -1
- package/src/lib/components/contact-merge-dialog.js +33 -10
- package/src/lib/components/contact-merge-dialog.js.map +1 -1
- package/src/lib/components/contact-properties-card.d.ts +0 -69
- package/src/lib/components/contact-properties-card.js +350 -60
- package/src/lib/components/contact-properties-card.js.map +1 -1
- package/src/lib/components/contact-reports-to-field.d.ts +46 -0
- package/src/lib/components/contact-reports-to-field.js +67 -0
- package/src/lib/components/contact-reports-to-field.js.map +1 -0
- package/src/lib/components/contacts-bulk-bar.d.ts +1 -8
- package/src/lib/components/contacts-bulk-bar.js +7 -19
- package/src/lib/components/contacts-bulk-bar.js.map +1 -1
- package/src/lib/components/contacts-section.js +46 -33
- package/src/lib/components/contacts-section.js.map +1 -1
- package/src/lib/components/crm-call-actions.d.ts +10 -0
- package/src/lib/components/crm-call-actions.js +26 -9
- package/src/lib/components/crm-call-actions.js.map +1 -1
- package/src/lib/components/crm-next-activity-column.js +1 -1
- package/src/lib/components/crm-next-activity-column.js.map +1 -1
- package/src/lib/components/crm-record-picker.d.ts +15 -0
- package/src/lib/components/crm-record-picker.js +16 -10
- package/src/lib/components/crm-record-picker.js.map +1 -1
- package/src/lib/components/crm-transfer-buttons.d.ts +54 -0
- package/src/lib/components/crm-transfer-buttons.js +167 -0
- package/src/lib/components/crm-transfer-buttons.js.map +1 -0
- package/src/lib/components/deal-contact-roles-card.d.ts +46 -0
- package/src/lib/components/deal-contact-roles-card.js +368 -0
- package/src/lib/components/deal-contact-roles-card.js.map +1 -0
- package/src/lib/components/deal-detail-page.d.ts +3 -2
- package/src/lib/components/deal-detail-page.js +25 -6
- package/src/lib/components/deal-detail-page.js.map +1 -1
- package/src/lib/components/deal-edit-drawer.d.ts +10 -0
- package/src/lib/components/deal-edit-drawer.js +219 -10
- package/src/lib/components/deal-edit-drawer.js.map +1 -1
- package/src/lib/components/deal-properties-card.d.ts +7 -0
- package/src/lib/components/deal-properties-card.js +34 -3
- package/src/lib/components/deal-properties-card.js.map +1 -1
- package/src/lib/components/deal-stage-card.d.ts +4 -0
- package/src/lib/components/deal-stage-card.js +10 -2
- package/src/lib/components/deal-stage-card.js.map +1 -1
- package/src/lib/components/deals-bulk-bar.d.ts +0 -3
- package/src/lib/components/deals-bulk-bar.js +7 -20
- package/src/lib/components/deals-bulk-bar.js.map +1 -1
- package/src/lib/components/deals-section.d.ts +3 -3
- package/src/lib/components/deals-section.js +123 -63
- package/src/lib/components/deals-section.js.map +1 -1
- package/src/lib/components/fields-section.js +31 -17
- package/src/lib/components/fields-section.js.map +1 -1
- package/src/lib/components/lead-convert-dialog.d.ts +4 -0
- package/src/lib/components/lead-convert-dialog.js +23 -1
- package/src/lib/components/lead-convert-dialog.js.map +1 -1
- package/src/lib/components/lead-detail-page.js +8 -2
- package/src/lib/components/lead-detail-page.js.map +1 -1
- package/src/lib/components/lead-profile-fields.d.ts +71 -0
- package/src/lib/components/lead-profile-fields.js +386 -0
- package/src/lib/components/lead-profile-fields.js.map +1 -0
- package/src/lib/components/lead-properties-card.d.ts +2 -1
- package/src/lib/components/lead-properties-card.js +85 -176
- package/src/lib/components/lead-properties-card.js.map +1 -1
- package/src/lib/components/lead-source-select.d.ts +4 -23
- package/src/lib/components/lead-source-select.js +9 -73
- package/src/lib/components/lead-source-select.js.map +1 -1
- package/src/lib/components/lead-status-chip.d.ts +9 -3
- package/src/lib/components/lead-status-chip.js +8 -4
- package/src/lib/components/lead-status-chip.js.map +1 -1
- package/src/lib/components/lead-status-options.d.ts +20 -0
- package/src/lib/components/lead-status-options.js +51 -0
- package/src/lib/components/lead-status-options.js.map +1 -0
- package/src/lib/components/lead-unqualify-dialog.d.ts +5 -0
- package/src/lib/components/lead-unqualify-dialog.js +50 -18
- package/src/lib/components/lead-unqualify-dialog.js.map +1 -1
- package/src/lib/components/leads-bulk-bar.d.ts +0 -3
- package/src/lib/components/leads-bulk-bar.js +29 -29
- package/src/lib/components/leads-bulk-bar.js.map +1 -1
- package/src/lib/components/leads-section.js +120 -68
- package/src/lib/components/leads-section.js.map +1 -1
- package/src/lib/components/linked-deals-card.d.ts +4 -0
- package/src/lib/components/linked-deals-card.js +47 -3
- package/src/lib/components/linked-deals-card.js.map +1 -1
- package/src/lib/components/log-activity-dialog.js +43 -3
- package/src/lib/components/log-activity-dialog.js.map +1 -1
- package/src/lib/components/new-contact-drawer.d.ts +8 -0
- package/src/lib/components/new-contact-drawer.js +108 -6
- package/src/lib/components/new-contact-drawer.js.map +1 -1
- package/src/lib/components/new-lead-drawer.d.ts +9 -2
- package/src/lib/components/new-lead-drawer.js +88 -121
- package/src/lib/components/new-lead-drawer.js.map +1 -1
- package/src/lib/components/picklist-select.d.ts +36 -0
- package/src/lib/components/picklist-select.js +114 -0
- package/src/lib/components/picklist-select.js.map +1 -0
- package/src/lib/components/picklist-values-card.d.ts +34 -0
- package/src/lib/components/{lead-source-values-card.js → picklist-values-card.js} +241 -58
- package/src/lib/components/picklist-values-card.js.map +1 -0
- package/src/lib/components/pipeline-stages-dialog.d.ts +7 -0
- package/src/lib/components/pipeline-stages-dialog.js +26 -4
- package/src/lib/components/pipeline-stages-dialog.js.map +1 -1
- package/src/lib/components/pipelines-dialog.js +15 -6
- package/src/lib/components/pipelines-dialog.js.map +1 -1
- package/src/lib/components/recent-activity-feed.js +20 -5
- package/src/lib/components/recent-activity-feed.js.map +1 -1
- package/src/lib/components/recipes-card.js +4 -2
- package/src/lib/components/recipes-card.js.map +1 -1
- package/src/lib/components/record-tasks-card.js +15 -8
- package/src/lib/components/record-tasks-card.js.map +1 -1
- package/src/lib/components/reports/forecast-card.d.ts +6 -0
- package/src/lib/components/reports/forecast-card.js +101 -3
- package/src/lib/components/reports/forecast-card.js.map +1 -1
- package/src/lib/components/reports/lead-funnel-card.d.ts +12 -0
- package/src/lib/components/reports/lead-funnel-card.js +9 -5
- package/src/lib/components/reports/lead-funnel-card.js.map +1 -1
- package/src/lib/components/reports/lead-source-card.d.ts +23 -0
- package/src/lib/components/reports/lead-source-card.js +318 -0
- package/src/lib/components/reports/lead-source-card.js.map +1 -0
- package/src/lib/components/reports/pipeline-card.js +2 -1
- package/src/lib/components/reports/pipeline-card.js.map +1 -1
- package/src/lib/components/reports/report-export.js +1 -1
- package/src/lib/components/reports/report-export.js.map +1 -1
- package/src/lib/components/reports-section.js +8 -0
- package/src/lib/components/reports-section.js.map +1 -1
- package/src/lib/components/sharing-rule-drawer.d.ts +5 -0
- package/src/lib/components/sharing-rule-drawer.js +108 -19
- package/src/lib/components/sharing-rule-drawer.js.map +1 -1
- package/src/lib/components/sharing-rules-card.js +11 -3
- package/src/lib/components/sharing-rules-card.js.map +1 -1
- package/src/lib/components/task-cells.d.ts +9 -1
- package/src/lib/components/task-cells.js +9 -4
- package/src/lib/components/task-cells.js.map +1 -1
- package/src/lib/components/task-edit-drawer.js +111 -43
- package/src/lib/components/task-edit-drawer.js.map +1 -1
- package/src/lib/components/tasks-bulk-bar.d.ts +0 -3
- package/src/lib/components/tasks-bulk-bar.js +7 -20
- package/src/lib/components/tasks-bulk-bar.js.map +1 -1
- package/src/lib/components/tasks-calendar.d.ts +3 -0
- package/src/lib/components/tasks-calendar.js +8 -1
- package/src/lib/components/tasks-calendar.js.map +1 -1
- package/src/lib/components/tasks-section.d.ts +3 -3
- package/src/lib/components/tasks-section.js +58 -43
- package/src/lib/components/tasks-section.js.map +1 -1
- package/src/lib/constants/api-routes.d.ts +2 -9
- package/src/lib/constants/api-routes.js +1 -7
- package/src/lib/constants/api-routes.js.map +1 -1
- package/src/lib/constants/bundle-common.d.ts +6 -0
- package/src/lib/constants/bundle-common.js +11 -0
- package/src/lib/constants/bundle-common.js.map +1 -1
- package/src/lib/constants/company-filters.d.ts +14 -0
- package/src/lib/constants/company-filters.js +51 -1
- package/src/lib/constants/company-filters.js.map +1 -1
- package/src/lib/constants/contact-filters.d.ts +2 -0
- package/src/lib/constants/contact-filters.js +18 -1
- package/src/lib/constants/contact-filters.js.map +1 -1
- package/src/lib/constants/deal-filters.d.ts +22 -1
- package/src/lib/constants/deal-filters.js +67 -4
- package/src/lib/constants/deal-filters.js.map +1 -1
- package/src/lib/declarations.console-server.d.ts +3 -0
- package/src/lib/declarations.console-server.js +35 -0
- package/src/lib/declarations.console-server.js.map +1 -1
- package/src/lib/declarations.d.ts +26 -0
- package/src/lib/declarations.js +35 -0
- package/src/lib/declarations.js.map +1 -0
- package/src/lib/declarations.server.d.ts +11 -0
- package/src/lib/declarations.server.js +97 -1
- package/src/lib/declarations.server.js.map +1 -1
- package/src/lib/hooks/use-company-picklists.d.ts +15 -0
- package/src/lib/hooks/use-company-picklists.js +55 -0
- package/src/lib/hooks/use-company-picklists.js.map +1 -0
- package/src/lib/hooks/use-crm-picklist.d.ts +25 -0
- package/src/lib/hooks/use-crm-picklist.js +53 -0
- package/src/lib/hooks/use-crm-picklist.js.map +1 -0
- package/src/lib/hooks/use-crm-record-names.d.ts +16 -0
- package/src/lib/hooks/use-crm-record-names.js +45 -19
- package/src/lib/hooks/use-crm-record-names.js.map +1 -1
- package/src/lib/hooks/use-crm-task-picklists.d.ts +11 -0
- package/src/lib/hooks/use-crm-task-picklists.js +45 -0
- package/src/lib/hooks/use-crm-task-picklists.js.map +1 -0
- package/src/lib/hooks/use-deals.d.ts +14 -0
- package/src/lib/hooks/use-deals.js +29 -0
- package/src/lib/hooks/use-deals.js.map +1 -1
- package/src/lib/hooks/use-lead-picklists.d.ts +14 -0
- package/src/lib/hooks/use-lead-picklists.js +46 -0
- package/src/lib/hooks/use-lead-picklists.js.map +1 -0
- package/src/lib/hooks/use-lead-source-picklist.d.ts +5 -19
- package/src/lib/hooks/use-lead-source-picklist.js +12 -22
- package/src/lib/hooks/use-lead-source-picklist.js.map +1 -1
- package/src/lib/hooks/use-lead-status-picklist.d.ts +9 -0
- package/src/lib/hooks/use-lead-status-picklist.js +40 -0
- package/src/lib/hooks/use-lead-status-picklist.js.map +1 -0
- package/src/lib/model/companies.d.ts +32 -3
- package/src/lib/model/companies.js +133 -16
- package/src/lib/model/companies.js.map +1 -1
- package/src/lib/model/contact-merge.d.ts +27 -3
- package/src/lib/model/contact-merge.js +81 -7
- package/src/lib/model/contact-merge.js.map +1 -1
- package/src/lib/model/contact-record.d.ts +17 -0
- package/src/lib/model/contact-record.js +17 -2
- package/src/lib/model/contact-record.js.map +1 -1
- package/src/lib/model/contact-update.d.ts +31 -2
- package/src/lib/model/contact-update.js +14 -0
- package/src/lib/model/contact-update.js.map +1 -1
- package/src/lib/model/crm-list-query.d.ts +5 -0
- package/src/lib/model/crm-list-query.js +8 -0
- package/src/lib/model/crm-list-query.js.map +1 -1
- package/src/lib/model/crm-next-activity.d.ts +107 -0
- package/src/lib/model/crm-next-activity.js +140 -0
- package/src/lib/model/crm-next-activity.js.map +1 -0
- package/src/lib/model/crm-recipes.d.ts +40 -0
- package/src/lib/model/crm-recipes.js +259 -0
- package/src/lib/model/crm-recipes.js.map +1 -0
- package/src/lib/model/crm-record-counts.d.ts +36 -0
- package/src/lib/model/crm-record-counts.js +54 -0
- package/src/lib/model/crm-record-counts.js.map +1 -0
- package/src/lib/model/crm-record-lists.d.ts +23 -0
- package/src/lib/model/crm-record-lists.js +161 -0
- package/src/lib/model/crm-record-lists.js.map +1 -0
- package/src/lib/model/crm-reports.d.ts +73 -3
- package/src/lib/model/crm-reports.js +120 -1
- package/src/lib/model/crm-reports.js.map +1 -1
- package/src/lib/model/crm-sharing.d.ts +21 -3
- package/src/lib/model/crm-sharing.js +27 -6
- package/src/lib/model/crm-sharing.js.map +1 -1
- package/src/lib/model/crm-task-reminders.d.ts +152 -0
- package/src/lib/model/crm-task-reminders.js +161 -0
- package/src/lib/model/crm-task-reminders.js.map +1 -0
- package/src/lib/model/deal-board-model.d.ts +8 -2
- package/src/lib/model/deal-board-model.js +15 -2
- package/src/lib/model/deal-board-model.js.map +1 -1
- package/src/lib/model/deal-contact-roles.d.ts +45 -0
- package/src/lib/model/deal-contact-roles.js +73 -0
- package/src/lib/model/deal-contact-roles.js.map +1 -0
- package/src/lib/model/deal-form-model.d.ts +56 -0
- package/src/lib/model/deal-form-model.js +79 -7
- package/src/lib/model/deal-form-model.js.map +1 -1
- package/src/lib/model/download-text-file.d.ts +23 -0
- package/src/lib/model/download-text-file.js +34 -0
- package/src/lib/model/download-text-file.js.map +1 -0
- package/src/lib/model/lead-filters.d.ts +36 -2
- package/src/lib/model/lead-filters.js +123 -2
- package/src/lib/model/lead-filters.js.map +1 -1
- package/src/lib/model/lead-source-direction.d.ts +38 -0
- package/src/lib/model/lead-source-direction.js +52 -0
- package/src/lib/model/lead-source-direction.js.map +1 -0
- package/src/lib/model/next-activity.d.ts +1 -1
- package/src/lib/model/next-activity.js.map +1 -1
- package/src/lib/model/picklist-values.d.ts +119 -0
- package/src/lib/model/picklist-values.js +256 -0
- package/src/lib/model/picklist-values.js.map +1 -0
- package/src/lib/model/record-facts-disclosed.d.ts +81 -0
- package/src/lib/model/record-facts-disclosed.js +281 -0
- package/src/lib/model/record-facts-disclosed.js.map +1 -0
- package/src/lib/model/record-facts.d.ts +215 -34
- package/src/lib/model/record-facts.js +307 -128
- package/src/lib/model/record-facts.js.map +1 -1
- package/src/lib/model/task-picklists.d.ts +52 -0
- package/src/lib/model/task-picklists.js +83 -0
- package/src/lib/model/task-picklists.js.map +1 -0
- package/src/lib/model/task-routes.d.ts +13 -0
- package/src/lib/model/task-routes.js +23 -4
- package/src/lib/model/task-routes.js.map +1 -1
- package/src/lib/plan-entitlements.js +6 -4
- package/src/lib/plan-entitlements.js.map +1 -1
- package/src/lib/plugin.js +17 -0
- package/src/lib/plugin.js.map +1 -1
- package/src/lib/server/api-v1/contacts.js +220 -14
- package/src/lib/server/api-v1/contacts.js.map +1 -1
- package/src/lib/server/api-v1/crm-activities.js +14 -1
- package/src/lib/server/api-v1/crm-activities.js.map +1 -1
- package/src/lib/server/api-v1/crm-companies.js +123 -14
- package/src/lib/server/api-v1/crm-companies.js.map +1 -1
- package/src/lib/server/api-v1/crm-deals.js +291 -26
- package/src/lib/server/api-v1/crm-deals.js.map +1 -1
- package/src/lib/server/api-v1/crm-leads.js +144 -38
- package/src/lib/server/api-v1/crm-leads.js.map +1 -1
- package/src/lib/server/api-v1/crm-pipelines.d.ts +6 -0
- package/src/lib/server/api-v1/crm-pipelines.js +8 -2
- package/src/lib/server/api-v1/crm-pipelines.js.map +1 -1
- package/src/lib/server/api-v1/crm-tasks.js +78 -34
- package/src/lib/server/api-v1/crm-tasks.js.map +1 -1
- package/src/lib/server/api-v1/openapi.d.ts +0 -11
- package/src/lib/server/api-v1/openapi.js +171 -16
- package/src/lib/server/api-v1/openapi.js.map +1 -1
- package/src/lib/server/assign-contact-owner.d.ts +188 -0
- package/src/lib/server/assign-contact-owner.js +446 -0
- package/src/lib/server/assign-contact-owner.js.map +1 -0
- package/src/lib/server/associate-company-by-domain.d.ts +70 -0
- package/src/lib/server/associate-company-by-domain.js +153 -0
- package/src/lib/server/associate-company-by-domain.js.map +1 -0
- package/src/lib/server/automation-steps.d.ts +140 -0
- package/src/lib/server/automation-steps.js +669 -0
- package/src/lib/server/automation-steps.js.map +1 -0
- package/src/lib/server/capture-contact.d.ts +17 -0
- package/src/lib/server/capture-contact.js +95 -26
- package/src/lib/server/capture-contact.js.map +1 -1
- package/src/lib/server/capture-host-contact.d.ts +104 -0
- package/src/lib/server/capture-host-contact.js +151 -0
- package/src/lib/server/capture-host-contact.js.map +1 -0
- package/src/lib/server/company-children.d.ts +25 -0
- package/src/lib/server/company-children.js +42 -0
- package/src/lib/server/company-children.js.map +1 -0
- package/src/lib/server/company-delete.d.ts +18 -0
- package/src/lib/server/company-delete.js +44 -21
- package/src/lib/server/company-delete.js.map +1 -1
- package/src/lib/server/contact-email-history.js +21 -19
- package/src/lib/server/contact-email-history.js.map +1 -1
- package/src/lib/server/contact-remove.js +27 -2
- package/src/lib/server/contact-remove.js.map +1 -1
- package/src/lib/server/contact-reports-to.d.ts +61 -0
- package/src/lib/server/contact-reports-to.js +114 -0
- package/src/lib/server/contact-reports-to.js.map +1 -0
- package/src/lib/server/contact-update.d.ts +42 -1
- package/src/lib/server/contact-update.js +204 -23
- package/src/lib/server/contact-update.js.map +1 -1
- package/src/lib/server/convert-host-lead.d.ts +46 -1
- package/src/lib/server/convert-host-lead.js +173 -15
- package/src/lib/server/convert-host-lead.js.map +1 -1
- package/src/lib/server/convert-open-lead.js +12 -5
- package/src/lib/server/convert-open-lead.js.map +1 -1
- package/src/lib/server/crm-email-activity.d.ts +118 -0
- package/src/lib/server/crm-email-activity.js +148 -0
- package/src/lib/server/crm-email-activity.js.map +1 -0
- package/src/lib/server/crm-inbound-email.js +1 -1
- package/src/lib/server/crm-inbound-email.js.map +1 -1
- package/src/lib/server/crm-next-activity.d.ts +74 -0
- package/src/lib/server/crm-next-activity.js +194 -0
- package/src/lib/server/crm-next-activity.js.map +1 -0
- package/src/lib/server/crm-record-indexes.d.ts +45 -0
- package/src/lib/server/crm-record-indexes.js +78 -0
- package/src/lib/server/crm-record-indexes.js.map +1 -0
- package/src/lib/server/crm-sharing.d.ts +9 -1
- package/src/lib/server/crm-sharing.js +23 -3
- package/src/lib/server/crm-sharing.js.map +1 -1
- package/src/lib/server/deal-contact-roles.d.ts +27 -0
- package/src/lib/server/deal-contact-roles.js +89 -0
- package/src/lib/server/deal-contact-roles.js.map +1 -0
- package/src/lib/server/email-send.js +2 -1
- package/src/lib/server/email-send.js.map +1 -1
- package/src/lib/server/lead-convert.d.ts +5 -0
- package/src/lib/server/lead-convert.js +19 -3
- package/src/lib/server/lead-convert.js.map +1 -1
- package/src/lib/server/lead-create.d.ts +17 -2
- package/src/lib/server/lead-create.js +46 -14
- package/src/lib/server/lead-create.js.map +1 -1
- package/src/lib/server/lead-nurturing.d.ts +6 -0
- package/src/lib/server/lead-nurturing.js +57 -20
- package/src/lib/server/lead-nurturing.js.map +1 -1
- package/src/lib/server/lead-picklists.d.ts +35 -0
- package/src/lib/server/lead-picklists.js +52 -0
- package/src/lib/server/lead-picklists.js.map +1 -0
- package/src/lib/server/lead-source-picklist.d.ts +1 -13
- package/src/lib/server/lead-source-picklist.js +6 -33
- package/src/lib/server/lead-source-picklist.js.map +1 -1
- package/src/lib/server/merge-contacts.js +23 -5
- package/src/lib/server/merge-contacts.js.map +1 -1
- package/src/lib/server/next-activity-routes.js +2 -1
- package/src/lib/server/next-activity-routes.js.map +1 -1
- package/src/lib/server/person-eraser.d.ts +53 -0
- package/src/lib/server/person-eraser.js +149 -0
- package/src/lib/server/person-eraser.js.map +1 -0
- package/src/lib/server/person-records.d.ts +69 -0
- package/src/lib/server/person-records.js +317 -0
- package/src/lib/server/person-records.js.map +1 -0
- package/src/lib/server/person-refund.d.ts +97 -0
- package/src/lib/server/person-refund.js +221 -0
- package/src/lib/server/person-refund.js.map +1 -0
- package/src/lib/server/picklist-values.d.ts +21 -0
- package/src/lib/server/picklist-values.js +308 -0
- package/src/lib/server/picklist-values.js.map +1 -0
- package/src/lib/server/read-picklist.d.ts +44 -0
- package/src/lib/server/read-picklist.js +65 -0
- package/src/lib/server/read-picklist.js.map +1 -0
- package/src/lib/server/recipe-routes.js +22 -8
- package/src/lib/server/recipe-routes.js.map +1 -1
- package/src/lib/server/record-email-state.js +7 -1
- package/src/lib/server/record-email-state.js.map +1 -1
- package/src/lib/server/record-facts.d.ts +3 -0
- package/src/lib/server/record-facts.js +233 -31
- package/src/lib/server/record-facts.js.map +1 -1
- package/src/lib/server/record-origin.d.ts +27 -0
- package/src/lib/server/record-origin.js +104 -0
- package/src/lib/server/record-origin.js.map +1 -0
- package/src/lib/server/record-timeline.js +40 -3
- package/src/lib/server/record-timeline.js.map +1 -1
- package/src/lib/server/suite-gate.js +4 -3
- package/src/lib/server/suite-gate.js.map +1 -1
- package/src/lib/server/task-reminders-route.js +2 -1
- package/src/lib/server/task-reminders-route.js.map +1 -1
- package/src/lib/server/task-routes.js +33 -17
- package/src/lib/server/task-routes.js.map +1 -1
- package/src/lib/server-deal-stage.d.ts +5 -1
- package/src/lib/server-deal-stage.js +10 -5
- package/src/lib/server-deal-stage.js.map +1 -1
- package/src/lib/server.d.ts +8 -3
- package/src/lib/server.js +47 -43
- package/src/lib/server.js.map +1 -1
- package/src/lib/testing/memory-firestore.d.ts +55 -0
- package/src/lib/testing/memory-firestore.js +335 -0
- package/src/lib/testing/memory-firestore.js.map +1 -0
- package/src/lib/testing/stand-in-email-send-index.d.ts +25 -0
- package/src/lib/testing/stand-in-email-send-index.js +49 -0
- package/src/lib/testing/stand-in-email-send-index.js.map +1 -0
- package/src/lib/transfer/activities.d.ts +30 -0
- package/src/lib/transfer/activities.js +132 -0
- package/src/lib/transfer/activities.js.map +1 -0
- package/src/lib/transfer/aliases.d.ts +22 -0
- package/src/lib/transfer/aliases.js +1342 -0
- package/src/lib/transfer/aliases.js.map +1 -0
- package/src/lib/transfer/common.d.ts +222 -0
- package/src/lib/transfer/common.js +832 -0
- package/src/lib/transfer/common.js.map +1 -0
- package/src/lib/transfer/companies.d.ts +43 -0
- package/src/lib/transfer/companies.js +549 -0
- package/src/lib/transfer/companies.js.map +1 -0
- package/src/lib/transfer/contacts.d.ts +31 -0
- package/src/lib/transfer/contacts.js +727 -0
- package/src/lib/transfer/contacts.js.map +1 -0
- package/src/lib/transfer/deals.d.ts +66 -0
- package/src/lib/transfer/deals.js +698 -0
- package/src/lib/transfer/deals.js.map +1 -0
- package/src/lib/transfer/email-templates-package.d.ts +40 -0
- package/src/lib/transfer/email-templates-package.js +76 -0
- package/src/lib/transfer/email-templates-package.js.map +1 -0
- package/src/lib/transfer/email-templates-package.server.d.ts +32 -0
- package/src/lib/transfer/email-templates-package.server.js +176 -0
- package/src/lib/transfer/email-templates-package.server.js.map +1 -0
- package/src/lib/transfer/fields.d.ts +102 -0
- package/src/lib/transfer/fields.js +1755 -0
- package/src/lib/transfer/fields.js.map +1 -0
- package/src/lib/transfer/leads.d.ts +30 -0
- package/src/lib/transfer/leads.js +582 -0
- package/src/lib/transfer/leads.js.map +1 -0
- package/src/lib/transfer/pipelines.d.ts +21 -0
- package/src/lib/transfer/pipelines.js +172 -0
- package/src/lib/transfer/pipelines.js.map +1 -0
- package/src/lib/transfer/register.d.ts +47 -0
- package/src/lib/transfer/register.js +277 -0
- package/src/lib/transfer/register.js.map +1 -0
- package/src/lib/transfer/tasks.d.ts +30 -0
- package/src/lib/transfer/tasks.js +418 -0
- package/src/lib/transfer/tasks.js.map +1 -0
- package/src/lib/transfer/ui.d.ts +20 -0
- package/src/lib/transfer/ui.js +42 -0
- package/src/lib/transfer/ui.js.map +1 -0
- package/src/lib/components/company-import-drawer.d.ts +0 -42
- package/src/lib/components/company-import-drawer.js +0 -99
- package/src/lib/components/company-import-drawer.js.map +0 -1
- package/src/lib/components/contact-import-drawer.d.ts +0 -46
- package/src/lib/components/contact-import-drawer.js +0 -149
- package/src/lib/components/contact-import-drawer.js.map +0 -1
- package/src/lib/components/crm-export-all-button.d.ts +0 -39
- package/src/lib/components/crm-export-all-button.js +0 -98
- package/src/lib/components/crm-export-all-button.js.map +0 -1
- package/src/lib/components/csv-import-drawer.d.ts +0 -139
- package/src/lib/components/csv-import-drawer.js +0 -757
- package/src/lib/components/csv-import-drawer.js.map +0 -1
- package/src/lib/components/deal-import-drawer.d.ts +0 -24
- package/src/lib/components/deal-import-drawer.js +0 -83
- package/src/lib/components/deal-import-drawer.js.map +0 -1
- package/src/lib/components/lead-import-drawer.d.ts +0 -27
- package/src/lib/components/lead-import-drawer.js +0 -118
- package/src/lib/components/lead-import-drawer.js.map +0 -1
- package/src/lib/components/lead-source-values-card.d.ts +0 -27
- package/src/lib/components/lead-source-values-card.js.map +0 -1
- package/src/lib/components/task-import-drawer.d.ts +0 -24
- package/src/lib/components/task-import-drawer.js +0 -82
- package/src/lib/components/task-import-drawer.js.map +0 -1
- package/src/lib/model/companies-csv.d.ts +0 -36
- package/src/lib/model/companies-csv.js +0 -38
- package/src/lib/model/companies-csv.js.map +0 -1
- package/src/lib/model/contacts-csv.d.ts +0 -54
- package/src/lib/model/contacts-csv.js +0 -67
- package/src/lib/model/contacts-csv.js.map +0 -1
- package/src/lib/model/crm-company-import.d.ts +0 -154
- package/src/lib/model/crm-company-import.js +0 -331
- package/src/lib/model/crm-company-import.js.map +0 -1
- package/src/lib/model/crm-csv.d.ts +0 -239
- package/src/lib/model/crm-csv.js +0 -467
- package/src/lib/model/crm-csv.js.map +0 -1
- package/src/lib/model/crm-deal-import.d.ts +0 -112
- package/src/lib/model/crm-deal-import.js +0 -263
- package/src/lib/model/crm-deal-import.js.map +0 -1
- package/src/lib/model/crm-import.d.ts +0 -250
- package/src/lib/model/crm-import.js +0 -467
- package/src/lib/model/crm-import.js.map +0 -1
- package/src/lib/model/crm-lead-import.d.ts +0 -138
- package/src/lib/model/crm-lead-import.js +0 -446
- package/src/lib/model/crm-lead-import.js.map +0 -1
- package/src/lib/model/crm-task-import.d.ts +0 -94
- package/src/lib/model/crm-task-import.js +0 -275
- package/src/lib/model/crm-task-import.js.map +0 -1
- package/src/lib/model/deals-csv.d.ts +0 -32
- package/src/lib/model/deals-csv.js +0 -36
- package/src/lib/model/deals-csv.js.map +0 -1
- package/src/lib/model/import-column-shapes.d.ts +0 -36
- package/src/lib/model/import-column-shapes.js +0 -76
- package/src/lib/model/import-column-shapes.js.map +0 -1
- package/src/lib/model/lead-source-values.d.ts +0 -82
- package/src/lib/model/lead-source-values.js +0 -149
- package/src/lib/model/lead-source-values.js.map +0 -1
- package/src/lib/model/leads-csv.d.ts +0 -40
- package/src/lib/model/leads-csv.js +0 -40
- package/src/lib/model/leads-csv.js.map +0 -1
- package/src/lib/model/tasks-csv.d.ts +0 -28
- package/src/lib/model/tasks-csv.js +0 -28
- package/src/lib/model/tasks-csv.js.map +0 -1
- package/src/lib/server/companies-import.d.ts +0 -57
- package/src/lib/server/companies-import.js +0 -242
- package/src/lib/server/companies-import.js.map +0 -1
- package/src/lib/server/contacts-import.d.ts +0 -109
- package/src/lib/server/contacts-import.js +0 -393
- package/src/lib/server/contacts-import.js.map +0 -1
- package/src/lib/server/deals-import.d.ts +0 -76
- package/src/lib/server/deals-import.js +0 -248
- package/src/lib/server/deals-import.js.map +0 -1
- package/src/lib/server/export-route.d.ts +0 -60
- package/src/lib/server/export-route.js +0 -447
- package/src/lib/server/export-route.js.map +0 -1
- package/src/lib/server/import-context.d.ts +0 -87
- package/src/lib/server/import-context.js +0 -182
- package/src/lib/server/import-context.js.map +0 -1
- package/src/lib/server/lead-source-values.d.ts +0 -50
- package/src/lib/server/lead-source-values.js +0 -191
- package/src/lib/server/lead-source-values.js.map +0 -1
- package/src/lib/server/leads-import.d.ts +0 -84
- package/src/lib/server/leads-import.js +0 -367
- package/src/lib/server/leads-import.js.map +0 -1
- package/src/lib/server/tasks-import.d.ts +0 -54
- package/src/lib/server/tasks-import.js +0 -160
- package/src/lib/server/tasks-import.js.map +0 -1
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
import { _ as _extends } from "@swc/helpers/_/_extends";
|
|
2
|
-
/**
|
|
3
|
-
* @license
|
|
4
|
-
* Copyright 2026 Aglyn LLC
|
|
5
|
-
*
|
|
6
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
-
* you may not use this file except in compliance with the License.
|
|
8
|
-
* You may obtain a copy of the License at
|
|
9
|
-
*
|
|
10
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
-
*
|
|
12
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
-
* See the License for the specific language governing permissions and
|
|
16
|
-
* limitations under the License.
|
|
17
|
-
*/ /**
|
|
18
|
-
* `POST /api/crm/companies-import` — one chunk of a companies file, written
|
|
19
|
-
* (AGL-2621).
|
|
20
|
-
*
|
|
21
|
-
* The browser has already read the file and applied the operator's column
|
|
22
|
-
* mapping; what arrives here is up to {@link COMPANY_IMPORT_CHUNK_SIZE} raw
|
|
23
|
-
* rows in the vocabulary `crm-company-import.ts` defines. This route judges
|
|
24
|
-
* each one through the same normalizers the company drawer runs, and
|
|
25
|
-
* writes it — the ONLY place either happens, so a stale tab cannot store
|
|
26
|
-
* something the server would have refused.
|
|
27
|
-
*
|
|
28
|
-
* ## Matched by domain, then by name
|
|
29
|
-
*
|
|
30
|
-
* A row is one company the org may already have. The domain is a key and
|
|
31
|
-
* the name a spelling, so a row with a domain is looked up by it first,
|
|
32
|
-
* and by the name's search key when no company carries the domain or the
|
|
33
|
-
* row has none — two files calling one business "Acme" and "Acme Inc" meet
|
|
34
|
-
* at `acme.com`, and a file with no domain column still finds "Acme" by
|
|
35
|
-
* name. Both lookups are narrowed to what the caller's scope can see: two
|
|
36
|
-
* clients of one agency may each have an "Acme" and must each get their
|
|
37
|
-
* own. A match is UPDATED with what the row carries, tags unioned; no
|
|
38
|
-
* match is CREATED with the stamp every CRM creator writes.
|
|
39
|
-
*
|
|
40
|
-
* ## The band is counted once per request
|
|
41
|
-
*
|
|
42
|
-
* A created company is a CRM record and meets the records band (AGL-2611).
|
|
43
|
-
* The aggregate is taken once at the first create and the verdict re-judged
|
|
44
|
-
* locally as the request creates more — `checkCrmRecordsQuota` is pure over
|
|
45
|
-
* a count — so two hundred rows cost three aggregate reads, not six
|
|
46
|
-
* hundred. A metered plan never refuses; a hard band refuses the rows past
|
|
47
|
-
* it as `records-band`, and updates to matched companies go through either
|
|
48
|
-
* way, because an update adds no record.
|
|
49
|
-
*/ import { checkCrmRecordsQuota, CRM_COLLECTIONS, crmCompanyListFields, crmNewRecordListFields, fieldDefinitionsForObject, nameSearchFields, visibleToTokens } from "@aglyn/aglyn/server";
|
|
50
|
-
import { COMPANY_IMPORT_CHUNK_SIZE, COMPANY_IMPORT_MAX_BODY_BYTES, companyImportMatchKey, normalizeCompanyImportRow } from "../model/crm-company-import.js";
|
|
51
|
-
import { crmRecordsQuotaForOrg, firebaseAdmin } from "@aglyn/tenant-data-admin";
|
|
52
|
-
import { FieldValue } from "firebase-admin/firestore";
|
|
53
|
-
import { ownerDirectory, readImportRows, resolveImportContext } from "./import-context.js";
|
|
54
|
-
/** The company a row refers to in this scope — by domain, then by name — or `null`. */ async function findCompany(companies, readTokens, row) {
|
|
55
|
-
const seen = (snapshot)=>{
|
|
56
|
-
var _snapshot_docs_find;
|
|
57
|
-
return (_snapshot_docs_find = snapshot.docs.find((doc)=>visibleToTokens(doc.get('visibleTo'), readTokens))) != null ? _snapshot_docs_find : null;
|
|
58
|
-
};
|
|
59
|
-
if (row.domain) {
|
|
60
|
-
const byDomain = seen(await companies.where('domain', '==', row.domain).limit(10).get());
|
|
61
|
-
if (byDomain) return byDomain;
|
|
62
|
-
}
|
|
63
|
-
return seen(await companies.where('nameLower', '==', nameSearchFields(row.name).nameLower).limit(10).get());
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* The fields a row writes — on a create and on an update alike. Only what
|
|
67
|
-
* the row carries: an update must not clear a website the file did not
|
|
68
|
-
* mention, so an absent optional is left absent here rather than deleted.
|
|
69
|
-
*/ function storedFields(row, ownerUid) {
|
|
70
|
-
return _extends({}, nameSearchFields(row.name), row.domain ? {
|
|
71
|
-
domain: row.domain
|
|
72
|
-
} : {}, row.website ? {
|
|
73
|
-
website: row.website
|
|
74
|
-
} : {}, row.phone ? {
|
|
75
|
-
phone: row.phone
|
|
76
|
-
} : {}, row.industry ? {
|
|
77
|
-
industry: row.industry
|
|
78
|
-
} : {}, ownerUid ? {
|
|
79
|
-
ownerUid
|
|
80
|
-
} : {}, row.address ? {
|
|
81
|
-
address: row.address
|
|
82
|
-
} : {}, row.notes ? {
|
|
83
|
-
notes: row.notes
|
|
84
|
-
} : {});
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* The row's custom values as a MERGE writes them: one dotted path per key,
|
|
88
|
-
* so a company already filed keeps every value the file did not carry
|
|
89
|
-
* (AGL-2661). A create spreads the map itself — see the loop below.
|
|
90
|
-
*/ function customUpdate(row) {
|
|
91
|
-
return Object.fromEntries(Object.entries(row.custom).map(([key, value])=>[
|
|
92
|
-
`custom.${key}`,
|
|
93
|
-
value
|
|
94
|
-
]));
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* The org's live COMPANY field definitions (AGL-2661) — the contact
|
|
98
|
-
* import's read, narrowed to the object this import writes. Read in full
|
|
99
|
-
* and filtered in memory: a holder has a handful of fields, and a `where`
|
|
100
|
-
* on `object` would need an index for a collection that fits in one page.
|
|
101
|
-
*/ async function loadCompanyFieldDefinitions(orgId, readTokens) {
|
|
102
|
-
const snapshot = await firebaseAdmin.app().firestore().collection('orgs').doc(orgId).collection(CRM_COLLECTIONS.contactFields).limit(200).get();
|
|
103
|
-
return fieldDefinitionsForObject(snapshot.docs.map((doc)=>doc.data()), 'company').filter((field)=>!!field.key && !field.retiredAt && visibleToTokens(field.visibleTo, readTokens));
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* `POST crm/companies-import` — `{ hostId, rows }` → a {@link CompanyImportChunkResult}.
|
|
107
|
-
*
|
|
108
|
-
* Rows are written one after another rather than in parallel: two rows
|
|
109
|
-
* for one company racing each other would each miss the other's create.
|
|
110
|
-
*/ export const crmCompaniesImportHandler = async (req, res)=>{
|
|
111
|
-
if (req.method !== 'POST') {
|
|
112
|
-
res.setHeader('Allow', 'POST');
|
|
113
|
-
return res.status(405).json({
|
|
114
|
-
error: 'Method not allowed'
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
const read = readImportRows(req, {
|
|
118
|
-
maxBodyBytes: COMPANY_IMPORT_MAX_BODY_BYTES,
|
|
119
|
-
chunkSize: COMPANY_IMPORT_CHUNK_SIZE
|
|
120
|
-
});
|
|
121
|
-
if ('error' in read) return res.status(read.status).json({
|
|
122
|
-
error: read.error
|
|
123
|
-
});
|
|
124
|
-
try {
|
|
125
|
-
const context = await resolveImportContext(req);
|
|
126
|
-
if (context.ok === false) return res.status(context.status).json(context.body);
|
|
127
|
-
const skipped = [];
|
|
128
|
-
const dropped = {};
|
|
129
|
-
const normalized = [];
|
|
130
|
-
const fields = await loadCompanyFieldDefinitions(context.orgId, context.readTokens);
|
|
131
|
-
/*
|
|
132
|
-
* A duplicate WITHIN the request is skipped rather than merged: the
|
|
133
|
-
* second row would update the first's record and the count would read
|
|
134
|
-
* one created and one merged for one company in one file. Across
|
|
135
|
-
* requests the lookup answers, and reports a merge.
|
|
136
|
-
*/ const seen = new Set();
|
|
137
|
-
read.rows.forEach((raw, index)=>{
|
|
138
|
-
const verdict = normalizeCompanyImportRow(raw, fields);
|
|
139
|
-
if (verdict.ok === false) {
|
|
140
|
-
skipped.push({
|
|
141
|
-
index,
|
|
142
|
-
name: verdict.input,
|
|
143
|
-
reason: verdict.reason
|
|
144
|
-
});
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
const key = companyImportMatchKey(verdict.row);
|
|
148
|
-
if (seen.has(key)) {
|
|
149
|
-
skipped.push({
|
|
150
|
-
index,
|
|
151
|
-
name: verdict.row.name,
|
|
152
|
-
reason: 'duplicate'
|
|
153
|
-
});
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
seen.add(key);
|
|
157
|
-
for (const entry of verdict.row.dropped){
|
|
158
|
-
var _dropped_entry_field;
|
|
159
|
-
dropped[entry.field] = ((_dropped_entry_field = dropped[entry.field]) != null ? _dropped_entry_field : 0) + 1;
|
|
160
|
-
}
|
|
161
|
-
normalized.push({
|
|
162
|
-
index,
|
|
163
|
-
row: verdict.row
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
const owners = await ownerDirectory(context.orgId, normalized.map((entry)=>entry.row));
|
|
167
|
-
const ownersUnresolved = new Set();
|
|
168
|
-
const orgRef = firebaseAdmin.app().firestore().collection('orgs').doc(context.orgId);
|
|
169
|
-
const companies = orgRef.collection(CRM_COLLECTIONS.companies);
|
|
170
|
-
const stamp = creationStamp(context);
|
|
171
|
-
let counted = null;
|
|
172
|
-
let createdHere = 0;
|
|
173
|
-
let created = 0;
|
|
174
|
-
let merged = 0;
|
|
175
|
-
for (const { index, row } of normalized){
|
|
176
|
-
let ownerUid;
|
|
177
|
-
if (row.ownerEmail) {
|
|
178
|
-
ownerUid = owners.get(row.ownerEmail);
|
|
179
|
-
if (!ownerUid) ownersUnresolved.add(row.ownerEmail);
|
|
180
|
-
}
|
|
181
|
-
const existing = await findCompany(companies, context.readTokens, row);
|
|
182
|
-
const stored = storedFields(row, ownerUid);
|
|
183
|
-
if (existing) {
|
|
184
|
-
await existing.ref.update(_extends({}, stored, crmCompanyListFields(_extends({}, existing.data(), stored)), row.tags.length ? {
|
|
185
|
-
tags: FieldValue.arrayUnion(...row.tags)
|
|
186
|
-
} : {}, customUpdate(row), {
|
|
187
|
-
updatedAt: FieldValue.serverTimestamp()
|
|
188
|
-
}));
|
|
189
|
-
merged += 1;
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
if (!counted) counted = await crmRecordsQuotaForOrg(context.org, orgRef);
|
|
193
|
-
const room = checkCrmRecordsQuota(context.org, counted.crmRecordsCount + createdHere);
|
|
194
|
-
if (!room.allowed) {
|
|
195
|
-
skipped.push({
|
|
196
|
-
index,
|
|
197
|
-
name: row.name,
|
|
198
|
-
reason: 'records-band'
|
|
199
|
-
});
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
await companies.add(_extends({}, stored, {
|
|
203
|
-
tags: row.tags
|
|
204
|
-
}, Object.keys(row.custom).length ? {
|
|
205
|
-
custom: row.custom
|
|
206
|
-
} : {}, stamp, crmNewRecordListFields('companies', _extends({}, stored, stamp))));
|
|
207
|
-
createdHere += 1;
|
|
208
|
-
created += 1;
|
|
209
|
-
}
|
|
210
|
-
const result = {
|
|
211
|
-
received: read.rows.length,
|
|
212
|
-
created,
|
|
213
|
-
merged,
|
|
214
|
-
skipped: skipped.sort((a, b)=>a.index - b.index),
|
|
215
|
-
dropped,
|
|
216
|
-
ownersUnresolved: [
|
|
217
|
-
...ownersUnresolved
|
|
218
|
-
]
|
|
219
|
-
};
|
|
220
|
-
return res.status(200).json(result);
|
|
221
|
-
} catch (error) {
|
|
222
|
-
console.error('crm/companies-import failed', error);
|
|
223
|
-
return res.status(500).json({
|
|
224
|
-
error: 'The import could not continue.'
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
/**
|
|
229
|
-
* What every company this import CREATES carries beside its fields: the
|
|
230
|
-
* scope every CRM creator stamps, the site as provenance, who imported it,
|
|
231
|
-
* and the clocks. A record written without `visibleTo` is seen by nobody.
|
|
232
|
-
*/ function creationStamp(context) {
|
|
233
|
-
return {
|
|
234
|
-
hostId: context.hostId,
|
|
235
|
-
visibleTo: context.scopeTokens,
|
|
236
|
-
createdByUid: context.uid,
|
|
237
|
-
createdAt: FieldValue.serverTimestamp(),
|
|
238
|
-
updatedAt: FieldValue.serverTimestamp()
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
//# sourceMappingURL=companies-import.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../libs/plugins/crm/src/lib/server/companies-import.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * `POST /api/crm/companies-import` — one chunk of a companies file, written\n * (AGL-2621).\n *\n * The browser has already read the file and applied the operator's column\n * mapping; what arrives here is up to {@link COMPANY_IMPORT_CHUNK_SIZE} raw\n * rows in the vocabulary `crm-company-import.ts` defines. This route judges\n * each one through the same normalizers the company drawer runs, and\n * writes it — the ONLY place either happens, so a stale tab cannot store\n * something the server would have refused.\n *\n * ## Matched by domain, then by name\n *\n * A row is one company the org may already have. The domain is a key and\n * the name a spelling, so a row with a domain is looked up by it first,\n * and by the name's search key when no company carries the domain or the\n * row has none — two files calling one business \"Acme\" and \"Acme Inc\" meet\n * at `acme.com`, and a file with no domain column still finds \"Acme\" by\n * name. Both lookups are narrowed to what the caller's scope can see: two\n * clients of one agency may each have an \"Acme\" and must each get their\n * own. A match is UPDATED with what the row carries, tags unioned; no\n * match is CREATED with the stamp every CRM creator writes.\n *\n * ## The band is counted once per request\n *\n * A created company is a CRM record and meets the records band (AGL-2611).\n * The aggregate is taken once at the first create and the verdict re-judged\n * locally as the request creates more — `checkCrmRecordsQuota` is pure over\n * a count — so two hundred rows cost three aggregate reads, not six\n * hundred. A metered plan never refuses; a hard band refuses the rows past\n * it as `records-band`, and updates to matched companies go through either\n * way, because an update adds no record.\n */\n\nimport {\n checkCrmRecordsQuota,\n type ContactFieldDefinition,\n CRM_COLLECTIONS,\n crmCompanyListFields,\n crmNewRecordListFields,\n fieldDefinitionsForObject,\n nameSearchFields,\n type PluginApiHandler,\n visibleToTokens,\n} from '@aglyn/aglyn/server'\nimport {\n COMPANY_IMPORT_CHUNK_SIZE,\n COMPANY_IMPORT_MAX_BODY_BYTES,\n type CompanyImportChunkResult,\n type CompanyImportRawRow,\n type CompanyImportRow,\n type CompanyImportSkippedRow,\n companyImportMatchKey,\n normalizeCompanyImportRow,\n} from '../model/crm-company-import'\nimport { crmRecordsQuotaForOrg, firebaseAdmin } from '@aglyn/tenant-data-admin'\nimport { FieldValue } from 'firebase-admin/firestore'\nimport {\n type ImportContext,\n ownerDirectory,\n readImportRows,\n resolveImportContext,\n} from './import-context'\n\ntype Companies = FirebaseFirestore.CollectionReference\n\n/** The company a row refers to in this scope — by domain, then by name — or `null`. */\nasync function findCompany(\n companies: Companies,\n readTokens: readonly string[],\n row: Pick<CompanyImportRow, 'name' | 'domain'>,\n): Promise<FirebaseFirestore.QueryDocumentSnapshot | null> {\n const seen = (snapshot: FirebaseFirestore.QuerySnapshot) =>\n snapshot.docs.find((doc) => visibleToTokens(doc.get('visibleTo'), readTokens)) ?? null\n if (row.domain) {\n const byDomain = seen(\n await companies.where('domain', '==', row.domain).limit(10).get(),\n )\n if (byDomain) return byDomain\n }\n return seen(\n await companies\n .where('nameLower', '==', nameSearchFields(row.name).nameLower)\n .limit(10)\n .get(),\n )\n}\n\n/**\n * The fields a row writes — on a create and on an update alike. Only what\n * the row carries: an update must not clear a website the file did not\n * mention, so an absent optional is left absent here rather than deleted.\n */\nfunction storedFields(\n row: CompanyImportRow,\n ownerUid: string | undefined,\n): Record<string, unknown> {\n return {\n ...nameSearchFields(row.name),\n ...(row.domain ? { domain: row.domain } : {}),\n ...(row.website ? { website: row.website } : {}),\n ...(row.phone ? { phone: row.phone } : {}),\n ...(row.industry ? { industry: row.industry } : {}),\n ...(ownerUid ? { ownerUid } : {}),\n ...(row.address ? { address: row.address } : {}),\n ...(row.notes ? { notes: row.notes } : {}),\n }\n}\n\n/**\n * The row's custom values as a MERGE writes them: one dotted path per key,\n * so a company already filed keeps every value the file did not carry\n * (AGL-2661). A create spreads the map itself — see the loop below.\n */\nfunction customUpdate(row: CompanyImportRow): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(row.custom).map(([key, value]) => [`custom.${key}`, value]),\n )\n}\n\n/**\n * The org's live COMPANY field definitions (AGL-2661) — the contact\n * import's read, narrowed to the object this import writes. Read in full\n * and filtered in memory: a holder has a handful of fields, and a `where`\n * on `object` would need an index for a collection that fits in one page.\n */\nasync function loadCompanyFieldDefinitions(\n orgId: string,\n readTokens: readonly string[],\n): Promise<ContactFieldDefinition[]> {\n const snapshot = await firebaseAdmin\n .app()\n .firestore()\n .collection('orgs')\n .doc(orgId)\n .collection(CRM_COLLECTIONS.contactFields)\n .limit(200)\n .get()\n return fieldDefinitionsForObject(\n snapshot.docs.map((doc) => doc.data() as ContactFieldDefinition),\n 'company',\n ).filter(\n (field) =>\n !!field.key && !field.retiredAt && visibleToTokens(field.visibleTo, readTokens),\n )\n}\n\n/**\n * `POST crm/companies-import` — `{ hostId, rows }` → a {@link CompanyImportChunkResult}.\n *\n * Rows are written one after another rather than in parallel: two rows\n * for one company racing each other would each miss the other's create.\n */\nexport const crmCompaniesImportHandler: PluginApiHandler = async (req, res) => {\n if (req.method !== 'POST') {\n res.setHeader('Allow', 'POST')\n return res.status(405).json({ error: 'Method not allowed' })\n }\n const read = readImportRows<CompanyImportRawRow>(req, {\n maxBodyBytes: COMPANY_IMPORT_MAX_BODY_BYTES,\n chunkSize: COMPANY_IMPORT_CHUNK_SIZE,\n })\n if ('error' in read) return res.status(read.status).json({ error: read.error })\n try {\n const context = await resolveImportContext(req)\n if (context.ok === false) return res.status(context.status).json(context.body)\n\n const skipped: CompanyImportSkippedRow[] = []\n const dropped: Record<string, number> = {}\n const normalized: { index: number; row: CompanyImportRow }[] = []\n const fields = await loadCompanyFieldDefinitions(context.orgId, context.readTokens)\n /*\n * A duplicate WITHIN the request is skipped rather than merged: the\n * second row would update the first's record and the count would read\n * one created and one merged for one company in one file. Across\n * requests the lookup answers, and reports a merge.\n */\n const seen = new Set<string>()\n read.rows.forEach((raw, index) => {\n const verdict = normalizeCompanyImportRow(raw, fields)\n if (verdict.ok === false) {\n skipped.push({ index, name: verdict.input, reason: verdict.reason })\n return\n }\n const key = companyImportMatchKey(verdict.row)\n if (seen.has(key)) {\n skipped.push({ index, name: verdict.row.name, reason: 'duplicate' })\n return\n }\n seen.add(key)\n for (const entry of verdict.row.dropped) {\n dropped[entry.field] = (dropped[entry.field] ?? 0) + 1\n }\n normalized.push({ index, row: verdict.row })\n })\n\n const owners = await ownerDirectory(\n context.orgId,\n normalized.map((entry) => entry.row),\n )\n const ownersUnresolved = new Set<string>()\n const orgRef = firebaseAdmin.app().firestore().collection('orgs').doc(context.orgId)\n const companies = orgRef.collection(CRM_COLLECTIONS.companies)\n const stamp = creationStamp(context)\n let counted: { crmRecordsCount: number } | null = null\n let createdHere = 0\n let created = 0\n let merged = 0\n\n for (const { index, row } of normalized) {\n let ownerUid: string | undefined\n if (row.ownerEmail) {\n ownerUid = owners.get(row.ownerEmail)\n if (!ownerUid) ownersUnresolved.add(row.ownerEmail)\n }\n const existing = await findCompany(companies, context.readTokens, row)\n const stored = storedFields(row, ownerUid)\n if (existing) {\n await existing.ref.update({\n ...stored,\n // The file may rename the company: what the list searches follows.\n ...crmCompanyListFields({ ...existing.data(), ...stored }),\n ...(row.tags.length ? { tags: FieldValue.arrayUnion(...row.tags) } : {}),\n ...customUpdate(row),\n updatedAt: FieldValue.serverTimestamp(),\n })\n merged += 1\n continue\n }\n if (!counted) counted = await crmRecordsQuotaForOrg(context.org as never, orgRef)\n const room = checkCrmRecordsQuota(\n context.org as never,\n counted.crmRecordsCount + createdHere,\n )\n if (!room.allowed) {\n skipped.push({ index, name: row.name, reason: 'records-band' })\n continue\n }\n await companies.add({\n ...stored,\n tags: row.tags,\n ...(Object.keys(row.custom).length ? { custom: row.custom } : {}),\n ...stamp,\n // What the Companies list searches and filters by (AGL-3321).\n ...crmNewRecordListFields('companies', { ...stored, ...stamp }),\n })\n createdHere += 1\n created += 1\n }\n\n const result: CompanyImportChunkResult = {\n received: read.rows.length,\n created,\n merged,\n skipped: skipped.sort((a, b) => a.index - b.index),\n dropped,\n ownersUnresolved: [...ownersUnresolved],\n }\n return res.status(200).json(result)\n } catch (error) {\n console.error('crm/companies-import failed', error)\n return res.status(500).json({ error: 'The import could not continue.' })\n }\n}\n\n/**\n * What every company this import CREATES carries beside its fields: the\n * scope every CRM creator stamps, the site as provenance, who imported it,\n * and the clocks. A record written without `visibleTo` is seen by nobody.\n */\nfunction creationStamp(\n context: Extract<ImportContext, { ok: true }>,\n): Record<string, unknown> {\n return {\n hostId: context.hostId,\n visibleTo: context.scopeTokens,\n createdByUid: context.uid,\n createdAt: FieldValue.serverTimestamp(),\n updatedAt: FieldValue.serverTimestamp(),\n }\n}\n"],"names":["checkCrmRecordsQuota","CRM_COLLECTIONS","crmCompanyListFields","crmNewRecordListFields","fieldDefinitionsForObject","nameSearchFields","visibleToTokens","COMPANY_IMPORT_CHUNK_SIZE","COMPANY_IMPORT_MAX_BODY_BYTES","companyImportMatchKey","normalizeCompanyImportRow","crmRecordsQuotaForOrg","firebaseAdmin","FieldValue","ownerDirectory","readImportRows","resolveImportContext","findCompany","companies","readTokens","row","seen","snapshot","docs","find","doc","get","domain","byDomain","where","limit","name","nameLower","storedFields","ownerUid","website","phone","industry","address","notes","customUpdate","Object","fromEntries","entries","custom","map","key","value","loadCompanyFieldDefinitions","orgId","app","firestore","collection","contactFields","data","filter","field","retiredAt","visibleTo","crmCompaniesImportHandler","req","res","method","setHeader","status","json","error","read","maxBodyBytes","chunkSize","context","ok","body","skipped","dropped","normalized","fields","Set","rows","forEach","raw","index","verdict","push","input","reason","has","add","entry","owners","ownersUnresolved","orgRef","stamp","creationStamp","counted","createdHere","created","merged","ownerEmail","existing","stored","ref","update","tags","length","arrayUnion","updatedAt","serverTimestamp","org","room","crmRecordsCount","allowed","keys","result","received","sort","a","b","console","hostId","scopeTokens","createdByUid","uid","createdAt"],"mappings":"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"}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2026 Aglyn LLC
|
|
4
|
-
*
|
|
5
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
-
* you may not use this file except in compliance with the License.
|
|
7
|
-
* You may obtain a copy of the License at
|
|
8
|
-
*
|
|
9
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
-
*
|
|
11
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
-
* See the License for the specific language governing permissions and
|
|
15
|
-
* limitations under the License.
|
|
16
|
-
*/
|
|
17
|
-
/**
|
|
18
|
-
* `POST /api/crm/contacts-import` — one chunk of a contact file, written
|
|
19
|
-
* (AGL-2602).
|
|
20
|
-
*
|
|
21
|
-
* The browser has already read the file and applied the operator's column
|
|
22
|
-
* mapping; what arrives here is up to {@link CONTACT_IMPORT_CHUNK_SIZE} raw
|
|
23
|
-
* rows in the field vocabulary `crm-import.ts` defines. This route judges
|
|
24
|
-
* each one and writes it, and it is the ONLY place either happens: the
|
|
25
|
-
* drawer shows a preview from the same mapper but stores nothing, so a
|
|
26
|
-
* stale tab cannot store something the server would have refused.
|
|
27
|
-
*
|
|
28
|
-
* ## Every row goes through the door every capture goes through
|
|
29
|
-
*
|
|
30
|
-
* `captureHostContact` — the runtime's wrapper over `upsertHostContact`,
|
|
31
|
-
* the one writer of the contacts collection for every door that is not the
|
|
32
|
-
* v1 API: forms, checkout, bookings, the newsletter box — is the writer
|
|
33
|
-
* here too, so a row this file creates raises `contactCreated` like any
|
|
34
|
-
* other capture (AGL-2605). That is what makes an import
|
|
35
|
-
* dedupe on the address the way a second form submission does, land in the
|
|
36
|
-
* capturing group's facet the way a form capture does, record consent
|
|
37
|
-
* against the capturing site, and stop at a hard band where a form
|
|
38
|
-
* capture stops. A bulk path with its own `add()` would be the fastest way
|
|
39
|
-
* to grow an unscoped, unbanded, unconsented copy of the address book.
|
|
40
|
-
*
|
|
41
|
-
* What the door did not know how to write until now — a phone, a title, a
|
|
42
|
-
* company, an owner, a stage, custom values — it now takes as `facet`, and
|
|
43
|
-
* what it did not say until now — created or merged or refused — it now
|
|
44
|
-
* returns as a verdict. Both changes are the door's, so the v1 API and the
|
|
45
|
-
* manual add can reach them next.
|
|
46
|
-
*
|
|
47
|
-
* ## Every lookup paid once per request, not once per row (AGL-3423)
|
|
48
|
-
*
|
|
49
|
-
* A request has sixty seconds, and a row that reads for itself spends them
|
|
50
|
-
* a round trip at a time: the door alone was a dozen serial reads and three
|
|
51
|
-
* aggregate counts per new person, and a two-hundred-row chunk of an
|
|
52
|
-
* Apollo export ran out of time before it answered. So nothing here is
|
|
53
|
-
* read per row:
|
|
54
|
-
*
|
|
55
|
-
* - The door's own lookups — the site, the consent group, who each address
|
|
56
|
-
* already is, who the site erased, the room in the records band — come
|
|
57
|
-
* from one `prepareContactCaptureBatch` for the whole chunk, which every
|
|
58
|
-
* row's capture is handed. The door still makes every decision.
|
|
59
|
-
* - An owner is named by email and stored by uid, so the org's roster is
|
|
60
|
-
* read once and every row resolves against it.
|
|
61
|
-
* - A company is named by name and stored by id, so the distinct names are
|
|
62
|
-
* looked up together, thirty to an `in` query, and the missing ones are
|
|
63
|
-
* created in one batched write — an Apollo file names a different company
|
|
64
|
-
* on nearly every row, and that was a read, a count and a write each.
|
|
65
|
-
*
|
|
66
|
-
* What is left per row is the row's own writes and what a new person sets
|
|
67
|
-
* off, and those run {@link CONTACT_IMPORT_CONCURRENCY} at a time. A row is
|
|
68
|
-
* started only inside {@link CONTACT_IMPORT_TIME_BUDGET_MS}; the rest are
|
|
69
|
-
* reported `not-reached`, so a slow chunk answers with what it did instead
|
|
70
|
-
* of being cut off at the limit with no answer at all.
|
|
71
|
-
*
|
|
72
|
-
* ## A retry is a merge, never a second person
|
|
73
|
-
*
|
|
74
|
-
* The door dedupes on the address, through the index and then the `email`
|
|
75
|
-
* query, so a row that landed before a request was cut off is found by the
|
|
76
|
-
* next attempt and merged into — the one-person-one-record rule a second
|
|
77
|
-
* form submission meets. A company is found by its `nameLower` the same way.
|
|
78
|
-
*
|
|
79
|
-
* ## Who may call it
|
|
80
|
-
*
|
|
81
|
-
* `resolveImportContext` (`import-context.ts`) — the two gates every CSV
|
|
82
|
-
* import route asks, shared with the companies import so one permission
|
|
83
|
-
* has one spelling.
|
|
84
|
-
*/
|
|
85
|
-
import { type PluginApiHandler } from '@aglyn/aglyn/server';
|
|
86
|
-
/** The one sentence every imported contact's timeline opens with. */
|
|
87
|
-
export declare const CONTACT_IMPORT_INTERACTION_SUMMARY = "Imported from CSV";
|
|
88
|
-
/**
|
|
89
|
-
* How many rows are written at once. Enough to overlap the round trips a
|
|
90
|
-
* row still pays; few enough that a chunk never has more writes in flight
|
|
91
|
-
* than one client connection handles comfortably.
|
|
92
|
-
*/
|
|
93
|
-
export declare const CONTACT_IMPORT_CONCURRENCY = 8;
|
|
94
|
-
/**
|
|
95
|
-
* How long after the request arrived a row may still be STARTED. The
|
|
96
|
-
* function is stopped at sixty seconds; this leaves the rows already in
|
|
97
|
-
* flight, and the mail-server check's grace, room to finish before then.
|
|
98
|
-
*/
|
|
99
|
-
export declare const CONTACT_IMPORT_TIME_BUDGET_MS = 40000;
|
|
100
|
-
/**
|
|
101
|
-
* `POST crm/contacts-import` — `{ hostId, rows }` → a {@link ContactImportChunkResult}.
|
|
102
|
-
*
|
|
103
|
-
* Rows are written {@link CONTACT_IMPORT_CONCURRENCY} at a time, which the
|
|
104
|
-
* band allows because it is no longer counted per row: the capture batch
|
|
105
|
-
* counted once, and every create is admitted from its tally — reserved in
|
|
106
|
-
* file order before any row is written, so which rows the band keeps does
|
|
107
|
-
* not depend on which write happened to finish first.
|
|
108
|
-
*/
|
|
109
|
-
export declare const crmContactsImportHandler: PluginApiHandler;
|