@pattern-stack/codegen 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/CHANGELOG.md +135 -0
- package/README.md +5 -5
- package/consumer-skills/codegen/SKILL.md +2 -2
- package/consumer-skills/events/typed-bus-and-outbox.md +1 -1
- 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 +64 -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/bridge/bridge.module.d.ts +0 -1
- package/dist/runtime/subsystems/bridge/bridge.module.js +294 -710
- package/dist/runtime/subsystems/bridge/bridge.module.js.map +1 -1
- package/dist/runtime/subsystems/bridge/index.d.ts +0 -1
- package/dist/runtime/subsystems/bridge/index.js +248 -664
- package/dist/runtime/subsystems/bridge/index.js.map +1 -1
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +18 -10
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/events/events.module.js +43 -244
- package/dist/runtime/subsystems/events/events.module.js.map +1 -1
- package/dist/runtime/subsystems/events/index.d.ts +0 -1
- package/dist/runtime/subsystems/events/index.js +39 -241
- package/dist/runtime/subsystems/events/index.js.map +1 -1
- package/dist/runtime/subsystems/index.d.ts +7 -7
- package/dist/runtime/subsystems/index.js +222 -839
- 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/{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 +28 -0
- package/dist/runtime/subsystems/{sync → integration}/index.js +171 -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 +47 -0
- package/dist/runtime/subsystems/integration/integration.tokens.js +18 -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/bullmq.config.d.ts +22 -3
- package/dist/runtime/subsystems/jobs/bullmq.config.js.map +1 -1
- package/dist/runtime/subsystems/jobs/index.d.ts +1 -4
- package/dist/runtime/subsystems/jobs/index.js +87 -506
- package/dist/runtime/subsystems/jobs/index.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js +3 -0
- package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-worker.module.d.ts +10 -3
- package/dist/runtime/subsystems/jobs/job-worker.module.js +248 -664
- package/dist/runtime/subsystems/jobs/job-worker.module.js.map +1 -1
- package/dist/runtime/subsystems/jobs/jobs-domain.module.d.ts +0 -1
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js +89 -391
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js.map +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 +412 -302
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/index.d.ts +22 -22
- package/dist/src/index.js +191 -191
- 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 +1 -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/events/event-bus.drizzle-backend.ts +32 -10
- package/runtime/subsystems/events/events.module.ts +38 -6
- package/runtime/subsystems/events/index.ts +7 -1
- package/runtime/subsystems/index.ts +11 -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/{sync/execute-sync.use-case.ts → integration/execute-integration.use-case.ts} +40 -40
- package/runtime/subsystems/{sync → integration}/index.ts +47 -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 +49 -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/jobs/bullmq.config.ts +23 -3
- package/runtime/subsystems/jobs/index.ts +13 -8
- package/runtime/subsystems/jobs/job-worker.bullmq-backend.ts +5 -2
- package/runtime/subsystems/jobs/job-worker.module.ts +27 -7
- package/runtime/subsystems/jobs/jobs-domain.module.ts +27 -2
- 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/backend/modules/core/{sync-source.providers.ejs.t → integration-source.providers.ejs.t} +2 -2
- package/templates/entity/new/clean-lite-ps/entity.ejs.t +1 -1
- package/templates/entity/new/clean-lite-ps/module.ejs.t +1 -1
- package/templates/entity/new/clean-lite-ps/prompt-extension.js +33 -33
- 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/events/domain-events.schema.ejs.t +43 -2
- 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/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
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,141 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.11.0] — 2026-05-30
|
|
8
|
+
|
|
9
|
+
Vocabulary rename per **ADR-0005 (swe-brain `.ai-docs/decisions/ADR-0005-rename-sync-to-integration.md`)**:
|
|
10
|
+
the data-movement domain `sync` → `integration` (reserving "sync" for
|
|
11
|
+
ElectricSQL-style replication), the `Synced` entity family → `Integrated`, and
|
|
12
|
+
the authenticated vendor-link `IntegrationStore` → `ConnectionStore`. This is a
|
|
13
|
+
clean break — there are no compat shims or deprecated aliases; consumers
|
|
14
|
+
migrate by **regenerating** off the renamed substrate (codegen owns the
|
|
15
|
+
physical/structural names).
|
|
16
|
+
|
|
17
|
+
### ⚠ BREAKING CHANGES
|
|
18
|
+
|
|
19
|
+
- **Integration engine (`sync` → `integration`).**
|
|
20
|
+
- `SyncModule` → `IntegrationModule` (`.forRoot({ backend, multiTenant? })`);
|
|
21
|
+
`ExecuteSyncUseCase` → `ExecuteIntegrationUseCase`.
|
|
22
|
+
- Tokens `SYNC_*` → `INTEGRATION_*` (cursor store, run recorder, field
|
|
23
|
+
differ, change source, sink, multi-tenant flag, module options).
|
|
24
|
+
- Protocols/ports/recorders/cursor-stores/errors `sync-*` → `integration-*`;
|
|
25
|
+
`runtime/subsystems/sync/**` → `runtime/subsystems/integration/**`.
|
|
26
|
+
- Tables `sync_runs` / `sync_run_items` / `sync_subscriptions` →
|
|
27
|
+
`integration_runs` / `integration_run_items` / `integration_subscriptions`;
|
|
28
|
+
cursor column `last_sync_at` → `last_integration_at`.
|
|
29
|
+
- Entity-YAML config block `sync:` → `integration:` (incl. `sync.inbound` →
|
|
30
|
+
`integration.inbound`); the per-entity `*-sync-source.module.ts` codegen
|
|
31
|
+
output → `*-integration-source.module.ts`.
|
|
32
|
+
- CLI: `codegen subsystem install sync` → `… install integration`; the
|
|
33
|
+
`/sync` skill → `/integration`.
|
|
34
|
+
- **`Synced` entity family → `Integrated`.**
|
|
35
|
+
- `SyncedEntityRepository` / `SyncedEntityService` → `IntegratedEntityRepository`
|
|
36
|
+
/ `IntegratedEntityService`; `SyncUpsertConfig` → `IntegrationUpsertConfig`;
|
|
37
|
+
`syncUpsertOne`/`syncUpsert`/`syncConfig`/`SyncFkResolver` →
|
|
38
|
+
`integrationUpsertOne`/`integrationUpsert`/`integrationConfig`/`IntegrationFkResolver`;
|
|
39
|
+
`junction-sync-repository.ts` → `junction-integration-repository.ts`.
|
|
40
|
+
- YAML `pattern: Synced` → `pattern: Integrated`.
|
|
41
|
+
- **Auth vendor-link `integration` → `connection`.**
|
|
42
|
+
- `IntegrationStore` ports → `ConnectionStore`:
|
|
43
|
+
`IIntegrationReader`/`IIntegrationTokenWriter`/`IIntegrationGrantSink` →
|
|
44
|
+
`IConnection*`; `DecryptedIntegration` → `DecryptedConnection`;
|
|
45
|
+
`IntegrationGrantInput`/`IntegrationTokenUpdate` → `Connection*`;
|
|
46
|
+
`IntegrationBrokenError` → `ConnectionBrokenError`; DI tokens
|
|
47
|
+
`AUTH_INTEGRATION_*` → `AUTH_CONNECTION_*`.
|
|
48
|
+
- Engine FK `integration_subscriptions.integration_id` → `connection_id`
|
|
49
|
+
(the column references the connected account/instance — a *connection*;
|
|
50
|
+
the table name stays `integration_subscriptions`).
|
|
51
|
+
- The `examples/auth-integrations` starter is fully renamed to the connection
|
|
52
|
+
vocabulary: `connection.yaml` entity (table `connections`),
|
|
53
|
+
`ConnectionsService`, `ConnectionsAuthModule`, `Connection*Adapter`,
|
|
54
|
+
vendored under `<modules>/connections/`. The `auth-integrations` subsystem
|
|
55
|
+
**install command** keeps its name.
|
|
56
|
+
|
|
57
|
+
### Preserved (NOT renamed)
|
|
58
|
+
|
|
59
|
+
- The CLI imperative **verb** `sync` in app-level event names
|
|
60
|
+
(`crm_sync_started`, `webhook_outbound_contact_sync`).
|
|
61
|
+
- ElectricSQL `frontend.sync` collection config (replication sense).
|
|
62
|
+
|
|
63
|
+
### Migration
|
|
64
|
+
|
|
65
|
+
No shims. Re-vendor the runtime (`codegen update`) and **regenerate** entities/
|
|
66
|
+
subsystems off the renamed names; update app code that references the renamed
|
|
67
|
+
symbols/tokens/tables/config keys. See ADR-0005 (swe-brain `.ai-docs/decisions/ADR-0005-rename-sync-to-integration.md`).
|
|
68
|
+
|
|
69
|
+
## [0.10.1] — 2026-05-28
|
|
70
|
+
|
|
71
|
+
Dogfood fixes found wiring `@pattern-stack/codegen@0.10.0` into a second
|
|
72
|
+
consumer (swe-brain): the type-check blockers that forced consumers to exclude
|
|
73
|
+
the vendored subsystem tree from `tsc` are gone. A drizzle-only install now
|
|
74
|
+
type-checks its full tree (`src/shared/subsystems/**` included) with no
|
|
75
|
+
`ioredis`/`bullmq` peer deps.
|
|
76
|
+
|
|
77
|
+
### Fixed
|
|
78
|
+
|
|
79
|
+
- **`fix(subsystems)` — detection + barrel emission key on `<name>.module.ts`
|
|
80
|
+
(#4, #2).** Installing one subsystem can vendor *protocol stubs* of another
|
|
81
|
+
(e.g. events vendors `bridge/bridge.protocol.ts`); detection used to report
|
|
82
|
+
those stub-only dirs as `installed` and the barrel emitted a phantom
|
|
83
|
+
`BridgeModule` import for a module that was never installed (TS2307).
|
|
84
|
+
Detection now requires the module file; `subsystem list` reports `incomplete`
|
|
85
|
+
for stub-only dirs; the barrel skips them.
|
|
86
|
+
- **`fix(events)` — drizzle backend type-checks against its paired schema
|
|
87
|
+
(#3).** `event-bus.drizzle-backend.ts` read a `tier` column the schema never
|
|
88
|
+
emitted and `tenant_id` columns only present under multi-tenancy. `tier` is
|
|
89
|
+
now always emitted; `tenant_id` access is gated behind `multiTenant`, so the
|
|
90
|
+
backend type-checks under any configuration.
|
|
91
|
+
- **`fix(subsystems)` — installs no longer vendor unselected backends (#6).** A
|
|
92
|
+
`--backend drizzle` install previously vendored the Redis and BullMQ backend
|
|
93
|
+
sources too, dragging `ioredis`/`bullmq` (uninstalled optional peers) into the
|
|
94
|
+
consumer's type-check. The copy filter now prunes `*.redis-backend.ts` /
|
|
95
|
+
`*.bullmq-backend.ts` for non-matching installs; modules lazy-load the chosen
|
|
96
|
+
backend via a non-literal dynamic import; backend-specific classes are no
|
|
97
|
+
longer re-exported from the public barrels; `bullmq.config.ts` is kept on
|
|
98
|
+
every install (peer-dep-free) for its static token references; the BullMQ
|
|
99
|
+
backend is `noImplicitAny`-clean.
|
|
100
|
+
- **`fix(barrel)` — empty-composer output emits the `DynamicModule` import.** A
|
|
101
|
+
generated `subsystems.ts` with no composer calls referenced `DynamicModule`
|
|
102
|
+
without importing it (latent since BULLMQ-1, surfaced by the stricter
|
|
103
|
+
detection above).
|
|
104
|
+
|
|
105
|
+
### Added
|
|
106
|
+
|
|
107
|
+
- **`feat(cli)` — `codegen subsystem remove` (#5, #7).** Real implementation:
|
|
108
|
+
deletes the vendored subsystem dir, regenerates the barrel, git-safety gated
|
|
109
|
+
with `--force`, and `--yes`/`-y` parity with `install`. Prints the manual
|
|
110
|
+
follow-ups it deliberately does *not* perform (config-block strip,
|
|
111
|
+
`forRoot` un-registration).
|
|
112
|
+
- **`test(smoke)` — `run-smoke-subsystems.ts`.** Exercises an events + jobs +
|
|
113
|
+
bridge drizzle install with a full-tree `tsc` (no subsystem excludes) + a
|
|
114
|
+
programmatic NestJS boot that validates the bridge reserved-pool dependency
|
|
115
|
+
graph. Wired into `just test-all`.
|
|
116
|
+
|
|
117
|
+
## [0.10.0] — 2026-05-27
|
|
118
|
+
|
|
119
|
+
### Added
|
|
120
|
+
|
|
121
|
+
- **`feat(cli)` — consumer skill distribution (ADR-035).** A curated
|
|
122
|
+
`consumer-skills/` set (a `codegen` router plus `entities`, `subsystems`,
|
|
123
|
+
`jobs`, `events`, `bridge`, `sync`) is vendored into a consumer's
|
|
124
|
+
`.claude/skills/` via a new `skills` noun (`codegen skills install` / `list`),
|
|
125
|
+
and by `codegen init` by default (`--no-skills` to opt out). Authored fresh
|
|
126
|
+
for a consumer audience; shipped in the npm `files` array.
|
|
127
|
+
- **`feat(cli)` — `codegen update`.** Re-syncs the vendored runtime closure,
|
|
128
|
+
installed subsystems' runtime, and consumer skills to the installed package
|
|
129
|
+
version after a bump. Drift-aware, git-clean gated (`--force`), `--dry-run`;
|
|
130
|
+
never touches consumer-owned files (config, `app.module.ts`, barrels).
|
|
131
|
+
- **`feat(parser)` — recursive YAML discovery.** Entity / relationship /
|
|
132
|
+
junction / event discovery routes through a single `findYamlFiles` helper;
|
|
133
|
+
domain-folder layouts (`entities/crm/account.yaml`) are first-class.
|
|
134
|
+
|
|
135
|
+
### Changed
|
|
136
|
+
|
|
137
|
+
- **Docs split.** `CONSUMER-SETUP.md` became a hub; the per-subsystem deep dives
|
|
138
|
+
moved to `docs/consumer/{events,bridge,sync,auth,openapi}.md` (progressive
|
|
139
|
+
disclosure), with jobs-API drift (`JobsModule` → `JobsDomainModule` +
|
|
140
|
+
`JobWorkerModule`, `JobHandlerBase`, `concurrency: { key }`) corrected.
|
|
141
|
+
|
|
7
142
|
## [0.9.0] — 2026-05-25
|
|
8
143
|
|
|
9
144
|
Bundles four merged PRs (none carried a version bump): the BullMQ backend and
|
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ entity:
|
|
|
23
23
|
name: contact
|
|
24
24
|
plural: contacts
|
|
25
25
|
table: contacts
|
|
26
|
-
pattern:
|
|
26
|
+
pattern: Integrated # Integrated | Activity | Metadata | Knowledge | Base (or app-defined)
|
|
27
27
|
|
|
28
28
|
fields:
|
|
29
29
|
email:
|
|
@@ -94,7 +94,7 @@ codegen subsystem install events # domain event bus (transactional outbox)
|
|
|
94
94
|
codegen subsystem install jobs # background job queue (pg-boss pattern)
|
|
95
95
|
codegen subsystem install cache # key-value cache with TTL
|
|
96
96
|
codegen subsystem install storage # file storage (local filesystem)
|
|
97
|
-
codegen subsystem install
|
|
97
|
+
codegen subsystem install integration # external-system integration engine (IChangeSource + orchestrator + audit log)
|
|
98
98
|
codegen subsystem install bridge # event-to-job bridge (durable async fanout via @JobHandler.triggers)
|
|
99
99
|
codegen subsystem install openapi-config # OpenAPI/Swagger — Zod DTOs as /docs-json + Swagger UI. See docs/CONSUMER-SETUP.md §OpenAPI
|
|
100
100
|
codegen subsystem install auth # OAuth integration auth (AuthModule + ports + state store + AuthController)
|
|
@@ -144,7 +144,7 @@ Families provide pre-built base classes with domain-specific query patterns:
|
|
|
144
144
|
|
|
145
145
|
| Family | When to Use | Key Methods |
|
|
146
146
|
|--------|-------------|-------------|
|
|
147
|
-
| `
|
|
147
|
+
| `integrated` | externally-integrated entities (contacts, accounts) | `findByExternalId`, `integrationUpsert`, `findAllByUserId` |
|
|
148
148
|
| `activity` | Time-based events (emails, calls, meetings) | `findByDateRange`, `findRecentByOpportunityId` |
|
|
149
149
|
| `metadata` | Key-value data (tags, custom fields) | `findByEntityIdAndType`, `upsertMany` |
|
|
150
150
|
| `knowledge` | Vector-searchable content | Stub (needs pgvector) |
|
|
@@ -163,9 +163,9 @@ queries:
|
|
|
163
163
|
- by: [user_id, status] # → FindContactByUserIdAndStatusUseCase (compound)
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
##
|
|
166
|
+
## Integration Detection (`detection:` block)
|
|
167
167
|
|
|
168
|
-
Entities that participate in the
|
|
168
|
+
Entities that participate in the integration subsystem may declare a `detection:` block describing how upstream changes are detected. The block is parsed by the canonical `DetectionConfigSchema` shipped from `runtime/subsystems/integration` — primitives (`PollChangeSource<T>`, `WebhookChangeSource<T>`) and the per-entity factory module emitted by codegen consume the same parsed shape, so YAML and runtime stay in lockstep (ADR-033, epic #226).
|
|
169
169
|
|
|
170
170
|
```yaml
|
|
171
171
|
detection:
|
|
@@ -7,7 +7,7 @@ description: >-
|
|
|
7
7
|
the `codegen` (aka `cdp`) CLI, install or wire an infrastructure subsystem, or
|
|
8
8
|
refresh the project after a package upgrade. This is the entry-point router;
|
|
9
9
|
it points at the focused `entities`, `subsystems`, `jobs`, `events`, `bridge`,
|
|
10
|
-
and `
|
|
10
|
+
and `integration` skills for deep work.
|
|
11
11
|
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
|
|
12
12
|
user-invocable: false
|
|
13
13
|
---
|
|
@@ -53,7 +53,7 @@ generation run the two barrels are rewritten and you wire them into
|
|
|
53
53
|
| Write a background `@JobHandler`, configure pools, set concurrency/ordering | the `jobs` skill |
|
|
54
54
|
| Author a domain event, publish via the outbox, use the typed event bus | the `events` skill |
|
|
55
55
|
| React to an event with a durable async job (the event-to-job bridge) | the `bridge` skill |
|
|
56
|
-
| Pull/push data from an external system (`IChangeSource` / `
|
|
56
|
+
| Pull/push data from an external system (`IChangeSource` / `IIntegrationSink`) | the `integration` skill |
|
|
57
57
|
|
|
58
58
|
## CLI quick reference
|
|
59
59
|
|
|
@@ -65,7 +65,7 @@ New code should prefer `TypedEventBus`.
|
|
|
65
65
|
|
|
66
66
|
## The outbox table and drain loop
|
|
67
67
|
|
|
68
|
-
`domain_events` is the outbox. Key columns: `id` (UUID, the idempotency key), `type`, `aggregate_id`, `aggregate_type`, `payload` (jsonb), `occurred_at`, `processed_at`, `status` (`pending | processed | failed`), `error`, `metadata`, and first-class `pool` / `direction` columns (populated from `metadata` at insert so the drain can filter by lane without unpacking JSON).
|
|
68
|
+
`domain_events` is the outbox. Key columns: `id` (UUID, the idempotency key), `type`, `aggregate_id`, `aggregate_type`, `payload` (jsonb), `occurred_at`, `processed_at`, `status` (`pending | processed | failed`), `error`, `metadata`, and first-class `pool` / `direction` / `tier` columns (populated from `metadata` at insert so the drain can filter by lane without unpacking JSON). `tier` (`'domain'` | `'audit'`, default `'domain'`) is always emitted; the `domain_events_tier_routing_check` constraint enforces that `tier='audit'` rows have null `pool`/`direction`. `tenant_id` is the only conditional column — emitted only under `events.multi_tenant: true`.
|
|
69
69
|
|
|
70
70
|
The drain loop (Drizzle backend):
|
|
71
71
|
1. Claims a batch (default 50) of `pending` rows with `FOR UPDATE SKIP LOCKED`, optionally filtered by pool, ordered by `occurred_at ASC`. `SKIP LOCKED` lets multiple worker processes drain concurrently without double-dispatching.
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description: Load when integrating an external system (CRM, billing, etc.) in a project that ran `codegen subsystem install
|
|
2
|
+
name: integration
|
|
3
|
+
description: Load when integrating an external system (CRM, billing, etc.) in a project that ran `codegen subsystem install integration`. Triggers include implementing `IChangeSource<T>` for a provider; writing an `IIntegrationSink<T>`; registering `IntegrationModule.forRoot(...)` in `app.module.ts`; building a per-entity feature module that binds the change source, sink, and `ExecuteIntegrationUseCase`; declaring a `detection:` block in entity YAML; querying the `integration_runs` / `integration_run_items` audit log or the structured `changed_fields` jsonb; or wiring cursor persistence, diffing, and multi-tenancy.
|
|
4
4
|
allowed-tools: Read, Write, Edit, Glob, Grep, Bash
|
|
5
5
|
user-invocable: false
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
<!-- managed by @pattern-stack/codegen — re-run `codegen skills install` to refresh. Edit the package source, not this vendored copy. -->
|
|
9
9
|
|
|
10
|
-
#
|
|
10
|
+
# Integration Subsystem
|
|
11
11
|
|
|
12
|
-
The
|
|
13
|
-
app. One orchestrator — `
|
|
12
|
+
The integration subsystem is a generic external-system integration engine for your
|
|
13
|
+
app. One orchestrator — `ExecuteIntegrationUseCase<T>` — runs *every* integration in
|
|
14
14
|
your codebase. You write per-provider detection code against a single port
|
|
15
15
|
(`IChangeSource<T>`) and per-entity write code against a single sink
|
|
16
|
-
(`
|
|
16
|
+
(`IIntegrationSink<T>`). Everything else — cursor persistence, field diffing,
|
|
17
17
|
per-record audit, run lifecycle — is provided by the subsystem.
|
|
18
18
|
|
|
19
|
-
You opt in with `codegen subsystem install
|
|
20
|
-
into `<paths.subsystems>/
|
|
21
|
-
`
|
|
22
|
-
(`
|
|
19
|
+
You opt in with `codegen subsystem install integration`, which vendors the runtime
|
|
20
|
+
into `<paths.subsystems>/integration/` (imported as `@shared/subsystems/integration`), adds a
|
|
21
|
+
`integration:` block to `codegen.config.yaml`, and emits the audit schema
|
|
22
|
+
(`integration-audit.schema.ts`). Unlike some subsystems, integration ships **no `generated/`
|
|
23
23
|
directory** — there are no codegen-emitted runtime artifacts from the base
|
|
24
24
|
install. (Per-entity change-source modules are emitted only if you declare a
|
|
25
25
|
`detection:` block in an entity YAML — see the change-sources L1 file.)
|
|
@@ -32,41 +32,41 @@ subsystem owns; step 1 is the only thing you write per provider:
|
|
|
32
32
|
1. **detect** upstream change *(you — `IChangeSource<T>`)*
|
|
33
33
|
2. **diff** against local state *(subsystem — `IFieldDiffer<T>`, default `DeepEqualDiffer`)*
|
|
34
34
|
3. **apply** the upsert or soft-delete *(your sink, called by the orchestrator)*
|
|
35
|
-
4. **record** the structured delta into `
|
|
35
|
+
4. **record** the structured delta into `integration_run_items` *(subsystem)*
|
|
36
36
|
5. **emit** an event on success *(you — wired in your sink, optional)*
|
|
37
37
|
|
|
38
38
|
Three detection modes (poll / CDC / webhook) converge on the single
|
|
39
39
|
`IChangeSource<T>` port; per-mode differences live in `Change<T>` metadata, not
|
|
40
40
|
in separate ports.
|
|
41
41
|
|
|
42
|
-
**
|
|
43
|
-
applies → records (`
|
|
42
|
+
**Integration is not events and not jobs.** Integration detects upstream change → diffs →
|
|
43
|
+
applies → records (`integration_runs` + `integration_run_items` pairs). It can be *triggered
|
|
44
44
|
by* a scheduled job (polling) or a webhook, and it can *emit* events on a
|
|
45
45
|
successful upsert — but the three subsystems have distinct lifecycles. See the
|
|
46
46
|
`jobs` and `events` skills for those.
|
|
47
47
|
|
|
48
|
-
**The audit is structured, not freeform.** `
|
|
48
|
+
**The audit is structured, not freeform.** `integration_run_items.changed_fields` is
|
|
49
49
|
`{ fieldName: { from, to } }` jsonb, validated at write time. That makes drift
|
|
50
50
|
queries ("when did this opportunity first become Closed Won?") one-shot SQL
|
|
51
51
|
filters instead of JSON scrapes.
|
|
52
52
|
|
|
53
53
|
## Wiring at a glance
|
|
54
54
|
|
|
55
|
-
`
|
|
55
|
+
`IntegrationModule.forRoot(...)` in `app.module.ts` wires the substrate — the cursor
|
|
56
56
|
store, run recorder, field differ, and multi-tenant flag. It is `global: true`
|
|
57
|
-
and **does NOT provide `
|
|
58
|
-
`
|
|
59
|
-
you register `
|
|
60
|
-
bindings. Putting it in `
|
|
57
|
+
and **does NOT provide `ExecuteIntegrationUseCase`**. The orchestrator depends on
|
|
58
|
+
`INTEGRATION_CHANGE_SOURCE` + `INTEGRATION_SINK`, which are per-entity and consumer-owned, so
|
|
59
|
+
you register `ExecuteIntegrationUseCase` in your *feature module* alongside those
|
|
60
|
+
bindings. Putting it in `IntegrationModule` would force Nest to resolve those tokens
|
|
61
61
|
at module compile time, before your feature module is imported.
|
|
62
62
|
|
|
63
63
|
```ts
|
|
64
|
-
import {
|
|
64
|
+
import { IntegrationModule } from '@shared/subsystems/integration';
|
|
65
65
|
|
|
66
66
|
@Module({
|
|
67
67
|
imports: [
|
|
68
68
|
DatabaseModule,
|
|
69
|
-
|
|
69
|
+
IntegrationModule.forRoot({ backend: 'drizzle' }), // 'memory' in tests
|
|
70
70
|
// ... per-entity feature modules, other subsystems
|
|
71
71
|
],
|
|
72
72
|
})
|
|
@@ -77,13 +77,13 @@ export class AppModule {}
|
|
|
77
77
|
|
|
78
78
|
| When the task involves… | Read |
|
|
79
79
|
|---|---|
|
|
80
|
-
| Implementing `IChangeSource<T>` or `
|
|
81
|
-
| The `
|
|
80
|
+
| Implementing `IChangeSource<T>` or `IIntegrationSink<T>`; the per-entity feature module; the `detection:` block + provider-keyed factory; triggering a run; multi-tenancy; loopback; testing | `change-sources-and-sinks.md` |
|
|
81
|
+
| The `integration_runs` / `integration_run_items` / `integration_subscriptions` shape; the structured `changed_fields` contract; worked drift / staleness / stuck-run queries; orchestrator run lifecycle and failure semantics | `audit-and-detection.md` |
|
|
82
82
|
|
|
83
83
|
## Non-obvious rules
|
|
84
84
|
|
|
85
85
|
1. **One port for three modes.** Poll, CDC, and webhook adapters all implement
|
|
86
|
-
`IChangeSource<T>` with `listChanges(subscription, cursor):
|
|
86
|
+
`IChangeSource<T>` with `listChanges(subscription, cursor): AintegrationIterable<Change<T>>`.
|
|
87
87
|
Per-mode concerns ride in `Change<T>` metadata (`source`, `dedupKey`,
|
|
88
88
|
`providerChangedFields`). Do not introduce `IPollSource` / `ICdcSource` /
|
|
89
89
|
`IWebhookSource` — the union is deliberate.
|
|
@@ -93,7 +93,7 @@ export class AppModule {}
|
|
|
93
93
|
The orchestrator is the only reader/writer of cursor storage — never inject
|
|
94
94
|
the cursor store inside a source or sink.
|
|
95
95
|
|
|
96
|
-
3. **`
|
|
96
|
+
3. **`IntegrationModule` does NOT provide `ExecuteIntegrationUseCase`.** Register the
|
|
97
97
|
orchestrator in your feature module's `providers` array next to your source
|
|
98
98
|
and sink bindings.
|
|
99
99
|
|
|
@@ -102,8 +102,8 @@ export class AppModule {}
|
|
|
102
102
|
insert (in both Drizzle and Memory backends). Do not treat it as freeform —
|
|
103
103
|
arbitrary keys break drift queries and get rejected.
|
|
104
104
|
|
|
105
|
-
5. **The
|
|
106
|
-
`
|
|
105
|
+
5. **The integration audit tables are subsystem-owned.** Query `integration_subscriptions`,
|
|
106
|
+
`integration_runs`, and `integration_run_items` freely for dashboards, but do not write to
|
|
107
107
|
them directly (bypassing the recorder's validation lands malformed data),
|
|
108
108
|
and do not author entity YAMLs for them (that produces redundant
|
|
109
109
|
repositories/services shadowing the subsystem).
|
|
@@ -124,9 +124,9 @@ export class AppModule {}
|
|
|
124
124
|
`IWebhookSource`). One `IChangeSource<T>` for all modes.
|
|
125
125
|
- Do not treat `changed_fields` as freeform jsonb — the `{ from, to }` shape is
|
|
126
126
|
load-bearing for drift queries and enforced at write.
|
|
127
|
-
- Do not provide `
|
|
127
|
+
- Do not provide `ExecuteIntegrationUseCase` in `IntegrationModule` — it forces eager
|
|
128
128
|
resolution of consumer-owned tokens.
|
|
129
|
-
- Do not write directly to the
|
|
129
|
+
- Do not write directly to the integration audit tables, and do not ship entity YAMLs
|
|
130
130
|
for them.
|
|
131
131
|
- Do not inject the cursor store inside a source or sink — the orchestrator
|
|
132
132
|
owns the get/put lifecycle.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Audit model, orchestrator flow, and diffing
|
|
4
4
|
|
|
5
|
-
The
|
|
5
|
+
The integration subsystem records every run into three tables and runs every
|
|
6
6
|
integration through one orchestrator loop. This file covers the table shapes,
|
|
7
7
|
the structured `changed_fields` contract, the queries you'll write against the
|
|
8
8
|
audit log, the orchestrator's run lifecycle and failure semantics, and how the
|
|
@@ -15,15 +15,15 @@ UIs, but never write to them directly (you'd bypass the recorder's validation),
|
|
|
15
15
|
and never author entity YAMLs for them (that produces redundant
|
|
16
16
|
repositories/services that shadow the subsystem).
|
|
17
17
|
|
|
18
|
-
### `
|
|
18
|
+
### `integration_subscriptions`
|
|
19
19
|
|
|
20
|
-
Cursor owner per `(
|
|
20
|
+
Cursor owner per `(connection_id, adapter, domain, external_ref)` tuple. The
|
|
21
21
|
cursor store reads/writes it.
|
|
22
22
|
|
|
23
23
|
| Column | Type | Notes |
|
|
24
24
|
|---|---|---|
|
|
25
25
|
| `id` | uuid PK | `defaultRandom()` |
|
|
26
|
-
| `
|
|
26
|
+
| `connection_id` | text | Opaque id of the connected account/instance (SFDC org id, GH installation id, …) |
|
|
27
27
|
| `adapter` | text | Short adapter label: `'salesforce'`, `'hubspot'` |
|
|
28
28
|
| `domain` | text | Canonical entity: `'opportunity'`, `'contact'` |
|
|
29
29
|
| `external_ref` | text NULL | Upstream scope (filter id, webhook subscription id); NULL = full domain |
|
|
@@ -31,21 +31,21 @@ cursor store reads/writes it.
|
|
|
31
31
|
| `config` | jsonb, default `{}` | Per-subscription config (`batchSize`, `highWatermark`, …) |
|
|
32
32
|
| `cursor` | jsonb NULL | Opaque; written by the cursor store; NULL until first successful run |
|
|
33
33
|
| `last_sync_at` | ts NULL | Stamped alongside `cursor` |
|
|
34
|
-
| `tenant_id` | text NULL | Present only when `
|
|
34
|
+
| `tenant_id` | text NULL | Present only when `integration.multi_tenant: true` |
|
|
35
35
|
| `created_at` / `updated_at` | ts | |
|
|
36
36
|
|
|
37
|
-
Indexes: a unique `(
|
|
37
|
+
Indexes: a unique `(connection_id, adapter, domain, external_ref)` tuple
|
|
38
38
|
(Postgres treats NULL `external_ref` as distinct — that's a consumer modeling
|
|
39
39
|
concern), and an `(enabled, last_sync_at)` scheduling index.
|
|
40
40
|
|
|
41
|
-
### `
|
|
41
|
+
### `integration_runs`
|
|
42
42
|
|
|
43
|
-
One row per `
|
|
43
|
+
One row per `ExecuteIntegrationUseCase.execute()` invocation.
|
|
44
44
|
|
|
45
45
|
| Column | Type | Notes |
|
|
46
46
|
|---|---|---|
|
|
47
47
|
| `id` | uuid PK | |
|
|
48
|
-
| `subscription_id` | uuid FK → `
|
|
48
|
+
| `subscription_id` | uuid FK → `integration_subscriptions.id` (cascade) | |
|
|
49
49
|
| `direction` | enum `inbound \| outbound` | Almost always `inbound`; `outbound` reserved for writeback |
|
|
50
50
|
| `action` | enum `poll \| cdc \| webhook \| manual \| writeback` | Provenance for self-identification |
|
|
51
51
|
| `status` | enum `running \| success \| no_changes \| failed` | `running` is in-flight only |
|
|
@@ -60,14 +60,14 @@ One row per `ExecuteSyncUseCase.execute()` invocation.
|
|
|
60
60
|
Indexes: `(subscription_id, started_at)` for timelines, `(status, started_at)`
|
|
61
61
|
for the stale-run sweeper.
|
|
62
62
|
|
|
63
|
-
### `
|
|
63
|
+
### `integration_run_items`
|
|
64
64
|
|
|
65
65
|
One row per upstream change processed within a run.
|
|
66
66
|
|
|
67
67
|
| Column | Type | Notes |
|
|
68
68
|
|---|---|---|
|
|
69
69
|
| `id` | uuid PK | |
|
|
70
|
-
| `
|
|
70
|
+
| `integration_run_id` | uuid FK → `integration_runs.id` (cascade) | |
|
|
71
71
|
| `entity_type` | text | Canonical domain (`'opportunity'`) |
|
|
72
72
|
| `external_id` | text | Upstream id |
|
|
73
73
|
| `local_id` | text NULL | Set on `created \| updated \| deleted`; null on `noop` |
|
|
@@ -79,7 +79,7 @@ One row per upstream change processed within a run.
|
|
|
79
79
|
| `created_at` | ts, default now | |
|
|
80
80
|
| `tenant_id` | text NULL | Present only when multi-tenant |
|
|
81
81
|
|
|
82
|
-
Indexes: `(
|
|
82
|
+
Indexes: `(integration_run_id, created_at)` for within-run timelines,
|
|
83
83
|
`(entity_type, external_id)` for per-record history.
|
|
84
84
|
|
|
85
85
|
## The `changed_fields` contract
|
|
@@ -119,12 +119,12 @@ taste, augment the differ's ignore list in your feature module (see Diffing).
|
|
|
119
119
|
|
|
120
120
|
## Common queries
|
|
121
121
|
|
|
122
|
-
**"What changed in the last 24 hours across all
|
|
122
|
+
**"What changed in the last 24 hours across all integration?"**
|
|
123
123
|
|
|
124
124
|
```sql
|
|
125
125
|
SELECT sr.action, sri.entity_type, sri.external_id, sri.operation, sri.changed_fields
|
|
126
|
-
FROM
|
|
127
|
-
JOIN
|
|
126
|
+
FROM integration_run_items sri
|
|
127
|
+
JOIN integration_runs sr ON sri.integration_run_id = sr.id
|
|
128
128
|
WHERE sri.created_at > now() - interval '1 day'
|
|
129
129
|
AND sri.status = 'success'
|
|
130
130
|
AND sri.operation != 'noop'
|
|
@@ -135,7 +135,7 @@ ORDER BY sri.created_at DESC;
|
|
|
135
135
|
|
|
136
136
|
```sql
|
|
137
137
|
SELECT id, adapter, domain, external_ref, last_sync_at
|
|
138
|
-
FROM
|
|
138
|
+
FROM integration_subscriptions
|
|
139
139
|
WHERE enabled = true
|
|
140
140
|
AND (last_sync_at IS NULL OR last_sync_at < now() - interval '1 hour')
|
|
141
141
|
ORDER BY last_sync_at ASC NULLS FIRST;
|
|
@@ -147,7 +147,7 @@ mid-run without reaching the completion path)
|
|
|
147
147
|
|
|
148
148
|
```sql
|
|
149
149
|
SELECT sr.id, sr.subscription_id, sr.started_at, sr.action
|
|
150
|
-
FROM
|
|
150
|
+
FROM integration_runs sr
|
|
151
151
|
WHERE sr.status = 'running'
|
|
152
152
|
AND sr.started_at < now() - interval '10 minutes';
|
|
153
153
|
```
|
|
@@ -156,7 +156,7 @@ WHERE sr.status = 'running'
|
|
|
156
156
|
|
|
157
157
|
```sql
|
|
158
158
|
SELECT sri.created_at
|
|
159
|
-
FROM
|
|
159
|
+
FROM integration_run_items sri
|
|
160
160
|
WHERE sri.entity_type = 'opportunity'
|
|
161
161
|
AND sri.external_id = '006Ab00000ABC'
|
|
162
162
|
AND sri.changed_fields -> 'stage_name' ->> 'to' = 'Closed Won'
|
|
@@ -173,7 +173,7 @@ SELECT sri.external_id,
|
|
|
173
173
|
sri.changed_fields -> 'amount' ->> 'from' AS old_amount,
|
|
174
174
|
sri.changed_fields -> 'amount' ->> 'to' AS new_amount,
|
|
175
175
|
sri.created_at
|
|
176
|
-
FROM
|
|
176
|
+
FROM integration_run_items sri
|
|
177
177
|
WHERE sri.entity_type = 'opportunity'
|
|
178
178
|
AND sri.created_at > now() - interval '7 days'
|
|
179
179
|
AND sri.changed_fields ? 'amount'
|
|
@@ -215,7 +215,7 @@ execute(input)
|
|
|
215
215
|
### Failure semantics worth memorizing
|
|
216
216
|
|
|
217
217
|
1. **`assertTenantId` fires before `startRun`.** Rejected multi-tenant inputs
|
|
218
|
-
never open a `
|
|
218
|
+
never open a `integration_runs` row — no dangling `status=running`. Backends
|
|
219
219
|
re-validate at their write boundary (defense in depth).
|
|
220
220
|
|
|
221
221
|
2. **Cursor advances per-yield, not per-success.** `latestCursor` updates on
|
|
@@ -289,7 +289,7 @@ as changes), but the diff output preserves the *raw* values:
|
|
|
289
289
|
cannot remove defaults):
|
|
290
290
|
|
|
291
291
|
```ts
|
|
292
|
-
{ provide:
|
|
292
|
+
{ provide: INTEGRATION_FIELD_DIFFER, useValue: new DeepEqualDiffer({ ignore: ['integration_version'] }) }
|
|
293
293
|
```
|
|
294
294
|
|
|
295
295
|
Bind it as `useValue: new DeepEqualDiffer(...)`, not `useClass` — the
|
|
@@ -299,4 +299,4 @@ constructor's optional options object confuses Nest's metadata reflection.
|
|
|
299
299
|
columns changed, set it on the `Change<T>` and the differ skips deep-equal over
|
|
300
300
|
untouched fields — but it still applies the ignore list. To write a fully
|
|
301
301
|
custom differ (type-aware enum normalization, hint-only inspection), implement
|
|
302
|
-
`IFieldDiffer<T>` and bind it to `
|
|
302
|
+
`IFieldDiffer<T>` and bind it to `INTEGRATION_FIELD_DIFFER`.
|