@kelpie/server 0.7.0 → 0.9.0
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/dist/lib/consumerEmailDomains.d.ts +2 -0
- package/dist/lib/consumerEmailDomains.d.ts.map +1 -0
- package/dist/lib/consumerEmailDomains.js +62 -0
- package/dist/lib/consumerEmailDomains.js.map +1 -0
- package/dist/lib/email.d.ts +7 -0
- package/dist/lib/email.d.ts.map +1 -1
- package/dist/lib/email.js.map +1 -1
- package/dist/lib/emailContent.d.ts +33 -0
- package/dist/lib/emailContent.d.ts.map +1 -0
- package/dist/lib/emailContent.js +54 -0
- package/dist/lib/emailContent.js.map +1 -0
- package/dist/lib/emailDomainAutoLink.d.ts +27 -0
- package/dist/lib/emailDomainAutoLink.d.ts.map +1 -0
- package/dist/lib/emailDomainAutoLink.js +119 -0
- package/dist/lib/emailDomainAutoLink.js.map +1 -0
- package/dist/lib/ids.d.ts +13 -0
- package/dist/lib/ids.d.ts.map +1 -1
- package/dist/lib/ids.js +13 -0
- package/dist/lib/ids.js.map +1 -1
- package/dist/modules/activities/repository.d.ts.map +1 -1
- package/dist/modules/activities/repository.js +19 -20
- package/dist/modules/activities/repository.js.map +1 -1
- package/dist/modules/activities/wording.d.ts +12 -0
- package/dist/modules/activities/wording.d.ts.map +1 -1
- package/dist/modules/activities/wording.js +16 -0
- package/dist/modules/activities/wording.js.map +1 -1
- package/dist/modules/agent-tasks/catalog.d.ts.map +1 -1
- package/dist/modules/agent-tasks/catalog.js +62 -0
- package/dist/modules/agent-tasks/catalog.js.map +1 -1
- package/dist/modules/agent-tasks/resolve.d.ts.map +1 -1
- package/dist/modules/agent-tasks/resolve.js +42 -9
- package/dist/modules/agent-tasks/resolve.js.map +1 -1
- package/dist/modules/agent-tasks/routes.d.ts +2 -0
- package/dist/modules/agent-tasks/routes.d.ts.map +1 -1
- package/dist/modules/attachedRecords.d.ts +6 -1
- package/dist/modules/attachedRecords.d.ts.map +1 -1
- package/dist/modules/attachedRecords.js +18 -2
- package/dist/modules/attachedRecords.js.map +1 -1
- package/dist/modules/auth/preferences.d.ts +11 -1
- package/dist/modules/auth/preferences.d.ts.map +1 -1
- package/dist/modules/auth/preferences.js +11 -0
- package/dist/modules/auth/preferences.js.map +1 -1
- package/dist/modules/auth/routes.d.ts.map +1 -1
- package/dist/modules/auth/routes.js +18 -0
- package/dist/modules/auth/routes.js.map +1 -1
- package/dist/modules/auth/schema.d.ts +20 -0
- package/dist/modules/auth/schema.d.ts.map +1 -1
- package/dist/modules/auth/schema.js +11 -1
- package/dist/modules/auth/schema.js.map +1 -1
- package/dist/modules/auth/service.d.ts.map +1 -1
- package/dist/modules/auth/service.js +27 -3
- package/dist/modules/auth/service.js.map +1 -1
- package/dist/modules/companies/index.d.ts.map +1 -1
- package/dist/modules/companies/index.js +3 -1
- package/dist/modules/companies/index.js.map +1 -1
- package/dist/modules/companies/repository.d.ts +2 -0
- package/dist/modules/companies/repository.d.ts.map +1 -1
- package/dist/modules/companies/repository.js +1 -0
- package/dist/modules/companies/repository.js.map +1 -1
- package/dist/modules/companies/routes.d.ts +16 -0
- package/dist/modules/companies/routes.d.ts.map +1 -1
- package/dist/modules/companies/routes.js +18 -0
- package/dist/modules/companies/routes.js.map +1 -1
- package/dist/modules/companies/schema.d.ts +37 -0
- package/dist/modules/companies/schema.d.ts.map +1 -1
- package/dist/modules/companies/schema.js +10 -1
- package/dist/modules/companies/schema.js.map +1 -1
- package/dist/modules/companies/service.d.ts +6 -0
- package/dist/modules/companies/service.d.ts.map +1 -1
- package/dist/modules/companies/service.js +45 -11
- package/dist/modules/companies/service.js.map +1 -1
- package/dist/modules/consent-purposes/capabilities.d.ts +7 -0
- package/dist/modules/consent-purposes/capabilities.d.ts.map +1 -0
- package/dist/modules/consent-purposes/capabilities.js +10 -0
- package/dist/modules/consent-purposes/capabilities.js.map +1 -0
- package/dist/modules/consent-purposes/events.d.ts +38 -0
- package/dist/modules/consent-purposes/events.d.ts.map +1 -0
- package/dist/modules/consent-purposes/events.js +17 -0
- package/dist/modules/consent-purposes/events.js.map +1 -0
- package/dist/modules/consent-purposes/index.d.ts +13 -0
- package/dist/modules/consent-purposes/index.d.ts.map +1 -0
- package/dist/modules/consent-purposes/index.js +41 -0
- package/dist/modules/consent-purposes/index.js.map +1 -0
- package/dist/modules/consent-purposes/repository.d.ts +21 -0
- package/dist/modules/consent-purposes/repository.d.ts.map +1 -0
- package/dist/modules/consent-purposes/repository.js +98 -0
- package/dist/modules/consent-purposes/repository.js.map +1 -0
- package/dist/modules/consent-purposes/routes.d.ts +39 -0
- package/dist/modules/consent-purposes/routes.d.ts.map +1 -0
- package/dist/modules/consent-purposes/routes.js +79 -0
- package/dist/modules/consent-purposes/routes.js.map +1 -0
- package/dist/modules/consent-purposes/schema.d.ts +175 -0
- package/dist/modules/consent-purposes/schema.d.ts.map +1 -0
- package/dist/modules/consent-purposes/schema.js +35 -0
- package/dist/modules/consent-purposes/schema.js.map +1 -0
- package/dist/modules/consent-purposes/service.d.ts +50 -0
- package/dist/modules/consent-purposes/service.d.ts.map +1 -0
- package/dist/modules/consent-purposes/service.js +263 -0
- package/dist/modules/consent-purposes/service.js.map +1 -0
- package/dist/modules/consent-purposes/starters.d.ts +17 -0
- package/dist/modules/consent-purposes/starters.d.ts.map +1 -0
- package/dist/modules/consent-purposes/starters.js +15 -0
- package/dist/modules/consent-purposes/starters.js.map +1 -0
- package/dist/modules/consent-purposes/tools.d.ts +4 -0
- package/dist/modules/consent-purposes/tools.d.ts.map +1 -0
- package/dist/modules/consent-purposes/tools.js +29 -0
- package/dist/modules/consent-purposes/tools.js.map +1 -0
- package/dist/modules/core.d.ts.map +1 -1
- package/dist/modules/core.js +21 -0
- package/dist/modules/core.js.map +1 -1
- package/dist/modules/custom-fields/capabilities.d.ts +12 -0
- package/dist/modules/custom-fields/capabilities.d.ts.map +1 -0
- package/dist/modules/custom-fields/capabilities.js +15 -0
- package/dist/modules/custom-fields/capabilities.js.map +1 -0
- package/dist/modules/custom-fields/events.d.ts +49 -0
- package/dist/modules/custom-fields/events.d.ts.map +1 -0
- package/dist/modules/custom-fields/events.js +25 -0
- package/dist/modules/custom-fields/events.js.map +1 -0
- package/dist/modules/custom-fields/index.d.ts +19 -0
- package/dist/modules/custom-fields/index.d.ts.map +1 -0
- package/dist/modules/custom-fields/index.js +46 -0
- package/dist/modules/custom-fields/index.js.map +1 -0
- package/dist/modules/custom-fields/repository.d.ts +37 -0
- package/dist/modules/custom-fields/repository.d.ts.map +1 -0
- package/dist/modules/custom-fields/repository.js +144 -0
- package/dist/modules/custom-fields/repository.js.map +1 -0
- package/dist/modules/custom-fields/routes.d.ts +44 -0
- package/dist/modules/custom-fields/routes.d.ts.map +1 -0
- package/dist/modules/custom-fields/routes.js +103 -0
- package/dist/modules/custom-fields/routes.js.map +1 -0
- package/dist/modules/custom-fields/schema.d.ts +215 -0
- package/dist/modules/custom-fields/schema.d.ts.map +1 -0
- package/dist/modules/custom-fields/schema.js +43 -0
- package/dist/modules/custom-fields/schema.js.map +1 -0
- package/dist/modules/custom-fields/service.d.ts +57 -0
- package/dist/modules/custom-fields/service.d.ts.map +1 -0
- package/dist/modules/custom-fields/service.js +273 -0
- package/dist/modules/custom-fields/service.js.map +1 -0
- package/dist/modules/custom-fields/tools.d.ts +4 -0
- package/dist/modules/custom-fields/tools.d.ts.map +1 -0
- package/dist/modules/custom-fields/tools.js +38 -0
- package/dist/modules/custom-fields/tools.js.map +1 -0
- package/dist/modules/custom-fields/values.d.ts +49 -0
- package/dist/modules/custom-fields/values.d.ts.map +1 -0
- package/dist/modules/custom-fields/values.js +249 -0
- package/dist/modules/custom-fields/values.js.map +1 -0
- package/dist/modules/custom-fields/wire.d.ts +12 -0
- package/dist/modules/custom-fields/wire.d.ts.map +1 -0
- package/dist/modules/custom-fields/wire.js +30 -0
- package/dist/modules/custom-fields/wire.js.map +1 -0
- package/dist/modules/dashboard/repository.d.ts.map +1 -1
- package/dist/modules/dashboard/repository.js +4 -3
- package/dist/modules/dashboard/repository.js.map +1 -1
- package/dist/modules/deals/index.d.ts +2 -1
- package/dist/modules/deals/index.d.ts.map +1 -1
- package/dist/modules/deals/index.js +5 -2
- package/dist/modules/deals/index.js.map +1 -1
- package/dist/modules/deals/repository.d.ts +0 -16
- package/dist/modules/deals/repository.d.ts.map +1 -1
- package/dist/modules/deals/repository.js +6 -76
- package/dist/modules/deals/repository.js.map +1 -1
- package/dist/modules/deals/routes.d.ts +14 -0
- package/dist/modules/deals/routes.d.ts.map +1 -1
- package/dist/modules/deals/routes.js +7 -0
- package/dist/modules/deals/routes.js.map +1 -1
- package/dist/modules/deals/schema.d.ts +20 -42
- package/dist/modules/deals/schema.d.ts.map +1 -1
- package/dist/modules/deals/schema.js +6 -11
- package/dist/modules/deals/schema.js.map +1 -1
- package/dist/modules/deals/service.d.ts +13 -2
- package/dist/modules/deals/service.d.ts.map +1 -1
- package/dist/modules/deals/service.js +43 -20
- package/dist/modules/deals/service.js.map +1 -1
- package/dist/modules/decisions/repository.d.ts.map +1 -1
- package/dist/modules/decisions/repository.js +2 -0
- package/dist/modules/decisions/repository.js.map +1 -1
- package/dist/modules/decisions/routes.d.ts +1 -0
- package/dist/modules/decisions/routes.d.ts.map +1 -1
- package/dist/modules/email-domain-linker/index.d.ts +12 -0
- package/dist/modules/email-domain-linker/index.d.ts.map +1 -0
- package/dist/modules/email-domain-linker/index.js +34 -0
- package/dist/modules/email-domain-linker/index.js.map +1 -0
- package/dist/modules/email-domain-linker/routes.d.ts +14 -0
- package/dist/modules/email-domain-linker/routes.d.ts.map +1 -0
- package/dist/modules/email-domain-linker/routes.js +15 -0
- package/dist/modules/email-domain-linker/routes.js.map +1 -0
- package/dist/modules/email-domain-linker/service.d.ts +37 -0
- package/dist/modules/email-domain-linker/service.d.ts.map +1 -0
- package/dist/modules/email-domain-linker/service.js +63 -0
- package/dist/modules/email-domain-linker/service.js.map +1 -0
- package/dist/modules/enquiries/events.d.ts +44 -0
- package/dist/modules/enquiries/events.d.ts.map +1 -0
- package/dist/modules/enquiries/events.js +19 -0
- package/dist/modules/enquiries/events.js.map +1 -0
- package/dist/modules/enquiries/index.d.ts +13 -0
- package/dist/modules/enquiries/index.d.ts.map +1 -0
- package/dist/modules/enquiries/index.js +44 -0
- package/dist/modules/enquiries/index.js.map +1 -0
- package/dist/modules/enquiries/repository.d.ts +30 -0
- package/dist/modules/enquiries/repository.d.ts.map +1 -0
- package/dist/modules/enquiries/repository.js +94 -0
- package/dist/modules/enquiries/repository.js.map +1 -0
- package/dist/modules/enquiries/routes.d.ts +52 -0
- package/dist/modules/enquiries/routes.d.ts.map +1 -0
- package/dist/modules/enquiries/routes.js +127 -0
- package/dist/modules/enquiries/routes.js.map +1 -0
- package/dist/modules/enquiries/schema.d.ts +290 -0
- package/dist/modules/enquiries/schema.d.ts.map +1 -0
- package/dist/modules/enquiries/schema.js +52 -0
- package/dist/modules/enquiries/schema.js.map +1 -0
- package/dist/modules/enquiries/service.d.ts +85 -0
- package/dist/modules/enquiries/service.d.ts.map +1 -0
- package/dist/modules/enquiries/service.js +370 -0
- package/dist/modules/enquiries/service.js.map +1 -0
- package/dist/modules/enquiries/tools.d.ts +4 -0
- package/dist/modules/enquiries/tools.d.ts.map +1 -0
- package/dist/modules/enquiries/tools.js +50 -0
- package/dist/modules/enquiries/tools.js.map +1 -0
- package/dist/modules/eventCatalogs.d.ts +4 -0
- package/dist/modules/eventCatalogs.d.ts.map +1 -1
- package/dist/modules/eventCatalogs.js +4 -0
- package/dist/modules/eventCatalogs.js.map +1 -1
- package/dist/modules/forms/embed.d.ts +20 -6
- package/dist/modules/forms/embed.d.ts.map +1 -1
- package/dist/modules/forms/embed.js +359 -43
- package/dist/modules/forms/embed.js.map +1 -1
- package/dist/modules/forms/events.d.ts +20 -7
- package/dist/modules/forms/events.d.ts.map +1 -1
- package/dist/modules/forms/events.js +20 -2
- package/dist/modules/forms/events.js.map +1 -1
- package/dist/modules/forms/fields.d.ts +14 -1
- package/dist/modules/forms/fields.d.ts.map +1 -1
- package/dist/modules/forms/fields.js +87 -3
- package/dist/modules/forms/fields.js.map +1 -1
- package/dist/modules/forms/index.d.ts.map +1 -1
- package/dist/modules/forms/index.js +12 -1
- package/dist/modules/forms/index.js.map +1 -1
- package/dist/modules/forms/mapping.d.ts +62 -5
- package/dist/modules/forms/mapping.d.ts.map +1 -1
- package/dist/modules/forms/mapping.js +139 -5
- package/dist/modules/forms/mapping.js.map +1 -1
- package/dist/modules/forms/publicRoutes.d.ts.map +1 -1
- package/dist/modules/forms/publicRoutes.js +29 -1
- package/dist/modules/forms/publicRoutes.js.map +1 -1
- package/dist/modules/forms/repository.d.ts +31 -0
- package/dist/modules/forms/repository.d.ts.map +1 -1
- package/dist/modules/forms/repository.js +90 -1
- package/dist/modules/forms/repository.js.map +1 -1
- package/dist/modules/forms/routes.d.ts +83 -1
- package/dist/modules/forms/routes.d.ts.map +1 -1
- package/dist/modules/forms/routes.js +185 -2
- package/dist/modules/forms/routes.js.map +1 -1
- package/dist/modules/forms/schema.d.ts +672 -1
- package/dist/modules/forms/schema.d.ts.map +1 -1
- package/dist/modules/forms/schema.js +146 -3
- package/dist/modules/forms/schema.js.map +1 -1
- package/dist/modules/forms/service.d.ts +54 -1
- package/dist/modules/forms/service.d.ts.map +1 -1
- package/dist/modules/forms/service.js +338 -28
- package/dist/modules/forms/service.js.map +1 -1
- package/dist/modules/forms/submission.d.ts +15 -0
- package/dist/modules/forms/submission.d.ts.map +1 -1
- package/dist/modules/forms/submission.js +418 -40
- package/dist/modules/forms/submission.js.map +1 -1
- package/dist/modules/import-export/drafts.d.ts +10 -0
- package/dist/modules/import-export/drafts.d.ts.map +1 -1
- package/dist/modules/import-export/drafts.js +16 -2
- package/dist/modules/import-export/drafts.js.map +1 -1
- package/dist/modules/import-export/exportRows.d.ts +7 -4
- package/dist/modules/import-export/exportRows.d.ts.map +1 -1
- package/dist/modules/import-export/exportRows.js +20 -5
- package/dist/modules/import-export/exportRows.js.map +1 -1
- package/dist/modules/import-export/plan.d.ts +12 -1
- package/dist/modules/import-export/plan.d.ts.map +1 -1
- package/dist/modules/import-export/plan.js +29 -2
- package/dist/modules/import-export/plan.js.map +1 -1
- package/dist/modules/import-export/presets.d.ts.map +1 -1
- package/dist/modules/import-export/presets.js +10 -0
- package/dist/modules/import-export/presets.js.map +1 -1
- package/dist/modules/import-export/repository.d.ts +11 -1
- package/dist/modules/import-export/repository.d.ts.map +1 -1
- package/dist/modules/import-export/repository.js +42 -9
- package/dist/modules/import-export/repository.js.map +1 -1
- package/dist/modules/import-export/routes.d.ts.map +1 -1
- package/dist/modules/import-export/routes.js +4 -0
- package/dist/modules/import-export/routes.js.map +1 -1
- package/dist/modules/import-export/schema.d.ts +17 -0
- package/dist/modules/import-export/schema.d.ts.map +1 -1
- package/dist/modules/import-export/schema.js +11 -0
- package/dist/modules/import-export/schema.js.map +1 -1
- package/dist/modules/import-export/service.d.ts +6 -0
- package/dist/modules/import-export/service.d.ts.map +1 -1
- package/dist/modules/import-export/service.js +14 -2
- package/dist/modules/import-export/service.js.map +1 -1
- package/dist/modules/import-export/streams.d.ts.map +1 -1
- package/dist/modules/import-export/streams.js +3 -3
- package/dist/modules/import-export/streams.js.map +1 -1
- package/dist/modules/import-export/tools.d.ts.map +1 -1
- package/dist/modules/import-export/tools.js +8 -0
- package/dist/modules/import-export/tools.js.map +1 -1
- package/dist/modules/import-export/validation.d.ts.map +1 -1
- package/dist/modules/import-export/validation.js +22 -1
- package/dist/modules/import-export/validation.js.map +1 -1
- package/dist/modules/import-export/writes.d.ts.map +1 -1
- package/dist/modules/import-export/writes.js +37 -4
- package/dist/modules/import-export/writes.js.map +1 -1
- package/dist/modules/lists/events.d.ts +42 -0
- package/dist/modules/lists/events.d.ts.map +1 -0
- package/dist/modules/lists/events.js +16 -0
- package/dist/modules/lists/events.js.map +1 -0
- package/dist/modules/lists/index.d.ts +10 -0
- package/dist/modules/lists/index.d.ts.map +1 -0
- package/dist/modules/lists/index.js +35 -0
- package/dist/modules/lists/index.js.map +1 -0
- package/dist/modules/lists/repository.d.ts +80 -0
- package/dist/modules/lists/repository.d.ts.map +1 -0
- package/dist/modules/lists/repository.js +178 -0
- package/dist/modules/lists/repository.js.map +1 -0
- package/dist/modules/lists/routes.d.ts +55 -0
- package/dist/modules/lists/routes.d.ts.map +1 -0
- package/dist/modules/lists/routes.js +168 -0
- package/dist/modules/lists/routes.js.map +1 -0
- package/dist/modules/lists/schema.d.ts +281 -0
- package/dist/modules/lists/schema.d.ts.map +1 -0
- package/dist/modules/lists/schema.js +83 -0
- package/dist/modules/lists/schema.js.map +1 -0
- package/dist/modules/lists/service.d.ts +82 -0
- package/dist/modules/lists/service.d.ts.map +1 -0
- package/dist/modules/lists/service.js +262 -0
- package/dist/modules/lists/service.js.map +1 -0
- package/dist/modules/lists/tools.d.ts +4 -0
- package/dist/modules/lists/tools.d.ts.map +1 -0
- package/dist/modules/lists/tools.js +86 -0
- package/dist/modules/lists/tools.js.map +1 -0
- package/dist/modules/mcp/index.d.ts.map +1 -1
- package/dist/modules/mcp/index.js +5 -0
- package/dist/modules/mcp/index.js.map +1 -1
- package/dist/modules/notes/routes.d.ts +1 -0
- package/dist/modules/notes/routes.d.ts.map +1 -1
- package/dist/modules/opportunities/index.d.ts.map +1 -1
- package/dist/modules/opportunities/index.js +3 -1
- package/dist/modules/opportunities/index.js.map +1 -1
- package/dist/modules/opportunities/repository.d.ts +2 -0
- package/dist/modules/opportunities/repository.d.ts.map +1 -1
- package/dist/modules/opportunities/repository.js +4 -0
- package/dist/modules/opportunities/repository.js.map +1 -1
- package/dist/modules/opportunities/routes.d.ts +16 -0
- package/dist/modules/opportunities/routes.d.ts.map +1 -1
- package/dist/modules/opportunities/routes.js +13 -0
- package/dist/modules/opportunities/routes.js.map +1 -1
- package/dist/modules/opportunities/schema.d.ts +20 -0
- package/dist/modules/opportunities/schema.d.ts.map +1 -1
- package/dist/modules/opportunities/schema.js +6 -1
- package/dist/modules/opportunities/schema.js.map +1 -1
- package/dist/modules/opportunities/service.d.ts +20 -3
- package/dist/modules/opportunities/service.d.ts.map +1 -1
- package/dist/modules/opportunities/service.js +99 -18
- package/dist/modules/opportunities/service.js.map +1 -1
- package/dist/modules/opportunities/tools.d.ts.map +1 -1
- package/dist/modules/opportunities/tools.js +2 -0
- package/dist/modules/opportunities/tools.js.map +1 -1
- package/dist/modules/partnerships/index.d.ts.map +1 -1
- package/dist/modules/partnerships/index.js +3 -1
- package/dist/modules/partnerships/index.js.map +1 -1
- package/dist/modules/partnerships/repository.d.ts +0 -17
- package/dist/modules/partnerships/repository.d.ts.map +1 -1
- package/dist/modules/partnerships/repository.js +6 -82
- package/dist/modules/partnerships/repository.js.map +1 -1
- package/dist/modules/partnerships/routes.d.ts +14 -0
- package/dist/modules/partnerships/routes.d.ts.map +1 -1
- package/dist/modules/partnerships/routes.js +7 -0
- package/dist/modules/partnerships/routes.js.map +1 -1
- package/dist/modules/partnerships/schema.d.ts +20 -41
- package/dist/modules/partnerships/schema.d.ts.map +1 -1
- package/dist/modules/partnerships/schema.js +6 -10
- package/dist/modules/partnerships/schema.js.map +1 -1
- package/dist/modules/partnerships/service.d.ts +11 -1
- package/dist/modules/partnerships/service.d.ts.map +1 -1
- package/dist/modules/partnerships/service.js +43 -20
- package/dist/modules/partnerships/service.js.map +1 -1
- package/dist/modules/people/consentHydration.d.ts +26 -0
- package/dist/modules/people/consentHydration.d.ts.map +1 -0
- package/dist/modules/people/consentHydration.js +100 -0
- package/dist/modules/people/consentHydration.js.map +1 -0
- package/dist/modules/people/index.d.ts.map +1 -1
- package/dist/modules/people/index.js +3 -1
- package/dist/modules/people/index.js.map +1 -1
- package/dist/modules/people/personConsentWrites.d.ts +40 -0
- package/dist/modules/people/personConsentWrites.d.ts.map +1 -0
- package/dist/modules/people/personConsentWrites.js +98 -0
- package/dist/modules/people/personConsentWrites.js.map +1 -0
- package/dist/modules/people/repository.d.ts +11 -0
- package/dist/modules/people/repository.d.ts.map +1 -1
- package/dist/modules/people/repository.js +21 -1
- package/dist/modules/people/repository.js.map +1 -1
- package/dist/modules/people/routes.d.ts +57 -4
- package/dist/modules/people/routes.d.ts.map +1 -1
- package/dist/modules/people/routes.js +104 -5
- package/dist/modules/people/routes.js.map +1 -1
- package/dist/modules/people/schema.d.ts +366 -1
- package/dist/modules/people/schema.d.ts.map +1 -1
- package/dist/modules/people/schema.js +92 -2
- package/dist/modules/people/schema.js.map +1 -1
- package/dist/modules/people/service.d.ts +30 -1
- package/dist/modules/people/service.d.ts.map +1 -1
- package/dist/modules/people/service.js +131 -36
- package/dist/modules/people/service.js.map +1 -1
- package/dist/modules/people/tools.d.ts.map +1 -1
- package/dist/modules/people/tools.js +4 -1
- package/dist/modules/people/tools.js.map +1 -1
- package/dist/modules/personLinks.d.ts +79 -0
- package/dist/modules/personLinks.d.ts.map +1 -0
- package/dist/modules/personLinks.js +155 -0
- package/dist/modules/personLinks.js.map +1 -0
- package/dist/modules/pipelines/routes.d.ts +1 -0
- package/dist/modules/pipelines/routes.d.ts.map +1 -1
- package/dist/modules/plans/routes.d.ts +1 -0
- package/dist/modules/plans/routes.d.ts.map +1 -1
- package/dist/modules/positions/routes.d.ts.map +1 -1
- package/dist/modules/positions/routes.js +4 -2
- package/dist/modules/positions/routes.js.map +1 -1
- package/dist/modules/raises/index.d.ts.map +1 -1
- package/dist/modules/raises/index.js +3 -1
- package/dist/modules/raises/index.js.map +1 -1
- package/dist/modules/raises/repository.d.ts +0 -17
- package/dist/modules/raises/repository.d.ts.map +1 -1
- package/dist/modules/raises/repository.js +6 -77
- package/dist/modules/raises/repository.js.map +1 -1
- package/dist/modules/raises/routes.d.ts +14 -0
- package/dist/modules/raises/routes.d.ts.map +1 -1
- package/dist/modules/raises/routes.js +7 -0
- package/dist/modules/raises/routes.js.map +1 -1
- package/dist/modules/raises/schema.d.ts +20 -41
- package/dist/modules/raises/schema.d.ts.map +1 -1
- package/dist/modules/raises/schema.js +6 -10
- package/dist/modules/raises/schema.js.map +1 -1
- package/dist/modules/raises/service.d.ts +11 -1
- package/dist/modules/raises/service.d.ts.map +1 -1
- package/dist/modules/raises/service.js +41 -18
- package/dist/modules/raises/service.js.map +1 -1
- package/dist/modules/recordTargets.d.ts.map +1 -1
- package/dist/modules/recordTargets.js +2 -0
- package/dist/modules/recordTargets.js.map +1 -1
- package/dist/modules/references.d.ts +10 -0
- package/dist/modules/references.d.ts.map +1 -1
- package/dist/modules/references.js +27 -4
- package/dist/modules/references.js.map +1 -1
- package/dist/modules/sample-data/fixture.d.ts +160 -0
- package/dist/modules/sample-data/fixture.d.ts.map +1 -0
- package/dist/modules/sample-data/fixture.js +501 -0
- package/dist/modules/sample-data/fixture.js.map +1 -0
- package/dist/modules/sample-data/index.d.ts +11 -0
- package/dist/modules/sample-data/index.d.ts.map +1 -0
- package/dist/modules/sample-data/index.js +44 -0
- package/dist/modules/sample-data/index.js.map +1 -0
- package/dist/modules/sample-data/routes.d.ts +15 -0
- package/dist/modules/sample-data/routes.d.ts.map +1 -0
- package/dist/modules/sample-data/routes.js +25 -0
- package/dist/modules/sample-data/routes.js.map +1 -0
- package/dist/modules/sample-data/service.d.ts +39 -0
- package/dist/modules/sample-data/service.d.ts.map +1 -0
- package/dist/modules/sample-data/service.js +481 -0
- package/dist/modules/sample-data/service.js.map +1 -0
- package/dist/modules/sample-data/tools.d.ts +4 -0
- package/dist/modules/sample-data/tools.d.ts.map +1 -0
- package/dist/modules/sample-data/tools.js +22 -0
- package/dist/modules/sample-data/tools.js.map +1 -0
- package/dist/modules/search/index.d.ts +1 -1
- package/dist/modules/search/index.d.ts.map +1 -1
- package/dist/modules/search/index.js +2 -1
- package/dist/modules/search/index.js.map +1 -1
- package/dist/modules/search/repository.d.ts +1 -0
- package/dist/modules/search/repository.d.ts.map +1 -1
- package/dist/modules/search/repository.js +23 -0
- package/dist/modules/search/repository.js.map +1 -1
- package/dist/modules/search/service.d.ts +3 -3
- package/dist/modules/search/service.d.ts.map +1 -1
- package/dist/modules/search/service.js +5 -4
- package/dist/modules/search/service.js.map +1 -1
- package/dist/modules/smtp-email/index.d.ts +1 -0
- package/dist/modules/smtp-email/index.d.ts.map +1 -1
- package/dist/modules/smtp-email/index.js +1 -0
- package/dist/modules/smtp-email/index.js.map +1 -1
- package/dist/modules/stagedRecords.d.ts +3 -3
- package/dist/modules/stagedRecords.d.ts.map +1 -1
- package/dist/modules/stagedRecords.js +9 -0
- package/dist/modules/stagedRecords.js.map +1 -1
- package/dist/modules/webhooks/payloads.d.ts.map +1 -1
- package/dist/modules/webhooks/payloads.js +15 -2
- package/dist/modules/webhooks/payloads.js.map +1 -1
- package/dist/modules/workspace/repository.d.ts +2 -0
- package/dist/modules/workspace/repository.d.ts.map +1 -1
- package/dist/modules/workspace/repository.js +7 -0
- package/dist/modules/workspace/repository.js.map +1 -1
- package/dist/modules/workspace/service.d.ts.map +1 -1
- package/dist/modules/workspace/service.js +20 -1
- package/dist/modules/workspace/service.js.map +1 -1
- package/dist/modules/workspace/starters.d.ts.map +1 -1
- package/dist/modules/workspace/starters.js +5 -0
- package/dist/modules/workspace/starters.js.map +1 -1
- package/dist/runtime/events.d.ts +1 -1
- package/dist/runtime/events.d.ts.map +1 -1
- package/dist/runtime/events.js +1 -0
- package/dist/runtime/events.js.map +1 -1
- package/dist/schema/index.d.ts +4 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +4 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/testing/database.d.ts +5 -1
- package/dist/testing/database.d.ts.map +1 -1
- package/dist/testing/database.js +81 -10
- package/dist/testing/database.js.map +1 -1
- package/migrations/0021_certain_maggott.sql +30 -0
- package/migrations/0022_stormy_manta.sql +1 -0
- package/migrations/0023_funny_maddog.sql +1 -0
- package/migrations/0024_third_king_cobra.sql +46 -0
- package/migrations/0025_worthless_chimera.sql +3 -0
- package/migrations/0026_late_aqueduct.sql +46 -0
- package/migrations/0027_brainy_silver_sable.sql +3 -0
- package/migrations/0028_freezing_scrambler.sql +19 -0
- package/migrations/0029_custom_fields.sql +26 -0
- package/migrations/0030_enquiries.sql +79 -0
- package/migrations/0031_consent.sql +45 -0
- package/migrations/0032_form_field_statement.sql +1 -0
- package/migrations/0033_form_field_consent_purpose_ids.sql +5 -0
- package/migrations/0034_drop_form_field_consent_purpose_id.sql +1 -0
- package/migrations/0035_form_field_consent_purpose_labels.sql +1 -0
- package/migrations/0036_form_field_notice_type.sql +2 -0
- package/migrations/meta/0021_snapshot.json +5389 -0
- package/migrations/meta/0022_snapshot.json +5396 -0
- package/migrations/meta/0023_snapshot.json +5403 -0
- package/migrations/meta/0024_snapshot.json +5516 -0
- package/migrations/meta/0025_snapshot.json +5336 -0
- package/migrations/meta/0026_snapshot.json +5710 -0
- package/migrations/meta/0027_snapshot.json +5716 -0
- package/migrations/meta/0028_snapshot.json +5740 -0
- package/migrations/meta/0029_snapshot.json +5935 -0
- package/migrations/meta/0030_snapshot.json +6245 -0
- package/migrations/meta/0031_snapshot.json +6572 -0
- package/migrations/meta/0032_snapshot.json +6578 -0
- package/migrations/meta/0033_snapshot.json +6572 -0
- package/migrations/meta/0034_snapshot.json +6566 -0
- package/migrations/meta/0035_snapshot.json +6573 -0
- package/migrations/meta/0036_snapshot.json +6573 -0
- package/migrations/meta/_journal.json +112 -0
- package/package.json +3 -2
- package/src/lib/consumerEmailDomains.ts +62 -0
- package/src/lib/email.ts +7 -0
- package/src/lib/emailContent.ts +91 -0
- package/src/lib/emailDomainAutoLink.ts +165 -0
- package/src/lib/ids.ts +13 -0
- package/src/modules/activities/repository.ts +22 -23
- package/src/modules/activities/wording.ts +18 -0
- package/src/modules/agent-tasks/catalog.ts +63 -0
- package/src/modules/agent-tasks/resolve.ts +64 -24
- package/src/modules/attachedRecords.ts +37 -3
- package/src/modules/auth/preferences.ts +13 -1
- package/src/modules/auth/routes.ts +22 -0
- package/src/modules/auth/schema.ts +12 -2
- package/src/modules/auth/service.ts +37 -3
- package/src/modules/companies/index.ts +3 -1
- package/src/modules/companies/repository.ts +3 -0
- package/src/modules/companies/routes.ts +20 -0
- package/src/modules/companies/schema.ts +11 -1
- package/src/modules/companies/service.ts +72 -12
- package/src/modules/consent-purposes/capabilities.ts +12 -0
- package/src/modules/consent-purposes/events.ts +38 -0
- package/src/modules/consent-purposes/index.ts +48 -0
- package/src/modules/consent-purposes/repository.ts +163 -0
- package/src/modules/consent-purposes/routes.ts +122 -0
- package/src/modules/consent-purposes/schema.ts +46 -0
- package/src/modules/consent-purposes/service.ts +423 -0
- package/src/modules/consent-purposes/starters.ts +32 -0
- package/src/modules/consent-purposes/tools.ts +44 -0
- package/src/modules/core.ts +21 -0
- package/src/modules/custom-fields/capabilities.ts +17 -0
- package/src/modules/custom-fields/events.ts +51 -0
- package/src/modules/custom-fields/index.ts +61 -0
- package/src/modules/custom-fields/repository.ts +225 -0
- package/src/modules/custom-fields/routes.ts +155 -0
- package/src/modules/custom-fields/schema.ts +61 -0
- package/src/modules/custom-fields/service.ts +439 -0
- package/src/modules/custom-fields/tools.ts +53 -0
- package/src/modules/custom-fields/values.ts +352 -0
- package/src/modules/custom-fields/wire.ts +32 -0
- package/src/modules/dashboard/repository.ts +4 -3
- package/src/modules/deals/index.ts +5 -2
- package/src/modules/deals/repository.ts +6 -106
- package/src/modules/deals/routes.ts +7 -0
- package/src/modules/deals/schema.ts +7 -15
- package/src/modules/deals/service.ts +92 -23
- package/src/modules/decisions/repository.ts +2 -0
- package/src/modules/email-domain-linker/index.ts +40 -0
- package/src/modules/email-domain-linker/routes.ts +40 -0
- package/src/modules/email-domain-linker/service.ts +122 -0
- package/src/modules/enquiries/events.ts +45 -0
- package/src/modules/enquiries/index.ts +50 -0
- package/src/modules/enquiries/repository.ts +164 -0
- package/src/modules/enquiries/routes.ts +172 -0
- package/src/modules/enquiries/schema.ts +59 -0
- package/src/modules/enquiries/service.ts +644 -0
- package/src/modules/enquiries/tools.ts +66 -0
- package/src/modules/eventCatalogs.ts +4 -0
- package/src/modules/forms/embed.ts +391 -44
- package/src/modules/forms/events.ts +30 -2
- package/src/modules/forms/fields.ts +102 -2
- package/src/modules/forms/index.ts +12 -1
- package/src/modules/forms/mapping.ts +183 -6
- package/src/modules/forms/publicRoutes.ts +43 -1
- package/src/modules/forms/repository.ts +162 -1
- package/src/modules/forms/routes.ts +212 -2
- package/src/modules/forms/schema.ts +166 -4
- package/src/modules/forms/service.ts +565 -41
- package/src/modules/forms/submission.ts +718 -44
- package/src/modules/import-export/drafts.ts +20 -1
- package/src/modules/import-export/exportRows.ts +21 -5
- package/src/modules/import-export/plan.ts +47 -2
- package/src/modules/import-export/presets.ts +10 -0
- package/src/modules/import-export/repository.ts +73 -8
- package/src/modules/import-export/routes.ts +4 -0
- package/src/modules/import-export/schema.ts +11 -0
- package/src/modules/import-export/service.ts +28 -2
- package/src/modules/import-export/streams.ts +3 -1
- package/src/modules/import-export/tools.ts +10 -0
- package/src/modules/import-export/validation.ts +28 -0
- package/src/modules/import-export/writes.ts +70 -5
- package/src/modules/lists/events.ts +41 -0
- package/src/modules/lists/index.ts +41 -0
- package/src/modules/lists/repository.ts +343 -0
- package/src/modules/lists/routes.ts +255 -0
- package/src/modules/lists/schema.ts +95 -0
- package/src/modules/lists/service.ts +505 -0
- package/src/modules/lists/tools.ts +128 -0
- package/src/modules/mcp/index.ts +5 -0
- package/src/modules/opportunities/index.ts +3 -1
- package/src/modules/opportunities/repository.ts +11 -0
- package/src/modules/opportunities/routes.ts +13 -0
- package/src/modules/opportunities/schema.ts +7 -1
- package/src/modules/opportunities/service.ts +188 -22
- package/src/modules/opportunities/tools.ts +2 -0
- package/src/modules/partnerships/index.ts +3 -1
- package/src/modules/partnerships/repository.ts +6 -117
- package/src/modules/partnerships/routes.ts +7 -0
- package/src/modules/partnerships/schema.ts +7 -14
- package/src/modules/partnerships/service.ts +93 -22
- package/src/modules/people/consentHydration.ts +167 -0
- package/src/modules/people/index.ts +3 -1
- package/src/modules/people/personConsentWrites.ts +177 -0
- package/src/modules/people/repository.ts +31 -0
- package/src/modules/people/routes.ts +127 -18
- package/src/modules/people/schema.ts +109 -3
- package/src/modules/people/service.ts +205 -39
- package/src/modules/people/tools.ts +5 -1
- package/src/modules/personLinks.ts +278 -0
- package/src/modules/positions/routes.ts +4 -2
- package/src/modules/raises/index.ts +3 -1
- package/src/modules/raises/repository.ts +6 -107
- package/src/modules/raises/routes.ts +7 -0
- package/src/modules/raises/schema.ts +7 -14
- package/src/modules/raises/service.ts +91 -20
- package/src/modules/recordTargets.ts +2 -0
- package/src/modules/references.ts +43 -4
- package/src/modules/sample-data/fixture.ts +690 -0
- package/src/modules/sample-data/index.ts +51 -0
- package/src/modules/sample-data/routes.ts +50 -0
- package/src/modules/sample-data/service.ts +679 -0
- package/src/modules/sample-data/tools.ts +32 -0
- package/src/modules/search/index.ts +2 -1
- package/src/modules/search/repository.ts +33 -1
- package/src/modules/search/service.ts +7 -5
- package/src/modules/smtp-email/index.ts +8 -1
- package/src/modules/stagedRecords.ts +18 -3
- package/src/modules/webhooks/payloads.ts +20 -2
- package/src/modules/workspace/repository.ts +12 -0
- package/src/modules/workspace/service.ts +27 -1
- package/src/modules/workspace/starters.ts +5 -0
- package/src/runtime/events.ts +1 -0
- package/src/schema/index.ts +4 -0
- package/src/testing/database.ts +97 -11
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import type { ConsentStatus, CustomFieldWireValue } from '@kelpie/schemas'
|
|
2
|
+
|
|
1
3
|
import { changedKeys } from '../../lib/changes.ts'
|
|
2
4
|
import { UNIQUE_VIOLATION, isReferenceViolation, postgresErrorCode } from '../../lib/database.ts'
|
|
3
5
|
import type { Database } from '../../lib/database.ts'
|
|
6
|
+
import { autoLinkPersonByEmailDomain } from '../../lib/emailDomainAutoLink.ts'
|
|
4
7
|
import { AppError } from '../../lib/errors.ts'
|
|
5
8
|
import type { IdFactory } from '../../lib/ids.ts'
|
|
6
9
|
import { normaliseEmail } from '../../lib/normalisation.ts'
|
|
@@ -18,11 +21,17 @@ import {
|
|
|
18
21
|
deleteRecordsAttachedTo,
|
|
19
22
|
deleteRecordsAttachedToCandidaciesOf,
|
|
20
23
|
} from '../attachedRecords.ts'
|
|
21
|
-
import {
|
|
24
|
+
import type { CustomFieldValuesValidator } from '../custom-fields/values.ts'
|
|
25
|
+
import * as personLinks from '../personLinks.ts'
|
|
26
|
+
import { referenceViolationTable } from '../../lib/database.ts'
|
|
27
|
+
import { referencedByPipelineRecords, referencedElsewhere } from '../references.ts'
|
|
22
28
|
import * as repository from './repository.ts'
|
|
23
29
|
import { DEFAULT_PERSON_SORT, PERSON_SORTS } from './repository.ts'
|
|
24
30
|
import type { PersonFilters, PersonRecord } from './repository.ts'
|
|
25
31
|
import type { Influence, PreferredChannel, Relationship, SocialProfile } from './schema.ts'
|
|
32
|
+
import { readConsentsFor, readConsentsForMany } from './consentHydration.ts'
|
|
33
|
+
import type { EffectiveConsent } from './consentHydration.ts'
|
|
34
|
+
import { applyManualConsentWrites, consentChangedPaths } from './personConsentWrites.ts'
|
|
26
35
|
|
|
27
36
|
/**
|
|
28
37
|
* People: who the workspace knows.
|
|
@@ -40,6 +49,7 @@ export interface PeopleDependencies {
|
|
|
40
49
|
readonly createId: IdFactory
|
|
41
50
|
readonly now: () => Date
|
|
42
51
|
readonly recordActivity: ActivityRecorder
|
|
52
|
+
readonly customFields: CustomFieldValuesValidator
|
|
43
53
|
}
|
|
44
54
|
|
|
45
55
|
/**
|
|
@@ -51,6 +61,10 @@ export interface PeopleDependencies {
|
|
|
51
61
|
*/
|
|
52
62
|
const PERSON_FIELD_LABELS: FieldLabels = {
|
|
53
63
|
name: 'Name',
|
|
64
|
+
salutation: 'Salutation',
|
|
65
|
+
firstName: 'First name',
|
|
66
|
+
lastName: 'Last name',
|
|
67
|
+
suffix: 'Suffix',
|
|
54
68
|
email: 'Email',
|
|
55
69
|
phones: 'Phone numbers',
|
|
56
70
|
socialProfiles: 'Social profiles',
|
|
@@ -62,6 +76,7 @@ const PERSON_FIELD_LABELS: FieldLabels = {
|
|
|
62
76
|
summary: 'Summary',
|
|
63
77
|
tags: 'Tags',
|
|
64
78
|
lastContactedAt: 'Last contacted',
|
|
79
|
+
doNotContact: 'Do not contact',
|
|
65
80
|
}
|
|
66
81
|
|
|
67
82
|
/**
|
|
@@ -70,10 +85,27 @@ const PERSON_FIELD_LABELS: FieldLabels = {
|
|
|
70
85
|
* Deliberately an alias rather than a parallel interface. A hand-written copy of
|
|
71
86
|
* fifteen fields drifts from the table the first time one is added.
|
|
72
87
|
*/
|
|
73
|
-
export type PersonView = Omit<PersonRecord, 'workspaceId'>
|
|
88
|
+
export type PersonView = Omit<PersonRecord, 'workspaceId'> & {
|
|
89
|
+
/**
|
|
90
|
+
* The effective consent status for every workspace purpose. An entry with
|
|
91
|
+
* `inherited: true` has no explicit `person_consents` row and carries the
|
|
92
|
+
* purpose's `default_status`; the rest have their own row.
|
|
93
|
+
*/
|
|
94
|
+
readonly consents: readonly EffectiveConsent[]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface PersonConsentWriteInput {
|
|
98
|
+
readonly purposeSlug: string
|
|
99
|
+
readonly status: ConsentStatus | null
|
|
100
|
+
}
|
|
74
101
|
|
|
75
102
|
export interface CreatePersonInput {
|
|
103
|
+
/** Already resolved. The route composes one from the parts when the caller sent none. */
|
|
76
104
|
readonly name: string
|
|
105
|
+
readonly salutation: string | null
|
|
106
|
+
readonly firstName: string | null
|
|
107
|
+
readonly lastName: string | null
|
|
108
|
+
readonly suffix: string | null
|
|
77
109
|
readonly email: string | null
|
|
78
110
|
readonly phones: readonly string[]
|
|
79
111
|
readonly socialProfiles: readonly SocialProfile[]
|
|
@@ -85,6 +117,15 @@ export interface CreatePersonInput {
|
|
|
85
117
|
readonly summary: string
|
|
86
118
|
readonly tags: readonly string[]
|
|
87
119
|
readonly lastContactedAt: Date | null
|
|
120
|
+
readonly doNotContact: boolean
|
|
121
|
+
/**
|
|
122
|
+
* Consent writes for named purposes. `status: null` deletes the row and
|
|
123
|
+
* inherits the purpose default; anything else upserts `source: manual`.
|
|
124
|
+
* Absent purposes are left alone.
|
|
125
|
+
*/
|
|
126
|
+
readonly consents: readonly PersonConsentWriteInput[]
|
|
127
|
+
/** Wire shape merge patch (undefined for a create without any): sent keys change, null clears. */
|
|
128
|
+
readonly customFields: Readonly<Record<string, CustomFieldWireValue | null>> | undefined
|
|
88
129
|
}
|
|
89
130
|
|
|
90
131
|
/** PATCH semantics: an absent field is left alone, and null clears a nullable one. */
|
|
@@ -98,10 +139,10 @@ export interface PeopleService {
|
|
|
98
139
|
remove(actor: Actor, id: string): Promise<void>
|
|
99
140
|
}
|
|
100
141
|
|
|
101
|
-
function toView(record: PersonRecord): PersonView {
|
|
142
|
+
function toView(record: PersonRecord, consents: readonly EffectiveConsent[]): PersonView {
|
|
102
143
|
const { workspaceId: _workspaceId, ...view } = record
|
|
103
144
|
|
|
104
|
-
return view
|
|
145
|
+
return { ...view, consents }
|
|
105
146
|
}
|
|
106
147
|
|
|
107
148
|
/**
|
|
@@ -112,6 +153,10 @@ function toView(record: PersonRecord): PersonView {
|
|
|
112
153
|
function toStoredColumns(input: UpdatePersonInput): Partial<repository.PersonColumns> {
|
|
113
154
|
return {
|
|
114
155
|
...(input.name === undefined ? {} : { name: input.name }),
|
|
156
|
+
...(input.salutation === undefined ? {} : { salutation: input.salutation }),
|
|
157
|
+
...(input.firstName === undefined ? {} : { firstName: input.firstName }),
|
|
158
|
+
...(input.lastName === undefined ? {} : { lastName: input.lastName }),
|
|
159
|
+
...(input.suffix === undefined ? {} : { suffix: input.suffix }),
|
|
115
160
|
...(input.email === undefined ? {} : { email: input.email === null ? null : normaliseEmail(input.email) }),
|
|
116
161
|
...(input.phones === undefined ? {} : { phones: input.phones }),
|
|
117
162
|
...(input.socialProfiles === undefined ? {} : { socialProfiles: input.socialProfiles }),
|
|
@@ -123,6 +168,7 @@ function toStoredColumns(input: UpdatePersonInput): Partial<repository.PersonCol
|
|
|
123
168
|
...(input.summary === undefined ? {} : { summary: input.summary }),
|
|
124
169
|
...(input.tags === undefined ? {} : { tags: [...input.tags] }),
|
|
125
170
|
...(input.lastContactedAt === undefined ? {} : { lastContactedAt: input.lastContactedAt }),
|
|
171
|
+
...(input.doNotContact === undefined ? {} : { doNotContact: input.doNotContact }),
|
|
126
172
|
}
|
|
127
173
|
}
|
|
128
174
|
|
|
@@ -150,12 +196,22 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
150
196
|
const workspaceId = requireWorkspaceId(actor)
|
|
151
197
|
const window = readListWindow(query, PERSON_SORTS, DEFAULT_PERSON_SORT)
|
|
152
198
|
const rows = await repository.listPeople(dependencies.db, workspaceId, filters, window)
|
|
199
|
+
const consentsByPerson = await readConsentsForMany(
|
|
200
|
+
dependencies.db,
|
|
201
|
+
workspaceId,
|
|
202
|
+
rows.map((row) => row.id),
|
|
203
|
+
)
|
|
153
204
|
|
|
154
|
-
return mapPage(toPage(rows, window, (person) => person.id),
|
|
205
|
+
return mapPage(toPage(rows, window, (person) => person.id), (record) =>
|
|
206
|
+
toView(record, consentsByPerson.get(record.id) ?? []),
|
|
207
|
+
)
|
|
155
208
|
},
|
|
156
209
|
|
|
157
210
|
async get(actor, id) {
|
|
158
|
-
|
|
211
|
+
const workspaceId = requireWorkspaceId(actor)
|
|
212
|
+
const record = await require(workspaceId, id)
|
|
213
|
+
const consents = await readConsentsFor(dependencies.db, workspaceId, id)
|
|
214
|
+
return toView(record, consents)
|
|
159
215
|
},
|
|
160
216
|
|
|
161
217
|
async create(actor, input) {
|
|
@@ -164,6 +220,12 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
164
220
|
|
|
165
221
|
return dependencies.transaction(
|
|
166
222
|
async ({ tx, events }) => {
|
|
223
|
+
const customFields = await dependencies.customFields.forCreate(
|
|
224
|
+
tx,
|
|
225
|
+
workspaceId,
|
|
226
|
+
'person',
|
|
227
|
+
input.customFields,
|
|
228
|
+
)
|
|
167
229
|
let created: PersonRecord
|
|
168
230
|
|
|
169
231
|
try {
|
|
@@ -171,6 +233,10 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
171
233
|
id,
|
|
172
234
|
workspaceId,
|
|
173
235
|
name: input.name,
|
|
236
|
+
salutation: input.salutation,
|
|
237
|
+
firstName: input.firstName,
|
|
238
|
+
lastName: input.lastName,
|
|
239
|
+
suffix: input.suffix,
|
|
174
240
|
email: input.email === null ? null : normaliseEmail(input.email),
|
|
175
241
|
phones: input.phones,
|
|
176
242
|
socialProfiles: input.socialProfiles,
|
|
@@ -182,6 +248,8 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
182
248
|
summary: input.summary,
|
|
183
249
|
tags: [...input.tags],
|
|
184
250
|
lastContactedAt: input.lastContactedAt,
|
|
251
|
+
doNotContact: input.doNotContact,
|
|
252
|
+
customFields,
|
|
185
253
|
})
|
|
186
254
|
} catch (error: unknown) {
|
|
187
255
|
if (postgresErrorCode(error) === UNIQUE_VIOLATION) {
|
|
@@ -191,6 +259,16 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
191
259
|
throw error
|
|
192
260
|
}
|
|
193
261
|
|
|
262
|
+
if (input.consents.length > 0) {
|
|
263
|
+
await applyManualConsentWrites(
|
|
264
|
+
tx,
|
|
265
|
+
workspaceId,
|
|
266
|
+
created.id,
|
|
267
|
+
input.consents,
|
|
268
|
+
dependencies.now(),
|
|
269
|
+
)
|
|
270
|
+
}
|
|
271
|
+
|
|
194
272
|
await dependencies.recordActivity(tx, workspaceId, actor, {
|
|
195
273
|
targetType: 'person',
|
|
196
274
|
targetId: created.id,
|
|
@@ -200,7 +278,17 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
200
278
|
|
|
201
279
|
events.emit('people.person.created', { type: 'person', id: created.id }, {})
|
|
202
280
|
|
|
203
|
-
|
|
281
|
+
// Sync auto-link. Inside the same transaction so the response returns
|
|
282
|
+
// with the Position already visible to a follow-up read; without this
|
|
283
|
+
// the UI would not see the new Position until a manual refresh.
|
|
284
|
+
await autoLinkPersonByEmailDomain(tx, events, workspaceId, created, {
|
|
285
|
+
createId: dependencies.createId,
|
|
286
|
+
now: dependencies.now,
|
|
287
|
+
recordActivity: dependencies.recordActivity,
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
const consents = await readConsentsFor(tx, workspaceId, created.id)
|
|
291
|
+
return toView(created, consents)
|
|
204
292
|
},
|
|
205
293
|
{ workspaceId, actor: toEventActor(actor) },
|
|
206
294
|
)
|
|
@@ -210,50 +298,109 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
210
298
|
const workspaceId = requireWorkspaceId(actor)
|
|
211
299
|
const existing = await require(workspaceId, id)
|
|
212
300
|
const columns = toStoredColumns(changes)
|
|
213
|
-
const
|
|
214
|
-
|
|
215
|
-
// A PATCH that changes nothing is not a write. Bumping `updated_at` for it
|
|
216
|
-
// would make the record look freshly touched to everything that sorts or
|
|
217
|
-
// filters by it.
|
|
218
|
-
if (changed.length === 0) {
|
|
219
|
-
return toView(existing)
|
|
220
|
-
}
|
|
301
|
+
const scalarChanged = changedKeys(existing, columns)
|
|
302
|
+
const consentWrites = changes.consents ?? []
|
|
221
303
|
|
|
222
304
|
return dependencies.transaction(
|
|
223
305
|
async ({ tx, events }) => {
|
|
306
|
+
const cf = await dependencies.customFields.forUpdate(
|
|
307
|
+
tx,
|
|
308
|
+
workspaceId,
|
|
309
|
+
'person',
|
|
310
|
+
existing.customFields,
|
|
311
|
+
changes.customFields,
|
|
312
|
+
)
|
|
313
|
+
const customFieldsChanged = cf !== undefined && cf.changedPaths.length > 0
|
|
314
|
+
|
|
315
|
+
const consentChanges =
|
|
316
|
+
consentWrites.length > 0
|
|
317
|
+
? await applyManualConsentWrites(
|
|
318
|
+
tx,
|
|
319
|
+
workspaceId,
|
|
320
|
+
id,
|
|
321
|
+
consentWrites,
|
|
322
|
+
dependencies.now(),
|
|
323
|
+
)
|
|
324
|
+
: []
|
|
325
|
+
const consentPaths = consentChangedPaths(consentChanges)
|
|
326
|
+
const consentActuallyChanged = consentPaths.length > 0
|
|
327
|
+
|
|
328
|
+
// A PATCH that changes nothing is not a write. Bumping `updated_at`
|
|
329
|
+
// would make the record look freshly touched to everything that sorts
|
|
330
|
+
// or filters by it.
|
|
331
|
+
if (
|
|
332
|
+
scalarChanged.length === 0 &&
|
|
333
|
+
!customFieldsChanged &&
|
|
334
|
+
!consentActuallyChanged
|
|
335
|
+
) {
|
|
336
|
+
const consents = await readConsentsFor(tx, workspaceId, id)
|
|
337
|
+
return toView(existing, consents)
|
|
338
|
+
}
|
|
339
|
+
|
|
224
340
|
let updated: PersonRecord | undefined
|
|
225
341
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
342
|
+
if (scalarChanged.length > 0 || customFieldsChanged) {
|
|
343
|
+
try {
|
|
344
|
+
updated = await repository.updatePerson(tx, workspaceId, id, {
|
|
345
|
+
...columns,
|
|
346
|
+
...(customFieldsChanged ? { customFields: cf.merged } : {}),
|
|
347
|
+
updatedAt: dependencies.now(),
|
|
348
|
+
})
|
|
349
|
+
} catch (error: unknown) {
|
|
350
|
+
if (postgresErrorCode(error) === UNIQUE_VIOLATION) {
|
|
351
|
+
throw duplicateEmail()
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
throw error
|
|
234
355
|
}
|
|
235
356
|
|
|
236
|
-
|
|
357
|
+
if (updated === undefined) {
|
|
358
|
+
throw AppError.notFound('Person not found')
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
updated = existing
|
|
237
362
|
}
|
|
238
363
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
364
|
+
const customFieldPaths = cf?.changedPaths ?? []
|
|
365
|
+
const activityChanged = [...scalarChanged, ...customFieldPaths, ...consentPaths]
|
|
242
366
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
367
|
+
if (activityChanged.length > 0) {
|
|
368
|
+
const labels: Record<string, string> = { ...PERSON_FIELD_LABELS, ...cf?.labels }
|
|
369
|
+
for (const change of consentChanges) {
|
|
370
|
+
labels[`consents.${change.purposeSlug}`] = `Consent · ${change.purposeLabel}`
|
|
371
|
+
}
|
|
372
|
+
const before: Record<string, unknown> = { ...existing, ...cf?.flatBefore }
|
|
373
|
+
const after: Record<string, unknown> = { ...columns, ...cf?.flatAfter }
|
|
374
|
+
for (const change of consentChanges) {
|
|
375
|
+
before[`consents.${change.purposeSlug}`] = change.previousStatus ?? 'inherits'
|
|
376
|
+
after[`consents.${change.purposeSlug}`] = change.status ?? 'inherits'
|
|
377
|
+
}
|
|
378
|
+
await dependencies.recordActivity(tx, workspaceId, actor, {
|
|
379
|
+
targetType: 'person',
|
|
380
|
+
targetId: id,
|
|
381
|
+
kind: 'updated',
|
|
382
|
+
...describeUpdate(activityChanged, labels, before, after),
|
|
383
|
+
})
|
|
384
|
+
}
|
|
249
385
|
|
|
250
386
|
events.emit(
|
|
251
387
|
'people.person.updated',
|
|
252
388
|
{ type: 'person', id },
|
|
253
|
-
{ changed },
|
|
389
|
+
{ changed: activityChanged },
|
|
254
390
|
)
|
|
255
391
|
|
|
256
|
-
|
|
392
|
+
// Sync auto-link when the email moved. Same-transaction rationale as
|
|
393
|
+
// the create path above.
|
|
394
|
+
if (scalarChanged.includes('email')) {
|
|
395
|
+
await autoLinkPersonByEmailDomain(tx, events, workspaceId, updated, {
|
|
396
|
+
createId: dependencies.createId,
|
|
397
|
+
now: dependencies.now,
|
|
398
|
+
recordActivity: dependencies.recordActivity,
|
|
399
|
+
})
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const consents = await readConsentsFor(tx, workspaceId, id)
|
|
403
|
+
return toView(updated, consents)
|
|
257
404
|
},
|
|
258
405
|
{ workspaceId, actor: toEventActor(actor) },
|
|
259
406
|
)
|
|
@@ -275,14 +422,33 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
275
422
|
// notes have to be taken here: no hiring service sees that delete.
|
|
276
423
|
await deleteRecordsAttachedToCandidaciesOf(tx, workspaceId, id)
|
|
277
424
|
|
|
425
|
+
// A person delete failing on a foreign key aborts the enclosing
|
|
426
|
+
// transaction, so the follow-up read that names the referring pipeline
|
|
427
|
+
// types would run against a dead tx. Wrap only the delete in a nested
|
|
428
|
+
// transaction: drizzle emits SAVEPOINT/ROLLBACK TO for it, so the
|
|
429
|
+
// outer tx survives the refusal and the listLinkedTargetTypes read
|
|
430
|
+
// below sees person_links.
|
|
431
|
+
let deleteError: unknown = null
|
|
432
|
+
|
|
278
433
|
try {
|
|
279
|
-
await
|
|
434
|
+
await tx.transaction(async (savepoint) => {
|
|
435
|
+
await repository.deletePerson(savepoint, workspaceId, id)
|
|
436
|
+
})
|
|
280
437
|
} catch (error: unknown) {
|
|
281
|
-
|
|
282
|
-
|
|
438
|
+
deleteError = error
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (deleteError !== null) {
|
|
442
|
+
if (isReferenceViolation(deleteError)) {
|
|
443
|
+
if (referenceViolationTable(deleteError) === 'person_links') {
|
|
444
|
+
const types = await personLinks.listLinkedTargetTypes(tx, workspaceId, id)
|
|
445
|
+
throw referencedByPipelineRecords('person', types)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
throw referencedElsewhere(deleteError, 'person')
|
|
283
449
|
}
|
|
284
450
|
|
|
285
|
-
throw
|
|
451
|
+
throw deleteError
|
|
286
452
|
}
|
|
287
453
|
|
|
288
454
|
events.emit('people.person.deleted', { type: 'person', id }, {})
|
|
@@ -19,7 +19,11 @@ export function registerPeopleTools(mcp: McpToolRegistry, service: PeopleService
|
|
|
19
19
|
registerCrudTools(mcp, {
|
|
20
20
|
resource: 'people',
|
|
21
21
|
subject: 'person',
|
|
22
|
-
about:
|
|
22
|
+
about:
|
|
23
|
+
'Someone the workspace knows. A job title belongs to a position, never to the person. ' +
|
|
24
|
+
'name is the display name every list shows; first_name, last_name, salutation and suffix ' +
|
|
25
|
+
'are optional parts beside it. A create with no name composes one from first_name and ' +
|
|
26
|
+
'last_name. Changing a part never rewrites name.',
|
|
23
27
|
service,
|
|
24
28
|
render: personResponse,
|
|
25
29
|
listArgs,
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { and, asc, eq, inArray, sql } from 'drizzle-orm'
|
|
2
|
+
import type { AnyPgColumn } from 'drizzle-orm/pg-core'
|
|
3
|
+
import type { PipelineKind } from '@kelpie/schemas'
|
|
4
|
+
|
|
5
|
+
import type { IdFactory } from '../lib/ids.ts'
|
|
6
|
+
import type { Queryable } from '../runtime/transaction.ts'
|
|
7
|
+
import { people, personLinks } from './people/schema.ts'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Shared reader/writer for `person_links`, the polymorphic table that holds a
|
|
11
|
+
* person's involvement in a pipeline record. Every deal/opportunity/raise/
|
|
12
|
+
* partnership service reaches through here rather than owning its own join
|
|
13
|
+
* table. `personLinks` is defined in `people/schema.ts` because the person
|
|
14
|
+
* side of the relation is what gives it the real foreign key.
|
|
15
|
+
*
|
|
16
|
+
* All functions take the caller's `Queryable` and `workspaceId` so every
|
|
17
|
+
* query rides the `(workspace_id, target_type, target_id)` index and lands in
|
|
18
|
+
* whatever transaction the caller opened.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* One target the caller writes to. Kept named rather than positional so
|
|
23
|
+
* `linkPeople(db, ids, ws, 'deal', dealId, personIds)` cannot swap the last
|
|
24
|
+
* two arguments silently.
|
|
25
|
+
*/
|
|
26
|
+
export interface PipelineTarget {
|
|
27
|
+
readonly targetType: PipelineKind
|
|
28
|
+
readonly targetId: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The people on one pipeline record, ordered by person_id so a response is
|
|
33
|
+
* stable across reads. Mirrors the deals repository's old `listPersonIds`.
|
|
34
|
+
*/
|
|
35
|
+
export async function listPersonIds(
|
|
36
|
+
db: Queryable,
|
|
37
|
+
workspaceId: string,
|
|
38
|
+
target: PipelineTarget,
|
|
39
|
+
): Promise<string[]> {
|
|
40
|
+
const rows = await db
|
|
41
|
+
.select({ personId: personLinks.personId })
|
|
42
|
+
.from(personLinks)
|
|
43
|
+
.where(
|
|
44
|
+
and(
|
|
45
|
+
eq(personLinks.workspaceId, workspaceId),
|
|
46
|
+
eq(personLinks.targetType, target.targetType),
|
|
47
|
+
eq(personLinks.targetId, target.targetId),
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
.orderBy(asc(personLinks.personId))
|
|
51
|
+
|
|
52
|
+
return rows.map((row) => row.personId)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The people on each of a page of pipeline records of one type, in one query
|
|
57
|
+
* rather than one per row. Ids missing from the map have no people.
|
|
58
|
+
*/
|
|
59
|
+
export async function listPersonIdsFor(
|
|
60
|
+
db: Queryable,
|
|
61
|
+
workspaceId: string,
|
|
62
|
+
targetType: PipelineKind,
|
|
63
|
+
targetIds: readonly string[],
|
|
64
|
+
): Promise<ReadonlyMap<string, readonly string[]>> {
|
|
65
|
+
if (targetIds.length === 0) {
|
|
66
|
+
return new Map()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const rows = await db
|
|
70
|
+
.select({ targetId: personLinks.targetId, personId: personLinks.personId })
|
|
71
|
+
.from(personLinks)
|
|
72
|
+
.where(
|
|
73
|
+
and(
|
|
74
|
+
eq(personLinks.workspaceId, workspaceId),
|
|
75
|
+
eq(personLinks.targetType, targetType),
|
|
76
|
+
inArray(personLinks.targetId, targetIds),
|
|
77
|
+
),
|
|
78
|
+
)
|
|
79
|
+
.orderBy(asc(personLinks.personId))
|
|
80
|
+
|
|
81
|
+
const byTarget = new Map<string, string[]>()
|
|
82
|
+
|
|
83
|
+
for (const row of rows) {
|
|
84
|
+
const existing = byTarget.get(row.targetId)
|
|
85
|
+
|
|
86
|
+
if (existing === undefined) {
|
|
87
|
+
byTarget.set(row.targetId, [row.personId])
|
|
88
|
+
} else {
|
|
89
|
+
existing.push(row.personId)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return byTarget
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Every pipeline record a person is on, in one query. Used by the person
|
|
98
|
+
* activity roll-up and the agent-tasks person case, which used to run one
|
|
99
|
+
* query per join table.
|
|
100
|
+
*/
|
|
101
|
+
export async function listTargetsOfPerson(
|
|
102
|
+
db: Queryable,
|
|
103
|
+
workspaceId: string,
|
|
104
|
+
personId: string,
|
|
105
|
+
): Promise<readonly PipelineTarget[]> {
|
|
106
|
+
const rows = await db
|
|
107
|
+
.select({ targetType: personLinks.targetType, targetId: personLinks.targetId })
|
|
108
|
+
.from(personLinks)
|
|
109
|
+
.where(and(eq(personLinks.workspaceId, workspaceId), eq(personLinks.personId, personId)))
|
|
110
|
+
|
|
111
|
+
return rows.map((row) => ({
|
|
112
|
+
targetType: row.targetType as PipelineKind,
|
|
113
|
+
targetId: row.targetId,
|
|
114
|
+
}))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* The distinct target types still pointing at a person. Used by the 409 on
|
|
119
|
+
* person delete to name each pipeline the person is on, without loading every
|
|
120
|
+
* row.
|
|
121
|
+
*/
|
|
122
|
+
export async function listLinkedTargetTypes(
|
|
123
|
+
db: Queryable,
|
|
124
|
+
workspaceId: string,
|
|
125
|
+
personId: string,
|
|
126
|
+
): Promise<readonly PipelineKind[]> {
|
|
127
|
+
const rows = await db
|
|
128
|
+
.selectDistinct({ targetType: personLinks.targetType })
|
|
129
|
+
.from(personLinks)
|
|
130
|
+
.where(and(eq(personLinks.workspaceId, workspaceId), eq(personLinks.personId, personId)))
|
|
131
|
+
|
|
132
|
+
return rows.map((row) => row.targetType as PipelineKind)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Bulk insert; callers pre-dedupe as today. No-op on empty. */
|
|
136
|
+
export async function linkPeople(
|
|
137
|
+
db: Queryable,
|
|
138
|
+
createId: IdFactory,
|
|
139
|
+
workspaceId: string,
|
|
140
|
+
target: PipelineTarget,
|
|
141
|
+
personIds: readonly string[],
|
|
142
|
+
): Promise<void> {
|
|
143
|
+
if (personIds.length === 0) {
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
await db.insert(personLinks).values(
|
|
148
|
+
personIds.map((personId) => ({
|
|
149
|
+
id: createId('personLink'),
|
|
150
|
+
workspaceId,
|
|
151
|
+
personId,
|
|
152
|
+
targetType: target.targetType,
|
|
153
|
+
targetId: target.targetId,
|
|
154
|
+
})),
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Bulk delete matching a set of people. No-op on empty. */
|
|
159
|
+
export async function unlinkPeople(
|
|
160
|
+
db: Queryable,
|
|
161
|
+
workspaceId: string,
|
|
162
|
+
target: PipelineTarget,
|
|
163
|
+
personIds: readonly string[],
|
|
164
|
+
): Promise<void> {
|
|
165
|
+
if (personIds.length === 0) {
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
await db
|
|
170
|
+
.delete(personLinks)
|
|
171
|
+
.where(
|
|
172
|
+
and(
|
|
173
|
+
eq(personLinks.workspaceId, workspaceId),
|
|
174
|
+
eq(personLinks.targetType, target.targetType),
|
|
175
|
+
eq(personLinks.targetId, target.targetId),
|
|
176
|
+
inArray(personLinks.personId, personIds),
|
|
177
|
+
),
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Link one person, skipping if the row already exists. Used by the forms
|
|
183
|
+
* post-submit actions: a resubmitting visitor does not double-attach.
|
|
184
|
+
*
|
|
185
|
+
* @returns `true` when a row was inserted, `false` when the link already existed.
|
|
186
|
+
*/
|
|
187
|
+
export async function linkPersonIfAbsent(
|
|
188
|
+
db: Queryable,
|
|
189
|
+
createId: IdFactory,
|
|
190
|
+
workspaceId: string,
|
|
191
|
+
target: PipelineTarget,
|
|
192
|
+
personId: string,
|
|
193
|
+
): Promise<boolean> {
|
|
194
|
+
const inserted = await db
|
|
195
|
+
.insert(personLinks)
|
|
196
|
+
.values({
|
|
197
|
+
id: createId('personLink'),
|
|
198
|
+
workspaceId,
|
|
199
|
+
personId,
|
|
200
|
+
targetType: target.targetType,
|
|
201
|
+
targetId: target.targetId,
|
|
202
|
+
})
|
|
203
|
+
.onConflictDoNothing({
|
|
204
|
+
target: [personLinks.personId, personLinks.targetType, personLinks.targetId],
|
|
205
|
+
})
|
|
206
|
+
.returning({ id: personLinks.id })
|
|
207
|
+
|
|
208
|
+
return inserted.length > 0
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Target-side cleanup, called from `attachedRecords.deleteRecordsAttachedTo`
|
|
213
|
+
* when a pipeline record is deleted.
|
|
214
|
+
*
|
|
215
|
+
* @returns the number of rows removed.
|
|
216
|
+
*/
|
|
217
|
+
export async function deleteLinksForTarget(
|
|
218
|
+
db: Queryable,
|
|
219
|
+
workspaceId: string,
|
|
220
|
+
target: PipelineTarget,
|
|
221
|
+
): Promise<number> {
|
|
222
|
+
const deleted = await db
|
|
223
|
+
.delete(personLinks)
|
|
224
|
+
.where(
|
|
225
|
+
and(
|
|
226
|
+
eq(personLinks.workspaceId, workspaceId),
|
|
227
|
+
eq(personLinks.targetType, target.targetType),
|
|
228
|
+
eq(personLinks.targetId, target.targetId),
|
|
229
|
+
),
|
|
230
|
+
)
|
|
231
|
+
.returning({ id: personLinks.id })
|
|
232
|
+
|
|
233
|
+
return deleted.length
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* The `?person_id=` exists-subquery SQL builder, correlated on the outer
|
|
238
|
+
* table's id and workspace columns. Replaces the identical `hasAnyOfPeople`
|
|
239
|
+
* helpers that used to live in each pipeline module's repository.
|
|
240
|
+
*/
|
|
241
|
+
export function anyPersonLinked(
|
|
242
|
+
targetType: PipelineKind,
|
|
243
|
+
targetIdColumn: AnyPgColumn,
|
|
244
|
+
workspaceIdColumn: AnyPgColumn,
|
|
245
|
+
personIds: readonly string[],
|
|
246
|
+
): ReturnType<typeof sql> {
|
|
247
|
+
return sql`exists (
|
|
248
|
+
select 1
|
|
249
|
+
from ${personLinks}
|
|
250
|
+
where ${personLinks.workspaceId} = ${workspaceIdColumn}
|
|
251
|
+
and ${personLinks.targetType} = ${targetType}
|
|
252
|
+
and ${personLinks.targetId} = ${targetIdColumn}
|
|
253
|
+
and ${inArray(personLinks.personId, personIds)}
|
|
254
|
+
)`
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* The names of these people in this workspace, keyed by id. Reads the
|
|
259
|
+
* `people` table because that is where names live; used by every pipeline
|
|
260
|
+
* service to validate `person_ids` and label the `linked`/`unlinked`
|
|
261
|
+
* activity. An id missing from the map does not exist in this workspace.
|
|
262
|
+
*/
|
|
263
|
+
export async function findPeopleNamed(
|
|
264
|
+
db: Queryable,
|
|
265
|
+
workspaceId: string,
|
|
266
|
+
personIds: readonly string[],
|
|
267
|
+
): Promise<ReadonlyMap<string, string>> {
|
|
268
|
+
if (personIds.length === 0) {
|
|
269
|
+
return new Map()
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const rows = await db
|
|
273
|
+
.select({ id: people.id, name: people.name })
|
|
274
|
+
.from(people)
|
|
275
|
+
.where(and(eq(people.workspaceId, workspaceId), inArray(people.id, personIds)))
|
|
276
|
+
|
|
277
|
+
return new Map(rows.map((row) => [row.id, row.name]))
|
|
278
|
+
}
|