@kelpie/server 0.10.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/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/repository.d.ts +0 -1
- package/dist/modules/lists/repository.d.ts.map +1 -1
- package/dist/modules/lists/repository.js +0 -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/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/repository.ts +0 -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
|
@@ -4,7 +4,10 @@ import {
|
|
|
4
4
|
MAX_IMPORT_ROWS,
|
|
5
5
|
OBJECT_COLUMNS,
|
|
6
6
|
SYNC_IMPORT_ROWS,
|
|
7
|
+
customFieldObjectTypeForExport,
|
|
7
8
|
findMatchKey,
|
|
9
|
+
knownImportColumnKeys,
|
|
10
|
+
pipelineKindForImport,
|
|
8
11
|
requiredColumns,
|
|
9
12
|
} from '@kelpie/schemas'
|
|
10
13
|
import type {
|
|
@@ -13,6 +16,7 @@ import type {
|
|
|
13
16
|
ImportCounts,
|
|
14
17
|
ImportJobStatus,
|
|
15
18
|
ImportObject,
|
|
19
|
+
ExportObject,
|
|
16
20
|
ImportPreviewRow,
|
|
17
21
|
ImportRowError,
|
|
18
22
|
ImportSource,
|
|
@@ -27,14 +31,20 @@ import type { Logger } from '../../lib/logger.ts'
|
|
|
27
31
|
import { normaliseDomain, normaliseEmail } from '../../lib/normalisation.ts'
|
|
28
32
|
import type { BufferedEvents, Queryable, TransactionScope } from '../../runtime/transaction.ts'
|
|
29
33
|
import type { ActivityRecorder } from '../activities/recorder.ts'
|
|
34
|
+
import { definitionsForObject } from '../custom-fields/repository.ts'
|
|
35
|
+
import { baseColumnKeySet } from './customFieldImport.ts'
|
|
30
36
|
import { toEventActor } from '../../lib/actor.ts'
|
|
31
|
-
import type { RecordObjectType } from '../../runtime/events.ts'
|
|
32
37
|
import type { Actor } from '../auth/actor.ts'
|
|
33
38
|
import { requireWorkspaceId } from '../auth/actor.ts'
|
|
34
39
|
import '../companies/events.ts'
|
|
35
40
|
import '../deals/events.ts'
|
|
41
|
+
import '../enquiries/events.ts'
|
|
42
|
+
import '../opportunities/events.ts'
|
|
43
|
+
import '../partnerships/events.ts'
|
|
36
44
|
import '../people/events.ts'
|
|
37
45
|
import '../positions/events.ts'
|
|
46
|
+
import '../raises/events.ts'
|
|
47
|
+
import '../custom-fields/events.ts'
|
|
38
48
|
import './events.ts'
|
|
39
49
|
|
|
40
50
|
/**
|
|
@@ -44,8 +54,10 @@ import './events.ts'
|
|
|
44
54
|
*/
|
|
45
55
|
function emitImportedRecordCreated(
|
|
46
56
|
events: BufferedEvents,
|
|
47
|
-
objectType:
|
|
57
|
+
objectType: import('./writes.ts').ImportWrittenObjectType,
|
|
48
58
|
recordId: string,
|
|
59
|
+
writeObject?: ImportObject,
|
|
60
|
+
draft?: { readonly objectType?: string; readonly key?: string },
|
|
49
61
|
): void {
|
|
50
62
|
switch (objectType) {
|
|
51
63
|
case 'person':
|
|
@@ -60,7 +72,27 @@ function emitImportedRecordCreated(
|
|
|
60
72
|
case 'deal':
|
|
61
73
|
events.emit('deals.deal.created', { type: 'deal', id: recordId }, {})
|
|
62
74
|
return
|
|
63
|
-
|
|
75
|
+
case 'opportunity':
|
|
76
|
+
events.emit('opportunities.opportunity.created', { type: 'opportunity', id: recordId }, {})
|
|
77
|
+
return
|
|
78
|
+
case 'enquiry':
|
|
79
|
+
events.emit('enquiries.enquiry.created', { type: 'enquiry', id: recordId }, {})
|
|
80
|
+
return
|
|
81
|
+
case 'partnership':
|
|
82
|
+
events.emit('partnerships.partnership.created', { type: 'partnership', id: recordId }, {})
|
|
83
|
+
return
|
|
84
|
+
case 'raise':
|
|
85
|
+
events.emit('raises.raise.created', { type: 'raise', id: recordId }, {})
|
|
86
|
+
return
|
|
87
|
+
case 'custom_field':
|
|
88
|
+
if (writeObject === 'custom_fields' && draft?.objectType !== undefined && draft.key !== undefined) {
|
|
89
|
+
events.emit(
|
|
90
|
+
'custom_fields.field.created',
|
|
91
|
+
{ type: 'custom_field', id: recordId },
|
|
92
|
+
{ objectType: draft.objectType, key: draft.key },
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
return
|
|
64
96
|
default:
|
|
65
97
|
throw new Error(`import produced an unexpected object type: ${objectType}`)
|
|
66
98
|
}
|
|
@@ -68,9 +100,10 @@ function emitImportedRecordCreated(
|
|
|
68
100
|
|
|
69
101
|
function emitImportedRecordUpdated(
|
|
70
102
|
events: BufferedEvents,
|
|
71
|
-
objectType:
|
|
103
|
+
objectType: import('./writes.ts').ImportWrittenObjectType,
|
|
72
104
|
recordId: string,
|
|
73
105
|
changed: readonly string[],
|
|
106
|
+
draft?: { readonly objectType?: string; readonly key?: string },
|
|
74
107
|
): void {
|
|
75
108
|
switch (objectType) {
|
|
76
109
|
case 'person':
|
|
@@ -93,6 +126,27 @@ function emitImportedRecordUpdated(
|
|
|
93
126
|
case 'deal':
|
|
94
127
|
events.emit('deals.deal.updated', { type: 'deal', id: recordId }, { changed })
|
|
95
128
|
return
|
|
129
|
+
case 'opportunity':
|
|
130
|
+
events.emit('opportunities.opportunity.updated', { type: 'opportunity', id: recordId }, { changed })
|
|
131
|
+
return
|
|
132
|
+
case 'enquiry':
|
|
133
|
+
events.emit('enquiries.enquiry.updated', { type: 'enquiry', id: recordId }, { changed })
|
|
134
|
+
return
|
|
135
|
+
case 'partnership':
|
|
136
|
+
events.emit('partnerships.partnership.updated', { type: 'partnership', id: recordId }, { changed })
|
|
137
|
+
return
|
|
138
|
+
case 'raise':
|
|
139
|
+
events.emit('raises.raise.updated', { type: 'raise', id: recordId }, { changed })
|
|
140
|
+
return
|
|
141
|
+
case 'custom_field':
|
|
142
|
+
if (draft?.objectType !== undefined && draft.key !== undefined) {
|
|
143
|
+
events.emit(
|
|
144
|
+
'custom_fields.field.updated',
|
|
145
|
+
{ type: 'custom_field', id: recordId },
|
|
146
|
+
{ objectType: draft.objectType, key: draft.key, changed },
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
return
|
|
96
150
|
default:
|
|
97
151
|
throw new Error(`import produced an unexpected object type: ${objectType}`)
|
|
98
152
|
}
|
|
@@ -184,8 +238,8 @@ export interface ImportExportService {
|
|
|
184
238
|
commit(actor: Actor, id: string, csv: string): Promise<ImportJobView>
|
|
185
239
|
deleteJob(actor: Actor, id: string): Promise<void>
|
|
186
240
|
/** CSV lines for a whole object, a page of records at a time. */
|
|
187
|
-
exportCsv(actor: Actor, object:
|
|
188
|
-
templateCsv(object:
|
|
241
|
+
exportCsv(actor: Actor, object: ExportObject): AsyncGenerator<string>
|
|
242
|
+
templateCsv(actor: Actor, object: ExportObject): Promise<string>
|
|
189
243
|
}
|
|
190
244
|
|
|
191
245
|
const EMPTY_COUNTS: ImportCounts = { total: 0, create: 0, update: 0, skip: 0, error: 0 }
|
|
@@ -271,8 +325,9 @@ export function createImportExportService(
|
|
|
271
325
|
matchKey: MatchKeyOption,
|
|
272
326
|
columnMap: ImportColumnMap,
|
|
273
327
|
headers: readonly string[],
|
|
328
|
+
customFieldKeys: readonly string[] = [],
|
|
274
329
|
): void {
|
|
275
|
-
const known = new Set(
|
|
330
|
+
const known = new Set(knownImportColumnKeys(object, customFieldKeys))
|
|
276
331
|
const present = new Set(headers)
|
|
277
332
|
const problems = [
|
|
278
333
|
...Object.keys(columnMap)
|
|
@@ -340,6 +395,33 @@ export function createImportExportService(
|
|
|
340
395
|
return matchKey.id === 'external_id'
|
|
341
396
|
? repository.findDealKeysByExternalId(db, workspaceId, column('external_id'))
|
|
342
397
|
: repository.findDealKeysByCompany(db, workspaceId, domains)
|
|
398
|
+
case 'opportunities':
|
|
399
|
+
return matchKey.id === 'name'
|
|
400
|
+
? repository.findOpportunityKeysByName(
|
|
401
|
+
db,
|
|
402
|
+
workspaceId,
|
|
403
|
+
column('name').map((name) => name.toLowerCase()),
|
|
404
|
+
)
|
|
405
|
+
: repository.findOpportunityKeysByCompany(db, workspaceId, domains)
|
|
406
|
+
case 'enquiries':
|
|
407
|
+
return matchKey.id === 'name'
|
|
408
|
+
? repository.findEnquiryKeysByName(
|
|
409
|
+
db,
|
|
410
|
+
workspaceId,
|
|
411
|
+
column('name').map((name) => name.toLowerCase()),
|
|
412
|
+
)
|
|
413
|
+
: repository.findEnquiryKeysByCompany(db, workspaceId, domains)
|
|
414
|
+
case 'partnerships':
|
|
415
|
+
return repository.findPartnershipKeysByCompany(db, workspaceId, domains)
|
|
416
|
+
case 'raises':
|
|
417
|
+
return repository.findRaiseKeysByCompany(db, workspaceId, domains)
|
|
418
|
+
case 'custom_fields':
|
|
419
|
+
return repository.findCustomFieldDefinitionKeys(
|
|
420
|
+
db,
|
|
421
|
+
workspaceId,
|
|
422
|
+
column('object_type'),
|
|
423
|
+
column('key'),
|
|
424
|
+
)
|
|
343
425
|
}
|
|
344
426
|
})()
|
|
345
427
|
|
|
@@ -369,14 +451,14 @@ export function createImportExportService(
|
|
|
369
451
|
): Promise<ImportLookups> {
|
|
370
452
|
const existing = await findExistingKeys(db, workspaceId, object, matchKey, rows)
|
|
371
453
|
|
|
372
|
-
if (object === 'companies') {
|
|
454
|
+
if (object === 'companies' || object === 'custom_fields') {
|
|
373
455
|
return {
|
|
374
456
|
existing,
|
|
375
457
|
personIdByEmail: new Map(),
|
|
376
458
|
companyIdByDomain: new Map(),
|
|
377
459
|
companyIdByName: new Map(),
|
|
378
460
|
memberIdByEmail: new Map(),
|
|
379
|
-
|
|
461
|
+
stageIdByName: new Map(),
|
|
380
462
|
}
|
|
381
463
|
}
|
|
382
464
|
|
|
@@ -401,10 +483,11 @@ export function createImportExportService(
|
|
|
401
483
|
),
|
|
402
484
|
companyIdByName: new Map(byName.map((row) => [row.name.toLowerCase(), row.id] as const)),
|
|
403
485
|
memberIdByEmail: new Map(),
|
|
404
|
-
|
|
486
|
+
stageIdByName: new Map(),
|
|
405
487
|
}
|
|
406
488
|
}
|
|
407
489
|
|
|
490
|
+
const pipelineKind = pipelineKindForImport(object)
|
|
408
491
|
const emails = distinct([
|
|
409
492
|
...rows.map((row) => normaliseEmail(row.mapped.person_email ?? '')),
|
|
410
493
|
...rows.flatMap((row) =>
|
|
@@ -428,46 +511,96 @@ export function createImportExportService(
|
|
|
428
511
|
),
|
|
429
512
|
companyIdByName: new Map(),
|
|
430
513
|
memberIdByEmail: new Map(),
|
|
431
|
-
|
|
514
|
+
stageIdByName: new Map(),
|
|
432
515
|
}
|
|
433
516
|
}
|
|
434
517
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
518
|
+
if (pipelineKind !== null) {
|
|
519
|
+
const [members, stages] = await Promise.all([
|
|
520
|
+
repository.listMemberEmails(db, workspaceId),
|
|
521
|
+
repository.listPipelineStages(db, workspaceId, pipelineKind),
|
|
522
|
+
])
|
|
523
|
+
const stagesByName = new Map<string, string>()
|
|
439
524
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
525
|
+
for (const stage of stages) {
|
|
526
|
+
stagesByName.set(stage.slug.toLowerCase(), stage.id)
|
|
527
|
+
stagesByName.set(stage.label.toLowerCase(), stage.id)
|
|
528
|
+
}
|
|
443
529
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
530
|
+
return {
|
|
531
|
+
existing,
|
|
532
|
+
personIdByEmail: new Map(
|
|
533
|
+
peopleRows.flatMap((row) => (row.email === null ? [] : [[row.email, row.id] as const])),
|
|
534
|
+
),
|
|
535
|
+
companyIdByDomain: new Map(
|
|
536
|
+
companyRows.flatMap((row) => (row.domain === null ? [] : [[row.domain, row.id] as const])),
|
|
537
|
+
),
|
|
538
|
+
companyIdByName: new Map(),
|
|
539
|
+
memberIdByEmail: new Map(members.map((member) => [member.email.toLowerCase(), member.id])),
|
|
540
|
+
stageIdByName: stagesByName,
|
|
541
|
+
}
|
|
447
542
|
}
|
|
448
543
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
544
|
+
throw new Error(`No lookup builder for import object ${object}`)
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
async function customFieldContext(
|
|
548
|
+
workspaceId: string,
|
|
549
|
+
object: ImportObject,
|
|
550
|
+
): Promise<{
|
|
551
|
+
readonly definitions: Awaited<ReturnType<typeof definitionsForObject>>
|
|
552
|
+
readonly keys: readonly string[]
|
|
553
|
+
}> {
|
|
554
|
+
const objectType = customFieldObjectTypeForExport(object)
|
|
555
|
+
|
|
556
|
+
if (objectType === null) {
|
|
557
|
+
return { definitions: [], keys: [] }
|
|
460
558
|
}
|
|
559
|
+
|
|
560
|
+
const definitions = await definitionsForObject(dependencies.db, workspaceId, objectType)
|
|
561
|
+
|
|
562
|
+
return { definitions, keys: definitions.map((definition) => definition.key) }
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function augmentColumnMap(
|
|
566
|
+
_object: ImportObject,
|
|
567
|
+
headers: readonly string[],
|
|
568
|
+
columnMap: ImportColumnMap,
|
|
569
|
+
customFieldKeys: readonly string[],
|
|
570
|
+
): ImportColumnMap {
|
|
571
|
+
const map = { ...columnMap }
|
|
572
|
+
|
|
573
|
+
for (const key of customFieldKeys) {
|
|
574
|
+
if (map[key] !== undefined) {
|
|
575
|
+
continue
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const match = headers.find((header) => header.toLowerCase() === key.toLowerCase())
|
|
579
|
+
|
|
580
|
+
if (match !== undefined) {
|
|
581
|
+
map[key] = match
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
return map
|
|
461
586
|
}
|
|
462
587
|
|
|
463
|
-
function contextFor(
|
|
588
|
+
function contextFor(
|
|
589
|
+
job: ImportJobRecord,
|
|
590
|
+
lookups: ImportLookups,
|
|
591
|
+
customFieldDefinitions: Awaited<ReturnType<typeof definitionsForObject>>,
|
|
592
|
+
): PlanContext {
|
|
593
|
+
const object = job.object as ImportObject
|
|
594
|
+
|
|
464
595
|
return {
|
|
465
|
-
object
|
|
466
|
-
matchKey: requireMatchKey(
|
|
596
|
+
object,
|
|
597
|
+
matchKey: requireMatchKey(object, job.matchKey),
|
|
467
598
|
conflictMode: job.conflictMode as ImportConflictMode,
|
|
468
599
|
onMissingCompany: job.onMissingCompany as OnMissingCompany,
|
|
469
600
|
consentPurposeId: job.consentPurposeId,
|
|
470
601
|
lookups,
|
|
602
|
+
customFieldDefinitions,
|
|
603
|
+
baseColumnKeys: baseColumnKeySet(OBJECT_COLUMNS[object]),
|
|
471
604
|
}
|
|
472
605
|
}
|
|
473
606
|
|
|
@@ -581,14 +714,16 @@ export function createImportExportService(
|
|
|
581
714
|
async function runDryRun(workspaceId: string, jobId: string, parsed: ParsedCsv): Promise<void> {
|
|
582
715
|
const job = await requireJob(workspaceId, jobId)
|
|
583
716
|
const { rows } = readFile(job, parsed)
|
|
717
|
+
const object = job.object as ImportObject
|
|
718
|
+
const { definitions } = await customFieldContext(workspaceId, object)
|
|
584
719
|
const lookups = await buildLookups(
|
|
585
720
|
dependencies.db,
|
|
586
721
|
workspaceId,
|
|
587
|
-
|
|
588
|
-
requireMatchKey(
|
|
722
|
+
object,
|
|
723
|
+
requireMatchKey(object, job.matchKey),
|
|
589
724
|
rows,
|
|
590
725
|
)
|
|
591
|
-
const planned = planRows(contextFor(job, lookups), rows)
|
|
726
|
+
const planned = planRows(contextFor(job, lookups, definitions), rows)
|
|
592
727
|
|
|
593
728
|
await repository.updateJob(dependencies.db, workspaceId, jobId, {
|
|
594
729
|
status: 'ready',
|
|
@@ -652,8 +787,9 @@ export function createImportExportService(
|
|
|
652
787
|
// Resolved inside the transaction, against the rows this commit has
|
|
653
788
|
// already written. That is what makes a file listing one company twice
|
|
654
789
|
// create it once, and what lets an interrupted commit be re-run.
|
|
790
|
+
const { definitions } = await customFieldContext(workspaceId, object)
|
|
655
791
|
const lookups = await buildLookups(tx, workspaceId, object, matchKey, [row])
|
|
656
|
-
const plan = planRow(contextFor(job, lookups), mapped)
|
|
792
|
+
const plan = planRow(contextFor(job, lookups, definitions), mapped)
|
|
657
793
|
|
|
658
794
|
const outcome: repository.RowOutcome = {
|
|
659
795
|
rowNumber: line.number,
|
|
@@ -678,7 +814,13 @@ export function createImportExportService(
|
|
|
678
814
|
)
|
|
679
815
|
|
|
680
816
|
if (plan.action === 'create') {
|
|
681
|
-
emitImportedRecordCreated(
|
|
817
|
+
emitImportedRecordCreated(
|
|
818
|
+
events,
|
|
819
|
+
written.objectType,
|
|
820
|
+
written.recordId,
|
|
821
|
+
object,
|
|
822
|
+
plan.write.object === 'custom_fields' ? plan.write.draft : undefined,
|
|
823
|
+
)
|
|
682
824
|
} else if (written.changedFields.length > 0) {
|
|
683
825
|
// An update that moved nothing publishes nothing. Re-running the same
|
|
684
826
|
// file must not wake every consumer watching for a change.
|
|
@@ -687,6 +829,7 @@ export function createImportExportService(
|
|
|
687
829
|
written.objectType,
|
|
688
830
|
written.recordId,
|
|
689
831
|
written.changedFields,
|
|
832
|
+
plan.write.object === 'custom_fields' ? plan.write.draft : undefined,
|
|
690
833
|
)
|
|
691
834
|
}
|
|
692
835
|
|
|
@@ -839,10 +982,21 @@ export function createImportExportService(
|
|
|
839
982
|
}
|
|
840
983
|
|
|
841
984
|
const matchKey = requireMatchKey(input.object, input.matchKeyId)
|
|
842
|
-
const
|
|
843
|
-
|
|
985
|
+
const { keys: customFieldKeys } = await customFieldContext(workspaceId, input.object)
|
|
986
|
+
let columnMap =
|
|
987
|
+
input.columnMap ??
|
|
988
|
+
augmentColumnMap(
|
|
989
|
+
input.object,
|
|
990
|
+
parsed.headers,
|
|
991
|
+
defaultColumnMap(input.source, input.object, parsed.headers),
|
|
992
|
+
customFieldKeys,
|
|
993
|
+
)
|
|
994
|
+
|
|
995
|
+
if (input.columnMap !== undefined) {
|
|
996
|
+
columnMap = augmentColumnMap(input.object, parsed.headers, columnMap, customFieldKeys)
|
|
997
|
+
}
|
|
844
998
|
|
|
845
|
-
requireUsableColumnMap(input.object, matchKey, columnMap, parsed.headers)
|
|
999
|
+
requireUsableColumnMap(input.object, matchKey, columnMap, parsed.headers, customFieldKeys)
|
|
846
1000
|
|
|
847
1001
|
// Consent is a People-only feature. A purpose on any other object is
|
|
848
1002
|
// refused up front; mapping the consent columns without one is refused
|
|
@@ -995,8 +1149,17 @@ export function createImportExportService(
|
|
|
995
1149
|
return streamExport(dependencies.db, requireWorkspaceId(actor), object)
|
|
996
1150
|
},
|
|
997
1151
|
|
|
998
|
-
templateCsv(object) {
|
|
999
|
-
|
|
1152
|
+
templateCsv(actor, object) {
|
|
1153
|
+
const workspaceId = requireWorkspaceId(actor)
|
|
1154
|
+
const objectType = customFieldObjectTypeForExport(object)
|
|
1155
|
+
|
|
1156
|
+
if (objectType === null) {
|
|
1157
|
+
return Promise.resolve(csvLine(templateHeadersFor(object)))
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
return definitionsForObject(dependencies.db, workspaceId, objectType).then((definitions) =>
|
|
1161
|
+
csvLine(templateHeadersFor(object, definitions)),
|
|
1162
|
+
)
|
|
1000
1163
|
},
|
|
1001
1164
|
}
|
|
1002
1165
|
}
|
|
@@ -1,14 +1,28 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { customFieldObjectTypeForExport } from '@kelpie/schemas'
|
|
2
|
+
import type { ExportObject } from '@kelpie/schemas'
|
|
2
3
|
|
|
3
4
|
import type { Database } from '../../lib/database.ts'
|
|
5
|
+
import { definitionsForObject } from '../custom-fields/repository.ts'
|
|
6
|
+
import type { CustomFieldDefinitionRecord } from '../custom-fields/repository.ts'
|
|
4
7
|
import { csvLine } from './csv.ts'
|
|
5
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
companyCells,
|
|
10
|
+
customFieldDefinitionRowCells,
|
|
11
|
+
dealCells,
|
|
12
|
+
enquiryCells,
|
|
13
|
+
headersFor,
|
|
14
|
+
opportunityCells,
|
|
15
|
+
partnershipCells,
|
|
16
|
+
personCells,
|
|
17
|
+
positionCells,
|
|
18
|
+
raiseCells,
|
|
19
|
+
} from './exportRows.ts'
|
|
6
20
|
import * as repository from './repository.ts'
|
|
7
21
|
|
|
8
22
|
/**
|
|
9
23
|
* A whole object as CSV, a page of records at a time.
|
|
10
24
|
*
|
|
11
|
-
* A generator rather than a string, because a workspace's
|
|
25
|
+
* A generator rather than a string, because a workspace's records do not have to
|
|
12
26
|
* fit in memory to be downloaded and `import-export.md` says the endpoint
|
|
13
27
|
* streams. The route pipes this straight into the response.
|
|
14
28
|
*
|
|
@@ -49,39 +63,68 @@ async function* pageThrough<TRow extends { readonly id: string }>(
|
|
|
49
63
|
}
|
|
50
64
|
}
|
|
51
65
|
|
|
52
|
-
|
|
53
|
-
async function dealPage(
|
|
66
|
+
async function linkedPersonEmailCells<T extends { readonly id: string }>(
|
|
54
67
|
db: Database,
|
|
55
68
|
workspaceId: string,
|
|
56
|
-
|
|
69
|
+
targetType: string,
|
|
70
|
+
rows: readonly T[],
|
|
71
|
+
toCells: (row: T, personEmails: readonly string[]) => readonly string[],
|
|
57
72
|
): Promise<readonly (readonly string[])[]> {
|
|
58
|
-
const emails = await repository.
|
|
73
|
+
const emails = await repository.readLinkedPersonEmails(
|
|
59
74
|
db,
|
|
60
75
|
workspaceId,
|
|
76
|
+
targetType,
|
|
61
77
|
rows.map((row) => row.id),
|
|
62
78
|
)
|
|
63
79
|
|
|
64
|
-
return rows.map((row) =>
|
|
80
|
+
return rows.map((row) => toCells(row, emails.get(row.id) ?? []))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function customFieldDefinitionsFor(
|
|
84
|
+
db: Database,
|
|
85
|
+
workspaceId: string,
|
|
86
|
+
object: ExportObject,
|
|
87
|
+
): Promise<readonly CustomFieldDefinitionRecord[]> {
|
|
88
|
+
const objectType = customFieldObjectTypeForExport(object)
|
|
89
|
+
|
|
90
|
+
if (objectType === null) {
|
|
91
|
+
return []
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return definitionsForObject(db, workspaceId, objectType)
|
|
65
95
|
}
|
|
66
96
|
|
|
67
97
|
export async function* streamExport(
|
|
68
98
|
db: Database,
|
|
69
99
|
workspaceId: string,
|
|
70
|
-
object:
|
|
100
|
+
object: ExportObject,
|
|
71
101
|
): AsyncGenerator<string> {
|
|
72
|
-
|
|
102
|
+
if (object === 'custom_fields') {
|
|
103
|
+
yield csvLine(headersFor(object))
|
|
104
|
+
|
|
105
|
+
yield* pageThrough({
|
|
106
|
+
read: (after) => repository.readCustomFieldDefinitions(db, workspaceId, after),
|
|
107
|
+
cells: (rows) => Promise.resolve(rows.map(customFieldDefinitionRowCells)),
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const definitions = await customFieldDefinitionsFor(db, workspaceId, object)
|
|
114
|
+
|
|
115
|
+
yield csvLine(headersFor(object, definitions))
|
|
73
116
|
|
|
74
117
|
switch (object) {
|
|
75
118
|
case 'companies':
|
|
76
119
|
yield* pageThrough({
|
|
77
120
|
read: (after) => repository.readCompanies(db, workspaceId, after),
|
|
78
|
-
cells: (rows) => Promise.resolve(rows.map(companyCells)),
|
|
121
|
+
cells: (rows) => Promise.resolve(rows.map((row) => companyCells(row, definitions))),
|
|
79
122
|
})
|
|
80
123
|
return
|
|
81
124
|
case 'people':
|
|
82
125
|
yield* pageThrough({
|
|
83
126
|
read: (after) => repository.readPeople(db, workspaceId, after),
|
|
84
|
-
cells: (rows) => Promise.resolve(rows.map(personCells)),
|
|
127
|
+
cells: (rows) => Promise.resolve(rows.map((row) => personCells(row, definitions))),
|
|
85
128
|
})
|
|
86
129
|
return
|
|
87
130
|
case 'positions':
|
|
@@ -93,7 +136,46 @@ export async function* streamExport(
|
|
|
93
136
|
case 'deals':
|
|
94
137
|
yield* pageThrough({
|
|
95
138
|
read: (after) => repository.readDeals(db, workspaceId, after),
|
|
96
|
-
cells: (rows) =>
|
|
139
|
+
cells: (rows) =>
|
|
140
|
+
linkedPersonEmailCells(db, workspaceId, 'deal', rows, (row, personEmails) =>
|
|
141
|
+
dealCells(row, personEmails, definitions),
|
|
142
|
+
),
|
|
143
|
+
})
|
|
144
|
+
return
|
|
145
|
+
case 'opportunities':
|
|
146
|
+
yield* pageThrough({
|
|
147
|
+
read: (after) => repository.readOpportunities(db, workspaceId, after),
|
|
148
|
+
cells: (rows) =>
|
|
149
|
+
linkedPersonEmailCells(db, workspaceId, 'opportunity', rows, (row, personEmails) =>
|
|
150
|
+
opportunityCells(row, personEmails, definitions),
|
|
151
|
+
),
|
|
152
|
+
})
|
|
153
|
+
return
|
|
154
|
+
case 'enquiries':
|
|
155
|
+
yield* pageThrough({
|
|
156
|
+
read: (after) => repository.readEnquiries(db, workspaceId, after),
|
|
157
|
+
cells: (rows) =>
|
|
158
|
+
linkedPersonEmailCells(db, workspaceId, 'enquiry', rows, (row, personEmails) =>
|
|
159
|
+
enquiryCells(row, personEmails, definitions),
|
|
160
|
+
),
|
|
161
|
+
})
|
|
162
|
+
return
|
|
163
|
+
case 'partnerships':
|
|
164
|
+
yield* pageThrough({
|
|
165
|
+
read: (after) => repository.readPartnerships(db, workspaceId, after),
|
|
166
|
+
cells: (rows) =>
|
|
167
|
+
linkedPersonEmailCells(db, workspaceId, 'partnership', rows, (row, personEmails) =>
|
|
168
|
+
partnershipCells(row, personEmails, definitions),
|
|
169
|
+
),
|
|
170
|
+
})
|
|
171
|
+
return
|
|
172
|
+
case 'raises':
|
|
173
|
+
yield* pageThrough({
|
|
174
|
+
read: (after) => repository.readRaises(db, workspaceId, after),
|
|
175
|
+
cells: (rows) =>
|
|
176
|
+
linkedPersonEmailCells(db, workspaceId, 'raise', rows, (row, personEmails) =>
|
|
177
|
+
raiseCells(row, personEmails, definitions),
|
|
178
|
+
),
|
|
97
179
|
})
|
|
98
180
|
return
|
|
99
181
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
EXPORT_OBJECTS,
|
|
2
3
|
IMPORT_CONFLICT_MODES,
|
|
3
4
|
IMPORT_OBJECTS,
|
|
4
5
|
IMPORT_SOURCES,
|
|
@@ -34,9 +35,13 @@ import type { ImportExportService } from './service.ts'
|
|
|
34
35
|
*/
|
|
35
36
|
export const MAX_INLINE_EXPORT_BYTES = 256 * 1024
|
|
36
37
|
|
|
37
|
-
const
|
|
38
|
+
const exportObjectArg = z
|
|
39
|
+
.enum(EXPORT_OBJECTS)
|
|
40
|
+
.describe(`Which object to export. One of: ${EXPORT_OBJECTS.join(', ')}.`)
|
|
41
|
+
|
|
42
|
+
const importObjectArg = z
|
|
38
43
|
.enum(IMPORT_OBJECTS)
|
|
39
|
-
.describe(`Which object to
|
|
44
|
+
.describe(`Which object to import. One of: ${IMPORT_OBJECTS.join(', ')}.`)
|
|
40
45
|
|
|
41
46
|
/** `column_map` is a real object here. The multipart route takes it as a JSON string. */
|
|
42
47
|
const columnMapArg = z
|
|
@@ -54,7 +59,7 @@ const csvArg = z
|
|
|
54
59
|
|
|
55
60
|
const previewArgs = z.strictObject({
|
|
56
61
|
source: z.enum(IMPORT_SOURCES).describe('Which export the file came out of.'),
|
|
57
|
-
object:
|
|
62
|
+
object: importObjectArg,
|
|
58
63
|
csv: csvArg,
|
|
59
64
|
conflict_mode: z
|
|
60
65
|
.enum(IMPORT_CONFLICT_MODES)
|
|
@@ -112,7 +117,7 @@ export function registerImportExportTools(mcp: McpToolRegistry, service: ImportE
|
|
|
112
117
|
description:
|
|
113
118
|
'Export every record of one object as CSV text. Refuses an export too large to sit in ' +
|
|
114
119
|
'a tool result, and names the download to use instead. Mirrors GET /v1/export/{object}.csv.',
|
|
115
|
-
inputSchema: z.strictObject({ object:
|
|
120
|
+
inputSchema: z.strictObject({ object: exportObjectArg }),
|
|
116
121
|
invoke: async ({ object }, actor) => ({
|
|
117
122
|
object,
|
|
118
123
|
csv: await collectCsv(service.exportCsv(actor, object)),
|
|
@@ -124,8 +129,11 @@ export function registerImportExportTools(mcp: McpToolRegistry, service: ImportE
|
|
|
124
129
|
description:
|
|
125
130
|
'The header row Kelpie expects for one object, with no records in it. Start a hand-built ' +
|
|
126
131
|
'import from this. Mirrors GET /v1/export/templates/{object}.csv.',
|
|
127
|
-
inputSchema: z.strictObject({ object:
|
|
128
|
-
invoke: ({ object }) =>
|
|
132
|
+
inputSchema: z.strictObject({ object: exportObjectArg }),
|
|
133
|
+
invoke: async ({ object }, actor) => ({
|
|
134
|
+
object,
|
|
135
|
+
csv: await service.templateCsv(actor, object),
|
|
136
|
+
}),
|
|
129
137
|
})
|
|
130
138
|
|
|
131
139
|
mcp.tool({
|