@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
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FormAttachTarget,
|
|
3
|
+
FormSubmissionLinkTarget,
|
|
4
|
+
PipelineKind,
|
|
5
|
+
} from '@kelpie/schemas'
|
|
6
|
+
import { PIPELINE_KINDS } from '@kelpie/schemas'
|
|
7
|
+
|
|
1
8
|
import { changedKeys } from '../../lib/changes.ts'
|
|
2
9
|
import type { Database } from '../../lib/database.ts'
|
|
3
10
|
import { AppError } from '../../lib/errors.ts'
|
|
@@ -10,7 +17,10 @@ import { toEventActor } from '../../lib/actor.ts'
|
|
|
10
17
|
import type { Actor } from '../auth/actor.ts'
|
|
11
18
|
import { requireWorkspaceId } from '../auth/actor.ts'
|
|
12
19
|
import './events.ts'
|
|
20
|
+
import * as consentPurposesRepository from '../consent-purposes/repository.ts'
|
|
21
|
+
import * as listsRepository from '../lists/repository.ts'
|
|
13
22
|
import * as pipelineRepository from '../pipelines/repository.ts'
|
|
23
|
+
import { missingTargets } from '../recordTargets.ts'
|
|
14
24
|
import { fieldsDiffer, findFieldProblems, storedOptions } from './fields.ts'
|
|
15
25
|
import type { FieldDraft, FieldShape } from './fields.ts'
|
|
16
26
|
import * as repository from './repository.ts'
|
|
@@ -46,9 +56,17 @@ export interface FormsDependencies {
|
|
|
46
56
|
readonly generatePublicKey?: () => string
|
|
47
57
|
}
|
|
48
58
|
|
|
49
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* A form as the API returns one: the stored row minus tenancy, with its
|
|
61
|
+
* fields, its list memberships, and its attach targets. `list_ids` and
|
|
62
|
+
* `attach_targets` are not columns of `forms` — they live in the joined
|
|
63
|
+
* `form_lists` / `form_attach_targets` tables — but they cross the wire
|
|
64
|
+
* nested under the form to keep write and read shapes symmetric.
|
|
65
|
+
*/
|
|
50
66
|
export type FormView = Omit<FormRecord, 'workspaceId'> & {
|
|
51
67
|
readonly fields: readonly FormFieldView[]
|
|
68
|
+
readonly listIds: readonly string[]
|
|
69
|
+
readonly attachTargets: readonly FormAttachTarget[]
|
|
52
70
|
}
|
|
53
71
|
|
|
54
72
|
export type FormFieldView = Omit<FormFieldRecord, 'workspaceId' | 'formId'>
|
|
@@ -57,6 +75,7 @@ export type FormSubmissionView = Omit<FormSubmissionRecord, 'workspaceId'>
|
|
|
57
75
|
|
|
58
76
|
export interface CreateFormInput {
|
|
59
77
|
readonly name: string
|
|
78
|
+
readonly title: string
|
|
60
79
|
readonly description: string | null
|
|
61
80
|
readonly status: FormStatus
|
|
62
81
|
readonly fields: readonly FieldDraft[]
|
|
@@ -64,11 +83,31 @@ export interface CreateFormInput {
|
|
|
64
83
|
readonly createDeal: boolean
|
|
65
84
|
readonly dealStageId: string | null
|
|
66
85
|
readonly dealNameTemplate: string | null
|
|
86
|
+
readonly createOpportunity: boolean
|
|
87
|
+
readonly opportunityKind: string | null
|
|
88
|
+
readonly opportunityStageId: string | null
|
|
89
|
+
readonly opportunityNameTemplate: string | null
|
|
90
|
+
readonly opportunityOwnerId: string | null
|
|
91
|
+
readonly createPartnership: boolean
|
|
92
|
+
readonly partnershipKind: string | null
|
|
93
|
+
readonly partnershipStageId: string | null
|
|
94
|
+
readonly partnershipNameTemplate: string | null
|
|
95
|
+
readonly partnershipOwnerId: string | null
|
|
96
|
+
readonly createEnquiry: boolean
|
|
97
|
+
readonly enquirySource: string | null
|
|
98
|
+
readonly enquiryStageId: string | null
|
|
99
|
+
readonly enquiryNameTemplate: string | null
|
|
100
|
+
readonly enquiryOwnerId: string | null
|
|
101
|
+
readonly personTags: readonly string[]
|
|
102
|
+
readonly companyTags: readonly string[]
|
|
103
|
+
readonly listIds: readonly string[]
|
|
104
|
+
readonly attachTargets: readonly FormAttachTarget[]
|
|
67
105
|
}
|
|
68
106
|
|
|
69
107
|
/** PATCH semantics: an absent field is left alone, and null clears a nullable one. */
|
|
70
108
|
export interface UpdateFormInput {
|
|
71
109
|
readonly name?: string | undefined
|
|
110
|
+
readonly title?: string | undefined
|
|
72
111
|
readonly description?: string | null | undefined
|
|
73
112
|
readonly status?: FormStatus | undefined
|
|
74
113
|
/** Absent leaves the field list alone. Present replaces all of it. */
|
|
@@ -77,6 +116,27 @@ export interface UpdateFormInput {
|
|
|
77
116
|
readonly createDeal?: boolean | undefined
|
|
78
117
|
readonly dealStageId?: string | null | undefined
|
|
79
118
|
readonly dealNameTemplate?: string | null | undefined
|
|
119
|
+
readonly createOpportunity?: boolean | undefined
|
|
120
|
+
readonly opportunityKind?: string | null | undefined
|
|
121
|
+
readonly opportunityStageId?: string | null | undefined
|
|
122
|
+
readonly opportunityNameTemplate?: string | null | undefined
|
|
123
|
+
readonly opportunityOwnerId?: string | null | undefined
|
|
124
|
+
readonly createPartnership?: boolean | undefined
|
|
125
|
+
readonly partnershipKind?: string | null | undefined
|
|
126
|
+
readonly partnershipStageId?: string | null | undefined
|
|
127
|
+
readonly partnershipNameTemplate?: string | null | undefined
|
|
128
|
+
readonly partnershipOwnerId?: string | null | undefined
|
|
129
|
+
readonly createEnquiry?: boolean | undefined
|
|
130
|
+
readonly enquirySource?: string | null | undefined
|
|
131
|
+
readonly enquiryStageId?: string | null | undefined
|
|
132
|
+
readonly enquiryNameTemplate?: string | null | undefined
|
|
133
|
+
readonly enquiryOwnerId?: string | null | undefined
|
|
134
|
+
readonly personTags?: readonly string[] | undefined
|
|
135
|
+
readonly companyTags?: readonly string[] | undefined
|
|
136
|
+
/** Absent leaves list memberships alone. Present replaces the whole set. */
|
|
137
|
+
readonly listIds?: readonly string[] | undefined
|
|
138
|
+
/** Absent leaves attach targets alone. Present replaces the whole set. */
|
|
139
|
+
readonly attachTargets?: readonly FormAttachTarget[] | undefined
|
|
80
140
|
}
|
|
81
141
|
|
|
82
142
|
export interface FormsService {
|
|
@@ -90,6 +150,13 @@ export interface FormsService {
|
|
|
90
150
|
formId: string,
|
|
91
151
|
query: ListQueryParameters,
|
|
92
152
|
): Promise<Page<FormSubmissionView>>
|
|
153
|
+
listSubmissionsLinkedTo(
|
|
154
|
+
actor: Actor,
|
|
155
|
+
target: FormSubmissionLinkTarget,
|
|
156
|
+
targetId: string,
|
|
157
|
+
query: ListQueryParameters,
|
|
158
|
+
): Promise<Page<FormSubmissionView>>
|
|
159
|
+
getSubmission(actor: Actor, formId: string, submissionId: string): Promise<FormSubmissionView>
|
|
93
160
|
}
|
|
94
161
|
|
|
95
162
|
function toFieldView(record: FormFieldRecord): FormFieldView {
|
|
@@ -98,10 +165,15 @@ function toFieldView(record: FormFieldRecord): FormFieldView {
|
|
|
98
165
|
return view
|
|
99
166
|
}
|
|
100
167
|
|
|
101
|
-
function toView(
|
|
168
|
+
function toView(
|
|
169
|
+
record: FormRecord,
|
|
170
|
+
fields: readonly FormFieldRecord[],
|
|
171
|
+
listIds: readonly string[],
|
|
172
|
+
attachTargets: readonly FormAttachTarget[],
|
|
173
|
+
): FormView {
|
|
102
174
|
const { workspaceId: _workspaceId, ...view } = record
|
|
103
175
|
|
|
104
|
-
return { ...view, fields: fields.map(toFieldView) }
|
|
176
|
+
return { ...view, fields: fields.map(toFieldView), listIds, attachTargets }
|
|
105
177
|
}
|
|
106
178
|
|
|
107
179
|
function toSubmissionView(record: FormSubmissionRecord): FormSubmissionView {
|
|
@@ -113,13 +185,98 @@ function toSubmissionView(record: FormSubmissionRecord): FormSubmissionView {
|
|
|
113
185
|
function toStoredColumns(input: UpdateFormInput): Partial<repository.FormColumns> {
|
|
114
186
|
return {
|
|
115
187
|
...(input.name === undefined ? {} : { name: input.name }),
|
|
188
|
+
...(input.title === undefined ? {} : { title: input.title }),
|
|
116
189
|
...(input.description === undefined ? {} : { description: input.description }),
|
|
117
190
|
...(input.status === undefined ? {} : { status: input.status }),
|
|
118
191
|
...(input.thankYouMessage === undefined ? {} : { thankYouMessage: input.thankYouMessage }),
|
|
119
192
|
...(input.createDeal === undefined ? {} : { createDeal: input.createDeal }),
|
|
120
193
|
...(input.dealStageId === undefined ? {} : { dealStageId: input.dealStageId }),
|
|
121
194
|
...(input.dealNameTemplate === undefined ? {} : { dealNameTemplate: input.dealNameTemplate }),
|
|
195
|
+
...(input.createOpportunity === undefined
|
|
196
|
+
? {}
|
|
197
|
+
: { createOpportunity: input.createOpportunity }),
|
|
198
|
+
...(input.opportunityKind === undefined ? {} : { opportunityKind: input.opportunityKind }),
|
|
199
|
+
...(input.opportunityStageId === undefined
|
|
200
|
+
? {}
|
|
201
|
+
: { opportunityStageId: input.opportunityStageId }),
|
|
202
|
+
...(input.opportunityNameTemplate === undefined
|
|
203
|
+
? {}
|
|
204
|
+
: { opportunityNameTemplate: input.opportunityNameTemplate }),
|
|
205
|
+
...(input.opportunityOwnerId === undefined
|
|
206
|
+
? {}
|
|
207
|
+
: { opportunityOwnerId: input.opportunityOwnerId }),
|
|
208
|
+
...(input.createPartnership === undefined
|
|
209
|
+
? {}
|
|
210
|
+
: { createPartnership: input.createPartnership }),
|
|
211
|
+
...(input.partnershipKind === undefined ? {} : { partnershipKind: input.partnershipKind }),
|
|
212
|
+
...(input.partnershipStageId === undefined
|
|
213
|
+
? {}
|
|
214
|
+
: { partnershipStageId: input.partnershipStageId }),
|
|
215
|
+
...(input.partnershipNameTemplate === undefined
|
|
216
|
+
? {}
|
|
217
|
+
: { partnershipNameTemplate: input.partnershipNameTemplate }),
|
|
218
|
+
...(input.partnershipOwnerId === undefined
|
|
219
|
+
? {}
|
|
220
|
+
: { partnershipOwnerId: input.partnershipOwnerId }),
|
|
221
|
+
...(input.createEnquiry === undefined ? {} : { createEnquiry: input.createEnquiry }),
|
|
222
|
+
...(input.enquirySource === undefined ? {} : { enquirySource: input.enquirySource }),
|
|
223
|
+
...(input.enquiryStageId === undefined ? {} : { enquiryStageId: input.enquiryStageId }),
|
|
224
|
+
...(input.enquiryNameTemplate === undefined
|
|
225
|
+
? {}
|
|
226
|
+
: { enquiryNameTemplate: input.enquiryNameTemplate }),
|
|
227
|
+
...(input.enquiryOwnerId === undefined ? {} : { enquiryOwnerId: input.enquiryOwnerId }),
|
|
228
|
+
...(input.personTags === undefined ? {} : { personTags: [...input.personTags] }),
|
|
229
|
+
...(input.companyTags === undefined ? {} : { companyTags: [...input.companyTags] }),
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Where the resulting-state validation puts its answers. */
|
|
234
|
+
interface ResultingState {
|
|
235
|
+
readonly fields: readonly FieldShape[]
|
|
236
|
+
readonly createDeal: boolean
|
|
237
|
+
readonly createOpportunity: boolean
|
|
238
|
+
readonly opportunityKind: string | null
|
|
239
|
+
readonly createPartnership: boolean
|
|
240
|
+
readonly partnershipKind: string | null
|
|
241
|
+
readonly listIds: readonly string[]
|
|
242
|
+
readonly attachTargets: readonly FormAttachTarget[]
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Sorts an attach-target list so a resent identical set is not a write. */
|
|
246
|
+
function sortAttachTargets(
|
|
247
|
+
targets: readonly FormAttachTarget[],
|
|
248
|
+
): readonly FormAttachTarget[] {
|
|
249
|
+
return [...targets].sort((left, right) => {
|
|
250
|
+
if (left.targetType !== right.targetType) {
|
|
251
|
+
return left.targetType < right.targetType ? -1 : 1
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return left.targetId < right.targetId ? -1 : left.targetId > right.targetId ? 1 : 0
|
|
255
|
+
})
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function sameStringSet(current: readonly string[], next: readonly string[]): boolean {
|
|
259
|
+
if (current.length !== next.length) {
|
|
260
|
+
return false
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const currentSet = new Set(current)
|
|
264
|
+
|
|
265
|
+
return next.every((value) => currentSet.has(value))
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function sameAttachTargets(
|
|
269
|
+
current: readonly FormAttachTarget[],
|
|
270
|
+
next: readonly FormAttachTarget[],
|
|
271
|
+
): boolean {
|
|
272
|
+
if (current.length !== next.length) {
|
|
273
|
+
return false
|
|
122
274
|
}
|
|
275
|
+
|
|
276
|
+
const key = (target: FormAttachTarget): string => `${target.targetType}:${target.targetId}`
|
|
277
|
+
const currentSet = new Set(current.map(key))
|
|
278
|
+
|
|
279
|
+
return next.every((target) => currentSet.has(key(target)))
|
|
123
280
|
}
|
|
124
281
|
|
|
125
282
|
export function createFormsService(dependencies: FormsDependencies): FormsService {
|
|
@@ -138,41 +295,196 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
|
|
|
138
295
|
}
|
|
139
296
|
|
|
140
297
|
/**
|
|
141
|
-
* A stage a form's
|
|
142
|
-
* pipeline.
|
|
298
|
+
* A stage a form's created records of `kind` may open in: in this workspace,
|
|
299
|
+
* and in the matching pipeline.
|
|
143
300
|
*
|
|
144
301
|
* The wrong-workspace case reads as missing, per `api.md`. The wrong-pipeline
|
|
145
|
-
* case is a request naming a real stage that can never hold a
|
|
146
|
-
* validation error rather than a missing record. Same rule
|
|
147
|
-
* applies to `stage_id`.
|
|
302
|
+
* case is a request naming a real stage that can never hold a record of
|
|
303
|
+
* `kind`, which is a validation error rather than a missing record. Same rule
|
|
304
|
+
* the deals service applies to `stage_id`.
|
|
305
|
+
*
|
|
306
|
+
* @param field The body-field name (`deal_stage_id`, `opportunity_stage_id`,
|
|
307
|
+
* `partnership_stage_id`) that the 422 detail should point at.
|
|
148
308
|
*/
|
|
149
|
-
async function
|
|
309
|
+
async function requireStageOfKind(
|
|
310
|
+
workspaceId: string,
|
|
311
|
+
kind: PipelineKind,
|
|
312
|
+
stageId: string,
|
|
313
|
+
field: string,
|
|
314
|
+
): Promise<void> {
|
|
150
315
|
const stage = await pipelineRepository.findStage(dependencies.db, workspaceId, stageId)
|
|
151
316
|
|
|
152
317
|
if (stage === undefined) {
|
|
153
318
|
throw AppError.notFound('Pipeline stage not found')
|
|
154
319
|
}
|
|
155
320
|
|
|
156
|
-
if (stage.kind !==
|
|
157
|
-
throw AppError.validationFailed(
|
|
158
|
-
{ field
|
|
321
|
+
if (stage.kind !== kind) {
|
|
322
|
+
throw AppError.validationFailed(`That stage is not part of the ${kind} pipeline`, [
|
|
323
|
+
{ field, message: `It belongs to the ${stage.kind} pipeline` },
|
|
159
324
|
])
|
|
160
325
|
}
|
|
161
326
|
}
|
|
162
327
|
|
|
163
328
|
/**
|
|
164
|
-
* @param createsDeal Part of the check, not context: whether a form needs a
|
|
165
|
-
* company mapping depends on it, so the two are validated together.
|
|
166
329
|
* @throws AppError 422 listing every problem with the field list at once.
|
|
167
330
|
*/
|
|
168
|
-
function requireUsableFields(
|
|
169
|
-
|
|
331
|
+
function requireUsableFields(
|
|
332
|
+
fields: readonly FieldShape[],
|
|
333
|
+
createsDeal: boolean,
|
|
334
|
+
createsPartnership: boolean,
|
|
335
|
+
): void {
|
|
336
|
+
const problems = findFieldProblems(fields, createsDeal, createsPartnership)
|
|
170
337
|
|
|
171
338
|
if (problems.length > 0) {
|
|
172
339
|
throw AppError.validationFailed('That field list cannot process a submission', problems)
|
|
173
340
|
}
|
|
174
341
|
}
|
|
175
342
|
|
|
343
|
+
/**
|
|
344
|
+
* The lists an action-configured form names must exist in this workspace and
|
|
345
|
+
* target `person` or `company`. A list of another target type would never
|
|
346
|
+
* receive a submitter or a company — a form only knows how to feed those two
|
|
347
|
+
* — so accepting it would misdirect the visitor's inbound landing.
|
|
348
|
+
*/
|
|
349
|
+
async function requireActionLists(
|
|
350
|
+
workspaceId: string,
|
|
351
|
+
listIds: readonly string[],
|
|
352
|
+
): Promise<void> {
|
|
353
|
+
if (listIds.length === 0) {
|
|
354
|
+
return
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const rows = await listsRepository.listListsById(dependencies.db, workspaceId, listIds)
|
|
358
|
+
const found = new Map(rows.map((row) => [row.id, row.targetType]))
|
|
359
|
+
const problems = listIds
|
|
360
|
+
.map((listId, index) => {
|
|
361
|
+
const targetType = found.get(listId)
|
|
362
|
+
|
|
363
|
+
if (targetType === undefined) {
|
|
364
|
+
return { field: `list_ids.${String(index)}`, message: `No list ${listId} here` }
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (targetType !== 'person' && targetType !== 'company') {
|
|
368
|
+
return {
|
|
369
|
+
field: `list_ids.${String(index)}`,
|
|
370
|
+
message: `A list feeding a form must target person or company (got ${targetType})`,
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
return undefined
|
|
375
|
+
})
|
|
376
|
+
.filter((problem): problem is NonNullable<typeof problem> => problem !== undefined)
|
|
377
|
+
|
|
378
|
+
if (problems.length > 0) {
|
|
379
|
+
throw AppError.validationFailed(`Some list_ids cannot receive a submission`, problems)
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Every attach target must exist in this workspace. Same `missingTargets`
|
|
385
|
+
* check notes and list members use, grouped per type so one query per
|
|
386
|
+
* pipeline kind resolves the whole set instead of one per row.
|
|
387
|
+
*/
|
|
388
|
+
async function requireAttachTargets(
|
|
389
|
+
workspaceId: string,
|
|
390
|
+
targets: readonly FormAttachTarget[],
|
|
391
|
+
): Promise<void> {
|
|
392
|
+
if (targets.length === 0) {
|
|
393
|
+
return
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const problems: { field: string; message: string }[] = []
|
|
397
|
+
|
|
398
|
+
for (const kind of PIPELINE_KINDS) {
|
|
399
|
+
const ofKind = targets.filter((target) => target.targetType === kind)
|
|
400
|
+
|
|
401
|
+
if (ofKind.length === 0) {
|
|
402
|
+
continue
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const missing = await missingTargets(
|
|
406
|
+
dependencies.db,
|
|
407
|
+
workspaceId,
|
|
408
|
+
kind,
|
|
409
|
+
ofKind.map((target) => target.targetId),
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
if (missing.length === 0) {
|
|
413
|
+
continue
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const missingSet = new Set(missing)
|
|
417
|
+
|
|
418
|
+
targets.forEach((target, index) => {
|
|
419
|
+
if (target.targetType === kind && missingSet.has(target.targetId)) {
|
|
420
|
+
problems.push({
|
|
421
|
+
field: `attach_targets.${String(index)}`,
|
|
422
|
+
message: `No ${kind} ${target.targetId} here`,
|
|
423
|
+
})
|
|
424
|
+
}
|
|
425
|
+
})
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (problems.length > 0) {
|
|
429
|
+
throw new AppError('not_found', 'Attach target not found', problems)
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Every consent field's `consent_purpose_id` must exist in this workspace.
|
|
435
|
+
* The FK on `form_fields.consent_purpose_id` catches this at the database
|
|
436
|
+
* on write; running the check here first turns the failure into a 422 with
|
|
437
|
+
* the offending field pinpointed instead of a foreign-key 500.
|
|
438
|
+
*/
|
|
439
|
+
async function requireConsentPurposes(
|
|
440
|
+
workspaceId: string,
|
|
441
|
+
fields: readonly FieldShape[],
|
|
442
|
+
): Promise<void> {
|
|
443
|
+
const consentIds = Array.from(
|
|
444
|
+
new Set(fields.flatMap((field) => [...field.consentPurposeIds])),
|
|
445
|
+
)
|
|
446
|
+
if (consentIds.length === 0) return
|
|
447
|
+
|
|
448
|
+
const rows = await consentPurposesRepository.listPurposesByIds(
|
|
449
|
+
dependencies.db,
|
|
450
|
+
workspaceId,
|
|
451
|
+
consentIds,
|
|
452
|
+
)
|
|
453
|
+
const found = new Set(rows.map((row) => row.id))
|
|
454
|
+
const problems: { field: string; message: string }[] = []
|
|
455
|
+
fields.forEach((field, index) => {
|
|
456
|
+
for (const purposeId of field.consentPurposeIds) {
|
|
457
|
+
if (!found.has(purposeId)) {
|
|
458
|
+
problems.push({
|
|
459
|
+
field: `fields.${String(index)}.consent_purpose_ids`,
|
|
460
|
+
message: `No consent purpose ${purposeId} in this workspace`,
|
|
461
|
+
})
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
})
|
|
465
|
+
if (problems.length > 0) {
|
|
466
|
+
throw AppError.validationFailed(
|
|
467
|
+
'One or more consent fields name a purpose that does not exist',
|
|
468
|
+
problems,
|
|
469
|
+
)
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Resulting-state validation for everything except the three stage-id
|
|
475
|
+
* checks: those depend on whether the id actually changed, which is only
|
|
476
|
+
* known at the call site, so they stay inline in create() and update().
|
|
477
|
+
*/
|
|
478
|
+
async function validateResultingState(
|
|
479
|
+
workspaceId: string,
|
|
480
|
+
state: ResultingState,
|
|
481
|
+
): Promise<void> {
|
|
482
|
+
requireUsableFields(state.fields, state.createDeal, state.createPartnership)
|
|
483
|
+
await requireConsentPurposes(workspaceId, state.fields)
|
|
484
|
+
await requireActionLists(workspaceId, state.listIds)
|
|
485
|
+
await requireAttachTargets(workspaceId, state.attachTargets)
|
|
486
|
+
}
|
|
487
|
+
|
|
176
488
|
/** Writes a field list as positions 0..n-1, which is the order it arrived in. */
|
|
177
489
|
function writeFields(
|
|
178
490
|
tx: Transaction,
|
|
@@ -192,11 +504,29 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
|
|
|
192
504
|
mapTo: field.mapTo,
|
|
193
505
|
options: storedOptions(field.options),
|
|
194
506
|
placeholder: field.placeholder,
|
|
507
|
+
statement: field.statement,
|
|
508
|
+
consentPurposeIds: [...field.consentPurposeIds],
|
|
509
|
+
// Prune the override map to just the purposes the field lists, so
|
|
510
|
+
// deselecting one clears its custom text rather than keeping it
|
|
511
|
+
// stored against a purpose the field no longer offers.
|
|
512
|
+
consentPurposeLabels: pruneLabels(field.consentPurposeIds, field.consentPurposeLabels),
|
|
195
513
|
sortOrder: index,
|
|
196
514
|
})),
|
|
197
515
|
)
|
|
198
516
|
}
|
|
199
517
|
|
|
518
|
+
function pruneLabels(
|
|
519
|
+
ids: readonly string[],
|
|
520
|
+
labels: Readonly<Record<string, string>>,
|
|
521
|
+
): Readonly<Record<string, string>> {
|
|
522
|
+
const allowed = new Set(ids)
|
|
523
|
+
const pruned: Record<string, string> = {}
|
|
524
|
+
for (const [key, value] of Object.entries(labels)) {
|
|
525
|
+
if (allowed.has(key) && value.length > 0) pruned[key] = value
|
|
526
|
+
}
|
|
527
|
+
return pruned
|
|
528
|
+
}
|
|
529
|
+
|
|
200
530
|
/** @returns The page's views, with every form's fields fetched in one query. */
|
|
201
531
|
async function toViews(records: readonly FormRecord[]): Promise<FormView[]> {
|
|
202
532
|
const fields = await repository.listFieldsFor(
|
|
@@ -204,11 +534,38 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
|
|
|
204
534
|
records.map((record) => record.id),
|
|
205
535
|
)
|
|
206
536
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
)
|
|
537
|
+
// list_ids and attach_targets are per-form, so a list-page fetch takes them
|
|
538
|
+
// in one round trip per form. In practice a list page is small (25 rows by
|
|
539
|
+
// default, per api.md), and the sets themselves are short.
|
|
540
|
+
return Promise.all(
|
|
541
|
+
records.map(async (record) => {
|
|
542
|
+
const [listRows, attachTargets] = await Promise.all([
|
|
543
|
+
repository.listFormLists(dependencies.db, record.id),
|
|
544
|
+
repository.listAttachTargets(dependencies.db, record.id),
|
|
545
|
+
])
|
|
546
|
+
|
|
547
|
+
return toView(
|
|
548
|
+
record,
|
|
549
|
+
fields.filter((field) => field.formId === record.id),
|
|
550
|
+
listRows.map((row) => row.listId),
|
|
551
|
+
attachTargets,
|
|
552
|
+
)
|
|
553
|
+
}),
|
|
554
|
+
)
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
async function hydrateOne(record: FormRecord): Promise<FormView> {
|
|
558
|
+
const [fields, listRows, attachTargets] = await Promise.all([
|
|
559
|
+
repository.listFields(dependencies.db, record.id),
|
|
560
|
+
repository.listFormLists(dependencies.db, record.id),
|
|
561
|
+
repository.listAttachTargets(dependencies.db, record.id),
|
|
562
|
+
])
|
|
563
|
+
|
|
564
|
+
return toView(
|
|
565
|
+
record,
|
|
566
|
+
fields,
|
|
567
|
+
listRows.map((row) => row.listId),
|
|
568
|
+
attachTargets,
|
|
212
569
|
)
|
|
213
570
|
}
|
|
214
571
|
|
|
@@ -226,38 +583,87 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
|
|
|
226
583
|
const workspaceId = requireWorkspaceId(actor)
|
|
227
584
|
const form = await require(workspaceId, id)
|
|
228
585
|
|
|
229
|
-
return
|
|
586
|
+
return hydrateOne(form)
|
|
230
587
|
},
|
|
231
588
|
|
|
232
589
|
async create(actor, input) {
|
|
233
590
|
const workspaceId = requireWorkspaceId(actor)
|
|
234
591
|
|
|
235
|
-
|
|
592
|
+
await validateResultingState(workspaceId, {
|
|
593
|
+
fields: input.fields,
|
|
594
|
+
createDeal: input.createDeal,
|
|
595
|
+
createOpportunity: input.createOpportunity,
|
|
596
|
+
opportunityKind: input.opportunityKind,
|
|
597
|
+
createPartnership: input.createPartnership,
|
|
598
|
+
partnershipKind: input.partnershipKind,
|
|
599
|
+
listIds: input.listIds,
|
|
600
|
+
attachTargets: input.attachTargets,
|
|
601
|
+
})
|
|
236
602
|
|
|
237
603
|
if (input.dealStageId !== null) {
|
|
238
|
-
await
|
|
604
|
+
await requireStageOfKind(workspaceId, 'deal', input.dealStageId, 'deal_stage_id')
|
|
605
|
+
}
|
|
606
|
+
if (input.opportunityStageId !== null) {
|
|
607
|
+
await requireStageOfKind(
|
|
608
|
+
workspaceId,
|
|
609
|
+
'opportunity',
|
|
610
|
+
input.opportunityStageId,
|
|
611
|
+
'opportunity_stage_id',
|
|
612
|
+
)
|
|
613
|
+
}
|
|
614
|
+
if (input.partnershipStageId !== null) {
|
|
615
|
+
await requireStageOfKind(
|
|
616
|
+
workspaceId,
|
|
617
|
+
'partnership',
|
|
618
|
+
input.partnershipStageId,
|
|
619
|
+
'partnership_stage_id',
|
|
620
|
+
)
|
|
621
|
+
}
|
|
622
|
+
if (input.enquiryStageId !== null) {
|
|
623
|
+
await requireStageOfKind(workspaceId, 'enquiry', input.enquiryStageId, 'enquiry_stage_id')
|
|
239
624
|
}
|
|
240
625
|
|
|
241
626
|
const id = dependencies.createId('form')
|
|
627
|
+
const sortedAttachTargets = sortAttachTargets(input.attachTargets)
|
|
242
628
|
|
|
243
629
|
return dependencies.transaction(async ({ tx, events }) => {
|
|
244
630
|
const created = await repository.insertForm(tx, {
|
|
245
631
|
id,
|
|
246
632
|
workspaceId,
|
|
247
633
|
name: input.name,
|
|
634
|
+
title: input.title,
|
|
248
635
|
description: input.description,
|
|
249
636
|
status: input.status,
|
|
250
637
|
thankYouMessage: input.thankYouMessage,
|
|
251
638
|
createDeal: input.createDeal,
|
|
252
639
|
dealStageId: input.dealStageId,
|
|
253
640
|
dealNameTemplate: input.dealNameTemplate,
|
|
641
|
+
createOpportunity: input.createOpportunity,
|
|
642
|
+
opportunityKind: input.opportunityKind,
|
|
643
|
+
opportunityStageId: input.opportunityStageId,
|
|
644
|
+
opportunityNameTemplate: input.opportunityNameTemplate,
|
|
645
|
+
opportunityOwnerId: input.opportunityOwnerId,
|
|
646
|
+
createPartnership: input.createPartnership,
|
|
647
|
+
partnershipKind: input.partnershipKind,
|
|
648
|
+
partnershipStageId: input.partnershipStageId,
|
|
649
|
+
partnershipNameTemplate: input.partnershipNameTemplate,
|
|
650
|
+
partnershipOwnerId: input.partnershipOwnerId,
|
|
651
|
+
createEnquiry: input.createEnquiry,
|
|
652
|
+
enquirySource: input.enquirySource,
|
|
653
|
+
enquiryStageId: input.enquiryStageId,
|
|
654
|
+
enquiryNameTemplate: input.enquiryNameTemplate,
|
|
655
|
+
enquiryOwnerId: input.enquiryOwnerId,
|
|
656
|
+
personTags: [...input.personTags],
|
|
657
|
+
companyTags: [...input.companyTags],
|
|
254
658
|
publicKey: generatePublicKey(),
|
|
255
659
|
})
|
|
256
660
|
const fields = await writeFields(tx, workspaceId, id, input.fields)
|
|
661
|
+
await repository.replaceFormLists(tx, workspaceId, id, input.listIds)
|
|
662
|
+
await repository.replaceAttachTargets(tx, workspaceId, id, sortedAttachTargets)
|
|
257
663
|
|
|
258
664
|
events.emit('forms.form.created', { type: 'form', id }, {})
|
|
259
665
|
|
|
260
|
-
return toView(created, fields)
|
|
666
|
+
return toView(created, fields, [...input.listIds], sortedAttachTargets)
|
|
261
667
|
}, { workspaceId, actor: toEventActor(actor) })
|
|
262
668
|
},
|
|
263
669
|
|
|
@@ -265,17 +671,68 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
|
|
|
265
671
|
const workspaceId = requireWorkspaceId(actor)
|
|
266
672
|
const existing = await require(workspaceId, id)
|
|
267
673
|
const stored = await repository.listFields(dependencies.db, id)
|
|
674
|
+
const storedListRows = await repository.listFormLists(dependencies.db, id)
|
|
675
|
+
const storedListIds = storedListRows.map((row) => row.listId)
|
|
676
|
+
const storedAttachTargets = await repository.listAttachTargets(dependencies.db, id)
|
|
677
|
+
|
|
678
|
+
const nextListIds = changes.listIds ?? storedListIds
|
|
679
|
+
const nextAttachTargets = sortAttachTargets(changes.attachTargets ?? storedAttachTargets)
|
|
268
680
|
|
|
269
681
|
// Validated against the state the request would leave behind, not against
|
|
270
682
|
// what it carried. Turning `create_deal` on is what makes a form with no
|
|
271
683
|
// company mapping unusable, and that request names no fields at all.
|
|
272
|
-
|
|
273
|
-
changes.fields ?? stored,
|
|
274
|
-
changes.createDeal ?? existing.createDeal,
|
|
275
|
-
|
|
684
|
+
await validateResultingState(workspaceId, {
|
|
685
|
+
fields: changes.fields ?? stored,
|
|
686
|
+
createDeal: changes.createDeal ?? existing.createDeal,
|
|
687
|
+
createOpportunity: changes.createOpportunity ?? existing.createOpportunity,
|
|
688
|
+
opportunityKind:
|
|
689
|
+
changes.opportunityKind === undefined
|
|
690
|
+
? existing.opportunityKind
|
|
691
|
+
: changes.opportunityKind,
|
|
692
|
+
createPartnership: changes.createPartnership ?? existing.createPartnership,
|
|
693
|
+
partnershipKind:
|
|
694
|
+
changes.partnershipKind === undefined
|
|
695
|
+
? existing.partnershipKind
|
|
696
|
+
: changes.partnershipKind,
|
|
697
|
+
listIds: nextListIds,
|
|
698
|
+
attachTargets: nextAttachTargets,
|
|
699
|
+
})
|
|
276
700
|
|
|
277
701
|
if (typeof changes.dealStageId === 'string' && changes.dealStageId !== existing.dealStageId) {
|
|
278
|
-
await
|
|
702
|
+
await requireStageOfKind(workspaceId, 'deal', changes.dealStageId, 'deal_stage_id')
|
|
703
|
+
}
|
|
704
|
+
if (
|
|
705
|
+
typeof changes.opportunityStageId === 'string' &&
|
|
706
|
+
changes.opportunityStageId !== existing.opportunityStageId
|
|
707
|
+
) {
|
|
708
|
+
await requireStageOfKind(
|
|
709
|
+
workspaceId,
|
|
710
|
+
'opportunity',
|
|
711
|
+
changes.opportunityStageId,
|
|
712
|
+
'opportunity_stage_id',
|
|
713
|
+
)
|
|
714
|
+
}
|
|
715
|
+
if (
|
|
716
|
+
typeof changes.partnershipStageId === 'string' &&
|
|
717
|
+
changes.partnershipStageId !== existing.partnershipStageId
|
|
718
|
+
) {
|
|
719
|
+
await requireStageOfKind(
|
|
720
|
+
workspaceId,
|
|
721
|
+
'partnership',
|
|
722
|
+
changes.partnershipStageId,
|
|
723
|
+
'partnership_stage_id',
|
|
724
|
+
)
|
|
725
|
+
}
|
|
726
|
+
if (
|
|
727
|
+
typeof changes.enquiryStageId === 'string' &&
|
|
728
|
+
changes.enquiryStageId !== existing.enquiryStageId
|
|
729
|
+
) {
|
|
730
|
+
await requireStageOfKind(
|
|
731
|
+
workspaceId,
|
|
732
|
+
'enquiry',
|
|
733
|
+
changes.enquiryStageId,
|
|
734
|
+
'enquiry_stage_id',
|
|
735
|
+
)
|
|
279
736
|
}
|
|
280
737
|
|
|
281
738
|
const columns = toStoredColumns(changes)
|
|
@@ -285,14 +742,25 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
|
|
|
285
742
|
// it would move every field id and publish a `record.updated` no consumer
|
|
286
743
|
// can act on, which is the same reason `changedKeys` guards the columns.
|
|
287
744
|
const rewritesFields = changes.fields !== undefined && fieldsDiffer(stored, changes.fields)
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
745
|
+
const rewritesLists =
|
|
746
|
+
changes.listIds !== undefined && !sameStringSet(storedListIds, changes.listIds)
|
|
747
|
+
const rewritesAttachTargets =
|
|
748
|
+
changes.attachTargets !== undefined &&
|
|
749
|
+
!sameAttachTargets(storedAttachTargets, changes.attachTargets)
|
|
750
|
+
|
|
751
|
+
if (
|
|
752
|
+
written.length === 0 &&
|
|
753
|
+
!rewritesFields &&
|
|
754
|
+
!rewritesLists &&
|
|
755
|
+
!rewritesAttachTargets
|
|
756
|
+
) {
|
|
757
|
+
return toView(existing, stored, storedListIds, storedAttachTargets)
|
|
291
758
|
}
|
|
292
759
|
|
|
293
760
|
return dependencies.transaction(async ({ tx, events }) => {
|
|
294
|
-
// A changed field list
|
|
295
|
-
// `updated_at` even when no column of the form
|
|
761
|
+
// A changed field list, list set, or attach-target set is a change to
|
|
762
|
+
// the form, so it stamps `updated_at` even when no column of the form
|
|
763
|
+
// itself moved.
|
|
296
764
|
const updated = await repository.updateForm(tx, workspaceId, id, {
|
|
297
765
|
...columns,
|
|
298
766
|
updatedAt: dependencies.now(),
|
|
@@ -312,13 +780,28 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
|
|
|
312
780
|
return writeFields(tx, workspaceId, id, changes.fields)
|
|
313
781
|
})()
|
|
314
782
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
783
|
+
if (rewritesLists) {
|
|
784
|
+
await repository.replaceFormLists(tx, workspaceId, id, nextListIds)
|
|
785
|
+
}
|
|
786
|
+
if (rewritesAttachTargets) {
|
|
787
|
+
await repository.replaceAttachTargets(tx, workspaceId, id, nextAttachTargets)
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
const changedFields: string[] = [...written]
|
|
791
|
+
|
|
792
|
+
if (rewritesFields) {
|
|
793
|
+
changedFields.push('fields')
|
|
794
|
+
}
|
|
795
|
+
if (rewritesLists) {
|
|
796
|
+
changedFields.push('listIds')
|
|
797
|
+
}
|
|
798
|
+
if (rewritesAttachTargets) {
|
|
799
|
+
changedFields.push('attachTargets')
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
events.emit('forms.form.updated', { type: 'form', id }, { changed: changedFields })
|
|
320
803
|
|
|
321
|
-
return toView(updated, fields)
|
|
804
|
+
return toView(updated, fields, nextListIds, nextAttachTargets)
|
|
322
805
|
}, { workspaceId, actor: toEventActor(actor) })
|
|
323
806
|
},
|
|
324
807
|
|
|
@@ -359,5 +842,46 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
|
|
|
359
842
|
toSubmissionView,
|
|
360
843
|
)
|
|
361
844
|
},
|
|
845
|
+
|
|
846
|
+
async listSubmissionsLinkedTo(actor, target, targetId, query) {
|
|
847
|
+
const workspaceId = requireWorkspaceId(actor)
|
|
848
|
+
|
|
849
|
+
// The target's existence is not checked here — a missing or cross-workspace
|
|
850
|
+
// target reads as an empty page, the same answer any other cross-workspace
|
|
851
|
+
// list returns. Adding a per-type existence check would need seven queries
|
|
852
|
+
// for one behaviour that the FK filter already produces.
|
|
853
|
+
const window = readListWindow(query, FORM_SUBMISSION_SORTS, DEFAULT_FORM_SUBMISSION_SORT)
|
|
854
|
+
const rows = await repository.listSubmissionsLinkedTo(
|
|
855
|
+
dependencies.db,
|
|
856
|
+
workspaceId,
|
|
857
|
+
target,
|
|
858
|
+
targetId,
|
|
859
|
+
window,
|
|
860
|
+
)
|
|
861
|
+
|
|
862
|
+
return mapPage(
|
|
863
|
+
toPage(rows, window, (submission) => submission.id),
|
|
864
|
+
toSubmissionView,
|
|
865
|
+
)
|
|
866
|
+
},
|
|
867
|
+
|
|
868
|
+
async getSubmission(actor, formId, submissionId) {
|
|
869
|
+
const workspaceId = requireWorkspaceId(actor)
|
|
870
|
+
|
|
871
|
+
await require(workspaceId, formId)
|
|
872
|
+
|
|
873
|
+
const row = await repository.findSubmission(
|
|
874
|
+
dependencies.db,
|
|
875
|
+
workspaceId,
|
|
876
|
+
formId,
|
|
877
|
+
submissionId,
|
|
878
|
+
)
|
|
879
|
+
|
|
880
|
+
if (row === undefined) {
|
|
881
|
+
throw AppError.notFound('Submission not found')
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
return toSubmissionView(row)
|
|
885
|
+
},
|
|
362
886
|
}
|
|
363
887
|
}
|