@kelpie/server 0.8.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/ids.d.ts +11 -0
- package/dist/lib/ids.d.ts.map +1 -1
- package/dist/lib/ids.js +11 -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 +15 -1
- package/dist/modules/attachedRecords.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/routes.d.ts +14 -0
- package/dist/modules/companies/routes.d.ts.map +1 -1
- package/dist/modules/companies/routes.js +7 -0
- package/dist/modules/companies/routes.js.map +1 -1
- package/dist/modules/companies/schema.d.ts +20 -0
- package/dist/modules/companies/schema.d.ts.map +1 -1
- package/dist/modules/companies/schema.js +6 -1
- package/dist/modules/companies/schema.js.map +1 -1
- package/dist/modules/companies/service.d.ts +5 -0
- package/dist/modules/companies/service.d.ts.map +1 -1
- package/dist/modules/companies/service.js +24 -12
- 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 +10 -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/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 +3 -0
- package/dist/modules/eventCatalogs.d.ts.map +1 -1
- package/dist/modules/eventCatalogs.js +3 -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/repository.d.ts +11 -0
- package/dist/modules/lists/repository.d.ts.map +1 -1
- package/dist/modules/lists/repository.js +13 -0
- package/dist/modules/lists/repository.js.map +1 -1
- package/dist/modules/lists/routes.d.ts +4 -0
- package/dist/modules/lists/routes.d.ts.map +1 -1
- package/dist/modules/lists/routes.js +8 -0
- package/dist/modules/lists/routes.js.map +1 -1
- package/dist/modules/lists/schema.d.ts +17 -0
- package/dist/modules/lists/schema.d.ts.map +1 -1
- package/dist/modules/lists/schema.js +10 -0
- package/dist/modules/lists/schema.js.map +1 -1
- package/dist/modules/lists/service.d.ts +14 -2
- package/dist/modules/lists/service.d.ts.map +1 -1
- package/dist/modules/lists/service.js +55 -7
- package/dist/modules/lists/service.js.map +1 -1
- 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.map +1 -1
- package/dist/modules/people/repository.js +5 -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 +115 -38
- 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/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 +21 -0
- package/dist/modules/sample-data/fixture.d.ts.map +1 -1
- package/dist/modules/sample-data/fixture.js +40 -0
- package/dist/modules/sample-data/fixture.js.map +1 -1
- package/dist/modules/sample-data/index.d.ts.map +1 -1
- package/dist/modules/sample-data/index.js +1 -0
- package/dist/modules/sample-data/index.js.map +1 -1
- package/dist/modules/sample-data/routes.d.ts.map +1 -1
- package/dist/modules/sample-data/routes.js +1 -0
- package/dist/modules/sample-data/routes.js.map +1 -1
- package/dist/modules/sample-data/service.d.ts +1 -0
- package/dist/modules/sample-data/service.d.ts.map +1 -1
- package/dist/modules/sample-data/service.js +77 -8
- package/dist/modules/sample-data/service.js.map +1 -1
- 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/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 +10 -0
- 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 +3 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +3 -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/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/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 +91 -0
- package/package.json +2 -2
- package/src/lib/ids.ts +11 -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 +29 -2
- package/src/modules/companies/index.ts +3 -1
- package/src/modules/companies/routes.ts +7 -0
- package/src/modules/companies/schema.ts +7 -1
- package/src/modules/companies/service.ts +48 -13
- 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 +10 -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/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 +3 -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/repository.ts +30 -0
- package/src/modules/lists/routes.ts +8 -0
- package/src/modules/lists/schema.ts +10 -0
- package/src/modules/lists/service.ts +110 -9
- 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 +5 -0
- package/src/modules/people/routes.ts +127 -18
- package/src/modules/people/schema.ts +109 -3
- package/src/modules/people/service.ts +186 -40
- package/src/modules/people/tools.ts +5 -1
- package/src/modules/personLinks.ts +278 -0
- 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 +63 -0
- package/src/modules/sample-data/index.ts +1 -0
- package/src/modules/sample-data/routes.ts +1 -0
- package/src/modules/sample-data/service.ts +97 -8
- 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/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 +14 -0
- package/src/modules/workspace/starters.ts +5 -0
- package/src/runtime/events.ts +1 -0
- package/src/schema/index.ts +3 -0
- package/src/testing/database.ts +97 -11
|
@@ -1,3 +1,5 @@
|
|
|
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'
|
|
@@ -19,11 +21,17 @@ import {
|
|
|
19
21
|
deleteRecordsAttachedTo,
|
|
20
22
|
deleteRecordsAttachedToCandidaciesOf,
|
|
21
23
|
} from '../attachedRecords.ts'
|
|
22
|
-
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'
|
|
23
28
|
import * as repository from './repository.ts'
|
|
24
29
|
import { DEFAULT_PERSON_SORT, PERSON_SORTS } from './repository.ts'
|
|
25
30
|
import type { PersonFilters, PersonRecord } from './repository.ts'
|
|
26
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'
|
|
27
35
|
|
|
28
36
|
/**
|
|
29
37
|
* People: who the workspace knows.
|
|
@@ -41,6 +49,7 @@ export interface PeopleDependencies {
|
|
|
41
49
|
readonly createId: IdFactory
|
|
42
50
|
readonly now: () => Date
|
|
43
51
|
readonly recordActivity: ActivityRecorder
|
|
52
|
+
readonly customFields: CustomFieldValuesValidator
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
/**
|
|
@@ -52,6 +61,10 @@ export interface PeopleDependencies {
|
|
|
52
61
|
*/
|
|
53
62
|
const PERSON_FIELD_LABELS: FieldLabels = {
|
|
54
63
|
name: 'Name',
|
|
64
|
+
salutation: 'Salutation',
|
|
65
|
+
firstName: 'First name',
|
|
66
|
+
lastName: 'Last name',
|
|
67
|
+
suffix: 'Suffix',
|
|
55
68
|
email: 'Email',
|
|
56
69
|
phones: 'Phone numbers',
|
|
57
70
|
socialProfiles: 'Social profiles',
|
|
@@ -63,6 +76,7 @@ const PERSON_FIELD_LABELS: FieldLabels = {
|
|
|
63
76
|
summary: 'Summary',
|
|
64
77
|
tags: 'Tags',
|
|
65
78
|
lastContactedAt: 'Last contacted',
|
|
79
|
+
doNotContact: 'Do not contact',
|
|
66
80
|
}
|
|
67
81
|
|
|
68
82
|
/**
|
|
@@ -71,10 +85,27 @@ const PERSON_FIELD_LABELS: FieldLabels = {
|
|
|
71
85
|
* Deliberately an alias rather than a parallel interface. A hand-written copy of
|
|
72
86
|
* fifteen fields drifts from the table the first time one is added.
|
|
73
87
|
*/
|
|
74
|
-
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
|
+
}
|
|
75
101
|
|
|
76
102
|
export interface CreatePersonInput {
|
|
103
|
+
/** Already resolved. The route composes one from the parts when the caller sent none. */
|
|
77
104
|
readonly name: string
|
|
105
|
+
readonly salutation: string | null
|
|
106
|
+
readonly firstName: string | null
|
|
107
|
+
readonly lastName: string | null
|
|
108
|
+
readonly suffix: string | null
|
|
78
109
|
readonly email: string | null
|
|
79
110
|
readonly phones: readonly string[]
|
|
80
111
|
readonly socialProfiles: readonly SocialProfile[]
|
|
@@ -86,6 +117,15 @@ export interface CreatePersonInput {
|
|
|
86
117
|
readonly summary: string
|
|
87
118
|
readonly tags: readonly string[]
|
|
88
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
|
|
89
129
|
}
|
|
90
130
|
|
|
91
131
|
/** PATCH semantics: an absent field is left alone, and null clears a nullable one. */
|
|
@@ -99,10 +139,10 @@ export interface PeopleService {
|
|
|
99
139
|
remove(actor: Actor, id: string): Promise<void>
|
|
100
140
|
}
|
|
101
141
|
|
|
102
|
-
function toView(record: PersonRecord): PersonView {
|
|
142
|
+
function toView(record: PersonRecord, consents: readonly EffectiveConsent[]): PersonView {
|
|
103
143
|
const { workspaceId: _workspaceId, ...view } = record
|
|
104
144
|
|
|
105
|
-
return view
|
|
145
|
+
return { ...view, consents }
|
|
106
146
|
}
|
|
107
147
|
|
|
108
148
|
/**
|
|
@@ -113,6 +153,10 @@ function toView(record: PersonRecord): PersonView {
|
|
|
113
153
|
function toStoredColumns(input: UpdatePersonInput): Partial<repository.PersonColumns> {
|
|
114
154
|
return {
|
|
115
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 }),
|
|
116
160
|
...(input.email === undefined ? {} : { email: input.email === null ? null : normaliseEmail(input.email) }),
|
|
117
161
|
...(input.phones === undefined ? {} : { phones: input.phones }),
|
|
118
162
|
...(input.socialProfiles === undefined ? {} : { socialProfiles: input.socialProfiles }),
|
|
@@ -124,6 +168,7 @@ function toStoredColumns(input: UpdatePersonInput): Partial<repository.PersonCol
|
|
|
124
168
|
...(input.summary === undefined ? {} : { summary: input.summary }),
|
|
125
169
|
...(input.tags === undefined ? {} : { tags: [...input.tags] }),
|
|
126
170
|
...(input.lastContactedAt === undefined ? {} : { lastContactedAt: input.lastContactedAt }),
|
|
171
|
+
...(input.doNotContact === undefined ? {} : { doNotContact: input.doNotContact }),
|
|
127
172
|
}
|
|
128
173
|
}
|
|
129
174
|
|
|
@@ -151,12 +196,22 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
151
196
|
const workspaceId = requireWorkspaceId(actor)
|
|
152
197
|
const window = readListWindow(query, PERSON_SORTS, DEFAULT_PERSON_SORT)
|
|
153
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
|
+
)
|
|
154
204
|
|
|
155
|
-
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
|
+
)
|
|
156
208
|
},
|
|
157
209
|
|
|
158
210
|
async get(actor, id) {
|
|
159
|
-
|
|
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)
|
|
160
215
|
},
|
|
161
216
|
|
|
162
217
|
async create(actor, input) {
|
|
@@ -165,6 +220,12 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
165
220
|
|
|
166
221
|
return dependencies.transaction(
|
|
167
222
|
async ({ tx, events }) => {
|
|
223
|
+
const customFields = await dependencies.customFields.forCreate(
|
|
224
|
+
tx,
|
|
225
|
+
workspaceId,
|
|
226
|
+
'person',
|
|
227
|
+
input.customFields,
|
|
228
|
+
)
|
|
168
229
|
let created: PersonRecord
|
|
169
230
|
|
|
170
231
|
try {
|
|
@@ -172,6 +233,10 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
172
233
|
id,
|
|
173
234
|
workspaceId,
|
|
174
235
|
name: input.name,
|
|
236
|
+
salutation: input.salutation,
|
|
237
|
+
firstName: input.firstName,
|
|
238
|
+
lastName: input.lastName,
|
|
239
|
+
suffix: input.suffix,
|
|
175
240
|
email: input.email === null ? null : normaliseEmail(input.email),
|
|
176
241
|
phones: input.phones,
|
|
177
242
|
socialProfiles: input.socialProfiles,
|
|
@@ -183,6 +248,8 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
183
248
|
summary: input.summary,
|
|
184
249
|
tags: [...input.tags],
|
|
185
250
|
lastContactedAt: input.lastContactedAt,
|
|
251
|
+
doNotContact: input.doNotContact,
|
|
252
|
+
customFields,
|
|
186
253
|
})
|
|
187
254
|
} catch (error: unknown) {
|
|
188
255
|
if (postgresErrorCode(error) === UNIQUE_VIOLATION) {
|
|
@@ -192,6 +259,16 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
192
259
|
throw error
|
|
193
260
|
}
|
|
194
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
|
+
|
|
195
272
|
await dependencies.recordActivity(tx, workspaceId, actor, {
|
|
196
273
|
targetType: 'person',
|
|
197
274
|
targetId: created.id,
|
|
@@ -210,7 +287,8 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
210
287
|
recordActivity: dependencies.recordActivity,
|
|
211
288
|
})
|
|
212
289
|
|
|
213
|
-
|
|
290
|
+
const consents = await readConsentsFor(tx, workspaceId, created.id)
|
|
291
|
+
return toView(created, consents)
|
|
214
292
|
},
|
|
215
293
|
{ workspaceId, actor: toEventActor(actor) },
|
|
216
294
|
)
|
|
@@ -220,52 +298,100 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
220
298
|
const workspaceId = requireWorkspaceId(actor)
|
|
221
299
|
const existing = await require(workspaceId, id)
|
|
222
300
|
const columns = toStoredColumns(changes)
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
// A PATCH that changes nothing is not a write. Bumping `updated_at` for it
|
|
226
|
-
// would make the record look freshly touched to everything that sorts or
|
|
227
|
-
// filters by it.
|
|
228
|
-
if (changed.length === 0) {
|
|
229
|
-
return toView(existing)
|
|
230
|
-
}
|
|
301
|
+
const scalarChanged = changedKeys(existing, columns)
|
|
302
|
+
const consentWrites = changes.consents ?? []
|
|
231
303
|
|
|
232
304
|
return dependencies.transaction(
|
|
233
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
|
+
|
|
234
340
|
let updated: PersonRecord | undefined
|
|
235
341
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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
|
|
244
355
|
}
|
|
245
356
|
|
|
246
|
-
|
|
357
|
+
if (updated === undefined) {
|
|
358
|
+
throw AppError.notFound('Person not found')
|
|
359
|
+
}
|
|
360
|
+
} else {
|
|
361
|
+
updated = existing
|
|
247
362
|
}
|
|
248
363
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
364
|
+
const customFieldPaths = cf?.changedPaths ?? []
|
|
365
|
+
const activityChanged = [...scalarChanged, ...customFieldPaths, ...consentPaths]
|
|
252
366
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
+
}
|
|
259
385
|
|
|
260
386
|
events.emit(
|
|
261
387
|
'people.person.updated',
|
|
262
388
|
{ type: 'person', id },
|
|
263
|
-
{ changed },
|
|
389
|
+
{ changed: activityChanged },
|
|
264
390
|
)
|
|
265
391
|
|
|
266
392
|
// Sync auto-link when the email moved. Same-transaction rationale as
|
|
267
393
|
// the create path above.
|
|
268
|
-
if (
|
|
394
|
+
if (scalarChanged.includes('email')) {
|
|
269
395
|
await autoLinkPersonByEmailDomain(tx, events, workspaceId, updated, {
|
|
270
396
|
createId: dependencies.createId,
|
|
271
397
|
now: dependencies.now,
|
|
@@ -273,7 +399,8 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
273
399
|
})
|
|
274
400
|
}
|
|
275
401
|
|
|
276
|
-
|
|
402
|
+
const consents = await readConsentsFor(tx, workspaceId, id)
|
|
403
|
+
return toView(updated, consents)
|
|
277
404
|
},
|
|
278
405
|
{ workspaceId, actor: toEventActor(actor) },
|
|
279
406
|
)
|
|
@@ -295,14 +422,33 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
|
|
|
295
422
|
// notes have to be taken here: no hiring service sees that delete.
|
|
296
423
|
await deleteRecordsAttachedToCandidaciesOf(tx, workspaceId, id)
|
|
297
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
|
+
|
|
298
433
|
try {
|
|
299
|
-
await
|
|
434
|
+
await tx.transaction(async (savepoint) => {
|
|
435
|
+
await repository.deletePerson(savepoint, workspaceId, id)
|
|
436
|
+
})
|
|
300
437
|
} catch (error: unknown) {
|
|
301
|
-
|
|
302
|
-
|
|
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')
|
|
303
449
|
}
|
|
304
450
|
|
|
305
|
-
throw
|
|
451
|
+
throw deleteError
|
|
306
452
|
}
|
|
307
453
|
|
|
308
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
|
+
}
|