@pattern-stack/codegen 0.10.1 → 0.12.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/CHANGELOG.md +122 -0
- package/README.md +5 -5
- package/consumer-skills/codegen/SKILL.md +2 -2
- package/consumer-skills/{sync → integration}/SKILL.md +29 -29
- package/consumer-skills/{sync → integration}/audit-and-detection.md +22 -22
- package/consumer-skills/{sync → integration}/change-sources-and-sinks.md +60 -60
- package/consumer-skills/subsystems/SKILL.md +8 -8
- package/consumer-skills/subsystems/wiring-and-order.md +7 -7
- package/dist/runtime/base-classes/index.d.ts +4 -4
- package/dist/runtime/base-classes/index.js +35 -35
- package/dist/runtime/base-classes/index.js.map +1 -1
- package/dist/runtime/base-classes/{synced-entity-repository.d.ts → integrated-entity-repository.d.ts} +15 -15
- package/dist/runtime/base-classes/{synced-entity-repository.js → integrated-entity-repository.js} +21 -21
- package/dist/runtime/base-classes/integrated-entity-repository.js.map +1 -0
- package/dist/runtime/base-classes/{synced-entity-service.d.ts → integrated-entity-service.d.ts} +6 -6
- package/dist/runtime/base-classes/{synced-entity-service.js → integrated-entity-service.js} +4 -4
- package/dist/runtime/base-classes/integrated-entity-service.js.map +1 -0
- package/dist/runtime/base-classes/{sync-upsert-config.d.ts → integration-upsert-config.d.ts} +13 -13
- package/dist/runtime/base-classes/integration-upsert-config.js +1 -0
- package/dist/runtime/base-classes/{junction-sync-repository.d.ts → junction-integration-repository.d.ts} +11 -11
- package/dist/runtime/base-classes/{junction-sync-repository.js → junction-integration-repository.js} +15 -15
- package/dist/runtime/base-classes/junction-integration-repository.js.map +1 -0
- package/dist/runtime/subsystems/auth/auth-oauth-state.schema.js.map +1 -1
- package/dist/runtime/subsystems/auth/auth.module.d.ts +4 -4
- package/dist/runtime/subsystems/auth/auth.module.js +3 -3
- package/dist/runtime/subsystems/auth/auth.module.js.map +1 -1
- package/dist/runtime/subsystems/auth/auth.tokens.d.ts +8 -8
- package/dist/runtime/subsystems/auth/auth.tokens.js +6 -6
- package/dist/runtime/subsystems/auth/auth.tokens.js.map +1 -1
- package/dist/runtime/subsystems/auth/backends/state-store.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/auth/controllers/auth.controller.d.ts +2 -2
- package/dist/runtime/subsystems/auth/controllers/auth.controller.js +3 -3
- package/dist/runtime/subsystems/auth/controllers/auth.controller.js.map +1 -1
- package/dist/runtime/subsystems/auth/index.d.ts +3 -3
- package/dist/runtime/subsystems/auth/index.js +40 -40
- package/dist/runtime/subsystems/auth/index.js.map +1 -1
- package/dist/runtime/subsystems/auth/middleware/requester-context.js.map +1 -1
- package/dist/runtime/subsystems/auth/protocols/auth-strategy.d.ts +3 -3
- package/dist/runtime/subsystems/auth/protocols/{integration-store.d.ts → connection-store.d.ts} +20 -20
- package/dist/runtime/subsystems/auth/protocols/connection-store.js +1 -0
- package/dist/runtime/subsystems/auth/protocols/provider-strategy.d.ts +3 -3
- package/dist/runtime/subsystems/auth/runtime/{integration-broken.error.d.ts → connection-broken.error.d.ts} +5 -5
- package/dist/runtime/subsystems/auth/runtime/connection-broken.error.js +19 -0
- package/dist/runtime/subsystems/auth/runtime/connection-broken.error.js.map +1 -0
- package/dist/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.d.ts +10 -10
- package/dist/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.js +28 -28
- package/dist/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.js.map +1 -1
- package/dist/runtime/subsystems/auth/runtime/with-auth-retry.d.ts +1 -1
- package/dist/runtime/subsystems/auth/runtime/with-auth-retry.js +3 -3
- package/dist/runtime/subsystems/auth/runtime/with-auth-retry.js.map +1 -1
- package/dist/runtime/subsystems/index.d.ts +11 -7
- package/dist/runtime/subsystems/index.js +1041 -67
- package/dist/runtime/subsystems/index.js.map +1 -1
- package/dist/runtime/subsystems/{sync → integration}/build-change-source.d.ts +3 -3
- package/dist/runtime/subsystems/{sync → integration}/build-change-source.js +3 -3
- package/dist/runtime/subsystems/integration/build-change-source.js.map +1 -0
- package/dist/runtime/subsystems/{sync → integration}/deep-equal.differ.d.ts +2 -2
- package/dist/runtime/subsystems/{sync → integration}/deep-equal.differ.js +1 -1
- package/dist/runtime/subsystems/integration/deep-equal.differ.js.map +1 -0
- package/dist/runtime/subsystems/{sync → integration}/detection-config.schema.d.ts +3 -3
- package/dist/runtime/subsystems/{sync → integration}/detection-config.schema.js +1 -1
- package/dist/runtime/subsystems/integration/detection-config.schema.js.map +1 -0
- package/dist/runtime/subsystems/integration/entity-change-source-registry.memory.d.ts +25 -0
- package/dist/runtime/subsystems/integration/entity-change-source-registry.memory.js +34 -0
- package/dist/runtime/subsystems/integration/entity-change-source-registry.memory.js.map +1 -0
- package/dist/runtime/subsystems/integration/entity-change-source-registry.protocol.d.ts +53 -0
- package/dist/runtime/subsystems/integration/entity-change-source-registry.protocol.js +13 -0
- package/dist/runtime/subsystems/integration/entity-change-source-registry.protocol.js.map +1 -0
- package/dist/runtime/subsystems/{sync/execute-sync.use-case.d.ts → integration/execute-integration.use-case.d.ts} +13 -13
- package/dist/runtime/subsystems/{sync/execute-sync.use-case.js → integration/execute-integration.use-case.js} +30 -30
- package/dist/runtime/subsystems/integration/execute-integration.use-case.js.map +1 -0
- package/dist/runtime/subsystems/integration/index.d.ts +30 -0
- package/dist/runtime/subsystems/{sync → integration}/index.js +206 -171
- package/dist/runtime/subsystems/integration/index.js.map +1 -0
- package/dist/runtime/subsystems/{sync/sync-audit.schema.d.ts → integration/integration-audit.schema.d.ts} +64 -64
- package/dist/runtime/subsystems/{sync/sync-audit.schema.js → integration/integration-audit.schema.js} +47 -47
- package/dist/runtime/subsystems/integration/integration-audit.schema.js.map +1 -0
- package/dist/runtime/subsystems/{sync/sync-change-source.protocol.d.ts → integration/integration-change-source.protocol.d.ts} +10 -10
- package/dist/runtime/subsystems/integration/integration-change-source.protocol.js +1 -0
- package/dist/runtime/subsystems/{sync/sync-cursor-store.drizzle-backend.d.ts → integration/integration-cursor-store.drizzle-backend.d.ts} +1 -1
- package/dist/runtime/subsystems/{sync/sync-cursor-store.drizzle-backend.js → integration/integration-cursor-store.drizzle-backend.js} +65 -65
- package/dist/runtime/subsystems/integration/integration-cursor-store.drizzle-backend.js.map +1 -0
- package/dist/runtime/subsystems/{sync/sync-cursor-store.memory-backend.d.ts → integration/integration-cursor-store.memory-backend.d.ts} +6 -6
- package/dist/runtime/subsystems/{sync/sync-cursor-store.memory-backend.js → integration/integration-cursor-store.memory-backend.js} +5 -5
- package/dist/runtime/subsystems/integration/integration-cursor-store.memory-backend.js.map +1 -0
- package/dist/runtime/subsystems/{sync/sync-cursor-store.protocol.d.ts → integration/integration-cursor-store.protocol.d.ts} +13 -13
- package/dist/runtime/subsystems/integration/integration-cursor-store.protocol.js +1 -0
- package/dist/runtime/subsystems/{sync/sync-errors.d.ts → integration/integration-errors.d.ts} +2 -2
- package/dist/runtime/subsystems/{sync/sync-errors.js → integration/integration-errors.js} +3 -3
- package/dist/runtime/subsystems/integration/integration-errors.js.map +1 -0
- package/dist/runtime/subsystems/{sync/sync-field-diff.protocol.d.ts → integration/integration-field-diff.protocol.d.ts} +2 -2
- package/dist/runtime/subsystems/{sync/sync-field-diff.protocol.js → integration/integration-field-diff.protocol.js} +2 -2
- package/dist/runtime/subsystems/integration/integration-field-diff.protocol.js.map +1 -0
- package/dist/runtime/subsystems/{sync/sync-loopback.protocol.d.ts → integration/integration-loopback.protocol.d.ts} +2 -2
- package/dist/runtime/subsystems/integration/integration-loopback.protocol.js +1 -0
- package/dist/runtime/subsystems/{sync/sync-middleware.protocol.d.ts → integration/integration-middleware.protocol.d.ts} +5 -5
- package/dist/runtime/subsystems/integration/integration-middleware.protocol.js +1 -0
- package/dist/runtime/subsystems/{sync/sync-run-recorder.drizzle-backend.d.ts → integration/integration-run-recorder.drizzle-backend.d.ts} +5 -5
- package/dist/runtime/subsystems/{sync/sync-run-recorder.drizzle-backend.js → integration/integration-run-recorder.drizzle-backend.js} +73 -73
- package/dist/runtime/subsystems/integration/integration-run-recorder.drizzle-backend.js.map +1 -0
- package/dist/runtime/subsystems/{sync/sync-run-recorder.memory-backend.d.ts → integration/integration-run-recorder.memory-backend.d.ts} +15 -15
- package/dist/runtime/subsystems/{sync/sync-run-recorder.memory-backend.js → integration/integration-run-recorder.memory-backend.js} +11 -11
- package/dist/runtime/subsystems/integration/integration-run-recorder.memory-backend.js.map +1 -0
- package/dist/runtime/subsystems/{sync/sync-run-recorder.protocol.d.ts → integration/integration-run-recorder.protocol.d.ts} +25 -25
- package/dist/runtime/subsystems/integration/integration-run-recorder.protocol.js +1 -0
- package/dist/runtime/subsystems/{sync/sync-sink.protocol.d.ts → integration/integration-sink.protocol.d.ts} +5 -5
- package/dist/runtime/subsystems/integration/integration-sink.protocol.js +1 -0
- package/dist/runtime/subsystems/{sync/sync.module.d.ts → integration/integration.module.d.ts} +24 -24
- package/dist/runtime/subsystems/{sync/sync.module.js → integration/integration.module.js} +132 -132
- package/dist/runtime/subsystems/integration/integration.module.js.map +1 -0
- package/dist/runtime/subsystems/integration/integration.tokens.d.ts +60 -0
- package/dist/runtime/subsystems/integration/integration.tokens.js +20 -0
- package/dist/runtime/subsystems/integration/integration.tokens.js.map +1 -0
- package/dist/runtime/subsystems/{sync → integration}/loopback.middleware.d.ts +5 -5
- package/dist/runtime/subsystems/{sync → integration}/loopback.middleware.js +1 -1
- package/dist/runtime/subsystems/integration/loopback.middleware.js.map +1 -0
- package/dist/runtime/subsystems/{sync → integration}/poll-change-source.d.ts +5 -5
- package/dist/runtime/subsystems/{sync → integration}/poll-change-source.js +1 -1
- package/dist/runtime/subsystems/integration/poll-change-source.js.map +1 -0
- package/dist/runtime/subsystems/{sync → integration}/webhook-change-source.d.ts +5 -5
- package/dist/runtime/subsystems/{sync → integration}/webhook-change-source.js +1 -1
- package/dist/runtime/subsystems/integration/webhook-change-source.js.map +1 -0
- package/dist/runtime/subsystems/jobs/job-worker.module.d.ts +1 -1
- package/dist/runtime/subsystems/observability/index.d.ts +4 -4
- package/dist/runtime/subsystems/observability/index.js +11 -11
- package/dist/runtime/subsystems/observability/index.js.map +1 -1
- package/dist/runtime/subsystems/observability/observability.module.d.ts +2 -2
- package/dist/runtime/subsystems/observability/observability.module.js +11 -11
- package/dist/runtime/subsystems/observability/observability.module.js.map +1 -1
- package/dist/runtime/subsystems/observability/observability.protocol.d.ts +11 -11
- package/dist/runtime/subsystems/observability/observability.service.d.ts +6 -6
- package/dist/runtime/subsystems/observability/observability.service.js +11 -11
- package/dist/runtime/subsystems/observability/observability.service.js.map +1 -1
- package/dist/runtime/subsystems/observability/observability.tokens.d.ts +1 -1
- package/dist/runtime/subsystems/observability/observability.tokens.js.map +1 -1
- package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.d.ts +3 -3
- package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.js.map +1 -1
- package/dist/runtime/subsystems/observability/reporters/index.d.ts +3 -3
- package/dist/runtime/subsystems/observability/reporters/index.js.map +1 -1
- package/dist/src/cli/index.js +1336 -376
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/index.d.ts +70 -22
- package/dist/src/index.js +290 -194
- package/dist/src/index.js.map +1 -1
- package/examples/auth-integrations/README.md +32 -32
- package/examples/auth-integrations/definitions/entities/{integration.yaml → connection.yaml} +10 -10
- package/examples/auth-integrations/runtime/{integrations/adapters/integration-grant-sink.adapter.ts → connections/adapters/connection-grant-sink.adapter.ts} +7 -7
- package/examples/auth-integrations/runtime/{integrations/adapters/integration-reader.adapter.ts → connections/adapters/connection-reader.adapter.ts} +10 -10
- package/examples/auth-integrations/runtime/{integrations/adapters/integration-token-writer.adapter.ts → connections/adapters/connection-token-writer.adapter.ts} +11 -11
- package/examples/auth-integrations/runtime/connections/connections-auth.module.ts +81 -0
- package/examples/auth-integrations/runtime/{integrations/facade/integrations.service.ts → connections/facade/connections.service.ts} +35 -35
- package/examples/auth-integrations/runtime/{integrations → connections}/oauth/use-cases/create-or-update-from-oauth-grant.use-case.ts +11 -11
- package/examples/auth-integrations/runtime/{integrations/oauth/use-cases/disconnect-integration.use-case.ts → connections/oauth/use-cases/disconnect-connection.use-case.ts} +6 -6
- package/examples/auth-integrations/runtime/connections/oauth/use-cases/list-user-connections.use-case.ts +21 -0
- package/examples/auth-integrations/runtime/connections/oauth/use-cases/mark-connection-requires-reauth.use-case.ts +21 -0
- package/package.json +9 -1
- package/runtime/base-classes/index.ts +8 -8
- package/runtime/base-classes/{synced-entity-repository.ts → integrated-entity-repository.ts} +36 -36
- package/runtime/base-classes/{synced-entity-service.ts → integrated-entity-service.ts} +6 -6
- package/runtime/base-classes/{sync-upsert-config.ts → integration-upsert-config.ts} +12 -12
- package/runtime/base-classes/{junction-sync-repository.ts → junction-integration-repository.ts} +28 -28
- package/runtime/subsystems/auth/auth-oauth-state.schema.ts +1 -1
- package/runtime/subsystems/auth/auth.module.ts +4 -4
- package/runtime/subsystems/auth/auth.tokens.ts +7 -7
- package/runtime/subsystems/auth/controllers/auth.controller.ts +7 -7
- package/runtime/subsystems/auth/index.ts +19 -19
- package/runtime/subsystems/auth/protocols/auth-strategy.ts +3 -3
- package/runtime/subsystems/auth/protocols/{integration-store.ts → connection-store.ts} +19 -19
- package/runtime/subsystems/auth/protocols/provider-strategy.ts +2 -2
- package/runtime/subsystems/auth/runtime/{integration-broken.error.ts → connection-broken.error.ts} +5 -5
- package/runtime/subsystems/auth/runtime/oauth2-refresh.strategy.ts +35 -35
- package/runtime/subsystems/auth/runtime/with-auth-retry.ts +3 -3
- package/runtime/subsystems/index.ts +26 -11
- package/runtime/subsystems/{sync → integration}/build-change-source.ts +3 -3
- package/runtime/subsystems/{sync → integration}/deep-equal.differ.ts +7 -7
- package/runtime/subsystems/{sync → integration}/detection-config.schema.ts +3 -3
- package/runtime/subsystems/integration/entity-change-source-registry.memory.ts +40 -0
- package/runtime/subsystems/integration/entity-change-source-registry.protocol.ts +59 -0
- package/runtime/subsystems/{sync/execute-sync.use-case.ts → integration/execute-integration.use-case.ts} +40 -40
- package/runtime/subsystems/{sync → integration}/index.ts +56 -47
- package/runtime/subsystems/{sync/sync-audit.schema.ts → integration/integration-audit.schema.ts} +61 -61
- package/runtime/subsystems/{sync/sync-change-source.protocol.ts → integration/integration-change-source.protocol.ts} +9 -9
- package/runtime/subsystems/{sync/sync-cursor-store.drizzle-backend.ts → integration/integration-cursor-store.drizzle-backend.ts} +30 -30
- package/runtime/subsystems/{sync/sync-cursor-store.memory-backend.ts → integration/integration-cursor-store.memory-backend.ts} +9 -9
- package/runtime/subsystems/{sync/sync-cursor-store.protocol.ts → integration/integration-cursor-store.protocol.ts} +13 -13
- package/runtime/subsystems/{sync/sync-errors.ts → integration/integration-errors.ts} +3 -3
- package/runtime/subsystems/{sync/sync-field-diff.protocol.ts → integration/integration-field-diff.protocol.ts} +2 -2
- package/runtime/subsystems/{sync/sync-loopback.protocol.ts → integration/integration-loopback.protocol.ts} +2 -2
- package/runtime/subsystems/{sync/sync-middleware.protocol.ts → integration/integration-middleware.protocol.ts} +6 -6
- package/runtime/subsystems/{sync/sync-run-recorder.drizzle-backend.ts → integration/integration-run-recorder.drizzle-backend.ts} +39 -39
- package/runtime/subsystems/{sync/sync-run-recorder.memory-backend.ts → integration/integration-run-recorder.memory-backend.ts} +23 -23
- package/runtime/subsystems/{sync/sync-run-recorder.protocol.ts → integration/integration-run-recorder.protocol.ts} +25 -25
- package/runtime/subsystems/{sync/sync-sink.protocol.ts → integration/integration-sink.protocol.ts} +4 -4
- package/runtime/subsystems/{sync/sync.module.ts → integration/integration.module.ts} +48 -48
- package/runtime/subsystems/integration/integration.tokens.ts +63 -0
- package/runtime/subsystems/{sync → integration}/loopback.middleware.ts +5 -5
- package/runtime/subsystems/{sync → integration}/poll-change-source.ts +7 -7
- package/runtime/subsystems/{sync → integration}/webhook-change-source.ts +7 -7
- package/runtime/subsystems/observability/index.ts +1 -1
- package/runtime/subsystems/observability/observability.module.ts +2 -2
- package/runtime/subsystems/observability/observability.protocol.ts +11 -11
- package/runtime/subsystems/observability/observability.service.ts +13 -13
- package/runtime/subsystems/observability/observability.tokens.ts +1 -1
- package/src/patterns/library/index.ts +4 -4
- package/src/patterns/library/{synced.pattern.ts → integrated.pattern.ts} +12 -12
- package/src/patterns/library/junction.pattern.ts +1 -1
- package/src/patterns/pattern-definition.ts +3 -3
- package/templates/entity/new/backend/modules/core/{sync-source.ejs.t → integration-source.ejs.t} +6 -6
- package/templates/entity/new/clean-lite-ps/entity.ejs.t +12 -3
- package/templates/entity/new/clean-lite-ps/module.ejs.t +1 -1
- package/templates/entity/new/clean-lite-ps/prompt-extension.js +243 -60
- package/templates/entity/new/clean-lite-ps/repository.ejs.t +27 -27
- package/templates/entity/new/frontend/collections/collection.ejs.t +26 -1
- package/templates/entity/new/frontend/collections/collections-base.ejs.t +11 -0
- package/templates/entity/new/frontend/entity/combined.ejs.t +31 -1
- package/templates/entity/new/prompt.js +27 -15
- package/templates/junction/new/entity.ejs.t +1 -1
- package/templates/junction/new/prompt.js +24 -24
- package/templates/junction/new/repository.ejs.t +19 -19
- package/templates/subsystem/auth/auth-oauth-state.schema.ejs.t +2 -2
- package/templates/subsystem/auth-config/prompt.js +1 -1
- package/templates/subsystem/auth-integrations/app-module-hook.ejs.t +5 -5
- package/templates/subsystem/bridge/prompt.js +1 -1
- package/templates/subsystem/integration/integration-audit.schema.ejs.t +192 -0
- package/templates/subsystem/{sync → integration}/prompt.js +12 -12
- package/templates/subsystem/{sync-config/codegen-config-sync-block.ejs.t → integration-config/codegen-config-integration-block.ejs.t} +7 -7
- package/templates/subsystem/integration-config/prompt.js +22 -0
- package/templates/subsystem/jobs/worker.ejs.t +2 -2
- package/templates/subsystem/observability/main-hook.ejs.t +1 -1
- package/templates/subsystem/observability/prompt.js +1 -1
- package/templates/subsystem/openapi-config/prompt.js +1 -1
- package/dist/runtime/base-classes/junction-sync-repository.js.map +0 -1
- package/dist/runtime/base-classes/sync-upsert-config.js +0 -1
- package/dist/runtime/base-classes/synced-entity-repository.js.map +0 -1
- package/dist/runtime/base-classes/synced-entity-service.js.map +0 -1
- package/dist/runtime/subsystems/auth/protocols/integration-store.js +0 -1
- package/dist/runtime/subsystems/auth/runtime/integration-broken.error.js +0 -19
- package/dist/runtime/subsystems/auth/runtime/integration-broken.error.js.map +0 -1
- package/dist/runtime/subsystems/sync/build-change-source.js.map +0 -1
- package/dist/runtime/subsystems/sync/deep-equal.differ.js.map +0 -1
- package/dist/runtime/subsystems/sync/detection-config.schema.js.map +0 -1
- package/dist/runtime/subsystems/sync/execute-sync.use-case.js.map +0 -1
- package/dist/runtime/subsystems/sync/index.d.ts +0 -28
- package/dist/runtime/subsystems/sync/index.js.map +0 -1
- package/dist/runtime/subsystems/sync/loopback.middleware.js.map +0 -1
- package/dist/runtime/subsystems/sync/poll-change-source.js.map +0 -1
- package/dist/runtime/subsystems/sync/sync-audit.schema.js.map +0 -1
- package/dist/runtime/subsystems/sync/sync-change-source.protocol.js +0 -1
- package/dist/runtime/subsystems/sync/sync-cursor-store.drizzle-backend.js.map +0 -1
- package/dist/runtime/subsystems/sync/sync-cursor-store.memory-backend.js.map +0 -1
- package/dist/runtime/subsystems/sync/sync-cursor-store.protocol.js +0 -1
- package/dist/runtime/subsystems/sync/sync-errors.js.map +0 -1
- package/dist/runtime/subsystems/sync/sync-field-diff.protocol.js.map +0 -1
- package/dist/runtime/subsystems/sync/sync-loopback.protocol.js +0 -1
- package/dist/runtime/subsystems/sync/sync-middleware.protocol.js +0 -1
- package/dist/runtime/subsystems/sync/sync-run-recorder.drizzle-backend.js.map +0 -1
- package/dist/runtime/subsystems/sync/sync-run-recorder.memory-backend.js.map +0 -1
- package/dist/runtime/subsystems/sync/sync-run-recorder.protocol.js +0 -1
- package/dist/runtime/subsystems/sync/sync-sink.protocol.js +0 -1
- package/dist/runtime/subsystems/sync/sync.module.js.map +0 -1
- package/dist/runtime/subsystems/sync/sync.tokens.d.ts +0 -47
- package/dist/runtime/subsystems/sync/sync.tokens.js +0 -18
- package/dist/runtime/subsystems/sync/sync.tokens.js.map +0 -1
- package/dist/runtime/subsystems/sync/webhook-change-source.js.map +0 -1
- package/examples/auth-integrations/runtime/integrations/integrations-auth.module.ts +0 -81
- package/examples/auth-integrations/runtime/integrations/oauth/use-cases/list-user-integrations.use-case.ts +0 -21
- package/examples/auth-integrations/runtime/integrations/oauth/use-cases/mark-integration-requires-reauth.use-case.ts +0 -21
- package/runtime/subsystems/sync/sync.tokens.ts +0 -49
- package/templates/entity/new/backend/modules/core/sync-source.providers.ejs.t +0 -18
- package/templates/subsystem/sync/sync-audit.schema.ejs.t +0 -192
- package/templates/subsystem/sync-config/prompt.js +0 -22
- /package/dist/runtime/base-classes/{sync-upsert-config.js.map → integration-upsert-config.js.map} +0 -0
- /package/dist/runtime/subsystems/auth/protocols/{integration-store.js.map → connection-store.js.map} +0 -0
- /package/dist/runtime/subsystems/{sync/sync-change-source.protocol.js.map → integration/integration-change-source.protocol.js.map} +0 -0
- /package/dist/runtime/subsystems/{sync/sync-cursor-store.protocol.js.map → integration/integration-cursor-store.protocol.js.map} +0 -0
- /package/dist/runtime/subsystems/{sync/sync-loopback.protocol.js.map → integration/integration-loopback.protocol.js.map} +0 -0
- /package/dist/runtime/subsystems/{sync/sync-middleware.protocol.js.map → integration/integration-middleware.protocol.js.map} +0 -0
- /package/dist/runtime/subsystems/{sync/sync-run-recorder.protocol.js.map → integration/integration-run-recorder.protocol.js.map} +0 -0
- /package/dist/runtime/subsystems/{sync/sync-sink.protocol.js.map → integration/integration-sink.protocol.js.map} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Typed errors + shared boundary helpers for the
|
|
2
|
+
* Typed errors + shared boundary helpers for the integration subsystem.
|
|
3
3
|
*
|
|
4
4
|
* Classes (not bare Error) so consumers can `instanceof` them in catch
|
|
5
5
|
* blocks and exception filters can map them to HTTP codes.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Thrown by the Drizzle cursor-store / run-recorder backends AND by the
|
|
12
|
-
* orchestrator entry point when `
|
|
12
|
+
* orchestrator entry point when `INTEGRATION_MULTI_TENANT` is enabled but the
|
|
13
13
|
* caller did not supply a non-null `tenantId`. Strict enforcement at the
|
|
14
14
|
* boundary — explicit `null` still throws.
|
|
15
15
|
*
|
|
@@ -24,7 +24,7 @@ export class MissingTenantIdError extends Error {
|
|
|
24
24
|
override readonly name = 'MissingTenantIdError';
|
|
25
25
|
constructor(operation: string) {
|
|
26
26
|
super(
|
|
27
|
-
`Missing tenantId for
|
|
27
|
+
`Missing tenantId for integration operation '${operation}'. IntegrationModule is ` +
|
|
28
28
|
`configured with multiTenant: true — every call must include a ` +
|
|
29
29
|
`non-null tenantId. Either pass the tenantId or disable multi-` +
|
|
30
30
|
`tenancy on the module.`,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Integration subsystem — field-diff protocol (port)
|
|
3
3
|
*
|
|
4
4
|
* `IFieldDiffer<T>` is the pluggable differ seam. The default implementation
|
|
5
5
|
* (`DeepEqualDiffer`, ships in SYNC-5) walks every field except an ignore
|
|
@@ -17,7 +17,7 @@ import { z } from 'zod';
|
|
|
17
17
|
// ============================================================================
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
|
-
* Structured per-field change. Enforced shape for `
|
|
20
|
+
* Structured per-field change. Enforced shape for `integration_run_items.changed_fields`.
|
|
21
21
|
*
|
|
22
22
|
* `created` items set `from: null, to: <value>` for every non-null field.
|
|
23
23
|
* `deleted` items set `from: <value>, to: null`.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Integration subsystem — loopback-fingerprint protocol (port)
|
|
3
3
|
*
|
|
4
4
|
* Optional port. When the local system writes to an upstream provider via an
|
|
5
5
|
* outbound path, the same change typically echoes back on the next inbound
|
|
6
|
-
* poll/CDC/webhook. A fingerprint store lets `
|
|
6
|
+
* poll/CDC/webhook. A fingerprint store lets `ExecuteIntegrationUseCase` skip
|
|
7
7
|
* records it already wrote, avoiding a diff-noop round trip and a spurious
|
|
8
8
|
* audit row.
|
|
9
9
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Integration subsystem — change-source middleware protocol (#226-1)
|
|
3
3
|
*
|
|
4
4
|
* `ChangeMiddleware<T>` lets consumers compose cross-cutting concerns
|
|
5
5
|
* (loopback suppression, redaction, throttling) onto an `IChangeSource<T>`
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* type ChangeMiddleware<T> =
|
|
13
13
|
* (next: ChangeIterator<T>) =>
|
|
14
|
-
* (subscription:
|
|
14
|
+
* (subscription: IntegrationSubscriptionView, cursor: unknown | null) =>
|
|
15
15
|
* AsyncIterable<Change<T>>;
|
|
16
16
|
*
|
|
17
17
|
* The middleware wraps the *next* iterator factory rather than the
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
* Loopback shipping as middleware (#226-5) is the canonical example —
|
|
27
27
|
* `createLoopbackMiddleware(store)` filters echoes of local writes
|
|
28
28
|
* before they reach the orchestrator's diff stage, replacing the prior
|
|
29
|
-
* `@Optional()
|
|
29
|
+
* `@Optional() INTEGRATION_LOOPBACK_FINGERPRINT_STORE` orchestrator branch.
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
32
|
import type {
|
|
33
33
|
Change,
|
|
34
|
-
|
|
35
|
-
} from './
|
|
34
|
+
IntegrationSubscriptionView,
|
|
35
|
+
} from './integration-change-source.protocol';
|
|
36
36
|
|
|
37
37
|
// ============================================================================
|
|
38
38
|
// ChangeIterator — the inner shape middleware wraps
|
|
@@ -44,7 +44,7 @@ import type {
|
|
|
44
44
|
* `IChangeSource<T>` instance method binds 1:1 to this signature.
|
|
45
45
|
*/
|
|
46
46
|
export type ChangeIterator<T> = (
|
|
47
|
-
subscription:
|
|
47
|
+
subscription: IntegrationSubscriptionView,
|
|
48
48
|
cursor: unknown | null,
|
|
49
49
|
) => AsyncIterable<Change<T>>;
|
|
50
50
|
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* DrizzleIntegrationRunRecorder — Drizzle-backed `IIntegrationRunRecorder` (SYNC-4).
|
|
3
3
|
*
|
|
4
4
|
* Generic write path only — extracted from the source app's
|
|
5
|
-
* `
|
|
5
|
+
* `IntegrationRunRecorderService`, minus CRM-specific convenience methods. Those
|
|
6
6
|
* stay consumer-owned; the subsystem ships the substrate.
|
|
7
7
|
*
|
|
8
8
|
* ## Responsibilities
|
|
9
9
|
*
|
|
10
|
-
* - `startRun` — INSERT
|
|
10
|
+
* - `startRun` — INSERT integration_runs row in status='running', returns id.
|
|
11
11
|
* - `recordItem` — validates `changedFields` via `FieldDiffSchema.parse`
|
|
12
12
|
* BEFORE the INSERT; a malformed shape throws before
|
|
13
13
|
* any DB call fires. Enforces the ADR-0003 contract at
|
|
14
14
|
* the write boundary.
|
|
15
|
-
* - `completeRun` — UPDATE
|
|
15
|
+
* - `completeRun` — UPDATE integration_runs with terminal status, counts,
|
|
16
16
|
* cursor_after, duration_ms, completed_at.
|
|
17
17
|
*
|
|
18
18
|
* ## Multi-tenancy
|
|
19
19
|
*
|
|
20
|
-
* When `
|
|
20
|
+
* When `INTEGRATION_MULTI_TENANT` is true (SYNC-6):
|
|
21
21
|
* - `startRun` and `recordItem` require non-null `tenantId` on input.
|
|
22
22
|
* Enforcement goes through the shared `assertTenantId` helper so the
|
|
23
23
|
* error message shape matches the orchestrator entry point + the
|
|
@@ -33,23 +33,23 @@ import type { DrizzleClient } from '../../types/drizzle';
|
|
|
33
33
|
import { DRIZZLE } from '../../constants/tokens';
|
|
34
34
|
import type {
|
|
35
35
|
CompleteRunInput,
|
|
36
|
-
|
|
36
|
+
IIntegrationRunRecorder,
|
|
37
37
|
RecordItemInput,
|
|
38
38
|
StartRunInput,
|
|
39
|
-
|
|
40
|
-
} from './
|
|
41
|
-
import {
|
|
42
|
-
import { FieldDiffSchema } from './
|
|
43
|
-
import {
|
|
44
|
-
import { assertTenantId } from './
|
|
39
|
+
IntegrationRunSummary,
|
|
40
|
+
} from './integration-run-recorder.protocol';
|
|
41
|
+
import { integrationRuns, integrationRunItems, integrationSubscriptions } from './integration-audit.schema';
|
|
42
|
+
import { FieldDiffSchema } from './integration-field-diff.protocol';
|
|
43
|
+
import { INTEGRATION_MULTI_TENANT } from './integration.tokens';
|
|
44
|
+
import { assertTenantId } from './integration-errors';
|
|
45
45
|
|
|
46
46
|
@Injectable()
|
|
47
|
-
export class
|
|
47
|
+
export class DrizzleIntegrationRunRecorder implements IIntegrationRunRecorder {
|
|
48
48
|
private readonly multiTenant: boolean;
|
|
49
49
|
|
|
50
50
|
constructor(
|
|
51
51
|
@Inject(DRIZZLE) private readonly db: DrizzleClient,
|
|
52
|
-
@Optional() @Inject(
|
|
52
|
+
@Optional() @Inject(INTEGRATION_MULTI_TENANT) multiTenant?: boolean,
|
|
53
53
|
) {
|
|
54
54
|
this.multiTenant = multiTenant ?? false;
|
|
55
55
|
}
|
|
@@ -61,7 +61,7 @@ export class DrizzleSyncRunRecorder implements ISyncRunRecorder {
|
|
|
61
61
|
});
|
|
62
62
|
|
|
63
63
|
const rows = await this.db
|
|
64
|
-
.insert(
|
|
64
|
+
.insert(integrationRuns)
|
|
65
65
|
.values({
|
|
66
66
|
subscriptionId: input.subscriptionId,
|
|
67
67
|
direction: input.direction,
|
|
@@ -70,14 +70,14 @@ export class DrizzleSyncRunRecorder implements ISyncRunRecorder {
|
|
|
70
70
|
cursorBefore: input.cursorBefore ?? null,
|
|
71
71
|
tenantId: input.tenantId ?? null,
|
|
72
72
|
})
|
|
73
|
-
.returning({ id:
|
|
73
|
+
.returning({ id: integrationRuns.id });
|
|
74
74
|
|
|
75
75
|
const id = rows[0]?.id;
|
|
76
76
|
if (!id) {
|
|
77
77
|
// Drizzle's insert().returning() contract: at least one row is
|
|
78
78
|
// returned for every successful INSERT. A missing id would indicate
|
|
79
79
|
// a driver misbehavior; throw loudly rather than return bogus data.
|
|
80
|
-
throw new Error('
|
|
80
|
+
throw new Error('DrizzleIntegrationRunRecorder: INSERT RETURNING produced no id');
|
|
81
81
|
}
|
|
82
82
|
return { id };
|
|
83
83
|
}
|
|
@@ -93,8 +93,8 @@ export class DrizzleSyncRunRecorder implements ISyncRunRecorder {
|
|
|
93
93
|
// the validation failure, not a DB constraint error.
|
|
94
94
|
FieldDiffSchema.parse(input.changedFields);
|
|
95
95
|
|
|
96
|
-
await this.db.insert(
|
|
97
|
-
|
|
96
|
+
await this.db.insert(integrationRunItems).values({
|
|
97
|
+
integrationRunId: input.integrationRunId,
|
|
98
98
|
entityType: input.entityType,
|
|
99
99
|
externalId: input.externalId,
|
|
100
100
|
localId: input.localId ?? null,
|
|
@@ -111,21 +111,21 @@ export class DrizzleSyncRunRecorder implements ISyncRunRecorder {
|
|
|
111
111
|
limit: number,
|
|
112
112
|
subscriptionId?: string,
|
|
113
113
|
tenantId?: string | null,
|
|
114
|
-
): Promise<
|
|
114
|
+
): Promise<IntegrationRunSummary[]> {
|
|
115
115
|
assertTenantId(tenantId, {
|
|
116
116
|
multiTenant: this.multiTenant,
|
|
117
117
|
operation: 'listRecent',
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
-
// JOIN against
|
|
121
|
-
// `
|
|
120
|
+
// JOIN against integration_subscriptions to resolve `connection_id` per run.
|
|
121
|
+
// `integration_runs.subscription_id` is a non-null FK so INNER JOIN is correct;
|
|
122
122
|
// there should be no orphaned runs.
|
|
123
123
|
const conditions: SQL[] = [];
|
|
124
124
|
if (subscriptionId !== undefined) {
|
|
125
|
-
conditions.push(eq(
|
|
125
|
+
conditions.push(eq(integrationRuns.subscriptionId, subscriptionId));
|
|
126
126
|
}
|
|
127
127
|
if (this.multiTenant) {
|
|
128
|
-
conditions.push(eq(
|
|
128
|
+
conditions.push(eq(integrationRuns.tenantId, tenantId as string));
|
|
129
129
|
}
|
|
130
130
|
const where =
|
|
131
131
|
conditions.length === 0
|
|
@@ -136,28 +136,28 @@ export class DrizzleSyncRunRecorder implements ISyncRunRecorder {
|
|
|
136
136
|
|
|
137
137
|
const rows = await this.db
|
|
138
138
|
.select({
|
|
139
|
-
id:
|
|
140
|
-
subscriptionId:
|
|
141
|
-
|
|
142
|
-
status:
|
|
143
|
-
startedAt:
|
|
144
|
-
completedAt:
|
|
145
|
-
recordsProcessed:
|
|
146
|
-
tenantId:
|
|
139
|
+
id: integrationRuns.id,
|
|
140
|
+
subscriptionId: integrationRuns.subscriptionId,
|
|
141
|
+
connectionId: integrationSubscriptions.connectionId,
|
|
142
|
+
status: integrationRuns.status,
|
|
143
|
+
startedAt: integrationRuns.startedAt,
|
|
144
|
+
completedAt: integrationRuns.completedAt,
|
|
145
|
+
recordsProcessed: integrationRuns.recordsProcessed,
|
|
146
|
+
tenantId: integrationRuns.tenantId,
|
|
147
147
|
})
|
|
148
|
-
.from(
|
|
148
|
+
.from(integrationRuns)
|
|
149
149
|
.innerJoin(
|
|
150
|
-
|
|
151
|
-
eq(
|
|
150
|
+
integrationSubscriptions,
|
|
151
|
+
eq(integrationRuns.subscriptionId, integrationSubscriptions.id),
|
|
152
152
|
)
|
|
153
153
|
.where(where)
|
|
154
|
-
.orderBy(desc(
|
|
154
|
+
.orderBy(desc(integrationRuns.startedAt))
|
|
155
155
|
.limit(limit);
|
|
156
156
|
|
|
157
157
|
return rows.map((row) => ({
|
|
158
158
|
id: row.id,
|
|
159
159
|
subscriptionId: row.subscriptionId,
|
|
160
|
-
|
|
160
|
+
connectionId: row.connectionId,
|
|
161
161
|
status: row.status,
|
|
162
162
|
startedAt: row.startedAt,
|
|
163
163
|
completedAt: row.completedAt,
|
|
@@ -168,7 +168,7 @@ export class DrizzleSyncRunRecorder implements ISyncRunRecorder {
|
|
|
168
168
|
|
|
169
169
|
async completeRun(runId: string, input: CompleteRunInput): Promise<void> {
|
|
170
170
|
await this.db
|
|
171
|
-
.update(
|
|
171
|
+
.update(integrationRuns)
|
|
172
172
|
.set({
|
|
173
173
|
status: input.status,
|
|
174
174
|
recordsFound: input.recordsFound,
|
|
@@ -178,6 +178,6 @@ export class DrizzleSyncRunRecorder implements ISyncRunRecorder {
|
|
|
178
178
|
error: input.error ?? null,
|
|
179
179
|
completedAt: new Date(),
|
|
180
180
|
})
|
|
181
|
-
.where(eq(
|
|
181
|
+
.where(eq(integrationRuns.id, runId));
|
|
182
182
|
}
|
|
183
183
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MemoryRunRecorder — in-memory backend for `
|
|
2
|
+
* MemoryRunRecorder — in-memory backend for `IIntegrationRunRecorder` (SYNC-6).
|
|
3
3
|
*
|
|
4
|
-
* Test double so `
|
|
4
|
+
* Test double so `IntegrationModule.forRoot({ backend: 'memory' })` is genuinely
|
|
5
5
|
* end-to-end runnable without Postgres. Mirrors the role of
|
|
6
6
|
* `MemoryCursorStore`: plain keyed state, `clear()` helper for
|
|
7
7
|
* `beforeEach` resets, public inspection surface so tests can assert on
|
|
@@ -27,34 +27,34 @@
|
|
|
27
27
|
import { Injectable } from '@nestjs/common';
|
|
28
28
|
import type {
|
|
29
29
|
CompleteRunInput,
|
|
30
|
-
|
|
30
|
+
IIntegrationRunRecorder,
|
|
31
31
|
RecordItemInput,
|
|
32
32
|
StartRunInput,
|
|
33
|
-
|
|
34
|
-
} from './
|
|
35
|
-
import { FieldDiffSchema } from './
|
|
33
|
+
IntegrationRunSummary,
|
|
34
|
+
} from './integration-run-recorder.protocol';
|
|
35
|
+
import { FieldDiffSchema } from './integration-field-diff.protocol';
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Optional per-subscription metadata a test can seed on the memory backend
|
|
39
|
-
* so `listRecent` can surface `
|
|
39
|
+
* so `listRecent` can surface `connectionId`. The memory recorder's write
|
|
40
40
|
* path never persists subscription rows (it only stores runs + items), so
|
|
41
|
-
* `listRecent` has no way to derive `
|
|
41
|
+
* `listRecent` has no way to derive `connectionId` on its own. Tests that
|
|
42
42
|
* care about the field should populate `subscriptions` before calling
|
|
43
43
|
* `listRecent`; calls that don't seed get an empty string and a stable
|
|
44
44
|
* shape (see `listRecent` below).
|
|
45
45
|
*/
|
|
46
|
-
export interface
|
|
47
|
-
|
|
46
|
+
export interface MemoryIntegrationSubscription {
|
|
47
|
+
connectionId: string;
|
|
48
48
|
adapter: string;
|
|
49
49
|
domain: string;
|
|
50
50
|
externalRef: string | null;
|
|
51
|
-
|
|
51
|
+
lastIntegrationAt?: Date | null;
|
|
52
52
|
updatedAt: Date;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Concrete run row as held in memory. Shape mirrors the interesting
|
|
57
|
-
* columns on `
|
|
57
|
+
* columns on `integration_runs` so assertions read like DB queries.
|
|
58
58
|
*/
|
|
59
59
|
export interface MemoryRunRecord {
|
|
60
60
|
id: string;
|
|
@@ -74,7 +74,7 @@ export interface MemoryRunRecord {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
@Injectable()
|
|
77
|
-
export class MemoryRunRecorder implements
|
|
77
|
+
export class MemoryRunRecorder implements IIntegrationRunRecorder {
|
|
78
78
|
/**
|
|
79
79
|
* All started runs keyed by id. Public so tests can inspect lifecycle
|
|
80
80
|
* transitions without poking through recording methods.
|
|
@@ -82,20 +82,20 @@ export class MemoryRunRecorder implements ISyncRunRecorder {
|
|
|
82
82
|
readonly runs: Map<string, MemoryRunRecord> = new Map();
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* Items keyed by `
|
|
86
|
-
* mirrors the timeline the `(
|
|
85
|
+
* Items keyed by `integration_run_id`, array order matches insertion order —
|
|
86
|
+
* mirrors the timeline the `(integration_run_id, created_at)` index produces
|
|
87
87
|
* in Postgres.
|
|
88
88
|
*/
|
|
89
89
|
readonly items: Map<string, RecordItemInput[]> = new Map();
|
|
90
90
|
|
|
91
91
|
/**
|
|
92
92
|
* Seedable subscription metadata — tests populate this to make
|
|
93
|
-
* `listRecent` return meaningful `
|
|
93
|
+
* `listRecent` return meaningful `connectionId` values. The memory
|
|
94
94
|
* backend doesn't track subscriptions on its own (only runs + items), so
|
|
95
95
|
* this map is the intentional extension point: tests write entries for
|
|
96
96
|
* the subscription ids they use, production code never touches it.
|
|
97
97
|
*/
|
|
98
|
-
readonly subscriptions: Map<string,
|
|
98
|
+
readonly subscriptions: Map<string, MemoryIntegrationSubscription> = new Map();
|
|
99
99
|
|
|
100
100
|
async startRun(input: StartRunInput): Promise<{ id: string }> {
|
|
101
101
|
const id = crypto.randomUUID();
|
|
@@ -123,10 +123,10 @@ export class MemoryRunRecorder implements ISyncRunRecorder {
|
|
|
123
123
|
// Same ADR-0003 contract as the Drizzle backend.
|
|
124
124
|
FieldDiffSchema.parse(input.changedFields);
|
|
125
125
|
|
|
126
|
-
const bucket = this.items.get(input.
|
|
126
|
+
const bucket = this.items.get(input.integrationRunId);
|
|
127
127
|
if (!bucket) {
|
|
128
128
|
throw new Error(
|
|
129
|
-
`MemoryRunRecorder.recordItem: no run started for id '${input.
|
|
129
|
+
`MemoryRunRecorder.recordItem: no run started for id '${input.integrationRunId}'. ` +
|
|
130
130
|
`Call startRun(...) first.`,
|
|
131
131
|
);
|
|
132
132
|
}
|
|
@@ -153,7 +153,7 @@ export class MemoryRunRecorder implements ISyncRunRecorder {
|
|
|
153
153
|
limit: number,
|
|
154
154
|
subscriptionId?: string,
|
|
155
155
|
_tenantId?: string | null,
|
|
156
|
-
): Promise<
|
|
156
|
+
): Promise<IntegrationRunSummary[]> {
|
|
157
157
|
// Memory backend accepts tenantId for contract symmetry but does not
|
|
158
158
|
// filter on it — state is process-local and cross-tenant isolation is
|
|
159
159
|
// not meaningful here (matches MemoryCursorStore behavior).
|
|
@@ -168,11 +168,11 @@ export class MemoryRunRecorder implements ISyncRunRecorder {
|
|
|
168
168
|
.map((r) => ({
|
|
169
169
|
id: r.id,
|
|
170
170
|
subscriptionId: r.subscriptionId,
|
|
171
|
-
//
|
|
171
|
+
// connectionId is only knowable if the test seeded subscriptions
|
|
172
172
|
// metadata; empty string otherwise. The Drizzle backend resolves
|
|
173
173
|
// it via JOIN, which is the production path.
|
|
174
|
-
|
|
175
|
-
this.subscriptions.get(r.subscriptionId)?.
|
|
174
|
+
connectionId:
|
|
175
|
+
this.subscriptions.get(r.subscriptionId)?.connectionId ?? '',
|
|
176
176
|
status: r.status,
|
|
177
177
|
startedAt: r.startedAt,
|
|
178
178
|
completedAt: r.completedAt,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Integration subsystem — run-recorder protocol (port)
|
|
3
3
|
*
|
|
4
|
-
* `
|
|
4
|
+
* `IIntegrationRunRecorder` is the write side of the audit log. `ExecuteIntegrationUseCase`
|
|
5
5
|
* (SYNC-5) calls `startRun` at the top of the loop, `recordItem` for each
|
|
6
6
|
* processed change, and `completeRun` in a `finally` block so a run always
|
|
7
7
|
* reaches a terminal status.
|
|
8
8
|
*
|
|
9
|
-
* The Drizzle backend (SYNC-4) persists against `
|
|
9
|
+
* The Drizzle backend (SYNC-4) persists against `integration_runs` / `integration_run_items`
|
|
10
10
|
* from the SYNC-1 schema. Tests use lightweight in-memory fakes — no
|
|
11
11
|
* dedicated memory backend ships; the surface is small enough that inline
|
|
12
12
|
* fakes keep the intent local to each spec.
|
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
* orchestrator before reaching the recorder, so the recorder's input is
|
|
18
18
|
* always a `FieldDiff`.
|
|
19
19
|
*/
|
|
20
|
-
import type { FieldDiff } from './
|
|
20
|
+
import type { FieldDiff } from './integration-field-diff.protocol';
|
|
21
21
|
|
|
22
22
|
// ============================================================================
|
|
23
23
|
// Lifecycle — inputs
|
|
24
24
|
// ============================================================================
|
|
25
25
|
|
|
26
|
-
/** Args for `startRun`. Mirrors the non-nullable columns on `
|
|
26
|
+
/** Args for `startRun`. Mirrors the non-nullable columns on `integration_runs`. */
|
|
27
27
|
export interface StartRunInput {
|
|
28
28
|
readonly subscriptionId: string;
|
|
29
29
|
readonly direction: 'inbound' | 'outbound';
|
|
@@ -31,16 +31,16 @@ export interface StartRunInput {
|
|
|
31
31
|
/** Cursor snapshot at run start, or `null` if this is the first run. */
|
|
32
32
|
readonly cursorBefore: unknown | null;
|
|
33
33
|
/**
|
|
34
|
-
* Tenant id when `
|
|
34
|
+
* Tenant id when `INTEGRATION_MULTI_TENANT` is enabled. The recorder's own
|
|
35
35
|
* boundary rule (SYNC-6) enforces non-null when the flag is on;
|
|
36
|
-
* orchestrator passes it through from `
|
|
36
|
+
* orchestrator passes it through from `ExecuteIntegrationInput.tenantId`.
|
|
37
37
|
*/
|
|
38
38
|
readonly tenantId?: string | null;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
/** Args for `recordItem`. Mirrors the non-nullable columns on `
|
|
41
|
+
/** Args for `recordItem`. Mirrors the non-nullable columns on `integration_run_items`. */
|
|
42
42
|
export interface RecordItemInput {
|
|
43
|
-
readonly
|
|
43
|
+
readonly integrationRunId: string;
|
|
44
44
|
readonly entityType: string;
|
|
45
45
|
readonly externalId: string;
|
|
46
46
|
readonly localId?: string | null;
|
|
@@ -71,24 +71,24 @@ export interface CompleteRunInput {
|
|
|
71
71
|
// ============================================================================
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
|
-
* Denormalized view of one `
|
|
75
|
-
* `
|
|
74
|
+
* Denormalized view of one `integration_runs` row, JOINed against
|
|
75
|
+
* `integration_subscriptions` to surface `connectionId` in a single read. Consumed
|
|
76
76
|
* by the OBS-5 observability composer (epic #195).
|
|
77
77
|
*
|
|
78
|
-
* `recordsProcessed` is the denormalized column on `
|
|
79
|
-
* count `
|
|
78
|
+
* `recordsProcessed` is the denormalized column on `integration_runs` — it does NOT
|
|
79
|
+
* count `integration_run_items` rows. A correlated subquery per run would be
|
|
80
80
|
* required for a true item count; deferred as a follow-up if needed.
|
|
81
81
|
*
|
|
82
|
-
* Memory backends can't know `
|
|
82
|
+
* Memory backends can't know `connectionId` without subscription metadata
|
|
83
83
|
* — see each memory backend for the seedable `subscriptions` side-map that
|
|
84
84
|
* tests populate. When metadata is missing, memory backends emit an empty
|
|
85
85
|
* string so the shape stays stable (documented in the memory backend).
|
|
86
86
|
*/
|
|
87
|
-
export interface
|
|
87
|
+
export interface IntegrationRunSummary {
|
|
88
88
|
readonly id: string;
|
|
89
89
|
readonly subscriptionId: string;
|
|
90
90
|
/** Resolved by Drizzle via JOIN; empty string from memory if not seeded. */
|
|
91
|
-
readonly
|
|
91
|
+
readonly connectionId: string;
|
|
92
92
|
readonly status: 'running' | 'success' | 'no_changes' | 'failed';
|
|
93
93
|
readonly startedAt: Date;
|
|
94
94
|
readonly completedAt: Date | null;
|
|
@@ -97,14 +97,14 @@ export interface SyncRunSummary {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
// ============================================================================
|
|
100
|
-
//
|
|
100
|
+
// IIntegrationRunRecorder
|
|
101
101
|
// ============================================================================
|
|
102
102
|
|
|
103
|
-
export interface
|
|
104
|
-
/** Opens a new `
|
|
103
|
+
export interface IIntegrationRunRecorder {
|
|
104
|
+
/** Opens a new `integration_runs` row in `status = 'running'`. Returns the run id. */
|
|
105
105
|
startRun(input: StartRunInput): Promise<{ id: string }>;
|
|
106
106
|
|
|
107
|
-
/** Appends one `
|
|
107
|
+
/** Appends one `integration_run_items` row. Throws if `changedFields` is malformed. */
|
|
108
108
|
recordItem(input: RecordItemInput): Promise<void>;
|
|
109
109
|
|
|
110
110
|
/**
|
|
@@ -115,16 +115,16 @@ export interface ISyncRunRecorder {
|
|
|
115
115
|
completeRun(runId: string, input: CompleteRunInput): Promise<void>;
|
|
116
116
|
|
|
117
117
|
/**
|
|
118
|
-
* Recent `
|
|
118
|
+
* Recent `integration_runs` rows ordered by `started_at DESC`, capped at `limit`.
|
|
119
119
|
*
|
|
120
|
-
* Filter is `subscriptionId` — the natural FK on `
|
|
121
|
-
* integration-wide view requires filtering on `
|
|
120
|
+
* Filter is `subscriptionId` — the natural FK on `integration_runs`. An
|
|
121
|
+
* integration-wide view requires filtering on `integration_subscriptions.connection_id`
|
|
122
122
|
* through the JOIN and is deferred as a follow-up (epic #195 OBS-4 spec).
|
|
123
123
|
*
|
|
124
124
|
* @param limit hard cap on rows returned (no implicit default)
|
|
125
125
|
* @param subscriptionId optional FK filter; omit for cross-subscription view
|
|
126
126
|
* @param tenantId required by Drizzle backend when
|
|
127
|
-
* `
|
|
127
|
+
* `INTEGRATION_MULTI_TENANT` is on (throws
|
|
128
128
|
* `MissingTenantIdError` otherwise); memory backend
|
|
129
129
|
* accepts but ignores
|
|
130
130
|
*/
|
|
@@ -132,5 +132,5 @@ export interface ISyncRunRecorder {
|
|
|
132
132
|
limit: number,
|
|
133
133
|
subscriptionId?: string,
|
|
134
134
|
tenantId?: string | null,
|
|
135
|
-
): Promise<
|
|
135
|
+
): Promise<IntegrationRunSummary[]>;
|
|
136
136
|
}
|
package/runtime/subsystems/{sync/sync-sink.protocol.ts → integration/integration-sink.protocol.ts}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Integration subsystem — integration-sink protocol (port)
|
|
3
3
|
*
|
|
4
4
|
* Write surface for the generic orchestrator. One per canonical entity type.
|
|
5
5
|
*
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* Implementations compose the entity's service + (when the entity has EAV)
|
|
14
14
|
* `FieldValueService` inside a single transaction. ADR-13-revised.
|
|
15
15
|
*/
|
|
16
|
-
export interface
|
|
16
|
+
export interface IIntegrationSink<TCanonical> {
|
|
17
17
|
/**
|
|
18
18
|
* Canonical-shaped view of local state, or `null` when no local row exists.
|
|
19
19
|
* Called once per change to source the diff's "before" side.
|
|
@@ -32,11 +32,11 @@ export interface ISyncSink<TCanonical> {
|
|
|
32
32
|
* - tolerate re-entry (same record twice in a window = no-op)
|
|
33
33
|
*
|
|
34
34
|
* Returns the local row id and the canonical projection of the saved row
|
|
35
|
-
* (so the orchestrator can record it on `
|
|
35
|
+
* (so the orchestrator can record it on `integration_run_items.local_id`).
|
|
36
36
|
*
|
|
37
37
|
* `provider` is the adapter domain string (e.g. `'salesforce-crm'`,
|
|
38
38
|
* `'hubspot-crm'`) persisted on the DB row. Passed from
|
|
39
|
-
* `
|
|
39
|
+
* `ExecuteIntegrationInput.provider`.
|
|
40
40
|
*/
|
|
41
41
|
upsertByExternalId(
|
|
42
42
|
userId: string,
|