@kelpie/server 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/ids.d.ts +11 -0
- package/dist/lib/ids.d.ts.map +1 -1
- package/dist/lib/ids.js +11 -0
- package/dist/lib/ids.js.map +1 -1
- package/dist/modules/activities/repository.d.ts.map +1 -1
- package/dist/modules/activities/repository.js +19 -20
- package/dist/modules/activities/repository.js.map +1 -1
- package/dist/modules/activities/wording.d.ts +12 -0
- package/dist/modules/activities/wording.d.ts.map +1 -1
- package/dist/modules/activities/wording.js +16 -0
- package/dist/modules/activities/wording.js.map +1 -1
- package/dist/modules/agent-tasks/catalog.d.ts.map +1 -1
- package/dist/modules/agent-tasks/catalog.js +62 -0
- package/dist/modules/agent-tasks/catalog.js.map +1 -1
- package/dist/modules/agent-tasks/resolve.d.ts.map +1 -1
- package/dist/modules/agent-tasks/resolve.js +42 -9
- package/dist/modules/agent-tasks/resolve.js.map +1 -1
- package/dist/modules/agent-tasks/routes.d.ts +2 -0
- package/dist/modules/agent-tasks/routes.d.ts.map +1 -1
- package/dist/modules/attachedRecords.d.ts +6 -1
- package/dist/modules/attachedRecords.d.ts.map +1 -1
- package/dist/modules/attachedRecords.js +15 -1
- package/dist/modules/attachedRecords.js.map +1 -1
- package/dist/modules/companies/index.d.ts.map +1 -1
- package/dist/modules/companies/index.js +3 -1
- package/dist/modules/companies/index.js.map +1 -1
- package/dist/modules/companies/routes.d.ts +14 -0
- package/dist/modules/companies/routes.d.ts.map +1 -1
- package/dist/modules/companies/routes.js +7 -0
- package/dist/modules/companies/routes.js.map +1 -1
- package/dist/modules/companies/schema.d.ts +20 -0
- package/dist/modules/companies/schema.d.ts.map +1 -1
- package/dist/modules/companies/schema.js +6 -1
- package/dist/modules/companies/schema.js.map +1 -1
- package/dist/modules/companies/service.d.ts +5 -0
- package/dist/modules/companies/service.d.ts.map +1 -1
- package/dist/modules/companies/service.js +24 -12
- package/dist/modules/companies/service.js.map +1 -1
- package/dist/modules/consent-purposes/capabilities.d.ts +7 -0
- package/dist/modules/consent-purposes/capabilities.d.ts.map +1 -0
- package/dist/modules/consent-purposes/capabilities.js +10 -0
- package/dist/modules/consent-purposes/capabilities.js.map +1 -0
- package/dist/modules/consent-purposes/events.d.ts +38 -0
- package/dist/modules/consent-purposes/events.d.ts.map +1 -0
- package/dist/modules/consent-purposes/events.js +17 -0
- package/dist/modules/consent-purposes/events.js.map +1 -0
- package/dist/modules/consent-purposes/index.d.ts +13 -0
- package/dist/modules/consent-purposes/index.d.ts.map +1 -0
- package/dist/modules/consent-purposes/index.js +41 -0
- package/dist/modules/consent-purposes/index.js.map +1 -0
- package/dist/modules/consent-purposes/repository.d.ts +21 -0
- package/dist/modules/consent-purposes/repository.d.ts.map +1 -0
- package/dist/modules/consent-purposes/repository.js +98 -0
- package/dist/modules/consent-purposes/repository.js.map +1 -0
- package/dist/modules/consent-purposes/routes.d.ts +39 -0
- package/dist/modules/consent-purposes/routes.d.ts.map +1 -0
- package/dist/modules/consent-purposes/routes.js +79 -0
- package/dist/modules/consent-purposes/routes.js.map +1 -0
- package/dist/modules/consent-purposes/schema.d.ts +175 -0
- package/dist/modules/consent-purposes/schema.d.ts.map +1 -0
- package/dist/modules/consent-purposes/schema.js +35 -0
- package/dist/modules/consent-purposes/schema.js.map +1 -0
- package/dist/modules/consent-purposes/service.d.ts +50 -0
- package/dist/modules/consent-purposes/service.d.ts.map +1 -0
- package/dist/modules/consent-purposes/service.js +263 -0
- package/dist/modules/consent-purposes/service.js.map +1 -0
- package/dist/modules/consent-purposes/starters.d.ts +17 -0
- package/dist/modules/consent-purposes/starters.d.ts.map +1 -0
- package/dist/modules/consent-purposes/starters.js +15 -0
- package/dist/modules/consent-purposes/starters.js.map +1 -0
- package/dist/modules/consent-purposes/tools.d.ts +4 -0
- package/dist/modules/consent-purposes/tools.d.ts.map +1 -0
- package/dist/modules/consent-purposes/tools.js +29 -0
- package/dist/modules/consent-purposes/tools.js.map +1 -0
- package/dist/modules/core.d.ts.map +1 -1
- package/dist/modules/core.js +10 -0
- package/dist/modules/core.js.map +1 -1
- package/dist/modules/custom-fields/capabilities.d.ts +12 -0
- package/dist/modules/custom-fields/capabilities.d.ts.map +1 -0
- package/dist/modules/custom-fields/capabilities.js +15 -0
- package/dist/modules/custom-fields/capabilities.js.map +1 -0
- package/dist/modules/custom-fields/events.d.ts +49 -0
- package/dist/modules/custom-fields/events.d.ts.map +1 -0
- package/dist/modules/custom-fields/events.js +25 -0
- package/dist/modules/custom-fields/events.js.map +1 -0
- package/dist/modules/custom-fields/index.d.ts +19 -0
- package/dist/modules/custom-fields/index.d.ts.map +1 -0
- package/dist/modules/custom-fields/index.js +46 -0
- package/dist/modules/custom-fields/index.js.map +1 -0
- package/dist/modules/custom-fields/repository.d.ts +37 -0
- package/dist/modules/custom-fields/repository.d.ts.map +1 -0
- package/dist/modules/custom-fields/repository.js +144 -0
- package/dist/modules/custom-fields/repository.js.map +1 -0
- package/dist/modules/custom-fields/routes.d.ts +44 -0
- package/dist/modules/custom-fields/routes.d.ts.map +1 -0
- package/dist/modules/custom-fields/routes.js +103 -0
- package/dist/modules/custom-fields/routes.js.map +1 -0
- package/dist/modules/custom-fields/schema.d.ts +215 -0
- package/dist/modules/custom-fields/schema.d.ts.map +1 -0
- package/dist/modules/custom-fields/schema.js +43 -0
- package/dist/modules/custom-fields/schema.js.map +1 -0
- package/dist/modules/custom-fields/service.d.ts +57 -0
- package/dist/modules/custom-fields/service.d.ts.map +1 -0
- package/dist/modules/custom-fields/service.js +273 -0
- package/dist/modules/custom-fields/service.js.map +1 -0
- package/dist/modules/custom-fields/tools.d.ts +4 -0
- package/dist/modules/custom-fields/tools.d.ts.map +1 -0
- package/dist/modules/custom-fields/tools.js +38 -0
- package/dist/modules/custom-fields/tools.js.map +1 -0
- package/dist/modules/custom-fields/values.d.ts +49 -0
- package/dist/modules/custom-fields/values.d.ts.map +1 -0
- package/dist/modules/custom-fields/values.js +249 -0
- package/dist/modules/custom-fields/values.js.map +1 -0
- package/dist/modules/custom-fields/wire.d.ts +12 -0
- package/dist/modules/custom-fields/wire.d.ts.map +1 -0
- package/dist/modules/custom-fields/wire.js +30 -0
- package/dist/modules/custom-fields/wire.js.map +1 -0
- package/dist/modules/dashboard/repository.d.ts.map +1 -1
- package/dist/modules/dashboard/repository.js +4 -3
- package/dist/modules/dashboard/repository.js.map +1 -1
- package/dist/modules/deals/index.d.ts +2 -1
- package/dist/modules/deals/index.d.ts.map +1 -1
- package/dist/modules/deals/index.js +5 -2
- package/dist/modules/deals/index.js.map +1 -1
- package/dist/modules/deals/repository.d.ts +0 -16
- package/dist/modules/deals/repository.d.ts.map +1 -1
- package/dist/modules/deals/repository.js +6 -76
- package/dist/modules/deals/repository.js.map +1 -1
- package/dist/modules/deals/routes.d.ts +14 -0
- package/dist/modules/deals/routes.d.ts.map +1 -1
- package/dist/modules/deals/routes.js +7 -0
- package/dist/modules/deals/routes.js.map +1 -1
- package/dist/modules/deals/schema.d.ts +20 -42
- package/dist/modules/deals/schema.d.ts.map +1 -1
- package/dist/modules/deals/schema.js +6 -11
- package/dist/modules/deals/schema.js.map +1 -1
- package/dist/modules/deals/service.d.ts +13 -2
- package/dist/modules/deals/service.d.ts.map +1 -1
- package/dist/modules/deals/service.js +43 -20
- package/dist/modules/deals/service.js.map +1 -1
- package/dist/modules/decisions/repository.d.ts.map +1 -1
- package/dist/modules/decisions/repository.js +2 -0
- package/dist/modules/decisions/repository.js.map +1 -1
- package/dist/modules/decisions/routes.d.ts +1 -0
- package/dist/modules/decisions/routes.d.ts.map +1 -1
- package/dist/modules/enquiries/events.d.ts +44 -0
- package/dist/modules/enquiries/events.d.ts.map +1 -0
- package/dist/modules/enquiries/events.js +19 -0
- package/dist/modules/enquiries/events.js.map +1 -0
- package/dist/modules/enquiries/index.d.ts +13 -0
- package/dist/modules/enquiries/index.d.ts.map +1 -0
- package/dist/modules/enquiries/index.js +44 -0
- package/dist/modules/enquiries/index.js.map +1 -0
- package/dist/modules/enquiries/repository.d.ts +30 -0
- package/dist/modules/enquiries/repository.d.ts.map +1 -0
- package/dist/modules/enquiries/repository.js +94 -0
- package/dist/modules/enquiries/repository.js.map +1 -0
- package/dist/modules/enquiries/routes.d.ts +52 -0
- package/dist/modules/enquiries/routes.d.ts.map +1 -0
- package/dist/modules/enquiries/routes.js +127 -0
- package/dist/modules/enquiries/routes.js.map +1 -0
- package/dist/modules/enquiries/schema.d.ts +290 -0
- package/dist/modules/enquiries/schema.d.ts.map +1 -0
- package/dist/modules/enquiries/schema.js +52 -0
- package/dist/modules/enquiries/schema.js.map +1 -0
- package/dist/modules/enquiries/service.d.ts +85 -0
- package/dist/modules/enquiries/service.d.ts.map +1 -0
- package/dist/modules/enquiries/service.js +370 -0
- package/dist/modules/enquiries/service.js.map +1 -0
- package/dist/modules/enquiries/tools.d.ts +4 -0
- package/dist/modules/enquiries/tools.d.ts.map +1 -0
- package/dist/modules/enquiries/tools.js +50 -0
- package/dist/modules/enquiries/tools.js.map +1 -0
- package/dist/modules/eventCatalogs.d.ts +3 -0
- package/dist/modules/eventCatalogs.d.ts.map +1 -1
- package/dist/modules/eventCatalogs.js +3 -0
- package/dist/modules/eventCatalogs.js.map +1 -1
- package/dist/modules/forms/embed.d.ts +20 -6
- package/dist/modules/forms/embed.d.ts.map +1 -1
- package/dist/modules/forms/embed.js +359 -43
- package/dist/modules/forms/embed.js.map +1 -1
- package/dist/modules/forms/events.d.ts +20 -7
- package/dist/modules/forms/events.d.ts.map +1 -1
- package/dist/modules/forms/events.js +20 -2
- package/dist/modules/forms/events.js.map +1 -1
- package/dist/modules/forms/fields.d.ts +14 -1
- package/dist/modules/forms/fields.d.ts.map +1 -1
- package/dist/modules/forms/fields.js +87 -3
- package/dist/modules/forms/fields.js.map +1 -1
- package/dist/modules/forms/index.d.ts.map +1 -1
- package/dist/modules/forms/index.js +12 -1
- package/dist/modules/forms/index.js.map +1 -1
- package/dist/modules/forms/mapping.d.ts +62 -5
- package/dist/modules/forms/mapping.d.ts.map +1 -1
- package/dist/modules/forms/mapping.js +139 -5
- package/dist/modules/forms/mapping.js.map +1 -1
- package/dist/modules/forms/publicRoutes.d.ts.map +1 -1
- package/dist/modules/forms/publicRoutes.js +29 -1
- package/dist/modules/forms/publicRoutes.js.map +1 -1
- package/dist/modules/forms/repository.d.ts +31 -0
- package/dist/modules/forms/repository.d.ts.map +1 -1
- package/dist/modules/forms/repository.js +90 -1
- package/dist/modules/forms/repository.js.map +1 -1
- package/dist/modules/forms/routes.d.ts +83 -1
- package/dist/modules/forms/routes.d.ts.map +1 -1
- package/dist/modules/forms/routes.js +185 -2
- package/dist/modules/forms/routes.js.map +1 -1
- package/dist/modules/forms/schema.d.ts +672 -1
- package/dist/modules/forms/schema.d.ts.map +1 -1
- package/dist/modules/forms/schema.js +146 -3
- package/dist/modules/forms/schema.js.map +1 -1
- package/dist/modules/forms/service.d.ts +54 -1
- package/dist/modules/forms/service.d.ts.map +1 -1
- package/dist/modules/forms/service.js +338 -28
- package/dist/modules/forms/service.js.map +1 -1
- package/dist/modules/forms/submission.d.ts +15 -0
- package/dist/modules/forms/submission.d.ts.map +1 -1
- package/dist/modules/forms/submission.js +418 -40
- package/dist/modules/forms/submission.js.map +1 -1
- package/dist/modules/import-export/drafts.d.ts +10 -0
- package/dist/modules/import-export/drafts.d.ts.map +1 -1
- package/dist/modules/import-export/drafts.js +16 -2
- package/dist/modules/import-export/drafts.js.map +1 -1
- package/dist/modules/import-export/exportRows.d.ts +7 -4
- package/dist/modules/import-export/exportRows.d.ts.map +1 -1
- package/dist/modules/import-export/exportRows.js +20 -5
- package/dist/modules/import-export/exportRows.js.map +1 -1
- package/dist/modules/import-export/plan.d.ts +12 -1
- package/dist/modules/import-export/plan.d.ts.map +1 -1
- package/dist/modules/import-export/plan.js +29 -2
- package/dist/modules/import-export/plan.js.map +1 -1
- package/dist/modules/import-export/presets.d.ts.map +1 -1
- package/dist/modules/import-export/presets.js +10 -0
- package/dist/modules/import-export/presets.js.map +1 -1
- package/dist/modules/import-export/repository.d.ts +11 -1
- package/dist/modules/import-export/repository.d.ts.map +1 -1
- package/dist/modules/import-export/repository.js +42 -9
- package/dist/modules/import-export/repository.js.map +1 -1
- package/dist/modules/import-export/routes.d.ts.map +1 -1
- package/dist/modules/import-export/routes.js +4 -0
- package/dist/modules/import-export/routes.js.map +1 -1
- package/dist/modules/import-export/schema.d.ts +17 -0
- package/dist/modules/import-export/schema.d.ts.map +1 -1
- package/dist/modules/import-export/schema.js +11 -0
- package/dist/modules/import-export/schema.js.map +1 -1
- package/dist/modules/import-export/service.d.ts +6 -0
- package/dist/modules/import-export/service.d.ts.map +1 -1
- package/dist/modules/import-export/service.js +14 -2
- package/dist/modules/import-export/service.js.map +1 -1
- package/dist/modules/import-export/streams.d.ts.map +1 -1
- package/dist/modules/import-export/streams.js +3 -3
- package/dist/modules/import-export/streams.js.map +1 -1
- package/dist/modules/import-export/tools.d.ts.map +1 -1
- package/dist/modules/import-export/tools.js +8 -0
- package/dist/modules/import-export/tools.js.map +1 -1
- package/dist/modules/import-export/validation.d.ts.map +1 -1
- package/dist/modules/import-export/validation.js +22 -1
- package/dist/modules/import-export/validation.js.map +1 -1
- package/dist/modules/import-export/writes.d.ts.map +1 -1
- package/dist/modules/import-export/writes.js +37 -4
- package/dist/modules/import-export/writes.js.map +1 -1
- package/dist/modules/lists/repository.d.ts +11 -0
- package/dist/modules/lists/repository.d.ts.map +1 -1
- package/dist/modules/lists/repository.js +13 -0
- package/dist/modules/lists/repository.js.map +1 -1
- package/dist/modules/lists/routes.d.ts +4 -0
- package/dist/modules/lists/routes.d.ts.map +1 -1
- package/dist/modules/lists/routes.js +8 -0
- package/dist/modules/lists/routes.js.map +1 -1
- package/dist/modules/lists/schema.d.ts +17 -0
- package/dist/modules/lists/schema.d.ts.map +1 -1
- package/dist/modules/lists/schema.js +10 -0
- package/dist/modules/lists/schema.js.map +1 -1
- package/dist/modules/lists/service.d.ts +14 -2
- package/dist/modules/lists/service.d.ts.map +1 -1
- package/dist/modules/lists/service.js +55 -7
- package/dist/modules/lists/service.js.map +1 -1
- package/dist/modules/mcp/index.d.ts.map +1 -1
- package/dist/modules/mcp/index.js +5 -0
- package/dist/modules/mcp/index.js.map +1 -1
- package/dist/modules/notes/routes.d.ts +1 -0
- package/dist/modules/notes/routes.d.ts.map +1 -1
- package/dist/modules/opportunities/index.d.ts.map +1 -1
- package/dist/modules/opportunities/index.js +3 -1
- package/dist/modules/opportunities/index.js.map +1 -1
- package/dist/modules/opportunities/repository.d.ts +2 -0
- package/dist/modules/opportunities/repository.d.ts.map +1 -1
- package/dist/modules/opportunities/repository.js +4 -0
- package/dist/modules/opportunities/repository.js.map +1 -1
- package/dist/modules/opportunities/routes.d.ts +16 -0
- package/dist/modules/opportunities/routes.d.ts.map +1 -1
- package/dist/modules/opportunities/routes.js +13 -0
- package/dist/modules/opportunities/routes.js.map +1 -1
- package/dist/modules/opportunities/schema.d.ts +20 -0
- package/dist/modules/opportunities/schema.d.ts.map +1 -1
- package/dist/modules/opportunities/schema.js +6 -1
- package/dist/modules/opportunities/schema.js.map +1 -1
- package/dist/modules/opportunities/service.d.ts +20 -3
- package/dist/modules/opportunities/service.d.ts.map +1 -1
- package/dist/modules/opportunities/service.js +99 -18
- package/dist/modules/opportunities/service.js.map +1 -1
- package/dist/modules/opportunities/tools.d.ts.map +1 -1
- package/dist/modules/opportunities/tools.js +2 -0
- package/dist/modules/opportunities/tools.js.map +1 -1
- package/dist/modules/partnerships/index.d.ts.map +1 -1
- package/dist/modules/partnerships/index.js +3 -1
- package/dist/modules/partnerships/index.js.map +1 -1
- package/dist/modules/partnerships/repository.d.ts +0 -17
- package/dist/modules/partnerships/repository.d.ts.map +1 -1
- package/dist/modules/partnerships/repository.js +6 -82
- package/dist/modules/partnerships/repository.js.map +1 -1
- package/dist/modules/partnerships/routes.d.ts +14 -0
- package/dist/modules/partnerships/routes.d.ts.map +1 -1
- package/dist/modules/partnerships/routes.js +7 -0
- package/dist/modules/partnerships/routes.js.map +1 -1
- package/dist/modules/partnerships/schema.d.ts +20 -41
- package/dist/modules/partnerships/schema.d.ts.map +1 -1
- package/dist/modules/partnerships/schema.js +6 -10
- package/dist/modules/partnerships/schema.js.map +1 -1
- package/dist/modules/partnerships/service.d.ts +11 -1
- package/dist/modules/partnerships/service.d.ts.map +1 -1
- package/dist/modules/partnerships/service.js +43 -20
- package/dist/modules/partnerships/service.js.map +1 -1
- package/dist/modules/people/consentHydration.d.ts +26 -0
- package/dist/modules/people/consentHydration.d.ts.map +1 -0
- package/dist/modules/people/consentHydration.js +100 -0
- package/dist/modules/people/consentHydration.js.map +1 -0
- package/dist/modules/people/index.d.ts.map +1 -1
- package/dist/modules/people/index.js +3 -1
- package/dist/modules/people/index.js.map +1 -1
- package/dist/modules/people/personConsentWrites.d.ts +40 -0
- package/dist/modules/people/personConsentWrites.d.ts.map +1 -0
- package/dist/modules/people/personConsentWrites.js +98 -0
- package/dist/modules/people/personConsentWrites.js.map +1 -0
- package/dist/modules/people/repository.d.ts.map +1 -1
- package/dist/modules/people/repository.js +5 -1
- package/dist/modules/people/repository.js.map +1 -1
- package/dist/modules/people/routes.d.ts +57 -4
- package/dist/modules/people/routes.d.ts.map +1 -1
- package/dist/modules/people/routes.js +104 -5
- package/dist/modules/people/routes.js.map +1 -1
- package/dist/modules/people/schema.d.ts +366 -1
- package/dist/modules/people/schema.d.ts.map +1 -1
- package/dist/modules/people/schema.js +92 -2
- package/dist/modules/people/schema.js.map +1 -1
- package/dist/modules/people/service.d.ts +30 -1
- package/dist/modules/people/service.d.ts.map +1 -1
- package/dist/modules/people/service.js +115 -38
- package/dist/modules/people/service.js.map +1 -1
- package/dist/modules/people/tools.d.ts.map +1 -1
- package/dist/modules/people/tools.js +4 -1
- package/dist/modules/people/tools.js.map +1 -1
- package/dist/modules/personLinks.d.ts +79 -0
- package/dist/modules/personLinks.d.ts.map +1 -0
- package/dist/modules/personLinks.js +155 -0
- package/dist/modules/personLinks.js.map +1 -0
- package/dist/modules/pipelines/routes.d.ts +1 -0
- package/dist/modules/pipelines/routes.d.ts.map +1 -1
- package/dist/modules/plans/routes.d.ts +1 -0
- package/dist/modules/plans/routes.d.ts.map +1 -1
- package/dist/modules/raises/index.d.ts.map +1 -1
- package/dist/modules/raises/index.js +3 -1
- package/dist/modules/raises/index.js.map +1 -1
- package/dist/modules/raises/repository.d.ts +0 -17
- package/dist/modules/raises/repository.d.ts.map +1 -1
- package/dist/modules/raises/repository.js +6 -77
- package/dist/modules/raises/repository.js.map +1 -1
- package/dist/modules/raises/routes.d.ts +14 -0
- package/dist/modules/raises/routes.d.ts.map +1 -1
- package/dist/modules/raises/routes.js +7 -0
- package/dist/modules/raises/routes.js.map +1 -1
- package/dist/modules/raises/schema.d.ts +20 -41
- package/dist/modules/raises/schema.d.ts.map +1 -1
- package/dist/modules/raises/schema.js +6 -10
- package/dist/modules/raises/schema.js.map +1 -1
- package/dist/modules/raises/service.d.ts +11 -1
- package/dist/modules/raises/service.d.ts.map +1 -1
- package/dist/modules/raises/service.js +41 -18
- package/dist/modules/raises/service.js.map +1 -1
- package/dist/modules/recordTargets.d.ts.map +1 -1
- package/dist/modules/recordTargets.js +2 -0
- package/dist/modules/recordTargets.js.map +1 -1
- package/dist/modules/references.d.ts +10 -0
- package/dist/modules/references.d.ts.map +1 -1
- package/dist/modules/references.js +27 -4
- package/dist/modules/references.js.map +1 -1
- package/dist/modules/sample-data/fixture.d.ts +21 -0
- package/dist/modules/sample-data/fixture.d.ts.map +1 -1
- package/dist/modules/sample-data/fixture.js +40 -0
- package/dist/modules/sample-data/fixture.js.map +1 -1
- package/dist/modules/sample-data/index.d.ts.map +1 -1
- package/dist/modules/sample-data/index.js +1 -0
- package/dist/modules/sample-data/index.js.map +1 -1
- package/dist/modules/sample-data/routes.d.ts.map +1 -1
- package/dist/modules/sample-data/routes.js +1 -0
- package/dist/modules/sample-data/routes.js.map +1 -1
- package/dist/modules/sample-data/service.d.ts +1 -0
- package/dist/modules/sample-data/service.d.ts.map +1 -1
- package/dist/modules/sample-data/service.js +77 -8
- package/dist/modules/sample-data/service.js.map +1 -1
- package/dist/modules/search/index.d.ts +1 -1
- package/dist/modules/search/index.d.ts.map +1 -1
- package/dist/modules/search/index.js +2 -1
- package/dist/modules/search/index.js.map +1 -1
- package/dist/modules/search/repository.d.ts +1 -0
- package/dist/modules/search/repository.d.ts.map +1 -1
- package/dist/modules/search/repository.js +23 -0
- package/dist/modules/search/repository.js.map +1 -1
- package/dist/modules/search/service.d.ts +3 -3
- package/dist/modules/search/service.d.ts.map +1 -1
- package/dist/modules/search/service.js +5 -4
- package/dist/modules/search/service.js.map +1 -1
- package/dist/modules/stagedRecords.d.ts +3 -3
- package/dist/modules/stagedRecords.d.ts.map +1 -1
- package/dist/modules/stagedRecords.js +9 -0
- package/dist/modules/stagedRecords.js.map +1 -1
- package/dist/modules/webhooks/payloads.d.ts.map +1 -1
- package/dist/modules/webhooks/payloads.js +15 -2
- package/dist/modules/webhooks/payloads.js.map +1 -1
- package/dist/modules/workspace/repository.d.ts +2 -0
- package/dist/modules/workspace/repository.d.ts.map +1 -1
- package/dist/modules/workspace/repository.js +7 -0
- package/dist/modules/workspace/repository.js.map +1 -1
- package/dist/modules/workspace/service.d.ts.map +1 -1
- package/dist/modules/workspace/service.js +10 -0
- package/dist/modules/workspace/service.js.map +1 -1
- package/dist/modules/workspace/starters.d.ts.map +1 -1
- package/dist/modules/workspace/starters.js +5 -0
- package/dist/modules/workspace/starters.js.map +1 -1
- package/dist/runtime/events.d.ts +1 -1
- package/dist/runtime/events.d.ts.map +1 -1
- package/dist/runtime/events.js +1 -0
- package/dist/runtime/events.js.map +1 -1
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/testing/database.d.ts +5 -1
- package/dist/testing/database.d.ts.map +1 -1
- package/dist/testing/database.js +81 -10
- package/dist/testing/database.js.map +1 -1
- package/migrations/0024_third_king_cobra.sql +46 -0
- package/migrations/0025_worthless_chimera.sql +3 -0
- package/migrations/0026_late_aqueduct.sql +46 -0
- package/migrations/0027_brainy_silver_sable.sql +3 -0
- package/migrations/0028_freezing_scrambler.sql +19 -0
- package/migrations/0029_custom_fields.sql +26 -0
- package/migrations/0030_enquiries.sql +79 -0
- package/migrations/0031_consent.sql +45 -0
- package/migrations/0032_form_field_statement.sql +1 -0
- package/migrations/0033_form_field_consent_purpose_ids.sql +5 -0
- package/migrations/0034_drop_form_field_consent_purpose_id.sql +1 -0
- package/migrations/0035_form_field_consent_purpose_labels.sql +1 -0
- package/migrations/0036_form_field_notice_type.sql +2 -0
- package/migrations/meta/0024_snapshot.json +5516 -0
- package/migrations/meta/0025_snapshot.json +5336 -0
- package/migrations/meta/0026_snapshot.json +5710 -0
- package/migrations/meta/0027_snapshot.json +5716 -0
- package/migrations/meta/0028_snapshot.json +5740 -0
- package/migrations/meta/0029_snapshot.json +5935 -0
- package/migrations/meta/0030_snapshot.json +6245 -0
- package/migrations/meta/0031_snapshot.json +6572 -0
- package/migrations/meta/0032_snapshot.json +6578 -0
- package/migrations/meta/0033_snapshot.json +6572 -0
- package/migrations/meta/0034_snapshot.json +6566 -0
- package/migrations/meta/0035_snapshot.json +6573 -0
- package/migrations/meta/0036_snapshot.json +6573 -0
- package/migrations/meta/_journal.json +91 -0
- package/package.json +2 -2
- package/src/lib/ids.ts +11 -0
- package/src/modules/activities/repository.ts +22 -23
- package/src/modules/activities/wording.ts +18 -0
- package/src/modules/agent-tasks/catalog.ts +63 -0
- package/src/modules/agent-tasks/resolve.ts +64 -24
- package/src/modules/attachedRecords.ts +29 -2
- package/src/modules/companies/index.ts +3 -1
- package/src/modules/companies/routes.ts +7 -0
- package/src/modules/companies/schema.ts +7 -1
- package/src/modules/companies/service.ts +48 -13
- package/src/modules/consent-purposes/capabilities.ts +12 -0
- package/src/modules/consent-purposes/events.ts +38 -0
- package/src/modules/consent-purposes/index.ts +48 -0
- package/src/modules/consent-purposes/repository.ts +163 -0
- package/src/modules/consent-purposes/routes.ts +122 -0
- package/src/modules/consent-purposes/schema.ts +46 -0
- package/src/modules/consent-purposes/service.ts +423 -0
- package/src/modules/consent-purposes/starters.ts +32 -0
- package/src/modules/consent-purposes/tools.ts +44 -0
- package/src/modules/core.ts +10 -0
- package/src/modules/custom-fields/capabilities.ts +17 -0
- package/src/modules/custom-fields/events.ts +51 -0
- package/src/modules/custom-fields/index.ts +61 -0
- package/src/modules/custom-fields/repository.ts +225 -0
- package/src/modules/custom-fields/routes.ts +155 -0
- package/src/modules/custom-fields/schema.ts +61 -0
- package/src/modules/custom-fields/service.ts +439 -0
- package/src/modules/custom-fields/tools.ts +53 -0
- package/src/modules/custom-fields/values.ts +352 -0
- package/src/modules/custom-fields/wire.ts +32 -0
- package/src/modules/dashboard/repository.ts +4 -3
- package/src/modules/deals/index.ts +5 -2
- package/src/modules/deals/repository.ts +6 -106
- package/src/modules/deals/routes.ts +7 -0
- package/src/modules/deals/schema.ts +7 -15
- package/src/modules/deals/service.ts +92 -23
- package/src/modules/decisions/repository.ts +2 -0
- package/src/modules/enquiries/events.ts +45 -0
- package/src/modules/enquiries/index.ts +50 -0
- package/src/modules/enquiries/repository.ts +164 -0
- package/src/modules/enquiries/routes.ts +172 -0
- package/src/modules/enquiries/schema.ts +59 -0
- package/src/modules/enquiries/service.ts +644 -0
- package/src/modules/enquiries/tools.ts +66 -0
- package/src/modules/eventCatalogs.ts +3 -0
- package/src/modules/forms/embed.ts +391 -44
- package/src/modules/forms/events.ts +30 -2
- package/src/modules/forms/fields.ts +102 -2
- package/src/modules/forms/index.ts +12 -1
- package/src/modules/forms/mapping.ts +183 -6
- package/src/modules/forms/publicRoutes.ts +43 -1
- package/src/modules/forms/repository.ts +162 -1
- package/src/modules/forms/routes.ts +212 -2
- package/src/modules/forms/schema.ts +166 -4
- package/src/modules/forms/service.ts +565 -41
- package/src/modules/forms/submission.ts +718 -44
- package/src/modules/import-export/drafts.ts +20 -1
- package/src/modules/import-export/exportRows.ts +21 -5
- package/src/modules/import-export/plan.ts +47 -2
- package/src/modules/import-export/presets.ts +10 -0
- package/src/modules/import-export/repository.ts +73 -8
- package/src/modules/import-export/routes.ts +4 -0
- package/src/modules/import-export/schema.ts +11 -0
- package/src/modules/import-export/service.ts +28 -2
- package/src/modules/import-export/streams.ts +3 -1
- package/src/modules/import-export/tools.ts +10 -0
- package/src/modules/import-export/validation.ts +28 -0
- package/src/modules/import-export/writes.ts +70 -5
- package/src/modules/lists/repository.ts +30 -0
- package/src/modules/lists/routes.ts +8 -0
- package/src/modules/lists/schema.ts +10 -0
- package/src/modules/lists/service.ts +110 -9
- package/src/modules/mcp/index.ts +5 -0
- package/src/modules/opportunities/index.ts +3 -1
- package/src/modules/opportunities/repository.ts +11 -0
- package/src/modules/opportunities/routes.ts +13 -0
- package/src/modules/opportunities/schema.ts +7 -1
- package/src/modules/opportunities/service.ts +188 -22
- package/src/modules/opportunities/tools.ts +2 -0
- package/src/modules/partnerships/index.ts +3 -1
- package/src/modules/partnerships/repository.ts +6 -117
- package/src/modules/partnerships/routes.ts +7 -0
- package/src/modules/partnerships/schema.ts +7 -14
- package/src/modules/partnerships/service.ts +93 -22
- package/src/modules/people/consentHydration.ts +167 -0
- package/src/modules/people/index.ts +3 -1
- package/src/modules/people/personConsentWrites.ts +177 -0
- package/src/modules/people/repository.ts +5 -0
- package/src/modules/people/routes.ts +127 -18
- package/src/modules/people/schema.ts +109 -3
- package/src/modules/people/service.ts +186 -40
- package/src/modules/people/tools.ts +5 -1
- package/src/modules/personLinks.ts +278 -0
- package/src/modules/raises/index.ts +3 -1
- package/src/modules/raises/repository.ts +6 -107
- package/src/modules/raises/routes.ts +7 -0
- package/src/modules/raises/schema.ts +7 -14
- package/src/modules/raises/service.ts +91 -20
- package/src/modules/recordTargets.ts +2 -0
- package/src/modules/references.ts +43 -4
- package/src/modules/sample-data/fixture.ts +63 -0
- package/src/modules/sample-data/index.ts +1 -0
- package/src/modules/sample-data/routes.ts +1 -0
- package/src/modules/sample-data/service.ts +97 -8
- package/src/modules/search/index.ts +2 -1
- package/src/modules/search/repository.ts +33 -1
- package/src/modules/search/service.ts +7 -5
- package/src/modules/stagedRecords.ts +18 -3
- package/src/modules/webhooks/payloads.ts +20 -2
- package/src/modules/workspace/repository.ts +12 -0
- package/src/modules/workspace/service.ts +14 -0
- package/src/modules/workspace/starters.ts +5 -0
- package/src/runtime/events.ts +1 -0
- package/src/schema/index.ts +3 -0
- package/src/testing/database.ts +97 -11
|
@@ -3,6 +3,9 @@ import type { StoredFormFieldOption } from './schema.ts'
|
|
|
3
3
|
import { PERSON_EMAIL_TARGET } from './schema.ts'
|
|
4
4
|
import type { FormFieldMapTarget, FormFieldType, FormOptionValueType } from './schema.ts'
|
|
5
5
|
|
|
6
|
+
/** The map target for a consent field. Repeatable, unique per purpose_id. */
|
|
7
|
+
const PERSON_CONSENT_TARGET = 'person.consent'
|
|
8
|
+
|
|
6
9
|
/**
|
|
7
10
|
* What a form's field list has to satisfy before it is stored.
|
|
8
11
|
*
|
|
@@ -20,6 +23,12 @@ export interface FieldDraft {
|
|
|
20
23
|
readonly mapTo: FormFieldMapTarget
|
|
21
24
|
readonly options: readonly OptionDraft[]
|
|
22
25
|
readonly placeholder: string | null
|
|
26
|
+
/** The intro sentence for a `consent` field. Ignored for every other type. */
|
|
27
|
+
readonly statement: string | null
|
|
28
|
+
/** Non-empty for `consent` fields; one checkbox per id in display order. */
|
|
29
|
+
readonly consentPurposeIds: readonly string[]
|
|
30
|
+
/** Per-purpose override for the checkbox text. Falls back to the workspace label. */
|
|
31
|
+
readonly consentPurposeLabels: Readonly<Record<string, string>>
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
export interface OptionDraft {
|
|
@@ -52,13 +61,19 @@ const COMPANY_TARGETS: readonly string[] = ['company.name', 'company.domain']
|
|
|
52
61
|
* or `company.domain` answer, so a deal-creating form without either would
|
|
53
62
|
* quietly never create a deal. Refused here rather than discovered later by
|
|
54
63
|
* somebody wondering where their inbound pipeline went.
|
|
64
|
+
* @param createsPartnership Same rule for partnerships: a Partnership belongs
|
|
65
|
+
* to a Company. Opportunities are exempt because `opportunities.company_id`
|
|
66
|
+
* is nullable — a form that creates an opportunity without resolving a
|
|
67
|
+
* company creates an opportunity without one, which is a valid state.
|
|
55
68
|
*/
|
|
56
69
|
export function findFieldProblems(
|
|
57
70
|
fields: readonly FieldShape[],
|
|
58
71
|
createsDeal: boolean,
|
|
72
|
+
createsPartnership = false,
|
|
59
73
|
): readonly ErrorDetail[] {
|
|
60
74
|
const problems: ErrorDetail[] = []
|
|
61
75
|
const seenTargets = new Set<string>()
|
|
76
|
+
const usedConsentPurposes = new Set<string>()
|
|
62
77
|
|
|
63
78
|
if (!fields.some((field) => field.mapTo === PERSON_EMAIL_TARGET)) {
|
|
64
79
|
problems.push({
|
|
@@ -67,17 +82,78 @@ export function findFieldProblems(
|
|
|
67
82
|
})
|
|
68
83
|
}
|
|
69
84
|
|
|
70
|
-
|
|
85
|
+
const hasCompanyField = fields.some((field) => COMPANY_TARGETS.includes(field.mapTo))
|
|
86
|
+
|
|
87
|
+
if (createsDeal && !hasCompanyField) {
|
|
71
88
|
problems.push({
|
|
72
89
|
field: 'fields',
|
|
73
90
|
message: `A form that creates deals needs a field mapped to ${COMPANY_TARGETS.join(' or ')}`,
|
|
74
91
|
})
|
|
75
92
|
}
|
|
76
93
|
|
|
94
|
+
if (createsPartnership && !hasCompanyField) {
|
|
95
|
+
problems.push({
|
|
96
|
+
field: 'fields',
|
|
97
|
+
message: `A form that creates partnerships needs a field mapped to ${COMPANY_TARGETS.join(' or ')}`,
|
|
98
|
+
})
|
|
99
|
+
}
|
|
100
|
+
|
|
77
101
|
for (const [index, field] of fields.entries()) {
|
|
78
102
|
const at = `fields.${String(index)}`
|
|
79
103
|
|
|
80
|
-
|
|
104
|
+
// `person.consent` is repeatable — a form may carry more than one consent
|
|
105
|
+
// (checkbox) or notice (implicit) field, each offering its own list of
|
|
106
|
+
// purposes — but no purpose may appear on two fields, whether as the
|
|
107
|
+
// same field's duplicate or on two fields at once. Everything else
|
|
108
|
+
// non-`submission` is unique per form.
|
|
109
|
+
if (field.mapTo === PERSON_CONSENT_TARGET) {
|
|
110
|
+
if (field.type !== 'consent' && field.type !== 'notice') {
|
|
111
|
+
problems.push({
|
|
112
|
+
field: `${at}.type`,
|
|
113
|
+
message: 'A person.consent field must be of type "consent" or "notice"',
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
if (field.type === 'notice' && (field.statement ?? '').trim().length === 0) {
|
|
117
|
+
problems.push({
|
|
118
|
+
field: `${at}.statement`,
|
|
119
|
+
message: 'A notice field needs a statement',
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
if (field.consentPurposeIds.length === 0) {
|
|
123
|
+
problems.push({
|
|
124
|
+
field: `${at}.consent_purpose_ids`,
|
|
125
|
+
message:
|
|
126
|
+
field.type === 'notice'
|
|
127
|
+
? 'A notice field needs at least one purpose it grants implicitly'
|
|
128
|
+
: 'A consent field needs at least one purpose',
|
|
129
|
+
})
|
|
130
|
+
} else {
|
|
131
|
+
const seenLocal = new Set<string>()
|
|
132
|
+
for (const purposeId of field.consentPurposeIds) {
|
|
133
|
+
if (seenLocal.has(purposeId)) {
|
|
134
|
+
problems.push({
|
|
135
|
+
field: `${at}.consent_purpose_ids`,
|
|
136
|
+
message: 'A consent field lists each purpose only once',
|
|
137
|
+
})
|
|
138
|
+
break
|
|
139
|
+
}
|
|
140
|
+
seenLocal.add(purposeId)
|
|
141
|
+
if (usedConsentPurposes.has(purposeId)) {
|
|
142
|
+
problems.push({
|
|
143
|
+
field: `${at}.consent_purpose_ids`,
|
|
144
|
+
message: 'Another consent field on this form already names this purpose',
|
|
145
|
+
})
|
|
146
|
+
} else {
|
|
147
|
+
usedConsentPurposes.add(purposeId)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
} else if (field.type === 'consent' || field.type === 'notice') {
|
|
152
|
+
problems.push({
|
|
153
|
+
field: `${at}.map_to`,
|
|
154
|
+
message: 'A consent or notice field must map to person.consent',
|
|
155
|
+
})
|
|
156
|
+
} else if (!REPEATABLE_TARGETS.has(field.mapTo)) {
|
|
81
157
|
if (seenTargets.has(field.mapTo)) {
|
|
82
158
|
problems.push({ field: `${at}.map_to`, message: `Another field already maps to ${field.mapTo}` })
|
|
83
159
|
}
|
|
@@ -150,6 +226,9 @@ export interface FieldShape {
|
|
|
150
226
|
readonly mapTo: string
|
|
151
227
|
readonly options: readonly StoredFormFieldOption[]
|
|
152
228
|
readonly placeholder: string | null
|
|
229
|
+
readonly statement: string | null
|
|
230
|
+
readonly consentPurposeIds: readonly string[]
|
|
231
|
+
readonly consentPurposeLabels: Readonly<Record<string, string>>
|
|
153
232
|
}
|
|
154
233
|
|
|
155
234
|
/**
|
|
@@ -180,11 +259,32 @@ export function fieldsDiffer(
|
|
|
180
259
|
field.required !== draft.required ||
|
|
181
260
|
field.mapTo !== draft.mapTo ||
|
|
182
261
|
field.placeholder !== draft.placeholder ||
|
|
262
|
+
field.statement !== draft.statement ||
|
|
263
|
+
stringListDiffer(field.consentPurposeIds, draft.consentPurposeIds) ||
|
|
264
|
+
labelMapDiffer(field.consentPurposeLabels, draft.consentPurposeLabels) ||
|
|
183
265
|
optionsDiffer(field.options, draft.options)
|
|
184
266
|
)
|
|
185
267
|
})
|
|
186
268
|
}
|
|
187
269
|
|
|
270
|
+
function labelMapDiffer(
|
|
271
|
+
stored: Readonly<Record<string, string>>,
|
|
272
|
+
drafts: Readonly<Record<string, string>>,
|
|
273
|
+
): boolean {
|
|
274
|
+
const storedKeys = Object.keys(stored)
|
|
275
|
+
const draftKeys = Object.keys(drafts)
|
|
276
|
+
if (storedKeys.length !== draftKeys.length) return true
|
|
277
|
+
return storedKeys.some((key) => stored[key] !== drafts[key])
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
function stringListDiffer(
|
|
281
|
+
stored: readonly string[],
|
|
282
|
+
drafts: readonly string[],
|
|
283
|
+
): boolean {
|
|
284
|
+
if (stored.length !== drafts.length) return true
|
|
285
|
+
return stored.some((value, index) => value !== drafts[index])
|
|
286
|
+
}
|
|
287
|
+
|
|
188
288
|
function optionsDiffer(
|
|
189
289
|
stored: readonly StoredFormFieldOption[],
|
|
190
290
|
drafts: readonly OptionDraft[],
|
|
@@ -23,7 +23,18 @@ import { registerFormsTools } from './tools.ts'
|
|
|
23
23
|
export function createFormsModule(migrationsDirectory: string): KelpieModule {
|
|
24
24
|
return {
|
|
25
25
|
id: 'forms',
|
|
26
|
-
requires: [
|
|
26
|
+
requires: [
|
|
27
|
+
'people',
|
|
28
|
+
'companies',
|
|
29
|
+
'positions',
|
|
30
|
+
'pipelines',
|
|
31
|
+
'deals',
|
|
32
|
+
'opportunities',
|
|
33
|
+
'partnerships',
|
|
34
|
+
'raises',
|
|
35
|
+
'lists',
|
|
36
|
+
'activities',
|
|
37
|
+
],
|
|
27
38
|
events: formsEvents,
|
|
28
39
|
|
|
29
40
|
register(context) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { composeName } from '@kelpie/schemas'
|
|
2
|
+
|
|
1
3
|
import type { ErrorDetail } from '../../lib/errors.ts'
|
|
2
4
|
import { normaliseDomain, normaliseEmail } from '../../lib/normalisation.ts'
|
|
3
5
|
import type { FormFieldRecord } from './repository.ts'
|
|
@@ -29,14 +31,48 @@ export type MappedAnswers = Partial<Record<FormFieldMapTarget, string>>
|
|
|
29
31
|
export interface SubmitIntent {
|
|
30
32
|
/** Normalised. The one value a submit cannot proceed without. */
|
|
31
33
|
readonly email: string
|
|
32
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* The name given, the one composed from the first and last name answers, or —
|
|
36
|
+
* when the form asked for no name at all — the part of the address before the
|
|
37
|
+
* `@`.
|
|
38
|
+
*/
|
|
33
39
|
readonly personName: string
|
|
40
|
+
/** The `person.first_name` answer only. Never split out of `personName`. */
|
|
41
|
+
readonly personFirstName: string | undefined
|
|
42
|
+
readonly personLastName: string | undefined
|
|
34
43
|
readonly companyName: string | undefined
|
|
35
44
|
/** The `company.domain` answer only. Never derived from the address; see `resolveDomain`. */
|
|
36
45
|
readonly companyDomain: string | undefined
|
|
37
46
|
readonly positionTitle: string | undefined
|
|
38
47
|
/** Only meaningful when the form creates deals. */
|
|
39
48
|
readonly dealName: string | undefined
|
|
49
|
+
/** Only meaningful when the form creates opportunities. */
|
|
50
|
+
readonly opportunityName: string | undefined
|
|
51
|
+
/** Only meaningful when the form creates partnerships. */
|
|
52
|
+
readonly partnershipName: string | undefined
|
|
53
|
+
/** Only meaningful when the form creates enquiries. */
|
|
54
|
+
readonly enquiryName: string | undefined
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** True for a consent-field answer that means "ticked". */
|
|
58
|
+
export function isConsentTicked(value: string | undefined): boolean {
|
|
59
|
+
if (value === undefined) return false
|
|
60
|
+
const trimmed = value.trim().toLowerCase()
|
|
61
|
+
return trimmed === 'true' || trimmed === 'on' || trimmed === '1' || trimmed === 'yes'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** One consent grant read off the answers, for the submit transaction to apply. */
|
|
65
|
+
export interface ConsentGrant {
|
|
66
|
+
readonly fieldId: string
|
|
67
|
+
readonly purposeId: string
|
|
68
|
+
/** The field-level intro sentence, shown above every checkbox in the field. */
|
|
69
|
+
readonly statement: string
|
|
70
|
+
/**
|
|
71
|
+
* The field's per-purpose text override for this purpose. Empty when the
|
|
72
|
+
* field defers to the workspace purpose's own label; the submit resolves
|
|
73
|
+
* that fallback with the purpose row it loads to record the activity.
|
|
74
|
+
*/
|
|
75
|
+
readonly customLabel: string
|
|
40
76
|
}
|
|
41
77
|
|
|
42
78
|
/**
|
|
@@ -45,12 +81,18 @@ export interface SubmitIntent {
|
|
|
45
81
|
* Blank answers are dropped, so a submitter who cleared a prefilled field does
|
|
46
82
|
* not overwrite a stored value with nothing. Two fields sharing a target is
|
|
47
83
|
* refused when the form is written, except for `submission`, which writes
|
|
48
|
-
* nothing and so cannot collide.
|
|
84
|
+
* nothing and so cannot collide, and `person.consent`, which is read by
|
|
85
|
+
* {@link readConsentGrants} instead — a form may carry several consent boxes,
|
|
86
|
+
* each granting a different purpose.
|
|
49
87
|
*/
|
|
50
88
|
export function mapAnswers(fields: readonly FormFieldRecord[], answers: Answers): MappedAnswers {
|
|
51
89
|
const mapped: MappedAnswers = {}
|
|
52
90
|
|
|
53
91
|
for (const field of fields) {
|
|
92
|
+
// `person.consent` (both `consent` and `notice` types) is read separately
|
|
93
|
+
// — a checkbox field by ticked ids, a notice implicitly by submission.
|
|
94
|
+
if (field.mapTo === 'person.consent') continue
|
|
95
|
+
|
|
54
96
|
const value = answers[field.id]?.trim()
|
|
55
97
|
|
|
56
98
|
if (value === undefined || value.length === 0) {
|
|
@@ -63,6 +105,67 @@ export function mapAnswers(fields: readonly FormFieldRecord[], answers: Answers)
|
|
|
63
105
|
return mapped
|
|
64
106
|
}
|
|
65
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Every ticked purpose across every consent field on this form, in field
|
|
110
|
+
* order then purpose order. A consent field's answer is a comma-separated
|
|
111
|
+
* list of the purpose ids the visitor ticked; anything not on the field's
|
|
112
|
+
* configured list is dropped silently — the embed offers only what the field
|
|
113
|
+
* declares, so an unlisted id has to be an unusual client.
|
|
114
|
+
*
|
|
115
|
+
* The statement is the field's `statement` when set, else the field's label —
|
|
116
|
+
* the sentence shown above the checkboxes.
|
|
117
|
+
*/
|
|
118
|
+
export function readConsentGrants(
|
|
119
|
+
fields: readonly FormFieldRecord[],
|
|
120
|
+
answers: Answers,
|
|
121
|
+
): readonly ConsentGrant[] {
|
|
122
|
+
const grants: ConsentGrant[] = []
|
|
123
|
+
for (const field of fields) {
|
|
124
|
+
if (field.consentPurposeIds.length === 0) continue
|
|
125
|
+
const statement = field.statement ?? field.label
|
|
126
|
+
|
|
127
|
+
// A `notice` field grants every configured purpose implicitly: the
|
|
128
|
+
// visitor's act of submitting the form is the consent, per the notice
|
|
129
|
+
// text they read. No answer to parse.
|
|
130
|
+
if (field.type === 'notice') {
|
|
131
|
+
for (const purposeId of field.consentPurposeIds) {
|
|
132
|
+
grants.push({
|
|
133
|
+
fieldId: field.id,
|
|
134
|
+
purposeId,
|
|
135
|
+
statement,
|
|
136
|
+
customLabel: '',
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (field.type !== 'consent') continue
|
|
143
|
+
const ticked = parseConsentAnswer(answers[field.id])
|
|
144
|
+
if (ticked.length === 0) continue
|
|
145
|
+
const allowed = new Set(field.consentPurposeIds)
|
|
146
|
+
for (const purposeId of ticked) {
|
|
147
|
+
if (!allowed.has(purposeId)) continue
|
|
148
|
+
grants.push({
|
|
149
|
+
fieldId: field.id,
|
|
150
|
+
purposeId,
|
|
151
|
+
statement,
|
|
152
|
+
customLabel: field.consentPurposeLabels[purposeId] ?? '',
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return grants
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Splits a consent field's answer into the ticked purpose ids. */
|
|
160
|
+
export function parseConsentAnswer(raw: string | undefined): readonly string[] {
|
|
161
|
+
if (raw === undefined) return []
|
|
162
|
+
const parts = raw
|
|
163
|
+
.split(',')
|
|
164
|
+
.map((part) => part.trim())
|
|
165
|
+
.filter((part) => part.length > 0)
|
|
166
|
+
return Array.from(new Set(parts))
|
|
167
|
+
}
|
|
168
|
+
|
|
66
169
|
/**
|
|
67
170
|
* Everything wrong with an answer map, as `api.md` field details.
|
|
68
171
|
*
|
|
@@ -88,6 +191,28 @@ export function findAnswerProblems(
|
|
|
88
191
|
}
|
|
89
192
|
|
|
90
193
|
for (const field of fields) {
|
|
194
|
+
// A consent field's answer is a comma-separated list of ticked purpose
|
|
195
|
+
// ids. Required means at least one must be ticked; unrequired means the
|
|
196
|
+
// list may be empty. Ids not on the field's own list are silently
|
|
197
|
+
// ignored on submit — the embed offers only what the field configures.
|
|
198
|
+
if (field.type === 'consent') {
|
|
199
|
+
const ticked = parseConsentAnswer(answers[field.id])
|
|
200
|
+
if (field.required && ticked.length === 0) {
|
|
201
|
+
problems.push({
|
|
202
|
+
field: `answers.${field.id}`,
|
|
203
|
+
message: `${field.label} needs at least one choice`,
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
continue
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// A notice field carries no answer — its consent is implicit in the
|
|
210
|
+
// submission. `required` is meaningless on it. An answer sent for it is
|
|
211
|
+
// silently ignored; the mapper never reads it either.
|
|
212
|
+
if (field.type === 'notice') {
|
|
213
|
+
continue
|
|
214
|
+
}
|
|
215
|
+
|
|
91
216
|
const value = answers[field.id]?.trim() ?? ''
|
|
92
217
|
|
|
93
218
|
if (value.length === 0) {
|
|
@@ -144,13 +269,30 @@ export function readIntent(mapped: MappedAnswers): SubmitIntent | undefined {
|
|
|
144
269
|
return undefined
|
|
145
270
|
}
|
|
146
271
|
|
|
272
|
+
const firstName = mapped['person.first_name']
|
|
273
|
+
const lastName = mapped['person.last_name']
|
|
274
|
+
// A form that asks for a first and last name rather than one name box is the
|
|
275
|
+
// common arrangement, so the pair composes the display name. The address's
|
|
276
|
+
// local part stays the last resort it always was, for a form that asks for
|
|
277
|
+
// neither.
|
|
278
|
+
const composed = composeName({ firstName, lastName })
|
|
279
|
+
|
|
147
280
|
return {
|
|
148
281
|
email,
|
|
149
|
-
personName:
|
|
282
|
+
personName:
|
|
283
|
+
mapped['person.name'] ??
|
|
284
|
+
(composed.length > 0 ? composed : undefined) ??
|
|
285
|
+
email.split('@')[0] ??
|
|
286
|
+
email,
|
|
287
|
+
personFirstName: firstName,
|
|
288
|
+
personLastName: lastName,
|
|
150
289
|
companyName: mapped['company.name'],
|
|
151
290
|
companyDomain: resolveDomain(mapped),
|
|
152
291
|
positionTitle: mapped['position.title'],
|
|
153
292
|
dealName: mapped['deal.name'],
|
|
293
|
+
opportunityName: mapped['opportunity.name'],
|
|
294
|
+
partnershipName: mapped['partnership.name'],
|
|
295
|
+
enquiryName: mapped['enquiry.name'],
|
|
154
296
|
}
|
|
155
297
|
}
|
|
156
298
|
|
|
@@ -178,13 +320,14 @@ export function companyNameFrom(intent: SubmitIntent): string | undefined {
|
|
|
178
320
|
}
|
|
179
321
|
|
|
180
322
|
/**
|
|
181
|
-
* Expands `{{company.name}}` and `{{person.name}}` in a
|
|
323
|
+
* Expands `{{company.name}}` and `{{person.name}}` in a create-trigger name
|
|
324
|
+
* template. Shared by the deal, opportunity, and partnership triggers.
|
|
182
325
|
*
|
|
183
326
|
* The fallbacks are the mockup's: a template is written once by an admin and
|
|
184
327
|
* then run against whatever arrives, so a submission with no company name must
|
|
185
|
-
* still produce a
|
|
328
|
+
* still produce a record with a name somebody can read on a board.
|
|
186
329
|
*/
|
|
187
|
-
export function
|
|
330
|
+
export function expandNameTemplate(
|
|
188
331
|
template: string,
|
|
189
332
|
values: { readonly companyName: string; readonly personName: string },
|
|
190
333
|
): string {
|
|
@@ -193,6 +336,40 @@ export function expandDealNameTemplate(
|
|
|
193
336
|
.replaceAll('{{person.name}}', values.personName.length > 0 ? values.personName : 'Lead')
|
|
194
337
|
}
|
|
195
338
|
|
|
339
|
+
/**
|
|
340
|
+
* The union merge for a form's tag actions. The stored order is preserved and
|
|
341
|
+
* new tags land at the end, so the timeline reads oldest-first. Never removes
|
|
342
|
+
* a tag a human set: `forms.md` §Tags is explicit on that.
|
|
343
|
+
*
|
|
344
|
+
* @returns The merged list, and `changed` = true when at least one new tag
|
|
345
|
+
* landed. The caller uses `changed` to decide whether to emit an update
|
|
346
|
+
* event, since a no-op merge should not publish `*.updated`.
|
|
347
|
+
*/
|
|
348
|
+
export function mergeTags(
|
|
349
|
+
stored: readonly string[],
|
|
350
|
+
inbound: readonly string[],
|
|
351
|
+
): { readonly next: readonly string[]; readonly changed: boolean } {
|
|
352
|
+
const known = new Set(stored)
|
|
353
|
+
const additions: string[] = []
|
|
354
|
+
|
|
355
|
+
for (const tag of inbound) {
|
|
356
|
+
const trimmed = tag.trim()
|
|
357
|
+
|
|
358
|
+
if (trimmed.length === 0 || known.has(trimmed)) {
|
|
359
|
+
continue
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
known.add(trimmed)
|
|
363
|
+
additions.push(trimmed)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (additions.length === 0) {
|
|
367
|
+
return { next: stored, changed: false }
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return { next: [...stored, ...additions], changed: true }
|
|
371
|
+
}
|
|
372
|
+
|
|
196
373
|
/** How far ahead a deal created by a form is expected to close (`forms.md` rule 6). */
|
|
197
374
|
export const DEAL_CLOSE_HORIZON_DAYS = 30
|
|
198
375
|
|
|
@@ -7,7 +7,10 @@ import { PUBLIC_ROUTE_PREFIX, readJsonBody, requestOrigin } from '../../lib/http
|
|
|
7
7
|
import { requireCapability } from '../../runtime/entitlements.ts'
|
|
8
8
|
import type { EntitlementRegistry } from '../../runtime/entitlements.ts'
|
|
9
9
|
import { moduleCapabilityName } from '../../runtime/moduleConfig.ts'
|
|
10
|
+
import * as consentPurposesRepository from '../consent-purposes/repository.ts'
|
|
11
|
+
import { findWorkspace } from '../workspace/repository.ts'
|
|
10
12
|
import { embedContentSecurityPolicy, renderEmbedPage } from './embed.ts'
|
|
13
|
+
import type { FormFieldRecord } from './repository.ts'
|
|
11
14
|
import * as repository from './repository.ts'
|
|
12
15
|
import type { FormSubmitService, SubmitOutcome } from './submission.ts'
|
|
13
16
|
|
|
@@ -35,6 +38,26 @@ export interface PublicFormRoutesDependencies {
|
|
|
35
38
|
readonly entitlements: EntitlementRegistry
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
/**
|
|
42
|
+
* The purpose labels every consent field on this form points at, keyed by id.
|
|
43
|
+
* Renders the embed with the display label beside each checkbox rather than
|
|
44
|
+
* an opaque id. A purpose that has since been removed drops out of the map;
|
|
45
|
+
* `renderField` falls back to the id when it does, so a stale field stays
|
|
46
|
+
* visible but obviously off.
|
|
47
|
+
*/
|
|
48
|
+
async function loadConsentPurposeLabels(
|
|
49
|
+
db: Database,
|
|
50
|
+
workspaceId: string,
|
|
51
|
+
fields: readonly FormFieldRecord[],
|
|
52
|
+
): Promise<ReadonlyMap<string, string>> {
|
|
53
|
+
const ids = Array.from(
|
|
54
|
+
new Set(fields.flatMap((field) => (field.type === 'consent' ? field.consentPurposeIds : []))),
|
|
55
|
+
)
|
|
56
|
+
if (ids.length === 0) return new Map()
|
|
57
|
+
const rows = await consentPurposesRepository.listPurposesByIds(db, workspaceId, ids)
|
|
58
|
+
return new Map(rows.map((row) => [row.id, row.label]))
|
|
59
|
+
}
|
|
60
|
+
|
|
38
61
|
function submitResponse(outcome: SubmitOutcome): Record<string, unknown> {
|
|
39
62
|
// The upserted record ids stay off this response on purpose. The caller is an
|
|
40
63
|
// unauthenticated website, and a Kelpie id is a ULID whose timestamp would tell
|
|
@@ -83,12 +106,31 @@ export function mountPublicFormRoutes(
|
|
|
83
106
|
// module off does not serve its embed either.
|
|
84
107
|
await requireCapability(dependencies.entitlements, form.workspaceId, moduleCapabilityName('forms'))
|
|
85
108
|
|
|
109
|
+
const workspace = await findWorkspace(dependencies.db, form.workspaceId)
|
|
110
|
+
|
|
111
|
+
if (workspace === undefined) {
|
|
112
|
+
throw AppError.notFound('Form not found')
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// `view=page` is the standalone hosted URL (brand chrome). The default —
|
|
116
|
+
// and what iframe snippets load — is the bare embed: fields only.
|
|
117
|
+
const layout = context.req.query('view') === 'page' ? 'page' : 'embed'
|
|
118
|
+
|
|
86
119
|
const nonce = generateNonce()
|
|
120
|
+
const fields = await repository.listFields(dependencies.db, form.id)
|
|
121
|
+
const consentPurposeLabels = await loadConsentPurposeLabels(
|
|
122
|
+
dependencies.db,
|
|
123
|
+
form.workspaceId,
|
|
124
|
+
fields,
|
|
125
|
+
)
|
|
87
126
|
const page = renderEmbedPage({
|
|
88
127
|
form,
|
|
89
|
-
fields
|
|
128
|
+
fields,
|
|
129
|
+
consentPurposeLabels,
|
|
90
130
|
submitUrl: `${requestOrigin(context)}${PUBLIC_ROUTE_PREFIX}/forms/${publicKey}/submit`,
|
|
91
131
|
nonce,
|
|
132
|
+
workspaceName: workspace.name,
|
|
133
|
+
layout,
|
|
92
134
|
})
|
|
93
135
|
|
|
94
136
|
context.header('Content-Security-Policy', embedContentSecurityPolicy(nonce))
|