@kelpie/server 0.9.0 → 0.11.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/app.d.ts.map +1 -1
- package/dist/app.js +2 -0
- package/dist/app.js.map +1 -1
- 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/actor.d.ts +3 -1
- package/dist/lib/actor.d.ts.map +1 -1
- package/dist/lib/actor.js.map +1 -1
- package/dist/lib/apiKeyScopes.d.ts +8 -0
- package/dist/lib/apiKeyScopes.d.ts.map +1 -0
- package/dist/lib/apiKeyScopes.js +166 -0
- package/dist/lib/apiKeyScopes.js.map +1 -0
- package/dist/modules/activities/repository.d.ts +2 -0
- package/dist/modules/activities/repository.d.ts.map +1 -1
- package/dist/modules/activities/repository.js +9 -0
- package/dist/modules/activities/repository.js.map +1 -1
- package/dist/modules/agent-tasks/repository.d.ts +2 -0
- package/dist/modules/agent-tasks/repository.d.ts.map +1 -1
- package/dist/modules/agent-tasks/repository.js +9 -0
- package/dist/modules/agent-tasks/repository.js.map +1 -1
- package/dist/modules/api-keys/routes.d.ts.map +1 -1
- package/dist/modules/api-keys/routes.js +4 -1
- package/dist/modules/api-keys/routes.js.map +1 -1
- package/dist/modules/api-keys/schema.d.ts +43 -0
- package/dist/modules/api-keys/schema.d.ts.map +1 -1
- package/dist/modules/api-keys/schema.js +2 -0
- package/dist/modules/api-keys/schema.js.map +1 -1
- package/dist/modules/api-keys/scopeMiddleware.d.ts +8 -0
- package/dist/modules/api-keys/scopeMiddleware.d.ts.map +1 -0
- package/dist/modules/api-keys/scopeMiddleware.js +21 -0
- package/dist/modules/api-keys/scopeMiddleware.js.map +1 -0
- package/dist/modules/api-keys/service.d.ts +3 -1
- package/dist/modules/api-keys/service.d.ts.map +1 -1
- package/dist/modules/api-keys/service.js +26 -1
- package/dist/modules/api-keys/service.js.map +1 -1
- package/dist/modules/auth/credentials.d.ts.map +1 -1
- package/dist/modules/auth/credentials.js +2 -0
- package/dist/modules/auth/credentials.js.map +1 -1
- package/dist/modules/consent-purposes/index.d.ts +1 -1
- package/dist/modules/consent-purposes/index.js +1 -1
- package/dist/modules/consent-purposes/schema.d.ts +3 -3
- package/dist/modules/consent-purposes/schema.js +3 -3
- package/dist/modules/consent-purposes/service.d.ts +1 -1
- package/dist/modules/consent-purposes/service.d.ts.map +1 -1
- package/dist/modules/consent-purposes/service.js +7 -16
- package/dist/modules/consent-purposes/service.js.map +1 -1
- package/dist/modules/consent-purposes/starters.d.ts +1 -1
- package/dist/modules/consent-purposes/tools.js +1 -1
- package/dist/modules/consent-purposes/tools.js.map +1 -1
- package/dist/modules/conversions/clearPointers.d.ts +10 -0
- package/dist/modules/conversions/clearPointers.d.ts.map +1 -0
- package/dist/modules/conversions/clearPointers.js +40 -0
- package/dist/modules/conversions/clearPointers.js.map +1 -0
- package/dist/modules/conversions/factory.d.ts +5 -0
- package/dist/modules/conversions/factory.d.ts.map +1 -0
- package/dist/modules/conversions/factory.js +18 -0
- package/dist/modules/conversions/factory.js.map +1 -0
- package/dist/modules/conversions/fieldMap.d.ts +55 -0
- package/dist/modules/conversions/fieldMap.d.ts.map +1 -0
- package/dist/modules/conversions/fieldMap.js +398 -0
- package/dist/modules/conversions/fieldMap.js.map +1 -0
- package/dist/modules/conversions/index.d.ts +7 -0
- package/dist/modules/conversions/index.d.ts.map +1 -0
- package/dist/modules/conversions/index.js +6 -0
- package/dist/modules/conversions/index.js.map +1 -0
- package/dist/modules/conversions/mcp.d.ts +7 -0
- package/dist/modules/conversions/mcp.d.ts.map +1 -0
- package/dist/modules/conversions/mcp.js +47 -0
- package/dist/modules/conversions/mcp.js.map +1 -0
- package/dist/modules/conversions/repoint.d.ts +19 -0
- package/dist/modules/conversions/repoint.d.ts.map +1 -0
- package/dist/modules/conversions/repoint.js +51 -0
- package/dist/modules/conversions/repoint.js.map +1 -0
- package/dist/modules/conversions/routes.d.ts +26 -0
- package/dist/modules/conversions/routes.d.ts.map +1 -0
- package/dist/modules/conversions/routes.js +23 -0
- package/dist/modules/conversions/routes.js.map +1 -0
- package/dist/modules/conversions/service.d.ts +28 -0
- package/dist/modules/conversions/service.d.ts.map +1 -0
- package/dist/modules/conversions/service.js +170 -0
- package/dist/modules/conversions/service.js.map +1 -0
- package/dist/modules/conversions/wire.d.ts +4 -0
- package/dist/modules/conversions/wire.d.ts.map +1 -0
- package/dist/modules/conversions/wire.js +28 -0
- package/dist/modules/conversions/wire.js.map +1 -0
- package/dist/modules/deals/events.d.ts +9 -0
- package/dist/modules/deals/events.d.ts.map +1 -1
- package/dist/modules/deals/events.js +4 -0
- package/dist/modules/deals/events.js.map +1 -1
- package/dist/modules/deals/index.d.ts.map +1 -1
- package/dist/modules/deals/index.js +4 -2
- package/dist/modules/deals/index.js.map +1 -1
- package/dist/modules/deals/routes.d.ts +2 -0
- package/dist/modules/deals/routes.d.ts.map +1 -1
- package/dist/modules/deals/routes.js +8 -1
- package/dist/modules/deals/routes.js.map +1 -1
- package/dist/modules/deals/schema.d.ts +34 -0
- package/dist/modules/deals/schema.d.ts.map +1 -1
- package/dist/modules/deals/schema.js +7 -2
- package/dist/modules/deals/schema.js.map +1 -1
- package/dist/modules/deals/service.d.ts.map +1 -1
- package/dist/modules/deals/service.js +2 -0
- package/dist/modules/deals/service.js.map +1 -1
- package/dist/modules/deals/tools.d.ts +2 -1
- package/dist/modules/deals/tools.d.ts.map +1 -1
- package/dist/modules/deals/tools.js +3 -1
- package/dist/modules/deals/tools.js.map +1 -1
- package/dist/modules/decisions/repository.d.ts +2 -1
- package/dist/modules/decisions/repository.d.ts.map +1 -1
- package/dist/modules/decisions/repository.js +9 -1
- package/dist/modules/decisions/repository.js.map +1 -1
- package/dist/modules/enquiries/events.d.ts +6 -2
- package/dist/modules/enquiries/events.d.ts.map +1 -1
- package/dist/modules/enquiries/events.js +5 -1
- package/dist/modules/enquiries/events.js.map +1 -1
- package/dist/modules/enquiries/index.d.ts.map +1 -1
- package/dist/modules/enquiries/index.js +4 -2
- package/dist/modules/enquiries/index.js.map +1 -1
- package/dist/modules/enquiries/routes.d.ts +2 -0
- package/dist/modules/enquiries/routes.d.ts.map +1 -1
- package/dist/modules/enquiries/routes.js +9 -9
- package/dist/modules/enquiries/routes.js.map +1 -1
- package/dist/modules/enquiries/schema.d.ts +36 -1
- package/dist/modules/enquiries/schema.d.ts.map +1 -1
- package/dist/modules/enquiries/schema.js +9 -3
- package/dist/modules/enquiries/schema.js.map +1 -1
- package/dist/modules/enquiries/service.d.ts +0 -8
- package/dist/modules/enquiries/service.d.ts.map +1 -1
- package/dist/modules/enquiries/service.js +3 -95
- package/dist/modules/enquiries/service.js.map +1 -1
- package/dist/modules/enquiries/tools.d.ts +2 -1
- package/dist/modules/enquiries/tools.d.ts.map +1 -1
- package/dist/modules/enquiries/tools.js +4 -16
- package/dist/modules/enquiries/tools.js.map +1 -1
- package/dist/modules/forms/applyMappedFields.d.ts +20 -0
- package/dist/modules/forms/applyMappedFields.d.ts.map +1 -0
- package/dist/modules/forms/applyMappedFields.js +169 -0
- package/dist/modules/forms/applyMappedFields.js.map +1 -0
- package/dist/modules/forms/applySubmissionFields.d.ts +18 -0
- package/dist/modules/forms/applySubmissionFields.d.ts.map +1 -0
- package/dist/modules/forms/applySubmissionFields.js +230 -0
- package/dist/modules/forms/applySubmissionFields.js.map +1 -0
- package/dist/modules/forms/fields.d.ts +7 -2
- package/dist/modules/forms/fields.d.ts.map +1 -1
- package/dist/modules/forms/fields.js +17 -6
- package/dist/modules/forms/fields.js.map +1 -1
- package/dist/modules/forms/mapping.d.ts +8 -2
- package/dist/modules/forms/mapping.d.ts.map +1 -1
- package/dist/modules/forms/mapping.js +11 -0
- package/dist/modules/forms/mapping.js.map +1 -1
- package/dist/modules/forms/repository.d.ts +0 -5
- package/dist/modules/forms/repository.d.ts.map +1 -1
- package/dist/modules/forms/repository.js +0 -2
- package/dist/modules/forms/repository.js.map +1 -1
- package/dist/modules/forms/routes.d.ts +2 -30
- package/dist/modules/forms/routes.d.ts.map +1 -1
- package/dist/modules/forms/routes.js +2 -2
- package/dist/modules/forms/routes.js.map +1 -1
- package/dist/modules/forms/schema.d.ts.map +1 -1
- package/dist/modules/forms/schema.js +1 -2
- package/dist/modules/forms/schema.js.map +1 -1
- package/dist/modules/forms/service.d.ts.map +1 -1
- package/dist/modules/forms/service.js +18 -3
- package/dist/modules/forms/service.js.map +1 -1
- package/dist/modules/forms/starters.d.ts +31 -0
- package/dist/modules/forms/starters.d.ts.map +1 -0
- package/dist/modules/forms/starters.js +94 -0
- package/dist/modules/forms/starters.js.map +1 -0
- package/dist/modules/forms/submission.d.ts +1 -0
- package/dist/modules/forms/submission.d.ts.map +1 -1
- package/dist/modules/forms/submission.js +58 -37
- package/dist/modules/forms/submission.js.map +1 -1
- package/dist/modules/import-export/customFieldCsv.d.ts +9 -0
- package/dist/modules/import-export/customFieldCsv.d.ts.map +1 -0
- package/dist/modules/import-export/customFieldCsv.js +39 -0
- package/dist/modules/import-export/customFieldCsv.js.map +1 -0
- package/dist/modules/import-export/customFieldImport.d.ts +19 -0
- package/dist/modules/import-export/customFieldImport.d.ts.map +1 -0
- package/dist/modules/import-export/customFieldImport.js +76 -0
- package/dist/modules/import-export/customFieldImport.js.map +1 -0
- package/dist/modules/import-export/drafts.d.ts +57 -3
- package/dist/modules/import-export/drafts.d.ts.map +1 -1
- package/dist/modules/import-export/drafts.js +65 -3
- package/dist/modules/import-export/drafts.js.map +1 -1
- package/dist/modules/import-export/exportRows.d.ts +15 -13
- package/dist/modules/import-export/exportRows.d.ts.map +1 -1
- package/dist/modules/import-export/exportRows.js +99 -26
- package/dist/modules/import-export/exportRows.js.map +1 -1
- package/dist/modules/import-export/plan.d.ts +42 -11
- package/dist/modules/import-export/plan.d.ts.map +1 -1
- package/dist/modules/import-export/plan.js +198 -56
- package/dist/modules/import-export/plan.js.map +1 -1
- package/dist/modules/import-export/repository.d.ts +58 -2
- package/dist/modules/import-export/repository.d.ts.map +1 -1
- package/dist/modules/import-export/repository.js +201 -12
- 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 +5 -5
- package/dist/modules/import-export/routes.js.map +1 -1
- package/dist/modules/import-export/service.d.ts +8 -3
- package/dist/modules/import-export/service.d.ts.map +1 -1
- package/dist/modules/import-export/service.js +133 -40
- package/dist/modules/import-export/service.js.map +1 -1
- package/dist/modules/import-export/streams.d.ts +2 -2
- package/dist/modules/import-export/streams.d.ts.map +1 -1
- package/dist/modules/import-export/streams.js +50 -9
- 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 +13 -7
- package/dist/modules/import-export/tools.js.map +1 -1
- package/dist/modules/import-export/validation.d.ts +5 -1
- package/dist/modules/import-export/validation.d.ts.map +1 -1
- package/dist/modules/import-export/validation.js +89 -2
- package/dist/modules/import-export/validation.js.map +1 -1
- package/dist/modules/import-export/writes.d.ts +2 -1
- package/dist/modules/import-export/writes.d.ts.map +1 -1
- package/dist/modules/import-export/writes.js +358 -25
- 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 +15 -1
- package/dist/modules/lists/repository.d.ts.map +1 -1
- package/dist/modules/lists/repository.js +19 -1
- package/dist/modules/lists/repository.js.map +1 -1
- package/dist/modules/lists/routes.d.ts +0 -2
- package/dist/modules/lists/routes.d.ts.map +1 -1
- package/dist/modules/lists/routes.js +0 -8
- package/dist/modules/lists/routes.js.map +1 -1
- package/dist/modules/lists/schema.d.ts +0 -17
- package/dist/modules/lists/schema.d.ts.map +1 -1
- package/dist/modules/lists/schema.js +0 -10
- package/dist/modules/lists/schema.js.map +1 -1
- package/dist/modules/lists/service.d.ts +2 -14
- package/dist/modules/lists/service.d.ts.map +1 -1
- package/dist/modules/lists/service.js +7 -53
- package/dist/modules/lists/service.js.map +1 -1
- package/dist/modules/lists/starters.d.ts +12 -0
- package/dist/modules/lists/starters.d.ts.map +1 -0
- package/dist/modules/lists/starters.js +4 -0
- package/dist/modules/lists/starters.js.map +1 -0
- package/dist/modules/mcp/protocol.d.ts.map +1 -1
- package/dist/modules/mcp/protocol.js +13 -0
- package/dist/modules/mcp/protocol.js.map +1 -1
- package/dist/modules/notes/repository.d.ts +2 -0
- package/dist/modules/notes/repository.d.ts.map +1 -1
- package/dist/modules/notes/repository.js +9 -0
- package/dist/modules/notes/repository.js.map +1 -1
- package/dist/modules/opportunities/events.d.ts +9 -0
- package/dist/modules/opportunities/events.d.ts.map +1 -1
- package/dist/modules/opportunities/events.js +4 -0
- package/dist/modules/opportunities/events.js.map +1 -1
- package/dist/modules/opportunities/index.d.ts.map +1 -1
- package/dist/modules/opportunities/index.js +4 -2
- package/dist/modules/opportunities/index.js.map +1 -1
- package/dist/modules/opportunities/routes.d.ts +2 -0
- package/dist/modules/opportunities/routes.d.ts.map +1 -1
- package/dist/modules/opportunities/routes.js +8 -1
- package/dist/modules/opportunities/routes.js.map +1 -1
- package/dist/modules/opportunities/schema.d.ts +34 -0
- package/dist/modules/opportunities/schema.d.ts.map +1 -1
- package/dist/modules/opportunities/schema.js +7 -2
- package/dist/modules/opportunities/schema.js.map +1 -1
- package/dist/modules/opportunities/service.d.ts.map +1 -1
- package/dist/modules/opportunities/service.js +2 -0
- package/dist/modules/opportunities/service.js.map +1 -1
- package/dist/modules/opportunities/tools.d.ts +2 -1
- package/dist/modules/opportunities/tools.d.ts.map +1 -1
- package/dist/modules/opportunities/tools.js +3 -1
- package/dist/modules/opportunities/tools.js.map +1 -1
- package/dist/modules/partnerships/events.d.ts +9 -0
- package/dist/modules/partnerships/events.d.ts.map +1 -1
- package/dist/modules/partnerships/events.js +4 -0
- package/dist/modules/partnerships/events.js.map +1 -1
- package/dist/modules/partnerships/index.d.ts.map +1 -1
- package/dist/modules/partnerships/index.js +4 -2
- package/dist/modules/partnerships/index.js.map +1 -1
- package/dist/modules/partnerships/routes.d.ts +2 -0
- package/dist/modules/partnerships/routes.d.ts.map +1 -1
- package/dist/modules/partnerships/routes.js +8 -1
- package/dist/modules/partnerships/routes.js.map +1 -1
- package/dist/modules/partnerships/schema.d.ts +34 -0
- package/dist/modules/partnerships/schema.d.ts.map +1 -1
- package/dist/modules/partnerships/schema.js +7 -2
- package/dist/modules/partnerships/schema.js.map +1 -1
- package/dist/modules/partnerships/service.d.ts.map +1 -1
- package/dist/modules/partnerships/service.js +2 -0
- package/dist/modules/partnerships/service.js.map +1 -1
- package/dist/modules/partnerships/tools.d.ts +2 -1
- package/dist/modules/partnerships/tools.d.ts.map +1 -1
- package/dist/modules/partnerships/tools.js +3 -1
- package/dist/modules/partnerships/tools.js.map +1 -1
- package/dist/modules/people/personConsentWrites.d.ts +1 -1
- package/dist/modules/people/schema.js +1 -1
- package/dist/modules/people/schema.js.map +1 -1
- package/dist/modules/plans/repository.d.ts +2 -0
- package/dist/modules/plans/repository.d.ts.map +1 -1
- package/dist/modules/plans/repository.js +9 -0
- package/dist/modules/plans/repository.js.map +1 -1
- package/dist/modules/raises/events.d.ts +9 -0
- package/dist/modules/raises/events.d.ts.map +1 -1
- package/dist/modules/raises/events.js +4 -0
- package/dist/modules/raises/events.js.map +1 -1
- package/dist/modules/raises/index.d.ts.map +1 -1
- package/dist/modules/raises/index.js +4 -2
- package/dist/modules/raises/index.js.map +1 -1
- package/dist/modules/raises/routes.d.ts +2 -0
- package/dist/modules/raises/routes.d.ts.map +1 -1
- package/dist/modules/raises/routes.js +8 -1
- package/dist/modules/raises/routes.js.map +1 -1
- package/dist/modules/raises/schema.d.ts +34 -0
- package/dist/modules/raises/schema.d.ts.map +1 -1
- package/dist/modules/raises/schema.js +7 -2
- package/dist/modules/raises/schema.js.map +1 -1
- package/dist/modules/raises/service.d.ts.map +1 -1
- package/dist/modules/raises/service.js +2 -0
- package/dist/modules/raises/service.js.map +1 -1
- package/dist/modules/raises/tools.d.ts +2 -1
- package/dist/modules/raises/tools.d.ts.map +1 -1
- package/dist/modules/raises/tools.js +3 -1
- package/dist/modules/raises/tools.js.map +1 -1
- package/dist/modules/workspace/routes.d.ts +0 -2
- package/dist/modules/workspace/routes.d.ts.map +1 -1
- package/dist/modules/workspace/routes.js +0 -6
- package/dist/modules/workspace/routes.js.map +1 -1
- package/dist/modules/workspace/schema.d.ts +0 -34
- package/dist/modules/workspace/schema.d.ts.map +1 -1
- package/dist/modules/workspace/schema.js +0 -2
- package/dist/modules/workspace/schema.js.map +1 -1
- package/dist/modules/workspace/seedStarterForms.d.ts +17 -0
- package/dist/modules/workspace/seedStarterForms.d.ts.map +1 -0
- package/dist/modules/workspace/seedStarterForms.js +71 -0
- package/dist/modules/workspace/seedStarterForms.js.map +1 -0
- package/dist/modules/workspace/service.d.ts +0 -4
- package/dist/modules/workspace/service.d.ts.map +1 -1
- package/dist/modules/workspace/service.js +20 -10
- package/dist/modules/workspace/service.js.map +1 -1
- package/dist/modules/workspace/tools.js +1 -1
- package/dist/modules/workspace/tools.js.map +1 -1
- package/dist/testing/fixtures.d.ts.map +1 -1
- package/dist/testing/fixtures.js +1 -0
- package/dist/testing/fixtures.js.map +1 -1
- package/migrations/0037_drop_lists_consent_purpose_id.sql +2 -0
- package/migrations/0038_smart_white_queen.sql +2 -0
- package/migrations/0039_form_map_to_open.sql +1 -0
- package/migrations/0040_pipeline_converted_to.sql +20 -0
- package/migrations/0041_api_key_scopes.sql +1 -0
- package/migrations/0042_drop_workspace_identity.sql +2 -0
- package/migrations/meta/0038_snapshot.json +6554 -0
- package/migrations/meta/_journal.json +42 -0
- package/package.json +2 -2
- package/src/app.ts +3 -0
- package/src/index.ts +6 -0
- package/src/lib/actor.ts +3 -1
- package/src/lib/apiKeyScopes.ts +213 -0
- package/src/modules/activities/repository.ts +24 -0
- package/src/modules/agent-tasks/repository.ts +24 -0
- package/src/modules/api-keys/routes.ts +5 -0
- package/src/modules/api-keys/schema.ts +2 -0
- package/src/modules/api-keys/scopeMiddleware.ts +30 -0
- package/src/modules/api-keys/service.ts +36 -2
- package/src/modules/auth/credentials.ts +4 -0
- package/src/modules/consent-purposes/index.ts +1 -1
- package/src/modules/consent-purposes/schema.ts +3 -3
- package/src/modules/consent-purposes/service.ts +7 -16
- package/src/modules/consent-purposes/starters.ts +1 -1
- package/src/modules/consent-purposes/tools.ts +1 -1
- package/src/modules/conversions/clearPointers.ts +81 -0
- package/src/modules/conversions/factory.ts +20 -0
- package/src/modules/conversions/fieldMap.ts +548 -0
- package/src/modules/conversions/index.ts +6 -0
- package/src/modules/conversions/mcp.ts +71 -0
- package/src/modules/conversions/repoint.ts +146 -0
- package/src/modules/conversions/routes.ts +68 -0
- package/src/modules/conversions/service.ts +310 -0
- package/src/modules/conversions/wire.ts +42 -0
- package/src/modules/deals/events.ts +9 -0
- package/src/modules/deals/index.ts +4 -2
- package/src/modules/deals/routes.ts +11 -1
- package/src/modules/deals/schema.ts +10 -2
- package/src/modules/deals/service.ts +3 -0
- package/src/modules/deals/tools.ts +9 -1
- package/src/modules/decisions/repository.ts +23 -1
- package/src/modules/enquiries/events.ts +8 -2
- package/src/modules/enquiries/index.ts +4 -2
- package/src/modules/enquiries/routes.ts +11 -13
- package/src/modules/enquiries/schema.ts +12 -3
- package/src/modules/enquiries/service.ts +3 -150
- package/src/modules/enquiries/tools.ts +9 -18
- package/src/modules/forms/applyMappedFields.ts +248 -0
- package/src/modules/forms/applySubmissionFields.ts +435 -0
- package/src/modules/forms/fields.ts +31 -7
- package/src/modules/forms/mapping.ts +20 -3
- package/src/modules/forms/repository.ts +0 -7
- package/src/modules/forms/routes.ts +1 -2
- package/src/modules/forms/schema.ts +0 -2
- package/src/modules/forms/service.ts +31 -4
- package/src/modules/forms/starters.ts +129 -0
- package/src/modules/forms/submission.ts +135 -69
- package/src/modules/import-export/customFieldCsv.ts +55 -0
- package/src/modules/import-export/customFieldImport.ts +111 -0
- package/src/modules/import-export/drafts.ts +151 -3
- package/src/modules/import-export/exportRows.ts +222 -68
- package/src/modules/import-export/plan.ts +321 -67
- package/src/modules/import-export/repository.ts +356 -14
- package/src/modules/import-export/routes.ts +8 -8
- package/src/modules/import-export/service.ts +208 -45
- package/src/modules/import-export/streams.ts +95 -13
- package/src/modules/import-export/tools.ts +14 -6
- package/src/modules/import-export/validation.ts +128 -0
- package/src/modules/import-export/writes.ts +559 -27
- package/src/modules/lists/index.ts +71 -0
- package/src/modules/lists/repository.ts +34 -2
- package/src/modules/lists/routes.ts +0 -8
- package/src/modules/lists/schema.ts +0 -10
- package/src/modules/lists/service.ts +9 -107
- package/src/modules/lists/starters.ts +16 -0
- package/src/modules/mcp/protocol.ts +18 -0
- package/src/modules/notes/repository.ts +24 -0
- package/src/modules/opportunities/events.ts +9 -0
- package/src/modules/opportunities/index.ts +4 -2
- package/src/modules/opportunities/routes.ts +11 -1
- package/src/modules/opportunities/schema.ts +10 -2
- package/src/modules/opportunities/service.ts +3 -0
- package/src/modules/opportunities/tools.ts +9 -1
- package/src/modules/partnerships/events.ts +9 -0
- package/src/modules/partnerships/index.ts +4 -2
- package/src/modules/partnerships/routes.ts +11 -1
- package/src/modules/partnerships/schema.ts +10 -2
- package/src/modules/partnerships/service.ts +3 -0
- package/src/modules/partnerships/tools.ts +9 -1
- package/src/modules/people/personConsentWrites.ts +1 -1
- package/src/modules/people/schema.ts +1 -1
- package/src/modules/plans/repository.ts +24 -0
- package/src/modules/raises/events.ts +9 -0
- package/src/modules/raises/index.ts +4 -2
- package/src/modules/raises/routes.ts +11 -1
- package/src/modules/raises/schema.ts +10 -2
- package/src/modules/raises/service.ts +3 -0
- package/src/modules/raises/tools.ts +9 -1
- package/src/modules/workspace/routes.ts +0 -6
- package/src/modules/workspace/schema.ts +0 -2
- package/src/modules/workspace/seedStarterForms.ts +98 -0
- package/src/modules/workspace/service.ts +23 -15
- package/src/modules/workspace/tools.ts +1 -1
- package/src/testing/fixtures.ts +1 -0
|
@@ -24,6 +24,8 @@ import '../opportunities/events.ts'
|
|
|
24
24
|
import * as partnershipRepository from '../partnerships/repository.ts'
|
|
25
25
|
import '../partnerships/events.ts'
|
|
26
26
|
import * as consentPurposesRepository from '../consent-purposes/repository.ts'
|
|
27
|
+
import * as customFieldsRepository from '../custom-fields/repository.ts'
|
|
28
|
+
import { CUSTOM_FIELD_OBJECT_TYPES } from '../custom-fields/schema.ts'
|
|
27
29
|
import '../people/events.ts'
|
|
28
30
|
import { upsertPersonConsent } from '../people/personConsentWrites.ts'
|
|
29
31
|
import * as peopleRepository from '../people/repository.ts'
|
|
@@ -33,6 +35,8 @@ import * as pipelineRepository from '../pipelines/repository.ts'
|
|
|
33
35
|
import '../positions/events.ts'
|
|
34
36
|
import * as positionRepository from '../positions/repository.ts'
|
|
35
37
|
import { targetExists } from '../recordTargets.ts'
|
|
38
|
+
import * as raiseRepository from '../raises/repository.ts'
|
|
39
|
+
import '../raises/events.ts'
|
|
36
40
|
import * as workspaceRepository from '../workspace/repository.ts'
|
|
37
41
|
import './events.ts'
|
|
38
42
|
import {
|
|
@@ -42,6 +46,7 @@ import {
|
|
|
42
46
|
expandNameTemplate,
|
|
43
47
|
expectedCloseFrom,
|
|
44
48
|
fillBlank,
|
|
49
|
+
fillPhonesBlank,
|
|
45
50
|
findAnswerProblems,
|
|
46
51
|
mapAnswers,
|
|
47
52
|
mergeTags,
|
|
@@ -51,6 +56,15 @@ import {
|
|
|
51
56
|
import type { Answers, ConsentGrant, SubmitIntent } from './mapping.ts'
|
|
52
57
|
import * as repository from './repository.ts'
|
|
53
58
|
import type { FormFieldRecord, FormRecord } from './repository.ts'
|
|
59
|
+
import {
|
|
60
|
+
applyCompanyMappedFields,
|
|
61
|
+
applyDealMappedFields,
|
|
62
|
+
applyEnquiryMappedFields,
|
|
63
|
+
applyOpportunityMappedFields,
|
|
64
|
+
applyPartnershipMappedFields,
|
|
65
|
+
applyPersonMappedFields,
|
|
66
|
+
applyRaiseMappedFields,
|
|
67
|
+
} from './applySubmissionFields.ts'
|
|
54
68
|
|
|
55
69
|
/**
|
|
56
70
|
* The public submit: `forms.md` rules 1 to 7, server-side.
|
|
@@ -290,6 +304,7 @@ export function createFormSubmitService(dependencies: SubmissionDependencies): F
|
|
|
290
304
|
const existing = await peopleRepository.findPersonByEmail(tx, workspaceId, intent.email)
|
|
291
305
|
|
|
292
306
|
if (existing === undefined) {
|
|
307
|
+
const phones = fillPhonesBlank([], intent.personPhone)
|
|
293
308
|
const created = await peopleRepository.insertPerson(tx, {
|
|
294
309
|
id: dependencies.createId('person'),
|
|
295
310
|
workspaceId,
|
|
@@ -298,10 +313,11 @@ export function createFormSubmitService(dependencies: SubmissionDependencies): F
|
|
|
298
313
|
lastName: intent.personLastName ?? null,
|
|
299
314
|
email: intent.email,
|
|
300
315
|
lastContactedAt: now,
|
|
316
|
+
...(phones === undefined ? {} : { phones: [...phones] }),
|
|
301
317
|
...NEW_PERSON_DEFAULTS,
|
|
302
318
|
})
|
|
303
319
|
|
|
304
|
-
return { record: created, created: true, filled: [] }
|
|
320
|
+
return { record: created, created: true, filled: phones === undefined ? [] : ['phones'] }
|
|
305
321
|
}
|
|
306
322
|
|
|
307
323
|
// Each part fills its own blank. A stored first name is what the team has
|
|
@@ -310,10 +326,12 @@ export function createFormSubmitService(dependencies: SubmissionDependencies): F
|
|
|
310
326
|
const filledName = fillBlank(existing.name, intent.personName)
|
|
311
327
|
const filledFirstName = fillBlank(existing.firstName, intent.personFirstName)
|
|
312
328
|
const filledLastName = fillBlank(existing.lastName, intent.personLastName)
|
|
329
|
+
const filledPhones = fillPhonesBlank(existing.phones, intent.personPhone)
|
|
313
330
|
const changes = {
|
|
314
331
|
...(filledName === undefined ? {} : { name: filledName }),
|
|
315
332
|
...(filledFirstName === undefined ? {} : { firstName: filledFirstName }),
|
|
316
333
|
...(filledLastName === undefined ? {} : { lastName: filledLastName }),
|
|
334
|
+
...(filledPhones === undefined ? {} : { phones: [...filledPhones] }),
|
|
317
335
|
}
|
|
318
336
|
const updated = await peopleRepository.updatePerson(tx, workspaceId, existing.id, {
|
|
319
337
|
...changes,
|
|
@@ -847,7 +865,15 @@ export function createFormSubmitService(dependencies: SubmissionDependencies): F
|
|
|
847
865
|
const { workspaceId } = form
|
|
848
866
|
const fields = await repository.listFields(dependencies.db, form.id)
|
|
849
867
|
const intent = readAnswers(fields, answers)
|
|
868
|
+
const mapped = mapAnswers(fields, answers)
|
|
850
869
|
const consentGrants = readConsentGrants(fields, answers)
|
|
870
|
+
const customFieldDefinitions = (
|
|
871
|
+
await Promise.all(
|
|
872
|
+
CUSTOM_FIELD_OBJECT_TYPES.map((objectType) =>
|
|
873
|
+
customFieldsRepository.definitionsForObject(dependencies.db, workspaceId, objectType),
|
|
874
|
+
),
|
|
875
|
+
)
|
|
876
|
+
).flat()
|
|
851
877
|
const [formListRows, attachTargets, consentPurposesForGrants] = await Promise.all([
|
|
852
878
|
repository.listFormLists(dependencies.db, form.id),
|
|
853
879
|
repository.listAttachTargets(dependencies.db, form.id),
|
|
@@ -855,10 +881,36 @@ export function createFormSubmitService(dependencies: SubmissionDependencies): F
|
|
|
855
881
|
])
|
|
856
882
|
|
|
857
883
|
return dependencies.transaction(async ({ tx, events }) => {
|
|
884
|
+
const now = dependencies.now()
|
|
858
885
|
// Core capture: atomic. A failure here fails the submit; every
|
|
859
886
|
// post-action below runs under its own savepoint and logs.
|
|
860
|
-
const
|
|
861
|
-
const
|
|
887
|
+
const personUpserted = await upsertPerson(tx, workspaceId, intent)
|
|
888
|
+
const personRecord = await applyPersonMappedFields(
|
|
889
|
+
tx,
|
|
890
|
+
workspaceId,
|
|
891
|
+
personUpserted.record,
|
|
892
|
+
mapped,
|
|
893
|
+
customFieldDefinitions,
|
|
894
|
+
now,
|
|
895
|
+
)
|
|
896
|
+
const person = { ...personUpserted, record: personRecord }
|
|
897
|
+
|
|
898
|
+
const companyUpserted = await upsertCompany(tx, workspaceId, intent)
|
|
899
|
+
const companyRecord =
|
|
900
|
+
companyUpserted === undefined
|
|
901
|
+
? undefined
|
|
902
|
+
: await applyCompanyMappedFields(
|
|
903
|
+
tx,
|
|
904
|
+
workspaceId,
|
|
905
|
+
companyUpserted.record,
|
|
906
|
+
mapped,
|
|
907
|
+
customFieldDefinitions,
|
|
908
|
+
now,
|
|
909
|
+
)
|
|
910
|
+
const company =
|
|
911
|
+
companyUpserted === undefined
|
|
912
|
+
? undefined
|
|
913
|
+
: { ...companyUpserted, record: companyRecord ?? companyUpserted.record }
|
|
862
914
|
const position =
|
|
863
915
|
company === undefined || intent.positionTitle === undefined
|
|
864
916
|
? undefined
|
|
@@ -976,6 +1028,66 @@ export function createFormSubmitService(dependencies: SubmissionDependencies): F
|
|
|
976
1028
|
)) ?? null)
|
|
977
1029
|
: null
|
|
978
1030
|
|
|
1031
|
+
if (dealId !== null) {
|
|
1032
|
+
const deal = await dealRepository.findDeal(tx, workspaceId, dealId)
|
|
1033
|
+
|
|
1034
|
+
if (deal !== undefined) {
|
|
1035
|
+
await applyDealMappedFields(
|
|
1036
|
+
tx,
|
|
1037
|
+
workspaceId,
|
|
1038
|
+
deal,
|
|
1039
|
+
mapped,
|
|
1040
|
+
customFieldDefinitions,
|
|
1041
|
+
now,
|
|
1042
|
+
)
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
if (opportunityId !== null) {
|
|
1047
|
+
const opportunity = await opportunityRepository.findOpportunity(tx, workspaceId, opportunityId)
|
|
1048
|
+
|
|
1049
|
+
if (opportunity !== undefined) {
|
|
1050
|
+
await applyOpportunityMappedFields(
|
|
1051
|
+
tx,
|
|
1052
|
+
workspaceId,
|
|
1053
|
+
opportunity,
|
|
1054
|
+
mapped,
|
|
1055
|
+
customFieldDefinitions,
|
|
1056
|
+
now,
|
|
1057
|
+
)
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
if (partnershipId !== null) {
|
|
1062
|
+
const partnership = await partnershipRepository.findPartnership(tx, workspaceId, partnershipId)
|
|
1063
|
+
|
|
1064
|
+
if (partnership !== undefined) {
|
|
1065
|
+
await applyPartnershipMappedFields(
|
|
1066
|
+
tx,
|
|
1067
|
+
workspaceId,
|
|
1068
|
+
partnership,
|
|
1069
|
+
mapped,
|
|
1070
|
+
customFieldDefinitions,
|
|
1071
|
+
now,
|
|
1072
|
+
)
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
if (enquiryId !== null) {
|
|
1077
|
+
const enquiry = await enquiryRepository.findEnquiry(tx, workspaceId, enquiryId)
|
|
1078
|
+
|
|
1079
|
+
if (enquiry !== undefined) {
|
|
1080
|
+
await applyEnquiryMappedFields(
|
|
1081
|
+
tx,
|
|
1082
|
+
workspaceId,
|
|
1083
|
+
enquiry,
|
|
1084
|
+
mapped,
|
|
1085
|
+
customFieldDefinitions,
|
|
1086
|
+
now,
|
|
1087
|
+
)
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
|
|
979
1091
|
// --- Tag merges ---
|
|
980
1092
|
|
|
981
1093
|
if (form.personTags.length > 0) {
|
|
@@ -1030,30 +1142,8 @@ export function createFormSubmitService(dependencies: SubmissionDependencies): F
|
|
|
1030
1142
|
|
|
1031
1143
|
// --- List memberships ---
|
|
1032
1144
|
|
|
1033
|
-
// Every purpose named by a person list on this form, so consent
|
|
1034
|
-
// capture below needs no per-row round trip.
|
|
1035
|
-
const listConsentPurposeIds = Array.from(
|
|
1036
|
-
new Set(
|
|
1037
|
-
formListRows
|
|
1038
|
-
.map((row) => row.consentPurposeId)
|
|
1039
|
-
.filter((id): id is string => id !== null),
|
|
1040
|
-
),
|
|
1041
|
-
)
|
|
1042
|
-
const listConsentPurposes =
|
|
1043
|
-
listConsentPurposeIds.length === 0
|
|
1044
|
-
? new Map<string, { readonly slug: string; readonly label: string }>()
|
|
1045
|
-
: new Map(
|
|
1046
|
-
(
|
|
1047
|
-
await consentPurposesRepository.listPurposesByIds(
|
|
1048
|
-
tx,
|
|
1049
|
-
workspaceId,
|
|
1050
|
-
listConsentPurposeIds,
|
|
1051
|
-
)
|
|
1052
|
-
).map((row) => [row.id, { slug: row.slug, label: row.label }]),
|
|
1053
|
-
)
|
|
1054
|
-
|
|
1055
1145
|
for (const row of formListRows) {
|
|
1056
|
-
|
|
1146
|
+
await runAction<boolean>(
|
|
1057
1147
|
tx,
|
|
1058
1148
|
events,
|
|
1059
1149
|
actionLog,
|
|
@@ -1096,49 +1186,6 @@ export function createFormSubmitService(dependencies: SubmissionDependencies): F
|
|
|
1096
1186
|
return { status: 'ok', detail: targetId, value: true }
|
|
1097
1187
|
},
|
|
1098
1188
|
)
|
|
1099
|
-
|
|
1100
|
-
// Consent capture rides with the add — only on person lists, only
|
|
1101
|
-
// when the list carries a purpose, and only when we actually added
|
|
1102
|
-
// (or the person was already on it, since a returning submitter
|
|
1103
|
-
// did the same thing again). A record already on the list has
|
|
1104
|
-
// already been consented for its purpose; the upsert reflects
|
|
1105
|
-
// that a fresh submit is fresh evidence.
|
|
1106
|
-
if (
|
|
1107
|
-
row.targetType === 'person' &&
|
|
1108
|
-
row.consentPurposeId !== null &&
|
|
1109
|
-
inserted !== null
|
|
1110
|
-
) {
|
|
1111
|
-
const purpose = listConsentPurposes.get(row.consentPurposeId)
|
|
1112
|
-
if (purpose !== undefined) {
|
|
1113
|
-
await runAction<void>(
|
|
1114
|
-
tx,
|
|
1115
|
-
events,
|
|
1116
|
-
actionLog,
|
|
1117
|
-
`consent:${row.listId}`,
|
|
1118
|
-
async (inner) => {
|
|
1119
|
-
await upsertPersonConsent(
|
|
1120
|
-
inner,
|
|
1121
|
-
workspaceId,
|
|
1122
|
-
person.record.id,
|
|
1123
|
-
row.consentPurposeId as string,
|
|
1124
|
-
purpose.slug,
|
|
1125
|
-
purpose.label,
|
|
1126
|
-
'granted',
|
|
1127
|
-
`list:${row.listId}`,
|
|
1128
|
-
dependencies.now(),
|
|
1129
|
-
)
|
|
1130
|
-
await dependencies.recordActivity(inner, workspaceId, FORM_ACTOR, {
|
|
1131
|
-
targetType: 'person',
|
|
1132
|
-
targetId: person.record.id,
|
|
1133
|
-
kind: 'updated',
|
|
1134
|
-
action: `granted ${purpose.label} consent via ${form.name}`,
|
|
1135
|
-
detail: `Added to list membership`,
|
|
1136
|
-
})
|
|
1137
|
-
return { status: 'ok', detail: purpose.slug }
|
|
1138
|
-
},
|
|
1139
|
-
)
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
1189
|
}
|
|
1143
1190
|
|
|
1144
1191
|
// --- Attach the submitter to pre-existing pipeline records ---
|
|
@@ -1172,6 +1219,25 @@ export function createFormSubmitService(dependencies: SubmissionDependencies): F
|
|
|
1172
1219
|
)
|
|
1173
1220
|
}
|
|
1174
1221
|
|
|
1222
|
+
for (const target of attachTargets) {
|
|
1223
|
+
if (target.targetType !== 'raise') {
|
|
1224
|
+
continue
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
const raise = await raiseRepository.findRaise(tx, workspaceId, target.targetId)
|
|
1228
|
+
|
|
1229
|
+
if (raise !== undefined) {
|
|
1230
|
+
await applyRaiseMappedFields(
|
|
1231
|
+
tx,
|
|
1232
|
+
workspaceId,
|
|
1233
|
+
raise,
|
|
1234
|
+
mapped,
|
|
1235
|
+
customFieldDefinitions,
|
|
1236
|
+
now,
|
|
1237
|
+
)
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1175
1241
|
// --- Persist submission + core activity + record events ---
|
|
1176
1242
|
|
|
1177
1243
|
const submission = await repository.insertSubmission(tx, {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { CustomFieldValue } from '@kelpie/schemas'
|
|
2
|
+
|
|
3
|
+
import type { CustomFieldDefinitionRecord } from '../custom-fields/repository.ts'
|
|
4
|
+
import { centsToMoney } from './mapping.ts'
|
|
5
|
+
|
|
6
|
+
/** Definition keys in workspace sort order — the extra CSV columns on a record export. */
|
|
7
|
+
export function customFieldHeaderKeys(
|
|
8
|
+
definitions: readonly CustomFieldDefinitionRecord[],
|
|
9
|
+
): readonly string[] {
|
|
10
|
+
return definitions.map((definition) => definition.key)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** One custom field value as a single CSV cell. */
|
|
14
|
+
export function serializeCustomFieldValue(value: CustomFieldValue | undefined): string {
|
|
15
|
+
if (value === undefined) {
|
|
16
|
+
return ''
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
20
|
+
return String(value)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (typeof value === 'boolean') {
|
|
24
|
+
return value ? 'true' : 'false'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (Array.isArray(value)) {
|
|
28
|
+
return value.join('|')
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (typeof value === 'object' && 'amountCents' in value && 'currency' in value) {
|
|
32
|
+
return `${centsToMoney(value.amountCents)}|${value.currency}`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return ''
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function customFieldCells(
|
|
39
|
+
values: Readonly<Record<string, CustomFieldValue>> | undefined,
|
|
40
|
+
keys: readonly string[],
|
|
41
|
+
): readonly string[] {
|
|
42
|
+
return keys.map((key) => serializeCustomFieldValue(values?.[key]))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function customFieldDefinitionCells(row: CustomFieldDefinitionRecord): readonly string[] {
|
|
46
|
+
return [
|
|
47
|
+
row.objectType,
|
|
48
|
+
row.key,
|
|
49
|
+
row.label,
|
|
50
|
+
row.type,
|
|
51
|
+
row.options.join('|'),
|
|
52
|
+
row.description,
|
|
53
|
+
String(row.sortOrder),
|
|
54
|
+
]
|
|
55
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { CustomFieldDefinitionRef, CustomFieldObjectType, CustomFieldType, CustomFieldWireValue } from '@kelpie/schemas'
|
|
2
|
+
|
|
3
|
+
import { parseCustomFieldAnswer } from '../forms/applyMappedFields.ts'
|
|
4
|
+
import type { CustomFieldDefinitionRecord } from '../custom-fields/repository.ts'
|
|
5
|
+
import { moneyToCents } from './mapping.ts'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Custom field columns on a record import: extract, parse, and validate keys.
|
|
9
|
+
*
|
|
10
|
+
* Extra CSV columns named by definition key round-trip with export. A blank cell
|
|
11
|
+
* says nothing about the field, the same additive rule every column follows.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** Kelpie columns declared for an object, not including workspace definition keys. */
|
|
15
|
+
export function baseColumnKeySet(objectColumns: readonly { readonly key: string }[]): ReadonlySet<string> {
|
|
16
|
+
return new Set(objectColumns.map((column) => column.key))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Non-base, non-blank cells keyed by custom field definition key. */
|
|
20
|
+
export function extractCustomFieldRaw(
|
|
21
|
+
mapped: Readonly<Record<string, string>>,
|
|
22
|
+
baseKeys: ReadonlySet<string>,
|
|
23
|
+
): Readonly<Record<string, string>> {
|
|
24
|
+
const custom: Record<string, string> = {}
|
|
25
|
+
|
|
26
|
+
for (const [key, value] of Object.entries(mapped)) {
|
|
27
|
+
if (baseKeys.has(key)) {
|
|
28
|
+
continue
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (value.trim().length === 0) {
|
|
32
|
+
continue
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
custom[key] = value
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return custom
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function parseCurrency(raw: string): CustomFieldWireValue | undefined {
|
|
42
|
+
const trimmed = raw.trim()
|
|
43
|
+
|
|
44
|
+
if (trimmed.length === 0) {
|
|
45
|
+
return undefined
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const [amountPart, currencyPart] = trimmed.split('|')
|
|
49
|
+
const currency = (currencyPart ?? 'USD').trim().toUpperCase()
|
|
50
|
+
|
|
51
|
+
if (!/^[A-Z]{3}$/u.test(currency)) {
|
|
52
|
+
return undefined
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const cents = moneyToCents(amountPart)
|
|
56
|
+
|
|
57
|
+
if (cents === undefined || cents === null) {
|
|
58
|
+
return undefined
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return { amount_cents: cents, currency }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Parses one inbound custom-field cell into a wire value for the validator. */
|
|
65
|
+
export function parseCustomFieldWireValue(
|
|
66
|
+
definition: CustomFieldDefinitionRecord,
|
|
67
|
+
raw: string,
|
|
68
|
+
): CustomFieldWireValue | undefined {
|
|
69
|
+
if (definition.type === 'currency') {
|
|
70
|
+
return parseCurrency(raw)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const ref: CustomFieldDefinitionRef = {
|
|
74
|
+
objectType: definition.objectType as CustomFieldObjectType,
|
|
75
|
+
key: definition.key,
|
|
76
|
+
label: definition.label,
|
|
77
|
+
type: definition.type as CustomFieldType,
|
|
78
|
+
}
|
|
79
|
+
const parsed = parseCustomFieldAnswer(ref, raw)
|
|
80
|
+
|
|
81
|
+
if (typeof parsed === 'string' && parsed.trim().length === 0) {
|
|
82
|
+
return undefined
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return parsed as CustomFieldWireValue
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Builds the wire map to pass to `createCustomFieldValues`. Unknown keys are omitted. */
|
|
89
|
+
export function customFieldWireValues(
|
|
90
|
+
raw: Readonly<Record<string, string>>,
|
|
91
|
+
definitions: readonly CustomFieldDefinitionRecord[],
|
|
92
|
+
): Readonly<Record<string, CustomFieldWireValue>> {
|
|
93
|
+
const byKey = new Map(definitions.map((definition) => [definition.key, definition]))
|
|
94
|
+
const out: Record<string, CustomFieldWireValue> = {}
|
|
95
|
+
|
|
96
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
97
|
+
const definition = byKey.get(key)
|
|
98
|
+
|
|
99
|
+
if (definition === undefined) {
|
|
100
|
+
continue
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const parsed = parseCustomFieldWireValue(definition, value)
|
|
104
|
+
|
|
105
|
+
if (parsed !== undefined) {
|
|
106
|
+
out[key] = parsed
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return out
|
|
111
|
+
}
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
composeName,
|
|
10
10
|
} from '@kelpie/schemas'
|
|
11
11
|
|
|
12
|
+
import type { CustomFieldWireValue } from '@kelpie/schemas'
|
|
13
|
+
|
|
12
14
|
import { normaliseDomain, normaliseEmail } from '../../lib/normalisation.ts'
|
|
13
15
|
import { moneyToCents, splitList } from './mapping.ts'
|
|
14
16
|
import { canonicalEnum } from './validation.ts'
|
|
@@ -40,6 +42,7 @@ export interface CompanyDraft {
|
|
|
40
42
|
readonly icpFit?: string
|
|
41
43
|
readonly summary?: string
|
|
42
44
|
readonly tags?: readonly string[]
|
|
45
|
+
readonly customFields?: Readonly<Record<string, CustomFieldWireValue>>
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
export interface PersonDraft {
|
|
@@ -57,6 +60,7 @@ export interface PersonDraft {
|
|
|
57
60
|
readonly relationship?: string
|
|
58
61
|
readonly summary?: string
|
|
59
62
|
readonly tags?: readonly string[]
|
|
63
|
+
readonly customFields?: Readonly<Record<string, CustomFieldWireValue>>
|
|
60
64
|
}
|
|
61
65
|
|
|
62
66
|
/** The deal columns a row carries directly. Company, stage, owner and people are resolved. */
|
|
@@ -70,6 +74,57 @@ export interface DealFieldsDraft {
|
|
|
70
74
|
readonly summary?: string
|
|
71
75
|
readonly tags?: readonly string[]
|
|
72
76
|
readonly externalId?: string
|
|
77
|
+
readonly customFields?: Readonly<Record<string, CustomFieldWireValue>>
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface OpportunityFieldsDraft {
|
|
81
|
+
readonly name?: string
|
|
82
|
+
readonly kind?: string
|
|
83
|
+
readonly expectedClose?: string
|
|
84
|
+
readonly summary?: string
|
|
85
|
+
readonly tags?: readonly string[]
|
|
86
|
+
readonly customFields?: Readonly<Record<string, CustomFieldWireValue>>
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface EnquiryFieldsDraft {
|
|
90
|
+
readonly name?: string
|
|
91
|
+
readonly source?: string
|
|
92
|
+
readonly summary?: string
|
|
93
|
+
readonly tags?: readonly string[]
|
|
94
|
+
readonly customFields?: Readonly<Record<string, CustomFieldWireValue>>
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface PartnershipFieldsDraft {
|
|
98
|
+
readonly name?: string
|
|
99
|
+
readonly kind?: string
|
|
100
|
+
readonly nextTouchpoint?: string
|
|
101
|
+
readonly goals?: string
|
|
102
|
+
readonly successLooksLike?: string
|
|
103
|
+
readonly summary?: string
|
|
104
|
+
readonly tags?: readonly string[]
|
|
105
|
+
readonly customFields?: Readonly<Record<string, CustomFieldWireValue>>
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface RaiseFieldsDraft {
|
|
109
|
+
readonly name?: string
|
|
110
|
+
readonly checkSizeCents?: number | null
|
|
111
|
+
readonly currency?: string
|
|
112
|
+
readonly thesisFit?: string
|
|
113
|
+
readonly passReason?: string
|
|
114
|
+
readonly expectedClose?: string
|
|
115
|
+
readonly summary?: string
|
|
116
|
+
readonly tags?: readonly string[]
|
|
117
|
+
readonly customFields?: Readonly<Record<string, CustomFieldWireValue>>
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface CustomFieldDefinitionDraft {
|
|
121
|
+
readonly objectType?: string
|
|
122
|
+
readonly key?: string
|
|
123
|
+
readonly label?: string
|
|
124
|
+
readonly type?: string
|
|
125
|
+
readonly options?: readonly string[]
|
|
126
|
+
readonly description?: string
|
|
127
|
+
readonly sortOrder?: number
|
|
73
128
|
}
|
|
74
129
|
|
|
75
130
|
/**
|
|
@@ -143,7 +198,10 @@ function present<T extends object>(draft: Supplied<T>): T {
|
|
|
143
198
|
return Object.fromEntries(Object.entries(draft).filter(([, value]) => value !== undefined)) as T
|
|
144
199
|
}
|
|
145
200
|
|
|
146
|
-
export function companyDraft(
|
|
201
|
+
export function companyDraft(
|
|
202
|
+
mapped: Readonly<Record<string, string>>,
|
|
203
|
+
customFields: Readonly<Record<string, CustomFieldWireValue>> = {},
|
|
204
|
+
): CompanyDraft {
|
|
147
205
|
const domain = text(mapped, 'domain')
|
|
148
206
|
|
|
149
207
|
return present<CompanyDraft>({
|
|
@@ -159,6 +217,7 @@ export function companyDraft(mapped: Readonly<Record<string, string>>): CompanyD
|
|
|
159
217
|
icpFit: enumeration(mapped, 'icp_fit', ICP_FITS),
|
|
160
218
|
summary: text(mapped, 'summary'),
|
|
161
219
|
tags: list(mapped, 'tags'),
|
|
220
|
+
customFields: Object.keys(customFields).length === 0 ? undefined : customFields,
|
|
162
221
|
})
|
|
163
222
|
}
|
|
164
223
|
|
|
@@ -168,7 +227,10 @@ export function companyDraft(mapped: Readonly<Record<string, string>>): CompanyD
|
|
|
168
227
|
* blank, and never the other way round: a `name` cell is never split to fill
|
|
169
228
|
* `first_name`, since a guessed part is stored exactly like one somebody typed.
|
|
170
229
|
*/
|
|
171
|
-
export function personDraft(
|
|
230
|
+
export function personDraft(
|
|
231
|
+
mapped: Readonly<Record<string, string>>,
|
|
232
|
+
customFields: Readonly<Record<string, CustomFieldWireValue>> = {},
|
|
233
|
+
): PersonDraft {
|
|
172
234
|
const email = text(mapped, 'email')
|
|
173
235
|
const firstName = text(mapped, 'first_name')
|
|
174
236
|
const lastName = text(mapped, 'last_name')
|
|
@@ -190,6 +252,7 @@ export function personDraft(mapped: Readonly<Record<string, string>>): PersonDra
|
|
|
190
252
|
relationship: enumeration(mapped, 'relationship', RELATIONSHIP_LEVELS),
|
|
191
253
|
summary: text(mapped, 'summary'),
|
|
192
254
|
tags: list(mapped, 'tags'),
|
|
255
|
+
customFields: Object.keys(customFields).length === 0 ? undefined : customFields,
|
|
193
256
|
})
|
|
194
257
|
}
|
|
195
258
|
|
|
@@ -217,6 +280,7 @@ export function affiliationCompanyDraft(mapped: Readonly<Record<string, string>>
|
|
|
217
280
|
icpFit: undefined,
|
|
218
281
|
summary: undefined,
|
|
219
282
|
tags: undefined,
|
|
283
|
+
customFields: undefined,
|
|
220
284
|
})
|
|
221
285
|
}
|
|
222
286
|
|
|
@@ -224,7 +288,10 @@ export function affiliationCompanyDraft(mapped: Readonly<Record<string, string>>
|
|
|
224
288
|
* `value` is required, so `moneyToCents` has already been checked by
|
|
225
289
|
* `validateRow` and cannot be undefined here.
|
|
226
290
|
*/
|
|
227
|
-
export function dealFieldsDraft(
|
|
291
|
+
export function dealFieldsDraft(
|
|
292
|
+
mapped: Readonly<Record<string, string>>,
|
|
293
|
+
customFields: Readonly<Record<string, CustomFieldWireValue>> = {},
|
|
294
|
+
): DealFieldsDraft {
|
|
228
295
|
const cents = moneyToCents(mapped.value)
|
|
229
296
|
|
|
230
297
|
return present<DealFieldsDraft>({
|
|
@@ -237,5 +304,86 @@ export function dealFieldsDraft(mapped: Readonly<Record<string, string>>): DealF
|
|
|
237
304
|
summary: text(mapped, 'summary'),
|
|
238
305
|
tags: list(mapped, 'tags'),
|
|
239
306
|
externalId: text(mapped, 'external_id'),
|
|
307
|
+
customFields: Object.keys(customFields).length === 0 ? undefined : customFields,
|
|
308
|
+
})
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export function opportunityFieldsDraft(
|
|
312
|
+
mapped: Readonly<Record<string, string>>,
|
|
313
|
+
customFields: Readonly<Record<string, CustomFieldWireValue>> = {},
|
|
314
|
+
): OpportunityFieldsDraft {
|
|
315
|
+
return present<OpportunityFieldsDraft>({
|
|
316
|
+
name: text(mapped, 'name'),
|
|
317
|
+
kind: text(mapped, 'kind'),
|
|
318
|
+
expectedClose: text(mapped, 'expected_close'),
|
|
319
|
+
summary: text(mapped, 'summary'),
|
|
320
|
+
tags: list(mapped, 'tags'),
|
|
321
|
+
customFields: Object.keys(customFields).length === 0 ? undefined : customFields,
|
|
322
|
+
})
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export function enquiryFieldsDraft(
|
|
326
|
+
mapped: Readonly<Record<string, string>>,
|
|
327
|
+
customFields: Readonly<Record<string, CustomFieldWireValue>> = {},
|
|
328
|
+
): EnquiryFieldsDraft {
|
|
329
|
+
return present<EnquiryFieldsDraft>({
|
|
330
|
+
name: text(mapped, 'name'),
|
|
331
|
+
source: text(mapped, 'source'),
|
|
332
|
+
summary: text(mapped, 'summary'),
|
|
333
|
+
tags: list(mapped, 'tags'),
|
|
334
|
+
customFields: Object.keys(customFields).length === 0 ? undefined : customFields,
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export function partnershipFieldsDraft(
|
|
339
|
+
mapped: Readonly<Record<string, string>>,
|
|
340
|
+
customFields: Readonly<Record<string, CustomFieldWireValue>> = {},
|
|
341
|
+
): PartnershipFieldsDraft {
|
|
342
|
+
return present<PartnershipFieldsDraft>({
|
|
343
|
+
name: text(mapped, 'name'),
|
|
344
|
+
kind: text(mapped, 'kind'),
|
|
345
|
+
nextTouchpoint: text(mapped, 'next_touchpoint'),
|
|
346
|
+
goals: text(mapped, 'goals'),
|
|
347
|
+
successLooksLike: text(mapped, 'success_looks_like'),
|
|
348
|
+
summary: text(mapped, 'summary'),
|
|
349
|
+
tags: list(mapped, 'tags'),
|
|
350
|
+
customFields: Object.keys(customFields).length === 0 ? undefined : customFields,
|
|
351
|
+
})
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export function raiseFieldsDraft(
|
|
355
|
+
mapped: Readonly<Record<string, string>>,
|
|
356
|
+
customFields: Readonly<Record<string, CustomFieldWireValue>> = {},
|
|
357
|
+
): RaiseFieldsDraft {
|
|
358
|
+
const cents = moneyToCents(mapped.check_size)
|
|
359
|
+
|
|
360
|
+
return present<RaiseFieldsDraft>({
|
|
361
|
+
name: text(mapped, 'name'),
|
|
362
|
+
checkSizeCents: cents === undefined ? undefined : cents,
|
|
363
|
+
currency: text(mapped, 'currency'),
|
|
364
|
+
thesisFit: text(mapped, 'thesis_fit'),
|
|
365
|
+
passReason: text(mapped, 'pass_reason'),
|
|
366
|
+
expectedClose: text(mapped, 'expected_close'),
|
|
367
|
+
summary: text(mapped, 'summary'),
|
|
368
|
+
tags: list(mapped, 'tags'),
|
|
369
|
+
customFields: Object.keys(customFields).length === 0 ? undefined : customFields,
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export function customFieldDefinitionDraft(
|
|
374
|
+
mapped: Readonly<Record<string, string>>,
|
|
375
|
+
): CustomFieldDefinitionDraft {
|
|
376
|
+
const sortOrderRaw = text(mapped, 'sort_order')
|
|
377
|
+
const sortOrder =
|
|
378
|
+
sortOrderRaw === undefined ? undefined : Number.parseInt(sortOrderRaw, 10)
|
|
379
|
+
|
|
380
|
+
return present<CustomFieldDefinitionDraft>({
|
|
381
|
+
objectType: text(mapped, 'object_type'),
|
|
382
|
+
key: text(mapped, 'key'),
|
|
383
|
+
label: text(mapped, 'label'),
|
|
384
|
+
type: text(mapped, 'type'),
|
|
385
|
+
options: list(mapped, 'options'),
|
|
386
|
+
description: text(mapped, 'description'),
|
|
387
|
+
sortOrder: sortOrder !== undefined && Number.isInteger(sortOrder) ? sortOrder : undefined,
|
|
240
388
|
})
|
|
241
389
|
}
|