@kelpie/server 0.8.0 → 0.10.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/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- 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/index.d.ts +38 -0
- package/dist/modules/lists/index.d.ts.map +1 -1
- package/dist/modules/lists/index.js +27 -0
- package/dist/modules/lists/index.js.map +1 -1
- package/dist/modules/lists/repository.d.ts +26 -0
- package/dist/modules/lists/repository.d.ts.map +1 -1
- package/dist/modules/lists/repository.js +32 -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/index.ts +6 -0
- 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/index.ts +71 -0
- package/src/modules/lists/repository.ts +64 -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
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import type { CustomFieldValue, CustomFieldWireValue } from '@kelpie/schemas'
|
|
2
|
+
|
|
3
|
+
import { AppError } from '../../lib/errors.ts'
|
|
4
|
+
import type { ErrorDetail } from '../../lib/errors.ts'
|
|
5
|
+
import type { Queryable } from '../../runtime/transaction.ts'
|
|
6
|
+
import { definitionsForObject } from './repository.ts'
|
|
7
|
+
import type { CustomFieldDefinitionRecord } from './repository.ts'
|
|
8
|
+
import type { CustomFieldObjectType } from './schema.ts'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The service half of custom-field values: definition-aware validation, merge
|
|
12
|
+
* semantics, and the per-key diff a `record.updated` event carries.
|
|
13
|
+
*
|
|
14
|
+
* The Zod layer on the record's route body only checks structure (that a value
|
|
15
|
+
* looks like text/number/boolean/list/money). Everything below reads the
|
|
16
|
+
* workspace's definitions and enforces the concrete type, the select-option
|
|
17
|
+
* membership, and the caps every type carries. Mismatches throw the same
|
|
18
|
+
* `AppError.validationFailed(msg, [{field: 'custom_fields.<key>', message}])`
|
|
19
|
+
* `readJsonBody` produces, so an unknown key and a wrong-type value read alike
|
|
20
|
+
* to a client.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const MAX_TEXT_LENGTH = 4096
|
|
24
|
+
const MAX_LONG_TEXT_LENGTH = 65536
|
|
25
|
+
const MAX_URL_LENGTH = 2048
|
|
26
|
+
const MAX_MULTI_SELECT_ENTRIES = 100
|
|
27
|
+
|
|
28
|
+
/** The stored jsonb value for one custom field, as the record carries it. */
|
|
29
|
+
export type StoredCustomFieldValue = CustomFieldValue
|
|
30
|
+
|
|
31
|
+
/** The result of merging a `PATCH` into the stored `custom_fields` object. */
|
|
32
|
+
export interface CustomFieldsMerge {
|
|
33
|
+
/** The whole custom_fields object to write, with keys sorted for stable diffs. */
|
|
34
|
+
readonly merged: Readonly<Record<string, StoredCustomFieldValue>>
|
|
35
|
+
/** Per-key change paths, `customFields.<key>`, for the `.updated` event's `changed`. */
|
|
36
|
+
readonly changedPaths: readonly string[]
|
|
37
|
+
/** Definition labels for the keys that changed, keyed by their `customFields.<key>` path. */
|
|
38
|
+
readonly labels: Readonly<Record<string, string>>
|
|
39
|
+
/** Flat before-values for `describeUpdate`, keyed by `customFields.<key>`. */
|
|
40
|
+
readonly flatBefore: Readonly<Record<string, StoredCustomFieldValue | undefined>>
|
|
41
|
+
/** Flat after-values for `describeUpdate`, keyed by `customFields.<key>`. */
|
|
42
|
+
readonly flatAfter: Readonly<Record<string, StoredCustomFieldValue | undefined>>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface CustomFieldValuesDependencies {
|
|
46
|
+
readonly db: Queryable
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface CustomFieldValuesValidator {
|
|
50
|
+
/**
|
|
51
|
+
* Validates and normalises the `custom_fields` a record is being created with.
|
|
52
|
+
* `null` keys are ignored. Missing keys are simply absent from the result.
|
|
53
|
+
*/
|
|
54
|
+
forCreate(
|
|
55
|
+
tx: Queryable,
|
|
56
|
+
workspaceId: string,
|
|
57
|
+
objectType: CustomFieldObjectType,
|
|
58
|
+
sent: Readonly<Record<string, CustomFieldWireValue | null>> | undefined,
|
|
59
|
+
): Promise<Readonly<Record<string, StoredCustomFieldValue>>>
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Merges a `PATCH` into the stored `custom_fields`, validating every sent
|
|
63
|
+
* key against the workspace's definitions. `null` clears a key. An unknown
|
|
64
|
+
* key is `422`.
|
|
65
|
+
*/
|
|
66
|
+
forUpdate(
|
|
67
|
+
tx: Queryable,
|
|
68
|
+
workspaceId: string,
|
|
69
|
+
objectType: CustomFieldObjectType,
|
|
70
|
+
stored: Readonly<Record<string, StoredCustomFieldValue>>,
|
|
71
|
+
sent: Readonly<Record<string, CustomFieldWireValue | null>> | undefined,
|
|
72
|
+
): Promise<CustomFieldsMerge | undefined>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function createCustomFieldValues(
|
|
76
|
+
_dependencies: CustomFieldValuesDependencies,
|
|
77
|
+
): CustomFieldValuesValidator {
|
|
78
|
+
return {
|
|
79
|
+
async forCreate(tx, workspaceId, objectType, sent) {
|
|
80
|
+
if (sent === undefined) {
|
|
81
|
+
return {}
|
|
82
|
+
}
|
|
83
|
+
const definitions = await definitionsForObject(tx, workspaceId, objectType)
|
|
84
|
+
const byKey = new Map(definitions.map((definition) => [definition.key, definition]))
|
|
85
|
+
const out: Record<string, StoredCustomFieldValue> = {}
|
|
86
|
+
|
|
87
|
+
for (const [key, value] of Object.entries(sent)) {
|
|
88
|
+
if (value === null) {
|
|
89
|
+
// A create with a `null` value has nothing to store; skip.
|
|
90
|
+
continue
|
|
91
|
+
}
|
|
92
|
+
const definition = byKey.get(key)
|
|
93
|
+
if (definition === undefined) {
|
|
94
|
+
throw unknownKey(key)
|
|
95
|
+
}
|
|
96
|
+
out[key] = validateValue(definition, value)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return normaliseCustomFields(out)
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
async forUpdate(tx, workspaceId, objectType, stored, sent) {
|
|
103
|
+
if (sent === undefined) {
|
|
104
|
+
return undefined
|
|
105
|
+
}
|
|
106
|
+
const definitions = await definitionsForObject(tx, workspaceId, objectType)
|
|
107
|
+
const byKey = new Map(definitions.map((definition) => [definition.key, definition]))
|
|
108
|
+
const next: Record<string, StoredCustomFieldValue> = { ...stored }
|
|
109
|
+
const changedPaths: string[] = []
|
|
110
|
+
const labels: Record<string, string> = {}
|
|
111
|
+
const flatBefore: Record<string, StoredCustomFieldValue | undefined> = {}
|
|
112
|
+
const flatAfter: Record<string, StoredCustomFieldValue | undefined> = {}
|
|
113
|
+
|
|
114
|
+
for (const [key, value] of Object.entries(sent)) {
|
|
115
|
+
const definition = byKey.get(key)
|
|
116
|
+
if (definition === undefined) {
|
|
117
|
+
throw unknownKey(key)
|
|
118
|
+
}
|
|
119
|
+
const path = `customFields.${key}`
|
|
120
|
+
const before = stored[key]
|
|
121
|
+
|
|
122
|
+
if (value === null) {
|
|
123
|
+
if (before === undefined) {
|
|
124
|
+
continue
|
|
125
|
+
}
|
|
126
|
+
delete next[key]
|
|
127
|
+
changedPaths.push(path)
|
|
128
|
+
labels[path] = definition.label
|
|
129
|
+
flatBefore[path] = before
|
|
130
|
+
flatAfter[path] = undefined
|
|
131
|
+
continue
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const validated = validateValue(definition, value)
|
|
135
|
+
if (!sameValue(before, validated)) {
|
|
136
|
+
next[key] = validated
|
|
137
|
+
changedPaths.push(path)
|
|
138
|
+
labels[path] = definition.label
|
|
139
|
+
flatBefore[path] = before
|
|
140
|
+
flatAfter[path] = validated
|
|
141
|
+
} else {
|
|
142
|
+
// Sent again with the identical value: no change, no path, but keep
|
|
143
|
+
// the value in `next` (a shallow copy already did that).
|
|
144
|
+
next[key] = validated
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
merged: normaliseCustomFields(next),
|
|
150
|
+
changedPaths,
|
|
151
|
+
labels,
|
|
152
|
+
flatBefore,
|
|
153
|
+
flatAfter,
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Rebuilds the object with keys in sorted order.
|
|
161
|
+
*
|
|
162
|
+
* `changedKeys` in `lib/changes.ts` compares by `JSON.stringify`, so two
|
|
163
|
+
* objects with the same entries but different insertion order would look
|
|
164
|
+
* different. Every stored write and every diffed comparison passes through
|
|
165
|
+
* this so the two agree.
|
|
166
|
+
*/
|
|
167
|
+
export function normaliseCustomFields(
|
|
168
|
+
values: Readonly<Record<string, StoredCustomFieldValue>>,
|
|
169
|
+
): Readonly<Record<string, StoredCustomFieldValue>> {
|
|
170
|
+
const sorted: Record<string, StoredCustomFieldValue> = {}
|
|
171
|
+
for (const key of Object.keys(values).sort()) {
|
|
172
|
+
sorted[key] = values[key] as StoredCustomFieldValue
|
|
173
|
+
}
|
|
174
|
+
return sorted
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function unknownKey(key: string): AppError {
|
|
178
|
+
return AppError.validationFailed('That custom field is not defined for this record type', [
|
|
179
|
+
{ field: `custom_fields.${key}`, message: 'Unknown field' },
|
|
180
|
+
])
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function typeError(key: string, message: string): AppError {
|
|
184
|
+
return AppError.validationFailed('That value does not match the custom field', [
|
|
185
|
+
{ field: `custom_fields.${key}`, message },
|
|
186
|
+
])
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function validateValue(
|
|
190
|
+
definition: CustomFieldDefinitionRecord,
|
|
191
|
+
value: CustomFieldWireValue,
|
|
192
|
+
): StoredCustomFieldValue {
|
|
193
|
+
switch (definition.type) {
|
|
194
|
+
case 'text':
|
|
195
|
+
return validateString(definition.key, value, MAX_TEXT_LENGTH)
|
|
196
|
+
|
|
197
|
+
case 'long_text':
|
|
198
|
+
return validateString(definition.key, value, MAX_LONG_TEXT_LENGTH)
|
|
199
|
+
|
|
200
|
+
case 'url':
|
|
201
|
+
return validateUrl(definition.key, value)
|
|
202
|
+
|
|
203
|
+
case 'date':
|
|
204
|
+
return validateDate(definition.key, value)
|
|
205
|
+
|
|
206
|
+
case 'number':
|
|
207
|
+
return validateNumber(definition.key, value)
|
|
208
|
+
|
|
209
|
+
case 'checkbox':
|
|
210
|
+
if (typeof value !== 'boolean') {
|
|
211
|
+
throw typeError(definition.key, 'Expected true or false')
|
|
212
|
+
}
|
|
213
|
+
return value
|
|
214
|
+
|
|
215
|
+
case 'select':
|
|
216
|
+
return validateSelect(definition, value)
|
|
217
|
+
|
|
218
|
+
case 'multi_select':
|
|
219
|
+
return validateMultiSelect(definition, value)
|
|
220
|
+
|
|
221
|
+
case 'currency':
|
|
222
|
+
return validateCurrency(definition.key, value)
|
|
223
|
+
|
|
224
|
+
default:
|
|
225
|
+
throw new Error(`custom-field type "${definition.type}" has no validator`)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function validateString(key: string, value: CustomFieldWireValue, max: number): string {
|
|
230
|
+
if (typeof value !== 'string') {
|
|
231
|
+
throw typeError(key, 'Expected a string')
|
|
232
|
+
}
|
|
233
|
+
if (value.length > max) {
|
|
234
|
+
throw typeError(key, `At most ${String(max)} characters`)
|
|
235
|
+
}
|
|
236
|
+
return value
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function validateUrl(key: string, value: CustomFieldWireValue): string {
|
|
240
|
+
const raw = validateString(key, value, MAX_URL_LENGTH)
|
|
241
|
+
let parsed: URL
|
|
242
|
+
try {
|
|
243
|
+
parsed = new URL(raw)
|
|
244
|
+
} catch {
|
|
245
|
+
throw typeError(key, 'Expected an http or https URL')
|
|
246
|
+
}
|
|
247
|
+
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
248
|
+
throw typeError(key, 'Expected an http or https URL')
|
|
249
|
+
}
|
|
250
|
+
return raw
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/u
|
|
254
|
+
|
|
255
|
+
function validateDate(key: string, value: CustomFieldWireValue): string {
|
|
256
|
+
if (typeof value !== 'string' || !DATE_PATTERN.test(value)) {
|
|
257
|
+
throw typeError(key, 'Expected a YYYY-MM-DD date')
|
|
258
|
+
}
|
|
259
|
+
const [year, month, day] = value.split('-').map((part) => Number(part))
|
|
260
|
+
const parsed = new Date(Date.UTC(year!, (month ?? 1) - 1, day ?? 1))
|
|
261
|
+
if (
|
|
262
|
+
parsed.getUTCFullYear() !== year ||
|
|
263
|
+
parsed.getUTCMonth() !== (month ?? 1) - 1 ||
|
|
264
|
+
parsed.getUTCDate() !== (day ?? 1)
|
|
265
|
+
) {
|
|
266
|
+
throw typeError(key, 'That date does not exist')
|
|
267
|
+
}
|
|
268
|
+
return value
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function validateNumber(key: string, value: CustomFieldWireValue): number {
|
|
272
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
273
|
+
throw typeError(key, 'Expected a finite number')
|
|
274
|
+
}
|
|
275
|
+
if (Math.abs(value) > Number.MAX_SAFE_INTEGER) {
|
|
276
|
+
throw typeError(key, 'Number is out of range')
|
|
277
|
+
}
|
|
278
|
+
return value
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function validateSelect(
|
|
282
|
+
definition: CustomFieldDefinitionRecord,
|
|
283
|
+
value: CustomFieldWireValue,
|
|
284
|
+
): string {
|
|
285
|
+
if (typeof value !== 'string') {
|
|
286
|
+
throw typeError(definition.key, 'Expected a string')
|
|
287
|
+
}
|
|
288
|
+
if (!definition.options.includes(value)) {
|
|
289
|
+
throw typeError(definition.key, `Not one of the field's options`)
|
|
290
|
+
}
|
|
291
|
+
return value
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function validateMultiSelect(
|
|
295
|
+
definition: CustomFieldDefinitionRecord,
|
|
296
|
+
value: CustomFieldWireValue,
|
|
297
|
+
): readonly string[] {
|
|
298
|
+
if (!Array.isArray(value)) {
|
|
299
|
+
throw typeError(definition.key, 'Expected a list of option keys')
|
|
300
|
+
}
|
|
301
|
+
if (value.length > MAX_MULTI_SELECT_ENTRIES) {
|
|
302
|
+
throw typeError(definition.key, `At most ${String(MAX_MULTI_SELECT_ENTRIES)} entries`)
|
|
303
|
+
}
|
|
304
|
+
const seen = new Set<string>()
|
|
305
|
+
for (const entry of value) {
|
|
306
|
+
if (typeof entry !== 'string') {
|
|
307
|
+
throw typeError(definition.key, 'Each entry must be a string')
|
|
308
|
+
}
|
|
309
|
+
if (!definition.options.includes(entry)) {
|
|
310
|
+
throw typeError(definition.key, `"${entry}" is not one of the field's options`)
|
|
311
|
+
}
|
|
312
|
+
if (seen.has(entry)) {
|
|
313
|
+
throw typeError(definition.key, `"${entry}" appears more than once`)
|
|
314
|
+
}
|
|
315
|
+
seen.add(entry)
|
|
316
|
+
}
|
|
317
|
+
// A stored multi_select is a plain array; sort for stable JSON comparison.
|
|
318
|
+
return [...value].sort()
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function validateCurrency(
|
|
322
|
+
key: string,
|
|
323
|
+
value: CustomFieldWireValue,
|
|
324
|
+
): { readonly amountCents: number; readonly currency: string } {
|
|
325
|
+
if (
|
|
326
|
+
typeof value !== 'object' ||
|
|
327
|
+
value === null ||
|
|
328
|
+
Array.isArray(value) ||
|
|
329
|
+
!('amount_cents' in value) ||
|
|
330
|
+
!('currency' in value)
|
|
331
|
+
) {
|
|
332
|
+
throw typeError(key, 'Expected { amount_cents, currency }')
|
|
333
|
+
}
|
|
334
|
+
const cents = value.amount_cents
|
|
335
|
+
if (typeof cents !== 'number' || !Number.isInteger(cents)) {
|
|
336
|
+
throw typeError(key, 'amount_cents must be a whole number of cents')
|
|
337
|
+
}
|
|
338
|
+
const currency = value.currency
|
|
339
|
+
if (typeof currency !== 'string' || !/^[A-Z]{3}$/u.test(currency)) {
|
|
340
|
+
throw typeError(key, 'currency must be a 3-letter uppercase code')
|
|
341
|
+
}
|
|
342
|
+
return { amountCents: cents, currency }
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function sameValue(before: unknown, after: unknown): boolean {
|
|
346
|
+
return JSON.stringify(before) === JSON.stringify(after)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** Collects one detail-list from several field-level rejections. Unused today; kept for future bulk validators. */
|
|
350
|
+
export function collectDetails(errors: readonly AppError[]): readonly ErrorDetail[] {
|
|
351
|
+
return errors.flatMap((error) => error.details ?? [])
|
|
352
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders the stored `custom_fields` for a record's wire body.
|
|
3
|
+
*
|
|
4
|
+
* Every value type serialises as itself with one exception: currency lives in
|
|
5
|
+
* the store as `{amountCents, currency}` (camelCase, from
|
|
6
|
+
* `customFieldValuesSchema`'s transform) and goes back over the wire as
|
|
7
|
+
* `{amount_cents, currency}` per the api.md snake_case rule. Every record
|
|
8
|
+
* module's response mapper calls this from one place so the two shapes cannot
|
|
9
|
+
* drift.
|
|
10
|
+
*/
|
|
11
|
+
export function renderCustomFieldsForWire(
|
|
12
|
+
values: Readonly<Record<string, unknown>>,
|
|
13
|
+
): Record<string, unknown> {
|
|
14
|
+
const out: Record<string, unknown> = {}
|
|
15
|
+
for (const [key, value] of Object.entries(values)) {
|
|
16
|
+
if (
|
|
17
|
+
typeof value === 'object' &&
|
|
18
|
+
value !== null &&
|
|
19
|
+
!Array.isArray(value) &&
|
|
20
|
+
'amountCents' in value &&
|
|
21
|
+
'currency' in value
|
|
22
|
+
) {
|
|
23
|
+
out[key] = {
|
|
24
|
+
amount_cents: (value as { amountCents: number }).amountCents,
|
|
25
|
+
currency: (value as { currency: string }).currency,
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
out[key] = value
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return out
|
|
32
|
+
}
|
|
@@ -8,6 +8,7 @@ import type { Queryable } from '../../runtime/transaction.ts'
|
|
|
8
8
|
import { activities } from '../activities/schema.ts'
|
|
9
9
|
import { decisions } from '../decisions/schema.ts'
|
|
10
10
|
import { deals } from '../deals/schema.ts'
|
|
11
|
+
import { enquiries } from '../enquiries/schema.ts'
|
|
11
12
|
import { notes } from '../notes/schema.ts'
|
|
12
13
|
import { opportunities } from '../opportunities/schema.ts'
|
|
13
14
|
import { partnerships } from '../partnerships/schema.ts'
|
|
@@ -88,11 +89,11 @@ function pipelineTable(table: PgTable, workspaceId: PgColumn, stageId: PgColumn)
|
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
/**
|
|
91
|
-
* Which table each pipeline kind lives in.
|
|
92
|
-
*
|
|
93
|
-
* are configured the same way.
|
|
92
|
+
* Which table each pipeline kind lives in. `pipeline_stages.kind` carries all
|
|
93
|
+
* five, and every pipeline's board columns are configured the same way.
|
|
94
94
|
*/
|
|
95
95
|
const PIPELINE_TABLES: Readonly<Record<PipelineKind, PipelineTable>> = {
|
|
96
|
+
enquiry: pipelineTable(enquiries, enquiries.workspaceId, enquiries.stageId),
|
|
96
97
|
deal: pipelineTable(deals, deals.workspaceId, deals.stageId),
|
|
97
98
|
opportunity: pipelineTable(opportunities, opportunities.workspaceId, opportunities.stageId),
|
|
98
99
|
raise: pipelineTable(raises, raises.workspaceId, raises.stageId),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { KelpieModule } from '../../runtime/module.ts'
|
|
2
2
|
import { createActivityRecorder } from '../activities/index.ts'
|
|
3
|
+
import { createCustomFieldValues } from '../custom-fields/index.ts'
|
|
3
4
|
import { dealsEvents } from './events.ts'
|
|
4
5
|
import { mountDealsRoutes } from './routes.ts'
|
|
5
6
|
import * as schema from './schema.ts'
|
|
@@ -12,12 +13,13 @@ import { registerDealsTools } from './tools.ts'
|
|
|
12
13
|
* Requires its relations because creating one checks that the company, stage,
|
|
13
14
|
* owner, and people are all in the caller's workspace before linking them, and
|
|
14
15
|
* `activities` because every write leaves its timeline entry in the same
|
|
15
|
-
* transaction.
|
|
16
|
+
* transaction. Also requires `custom-fields` so the validator is present when
|
|
17
|
+
* this service constructs.
|
|
16
18
|
*/
|
|
17
19
|
export function createDealsModule(migrationsDirectory: string): KelpieModule {
|
|
18
20
|
return {
|
|
19
21
|
id: 'deals',
|
|
20
|
-
requires: ['companies', 'people', 'pipelines', 'activities'],
|
|
22
|
+
requires: ['companies', 'people', 'pipelines', 'activities', 'custom-fields'],
|
|
21
23
|
events: dealsEvents,
|
|
22
24
|
|
|
23
25
|
register(context) {
|
|
@@ -30,6 +32,7 @@ export function createDealsModule(migrationsDirectory: string): KelpieModule {
|
|
|
30
32
|
createId: context.createId,
|
|
31
33
|
now: context.now,
|
|
32
34
|
}),
|
|
35
|
+
customFields: createCustomFieldValues({ db: context.db }),
|
|
33
36
|
})
|
|
34
37
|
|
|
35
38
|
context.schema(schema, migrationsDirectory)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { and,
|
|
1
|
+
import { and, eq, ilike, inArray, or, sql } from 'drizzle-orm'
|
|
2
2
|
import type { SQL } from 'drizzle-orm'
|
|
3
3
|
|
|
4
4
|
import { keysetCondition, orderByWindow, textSort, timestampSort } from '../../lib/pagination.ts'
|
|
@@ -6,9 +6,9 @@ import type { ListWindow, SortableFields } from '../../lib/pagination.ts'
|
|
|
6
6
|
import { arrayContainsPattern, containsPattern } from '../../lib/search.ts'
|
|
7
7
|
import type { Queryable } from '../../runtime/transaction.ts'
|
|
8
8
|
import { companies } from '../companies/schema.ts'
|
|
9
|
-
import {
|
|
9
|
+
import { anyPersonLinked } from '../personLinks.ts'
|
|
10
10
|
import { workspaceMembers } from '../workspace/schema.ts'
|
|
11
|
-
import {
|
|
11
|
+
import { deals } from './schema.ts'
|
|
12
12
|
|
|
13
13
|
export type DealRecord = typeof deals.$inferSelect
|
|
14
14
|
|
|
@@ -49,15 +49,6 @@ function companyNameMatches(pattern: string): SQL {
|
|
|
49
49
|
)`
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function hasAnyOfPeople(personIds: readonly string[]): SQL {
|
|
53
|
-
return sql`exists (
|
|
54
|
-
select 1
|
|
55
|
-
from ${dealPeople}
|
|
56
|
-
where ${dealPeople.dealId} = ${deals.id}
|
|
57
|
-
and ${inArray(dealPeople.personId, personIds)}
|
|
58
|
-
)`
|
|
59
|
-
}
|
|
60
|
-
|
|
61
52
|
function matchesTerm(term: string): SQL | undefined {
|
|
62
53
|
const pattern = containsPattern(term)
|
|
63
54
|
|
|
@@ -76,7 +67,9 @@ function conditionsFor(workspaceId: string, filters: DealFilters): (SQL | undefi
|
|
|
76
67
|
filters.term === undefined ? undefined : matchesTerm(filters.term),
|
|
77
68
|
filters.companyIds === undefined ? undefined : inArray(deals.companyId, filters.companyIds),
|
|
78
69
|
filters.stageIds === undefined ? undefined : inArray(deals.stageId, filters.stageIds),
|
|
79
|
-
filters.personIds === undefined
|
|
70
|
+
filters.personIds === undefined
|
|
71
|
+
? undefined
|
|
72
|
+
: anyPersonLinked('deal', deals.id, deals.workspaceId, filters.personIds),
|
|
80
73
|
]
|
|
81
74
|
}
|
|
82
75
|
|
|
@@ -143,99 +136,6 @@ export async function deleteDeal(db: Queryable, workspaceId: string, id: string)
|
|
|
143
136
|
return deleted.length
|
|
144
137
|
}
|
|
145
138
|
|
|
146
|
-
/** The people on one deal. Ordered by id so a response is stable across reads. */
|
|
147
|
-
export async function listPersonIds(db: Queryable, dealId: string): Promise<string[]> {
|
|
148
|
-
const rows = await db
|
|
149
|
-
.select({ personId: dealPeople.personId })
|
|
150
|
-
.from(dealPeople)
|
|
151
|
-
.where(eq(dealPeople.dealId, dealId))
|
|
152
|
-
.orderBy(asc(dealPeople.personId))
|
|
153
|
-
|
|
154
|
-
return rows.map((row) => row.personId)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* The people on each of a page of deals, in one query rather than one per row.
|
|
159
|
-
*
|
|
160
|
-
* @returns Ids missing from the map have no people.
|
|
161
|
-
*/
|
|
162
|
-
export async function listPersonIdsFor(
|
|
163
|
-
db: Queryable,
|
|
164
|
-
dealIds: readonly string[],
|
|
165
|
-
): Promise<ReadonlyMap<string, readonly string[]>> {
|
|
166
|
-
if (dealIds.length === 0) {
|
|
167
|
-
return new Map()
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const rows = await db
|
|
171
|
-
.select({ dealId: dealPeople.dealId, personId: dealPeople.personId })
|
|
172
|
-
.from(dealPeople)
|
|
173
|
-
.where(inArray(dealPeople.dealId, dealIds))
|
|
174
|
-
.orderBy(asc(dealPeople.personId))
|
|
175
|
-
|
|
176
|
-
const byDeal = new Map<string, string[]>()
|
|
177
|
-
|
|
178
|
-
for (const row of rows) {
|
|
179
|
-
const existing = byDeal.get(row.dealId)
|
|
180
|
-
|
|
181
|
-
if (existing === undefined) {
|
|
182
|
-
byDeal.set(row.dealId, [row.personId])
|
|
183
|
-
} else {
|
|
184
|
-
existing.push(row.personId)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return byDeal
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
export async function insertDealPeople(
|
|
192
|
-
db: Queryable,
|
|
193
|
-
dealId: string,
|
|
194
|
-
personIds: readonly string[],
|
|
195
|
-
): Promise<void> {
|
|
196
|
-
if (personIds.length === 0) {
|
|
197
|
-
return
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
await db.insert(dealPeople).values(personIds.map((personId) => ({ dealId, personId })))
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
export async function deleteDealPeople(
|
|
204
|
-
db: Queryable,
|
|
205
|
-
dealId: string,
|
|
206
|
-
personIds: readonly string[],
|
|
207
|
-
): Promise<void> {
|
|
208
|
-
if (personIds.length === 0) {
|
|
209
|
-
return
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
await db
|
|
213
|
-
.delete(dealPeople)
|
|
214
|
-
.where(and(eq(dealPeople.dealId, dealId), inArray(dealPeople.personId, personIds)))
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* The names of these people in this workspace, keyed by id. An id missing from
|
|
219
|
-
* the map does not exist here, which is how `person_ids` is validated. Reads the
|
|
220
|
-
* `people` *table*, per the cross-relation rule in `architecture.md`.
|
|
221
|
-
*/
|
|
222
|
-
export async function findPeopleNamed(
|
|
223
|
-
db: Queryable,
|
|
224
|
-
workspaceId: string,
|
|
225
|
-
personIds: readonly string[],
|
|
226
|
-
): Promise<ReadonlyMap<string, string>> {
|
|
227
|
-
if (personIds.length === 0) {
|
|
228
|
-
return new Map()
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const rows = await db
|
|
232
|
-
.select({ id: people.id, name: people.name })
|
|
233
|
-
.from(people)
|
|
234
|
-
.where(and(eq(people.workspaceId, workspaceId), inArray(people.id, personIds)))
|
|
235
|
-
|
|
236
|
-
return new Map(rows.map((row) => [row.id, row.name]))
|
|
237
|
-
}
|
|
238
|
-
|
|
239
139
|
/** Whether a member belongs to this workspace, for validating `owner_id`. */
|
|
240
140
|
export async function memberExists(
|
|
241
141
|
db: Queryable,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { customFieldsPatchShape } from '@kelpie/schemas'
|
|
1
2
|
import type { Context, Hono } from 'hono'
|
|
2
3
|
import { z } from 'zod'
|
|
3
4
|
|
|
@@ -6,6 +7,7 @@ import { pageBody, readIdFilter, readJsonBody, readListParameters } from '../../
|
|
|
6
7
|
import type { Actor } from '../auth/actor.ts'
|
|
7
8
|
import { resolveActorFrom } from '../auth/credentials.ts'
|
|
8
9
|
import type { CredentialDependencies } from '../auth/credentials.ts'
|
|
10
|
+
import { renderCustomFieldsForWire } from '../custom-fields/wire.ts'
|
|
9
11
|
import type { CreateDealInput, DealView, DealsService, UpdateDealInput } from './service.ts'
|
|
10
12
|
|
|
11
13
|
/** Wire shapes for `/v1/deals`. Bodies are strict; an unknown field is a 422, per `api.md`. */
|
|
@@ -26,6 +28,7 @@ const dealShape = {
|
|
|
26
28
|
summary: z.string(),
|
|
27
29
|
tags: z.array(z.string().min(1)),
|
|
28
30
|
external_id: z.string().min(1).nullable(),
|
|
31
|
+
custom_fields: customFieldsPatchShape,
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
/**
|
|
@@ -48,6 +51,7 @@ export const createBody = z.strictObject({
|
|
|
48
51
|
summary: dealShape.summary.default(''),
|
|
49
52
|
tags: dealShape.tags.default([]),
|
|
50
53
|
external_id: dealShape.external_id.default(null),
|
|
54
|
+
custom_fields: dealShape.custom_fields.default({}),
|
|
51
55
|
})
|
|
52
56
|
|
|
53
57
|
export const updateBody = z.strictObject(dealShape).partial()
|
|
@@ -72,6 +76,7 @@ export function toCreateInput(body: z.infer<typeof createBody>): CreateDealInput
|
|
|
72
76
|
summary: body.summary,
|
|
73
77
|
tags: body.tags,
|
|
74
78
|
externalId: body.external_id,
|
|
79
|
+
customFields: body.custom_fields,
|
|
75
80
|
}
|
|
76
81
|
}
|
|
77
82
|
|
|
@@ -91,6 +96,7 @@ export function toUpdateInput(body: z.infer<typeof updateBody>): UpdateDealInput
|
|
|
91
96
|
...(body.summary === undefined ? {} : { summary: body.summary }),
|
|
92
97
|
...(body.tags === undefined ? {} : { tags: body.tags }),
|
|
93
98
|
...(body.external_id === undefined ? {} : { externalId: body.external_id }),
|
|
99
|
+
...(body.custom_fields === undefined ? {} : { customFields: body.custom_fields }),
|
|
94
100
|
}
|
|
95
101
|
}
|
|
96
102
|
|
|
@@ -111,6 +117,7 @@ export function dealResponse(deal: DealView): Record<string, unknown> {
|
|
|
111
117
|
summary: deal.summary,
|
|
112
118
|
tags: deal.tags,
|
|
113
119
|
external_id: deal.externalId,
|
|
120
|
+
custom_fields: renderCustomFieldsForWire(deal.customFields),
|
|
114
121
|
created_at: deal.createdAt.toISOString(),
|
|
115
122
|
updated_at: deal.updatedAt.toISOString(),
|
|
116
123
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { CustomFieldValue } from '@kelpie/schemas'
|
|
2
|
+
import { bigint, date, index, jsonb, pgTable, text } from 'drizzle-orm/pg-core'
|
|
2
3
|
|
|
3
4
|
import { createdAt, primaryId, searchVector, updatedAt } from '../../lib/columns.ts'
|
|
4
5
|
import type { SearchVectorPart } from '../../lib/columns.ts'
|
|
5
6
|
import { companies } from '../companies/schema.ts'
|
|
6
|
-
import { people } from '../people/schema.ts'
|
|
7
7
|
import { pipelineStages } from '../pipelines/schema.ts'
|
|
8
8
|
import { workspaceMembers, workspaces } from '../workspace/schema.ts'
|
|
9
9
|
|
|
@@ -38,6 +38,11 @@ export const deals = pgTable(
|
|
|
38
38
|
summary: text('summary').notNull().default(''),
|
|
39
39
|
tags: text('tags').array().notNull().default([]),
|
|
40
40
|
externalId: text('external_id'),
|
|
41
|
+
// Workspace-defined fields, keyed by definition key. See people/schema.ts.
|
|
42
|
+
customFields: jsonb('custom_fields')
|
|
43
|
+
.$type<Readonly<Record<string, CustomFieldValue>>>()
|
|
44
|
+
.notNull()
|
|
45
|
+
.default({}),
|
|
41
46
|
createdAt: createdAt(),
|
|
42
47
|
updatedAt: updatedAt(),
|
|
43
48
|
searchVector: searchVector((): readonly SearchVectorPart[] => [
|
|
@@ -57,16 +62,3 @@ export const deals = pgTable(
|
|
|
57
62
|
],
|
|
58
63
|
)
|
|
59
64
|
|
|
60
|
-
/** People attached to a deal. Restrict on person: a deal contact cannot vanish. */
|
|
61
|
-
export const dealPeople = pgTable(
|
|
62
|
-
'deal_people',
|
|
63
|
-
{
|
|
64
|
-
dealId: text('deal_id')
|
|
65
|
-
.notNull()
|
|
66
|
-
.references(() => deals.id, { onDelete: 'cascade' }),
|
|
67
|
-
personId: text('person_id')
|
|
68
|
-
.notNull()
|
|
69
|
-
.references(() => people.id, { onDelete: 'restrict' }),
|
|
70
|
-
},
|
|
71
|
-
(table) => [primaryKey({ columns: [table.dealId, table.personId] })],
|
|
72
|
-
)
|