@friggframework/core 2.0.0-next.12 → 2.0.0-next.121
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/.eslintrc.json +18 -1
- package/CLAUDE.md +830 -0
- package/README.md +996 -50
- package/admin-scripts/index.js +52 -0
- package/admin-scripts/repositories/admin-script-execution-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/admin-script-execution-repository-factory.js +51 -0
- package/admin-scripts/repositories/admin-script-execution-repository-interface.js +171 -0
- package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +238 -0
- package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +278 -0
- package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/script-schedule-repository-factory.js +51 -0
- package/admin-scripts/repositories/script-schedule-repository-interface.js +108 -0
- package/admin-scripts/repositories/script-schedule-repository-mongo.js +179 -0
- package/admin-scripts/repositories/script-schedule-repository-postgres.js +210 -0
- package/application/commands/README.md +451 -0
- package/application/commands/admin-script-commands.js +359 -0
- package/application/commands/credential-commands.js +262 -0
- package/application/commands/entity-commands.js +294 -0
- package/application/commands/integration-commands.js +419 -0
- package/application/commands/integration-mapping-commands.js +25 -0
- package/application/commands/process-commands.js +135 -0
- package/application/commands/report-commands.js +188 -0
- package/application/commands/scheduler-commands.js +263 -0
- package/application/commands/usage-commands.js +56 -0
- package/application/commands/user-commands.js +312 -0
- package/application/index.js +83 -0
- package/artifacts/repositories/artifact-repository-factory.js +19 -0
- package/artifacts/repositories/artifact-repository-interface.js +27 -0
- package/artifacts/repositories/artifact-repository-local.js +42 -0
- package/artifacts/repositories/artifact-repository-s3.js +61 -0
- package/assertions/index.js +0 -3
- package/core/CLAUDE.md +715 -0
- package/core/Worker.js +55 -24
- package/core/create-handler.js +121 -38
- package/core/index.js +8 -1
- package/core/invocation-scope.js +225 -0
- package/core/parameters-to-env.js +257 -0
- package/core/secrets-to-env.js +7 -6
- package/core/ssm-preload.mjs +34 -0
- package/credential/repositories/credential-active-type.js +32 -0
- package/credential/repositories/credential-repository-documentdb.js +355 -0
- package/credential/repositories/credential-repository-factory.js +54 -0
- package/credential/repositories/credential-repository-interface.js +113 -0
- package/credential/repositories/credential-repository-mongo.js +294 -0
- package/credential/repositories/credential-repository-postgres.js +312 -0
- package/credential/repositories/credential-repository.js +300 -0
- package/credential/use-cases/get-credential-for-user.js +25 -0
- package/credential/use-cases/update-authentication-status.js +15 -0
- package/database/MONGODB_TRANSACTION_FIX.md +198 -0
- package/database/adapters/lambda-invoker.js +97 -0
- package/database/config.js +147 -0
- package/database/documentdb-encryption-service.js +334 -0
- package/database/documentdb-utils.js +196 -0
- package/database/encryption/README.md +863 -0
- package/database/encryption/documentdb-encryption-service.md +3575 -0
- package/database/encryption/encryption-schema-registry.js +404 -0
- package/database/encryption/field-encryption-service.js +254 -0
- package/database/encryption/integration-mapping-encryption.js +97 -0
- package/database/encryption/logger.js +82 -0
- package/database/encryption/prisma-encryption-extension.js +241 -0
- package/database/index.js +21 -21
- package/database/prisma.js +182 -0
- package/database/repositories/health-check-repository-documentdb.js +138 -0
- package/database/repositories/health-check-repository-factory.js +48 -0
- package/database/repositories/health-check-repository-interface.js +82 -0
- package/database/repositories/health-check-repository-mongodb.js +89 -0
- package/database/repositories/health-check-repository-postgres.js +82 -0
- package/database/repositories/migration-status-repository-s3.js +137 -0
- package/database/use-cases/check-database-health-use-case.js +29 -0
- package/database/use-cases/check-database-state-use-case.js +81 -0
- package/database/use-cases/check-encryption-health-use-case.js +83 -0
- package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
- package/database/use-cases/get-migration-status-use-case.js +93 -0
- package/database/use-cases/resolve-migration-via-worker-use-case.js +49 -0
- package/database/use-cases/run-database-migration-use-case.js +139 -0
- package/database/use-cases/test-encryption-use-case.js +253 -0
- package/database/use-cases/trigger-database-migration-use-case.js +157 -0
- package/database/utils/mongodb-collection-utils.js +94 -0
- package/database/utils/mongodb-schema-init.js +108 -0
- package/database/utils/prisma-runner.js +491 -0
- package/database/utils/prisma-schema-parser.js +182 -0
- package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
- package/encrypt/Cryptor.js +34 -168
- package/encrypt/index.js +1 -2
- package/errors/client-safe-error.js +26 -0
- package/errors/fetch-error.js +59 -57
- package/errors/index.js +6 -0
- package/errors/mapping-already-exists-error.js +14 -0
- package/generated/prisma-mongodb/client.d.ts +1 -0
- package/generated/prisma-mongodb/client.js +5 -0
- package/generated/prisma-mongodb/default.d.ts +1 -0
- package/generated/prisma-mongodb/default.js +5 -0
- package/generated/prisma-mongodb/edge.d.ts +1 -0
- package/generated/prisma-mongodb/edge.js +386 -0
- package/generated/prisma-mongodb/index-browser.js +368 -0
- package/generated/prisma-mongodb/index.d.ts +27065 -0
- package/generated/prisma-mongodb/index.js +411 -0
- package/generated/prisma-mongodb/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
- package/generated/prisma-mongodb/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
- package/generated/prisma-mongodb/package.json +183 -0
- package/generated/prisma-mongodb/runtime/edge-esm.js +35 -0
- package/generated/prisma-mongodb/runtime/edge.js +35 -0
- package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-mongodb/runtime/index-browser.js +17 -0
- package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
- package/generated/prisma-mongodb/runtime/library.js +147 -0
- package/generated/prisma-mongodb/runtime/react-native.js +84 -0
- package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +85 -0
- package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +38 -0
- package/generated/prisma-mongodb/schema.prisma +455 -0
- package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +5 -0
- package/generated/prisma-mongodb/wasm-worker-loader.mjs +5 -0
- package/generated/prisma-mongodb/wasm.d.ts +1 -0
- package/generated/prisma-mongodb/wasm.js +393 -0
- package/generated/prisma-postgresql/client.d.ts +1 -0
- package/generated/prisma-postgresql/client.js +5 -0
- package/generated/prisma-postgresql/default.d.ts +1 -0
- package/generated/prisma-postgresql/default.js +5 -0
- package/generated/prisma-postgresql/edge.d.ts +1 -0
- package/generated/prisma-postgresql/edge.js +407 -0
- package/generated/prisma-postgresql/index-browser.js +389 -0
- package/generated/prisma-postgresql/index.d.ts +29904 -0
- package/generated/prisma-postgresql/index.js +432 -0
- package/generated/prisma-postgresql/libquery_engine-debian-openssl-3.0.x.so.node +0 -0
- package/generated/prisma-postgresql/libquery_engine-rhel-openssl-3.0.x.so.node +0 -0
- package/generated/prisma-postgresql/package.json +183 -0
- package/generated/prisma-postgresql/query_engine_bg.js +2 -0
- package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
- package/generated/prisma-postgresql/runtime/edge-esm.js +35 -0
- package/generated/prisma-postgresql/runtime/edge.js +35 -0
- package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-postgresql/runtime/index-browser.js +17 -0
- package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
- package/generated/prisma-postgresql/runtime/library.js +147 -0
- package/generated/prisma-postgresql/runtime/react-native.js +84 -0
- package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +85 -0
- package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +38 -0
- package/generated/prisma-postgresql/schema.prisma +436 -0
- package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +5 -0
- package/generated/prisma-postgresql/wasm-worker-loader.mjs +5 -0
- package/generated/prisma-postgresql/wasm.d.ts +1 -0
- package/generated/prisma-postgresql/wasm.js +414 -0
- package/handlers/WEBHOOKS.md +682 -0
- package/handlers/app-definition-loader.js +103 -0
- package/handlers/app-handler-helpers.js +20 -6
- package/handlers/backend-utils.js +272 -46
- package/handlers/database-migration-handler.js +236 -0
- package/handlers/integration-event-dispatcher.js +68 -0
- package/handlers/middleware/admin-auth.js +73 -0
- package/handlers/routers/HEALTHCHECK.md +342 -0
- package/handlers/routers/auth.js +4 -15
- package/handlers/routers/db-migration.handler.js +29 -0
- package/handlers/routers/db-migration.js +329 -0
- package/handlers/routers/health.js +518 -0
- package/handlers/routers/integration-defined-routers.js +85 -10
- package/handlers/routers/integration-webhook-routers.js +87 -0
- package/handlers/routers/user.js +27 -5
- package/handlers/routers/websocket.js +31 -9
- package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
- package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
- package/handlers/workers/db-migration.js +438 -0
- package/handlers/workers/dlq-processor.js +89 -0
- package/handlers/workers/integration-defined-workers.js +13 -7
- package/index.js +123 -47
- package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +238 -0
- package/infrastructure/scheduler/index.js +33 -0
- package/infrastructure/scheduler/mock-scheduler-adapter.js +143 -0
- package/infrastructure/scheduler/scheduler-service-factory.js +73 -0
- package/infrastructure/scheduler/scheduler-service-interface.js +47 -0
- package/integrations/EXTENSIONS.md +240 -0
- package/integrations/WEBHOOK-QUICKSTART.md +151 -0
- package/integrations/extension.js +254 -0
- package/integrations/index.js +20 -10
- package/integrations/integration-base.js +777 -74
- package/integrations/integration-router.js +399 -180
- package/integrations/options.js +1 -1
- package/integrations/repositories/config-patch-shared.js +43 -0
- package/integrations/repositories/integration-mapping-query-pipeline.js +152 -0
- package/integrations/repositories/integration-mapping-query.js +193 -0
- package/integrations/repositories/integration-mapping-repository-documentdb.js +406 -0
- package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
- package/integrations/repositories/integration-mapping-repository-interface.js +183 -0
- package/integrations/repositories/integration-mapping-repository-mongo.js +284 -0
- package/integrations/repositories/integration-mapping-repository-postgres.js +403 -0
- package/integrations/repositories/integration-mapping-repository.js +185 -0
- package/integrations/repositories/integration-repository-documentdb.js +354 -0
- package/integrations/repositories/integration-repository-factory.js +51 -0
- package/integrations/repositories/integration-repository-interface.js +219 -0
- package/integrations/repositories/integration-repository-mongo.js +502 -0
- package/integrations/repositories/integration-repository-postgres.js +550 -0
- package/integrations/repositories/process-repository-documentdb.js +311 -0
- package/integrations/repositories/process-repository-factory.js +53 -0
- package/integrations/repositories/process-repository-interface.js +136 -0
- package/integrations/repositories/process-repository-mongo.js +262 -0
- package/integrations/repositories/process-repository-postgres.js +380 -0
- package/integrations/repositories/process-update-ops-shared.js +112 -0
- package/integrations/repositories/report-id.js +13 -0
- package/integrations/tests/doubles/config-capturing-integration.js +81 -0
- package/integrations/tests/doubles/dummy-integration-class.js +113 -0
- package/integrations/tests/doubles/test-integration-repository.js +146 -0
- package/integrations/use-cases/add-entities-to-integration.js +92 -0
- package/integrations/use-cases/create-integration.js +253 -0
- package/integrations/use-cases/create-process.js +130 -0
- package/integrations/use-cases/delete-integration-for-user.js +130 -0
- package/integrations/use-cases/find-integration-by-entity-external-id.js +74 -0
- package/integrations/use-cases/find-integration-context-by-external-entity-id.js +76 -0
- package/integrations/use-cases/get-integration-for-user.js +78 -0
- package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
- package/integrations/use-cases/get-integration-instance.js +83 -0
- package/integrations/use-cases/get-integrations-for-user.js +88 -0
- package/integrations/use-cases/get-possible-integrations.js +27 -0
- package/integrations/use-cases/get-process.js +89 -0
- package/integrations/use-cases/index.js +19 -0
- package/integrations/use-cases/list-integrations-by-entity-external-id.js +46 -0
- package/integrations/use-cases/load-integration-context.js +71 -0
- package/integrations/use-cases/patch-integration-config.js +39 -0
- package/integrations/use-cases/process-errors.js +28 -0
- package/integrations/use-cases/remove-entities-from-integration.js +70 -0
- package/integrations/use-cases/update-integration-config.js +32 -0
- package/integrations/use-cases/update-integration-messages.js +44 -0
- package/integrations/use-cases/update-integration-status.js +32 -0
- package/integrations/use-cases/update-integration.js +92 -0
- package/integrations/use-cases/update-process-metrics.js +222 -0
- package/integrations/use-cases/update-process-state.js +163 -0
- package/integrations/utils/assert-entity-ids-input.js +42 -0
- package/integrations/utils/map-integration-dto.js +37 -0
- package/jest-global-setup-noop.js +3 -0
- package/jest-global-teardown-noop.js +3 -0
- package/jest.config.js +2 -0
- package/logs/.eslintrc.json +26 -1
- package/logs/__fixtures__/events.js +82 -0
- package/logs/__fixtures__/matchers.js +45 -0
- package/logs/__fixtures__/secrets.js +59 -0
- package/logs/__fixtures__/vectors.js +329 -0
- package/logs/__fixtures__/with-env.js +45 -0
- package/logs/context.js +109 -0
- package/logs/contract-keys.js +67 -0
- package/logs/debug-shims.js +46 -0
- package/logs/denied-keys.js +21 -0
- package/logs/index.js +14 -3
- package/logs/jest-logger-setup.js +25 -0
- package/logs/levels.js +71 -0
- package/logs/logger-runtime.js +137 -0
- package/logs/logger.js +134 -46
- package/logs/record.js +276 -0
- package/logs/redact.js +328 -0
- package/logs/serialize.js +329 -0
- package/logs/sinks.js +93 -0
- package/logs/summarize-event.js +163 -0
- package/{module-plugin → modules}/index.js +0 -10
- package/modules/module-factory.js +56 -0
- package/modules/module.js +320 -0
- package/modules/repositories/module-repository-documentdb.js +350 -0
- package/modules/repositories/module-repository-factory.js +40 -0
- package/modules/repositories/module-repository-interface.js +145 -0
- package/modules/repositories/module-repository-mongo.js +436 -0
- package/modules/repositories/module-repository-postgres.js +481 -0
- package/modules/repositories/module-repository.js +369 -0
- package/modules/requester/api-key.js +52 -0
- package/modules/requester/oauth-2.js +561 -0
- package/modules/requester/requester.js +605 -0
- package/{module-plugin → modules}/test/mock-api/api.js +8 -3
- package/{module-plugin → modules}/test/mock-api/definition.js +14 -10
- package/modules/tests/doubles/test-module-factory.js +16 -0
- package/modules/tests/doubles/test-module-repository.js +39 -0
- package/modules/use-cases/get-entities-for-user.js +32 -0
- package/modules/use-cases/get-entity-options-by-id.js +71 -0
- package/modules/use-cases/get-entity-options-by-type.js +34 -0
- package/modules/use-cases/get-module-instance-from-type.js +34 -0
- package/modules/use-cases/get-module.js +74 -0
- package/modules/use-cases/process-authorization-callback.js +294 -0
- package/modules/use-cases/refresh-entity-options.js +72 -0
- package/modules/use-cases/test-module-auth.js +72 -0
- package/modules/utils/map-module-dto.js +20 -0
- package/modules/utils/to-credential-id.js +14 -0
- package/package.json +92 -52
- package/prisma-mongodb/schema.prisma +455 -0
- package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
- package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
- package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
- package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +25 -0
- package/prisma-postgresql/migrations/20260422120000_add_entity_data_column/migration.sql +10 -0
- package/prisma-postgresql/migrations/20260422120001_create_process_table/migration.sql +48 -0
- package/prisma-postgresql/migrations/20260625000000_add_user_organization_id_index/migration.sql +2 -0
- package/prisma-postgresql/migrations/20260703000000_add_integration_status_in_creation_in_deletion/migration.sql +11 -0
- package/prisma-postgresql/migrations/20260703000001_integration_status_default_in_creation/migration.sql +8 -0
- package/prisma-postgresql/migrations/20260705000000_create_usage_counter/migration.sql +26 -0
- package/prisma-postgresql/migrations/20260706000000_add_admin_script_execution_and_schedule/migration.sql +61 -0
- package/prisma-postgresql/migrations/migration_lock.toml +3 -0
- package/prisma-postgresql/schema.prisma +436 -0
- package/queues/queue-delivery.js +41 -0
- package/queues/queuer-util.js +89 -21
- package/reporting/README.md +154 -0
- package/reporting/builtin-reports.js +6 -0
- package/reporting/index.js +13 -0
- package/reporting/report-base.js +49 -0
- package/reporting/reports/integrations-report.js +221 -0
- package/syncs/manager.js +468 -443
- package/syncs/repositories/sync-repository-documentdb.js +240 -0
- package/syncs/repositories/sync-repository-factory.js +43 -0
- package/syncs/repositories/sync-repository-interface.js +109 -0
- package/syncs/repositories/sync-repository-mongo.js +239 -0
- package/syncs/repositories/sync-repository-postgres.js +319 -0
- package/syncs/sync.js +0 -1
- package/telemetry/README.md +331 -0
- package/telemetry/bind-telemetry-context.js +77 -0
- package/telemetry/canonical-counters.js +52 -0
- package/telemetry/exporters.js +85 -0
- package/telemetry/index.js +26 -0
- package/telemetry/instrument-handler.js +104 -0
- package/telemetry/no-op-telemetry.js +71 -0
- package/telemetry/north-star.js +103 -0
- package/telemetry/otel-telemetry.js +232 -0
- package/telemetry/plugin-subscribers.js +77 -0
- package/telemetry/telemetry-config.js +120 -0
- package/telemetry/telemetry-context.js +51 -0
- package/telemetry/telemetry-event-bus.js +58 -0
- package/telemetry/telemetry-runtime.js +164 -0
- package/telemetry/telemetry-service.js +52 -0
- package/telemetry/usage-rollup-subscriber.js +116 -0
- package/token/repositories/token-repository-documentdb.js +137 -0
- package/token/repositories/token-repository-factory.js +40 -0
- package/token/repositories/token-repository-interface.js +131 -0
- package/token/repositories/token-repository-mongo.js +219 -0
- package/token/repositories/token-repository-postgres.js +264 -0
- package/token/repositories/token-repository.js +219 -0
- package/types/associations/index.d.ts +0 -17
- package/types/core/index.d.ts +12 -4
- package/types/database/index.d.ts +10 -2
- package/types/encrypt/index.d.ts +5 -3
- package/types/errors/index.d.ts +24 -10
- package/types/integrations/index.d.ts +3 -8
- package/types/logs/index.d.ts +61 -2
- package/types/module-plugin/index.d.ts +20 -69
- package/types/syncs/index.d.ts +0 -17
- package/usage/README.md +54 -0
- package/usage/index.js +17 -0
- package/usage/repositories/usage-repository-documentdb.js +194 -0
- package/usage/repositories/usage-repository-factory.js +25 -0
- package/usage/repositories/usage-repository-interface.js +37 -0
- package/usage/repositories/usage-repository-prisma.js +146 -0
- package/usage/tracked-metrics.js +38 -0
- package/usage/usage-windows.js +24 -0
- package/user/repositories/user-repository-documentdb.js +426 -0
- package/user/repositories/user-repository-factory.js +52 -0
- package/user/repositories/user-repository-interface.js +214 -0
- package/user/repositories/user-repository-mongo.js +323 -0
- package/user/repositories/user-repository-postgres.js +377 -0
- package/user/tests/doubles/test-user-repository.js +72 -0
- package/user/use-cases/authenticate-user.js +143 -0
- package/user/use-cases/authenticate-with-shared-secret.js +48 -0
- package/user/use-cases/create-individual-user.js +61 -0
- package/user/use-cases/create-organization-user.js +47 -0
- package/user/use-cases/create-token-for-user-id.js +30 -0
- package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
- package/user/use-cases/get-user-from-bearer-token.js +82 -0
- package/user/use-cases/get-user-from-x-frigg-headers.js +132 -0
- package/user/use-cases/login-user.js +122 -0
- package/user/user.js +125 -0
- package/utils/backend-path.js +38 -0
- package/utils/index.js +6 -0
- package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +44 -0
- package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
- package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
- package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
- package/websocket/repositories/websocket-connection-repository.js +161 -0
- package/assertions/is-equal.js +0 -17
- package/associations/model.js +0 -54
- package/database/models/IndividualUser.js +0 -76
- package/database/models/OrganizationUser.js +0 -29
- package/database/models/State.js +0 -9
- package/database/models/Token.js +0 -70
- package/database/models/UserModel.js +0 -7
- package/database/models/WebsocketConnection.js +0 -49
- package/database/mongo.js +0 -45
- package/database/mongoose.js +0 -5
- package/encrypt/Cryptor.test.js +0 -32
- package/encrypt/encrypt.js +0 -132
- package/encrypt/encrypt.test.js +0 -1069
- package/encrypt/test-encrypt.js +0 -107
- package/errors/base-error.test.js +0 -32
- package/errors/fetch-error.test.js +0 -79
- package/errors/halt-error.test.js +0 -11
- package/errors/validation-errors.test.js +0 -120
- package/handlers/routers/middleware/loadUser.js +0 -15
- package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
- package/integrations/create-frigg-backend.js +0 -31
- package/integrations/integration-factory.js +0 -251
- package/integrations/integration-mapping.js +0 -43
- package/integrations/integration-model.js +0 -46
- package/integrations/integration-user.js +0 -144
- package/integrations/test/integration-base.test.js +0 -144
- package/lambda/TimeoutCatcher.test.js +0 -68
- package/logs/logger.test.js +0 -76
- package/module-plugin/auther.js +0 -393
- package/module-plugin/credential.js +0 -22
- package/module-plugin/entity-manager.js +0 -70
- package/module-plugin/entity.js +0 -46
- package/module-plugin/manager.js +0 -169
- package/module-plugin/module-factory.js +0 -61
- package/module-plugin/requester/api-key.js +0 -36
- package/module-plugin/requester/oauth-2.js +0 -219
- package/module-plugin/requester/requester.js +0 -165
- package/module-plugin/requester/requester.test.js +0 -28
- package/module-plugin/test/auther.test.js +0 -97
- package/syncs/model.js +0 -62
- /package/{module-plugin → modules}/ModuleConstants.js +0 -0
- /package/{module-plugin → modules}/requester/basic.js +0 -0
- /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
package/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const {
|
|
2
|
-
expectShallowEqualDbObject,
|
|
3
2
|
get,
|
|
4
3
|
getAll,
|
|
5
4
|
verifyType,
|
|
@@ -12,61 +11,103 @@ const {
|
|
|
12
11
|
Worker,
|
|
13
12
|
loadInstalledModules,
|
|
14
13
|
createHandler,
|
|
14
|
+
runInvocationScope,
|
|
15
15
|
} = require('./core/index');
|
|
16
16
|
const {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
OrganizationUser,
|
|
23
|
-
State,
|
|
24
|
-
Token,
|
|
25
|
-
UserModel,
|
|
26
|
-
WebsocketConnection,
|
|
17
|
+
prisma,
|
|
18
|
+
connectPrisma,
|
|
19
|
+
disconnectPrisma,
|
|
20
|
+
TokenRepository,
|
|
21
|
+
WebsocketConnectionRepository,
|
|
27
22
|
} = require('./database/index');
|
|
28
|
-
const {
|
|
23
|
+
const {
|
|
24
|
+
createUserRepository,
|
|
25
|
+
UserRepositoryMongo,
|
|
26
|
+
UserRepositoryPostgres,
|
|
27
|
+
} = require('./user/repositories/user-repository-factory');
|
|
28
|
+
const {
|
|
29
|
+
GetUserFromXFriggHeaders,
|
|
30
|
+
} = require('./user/use-cases/get-user-from-x-frigg-headers');
|
|
31
|
+
const {
|
|
32
|
+
GetUserFromAdopterJwt,
|
|
33
|
+
} = require('./user/use-cases/get-user-from-adopter-jwt');
|
|
34
|
+
const { AuthenticateUser } = require('./user/use-cases/authenticate-user');
|
|
35
|
+
|
|
36
|
+
const {
|
|
37
|
+
CredentialRepository,
|
|
38
|
+
} = require('./credential/repositories/credential-repository');
|
|
39
|
+
const {
|
|
40
|
+
ModuleRepository,
|
|
41
|
+
} = require('./modules/repositories/module-repository');
|
|
42
|
+
const {
|
|
43
|
+
IntegrationMappingRepository,
|
|
44
|
+
} = require('./integrations/repositories/integration-mapping-repository');
|
|
45
|
+
const { CreateProcess } = require('./integrations/use-cases/create-process');
|
|
46
|
+
const {
|
|
47
|
+
UpdateProcessState,
|
|
48
|
+
} = require('./integrations/use-cases/update-process-state');
|
|
49
|
+
const {
|
|
50
|
+
UpdateProcessMetrics,
|
|
51
|
+
} = require('./integrations/use-cases/update-process-metrics');
|
|
52
|
+
const { GetProcess } = require('./integrations/use-cases/get-process');
|
|
53
|
+
const { Cryptor } = require('./encrypt');
|
|
29
54
|
const {
|
|
30
55
|
BaseError,
|
|
31
56
|
FetchError,
|
|
32
57
|
HaltError,
|
|
33
58
|
RequiredPropertyError,
|
|
34
59
|
ParameterTypeError,
|
|
60
|
+
MappingAlreadyExistsError,
|
|
35
61
|
} = require('./errors/index');
|
|
36
62
|
const {
|
|
37
63
|
IntegrationBase,
|
|
38
|
-
IntegrationModel,
|
|
39
64
|
Options,
|
|
40
|
-
IntegrationMapping,
|
|
41
|
-
IntegrationFactory,
|
|
42
|
-
IntegrationHelper,
|
|
43
65
|
createIntegrationRouter,
|
|
44
66
|
checkRequiredParams,
|
|
45
|
-
|
|
67
|
+
getModulesDefinitionFromIntegrationClasses,
|
|
68
|
+
LoadIntegrationContextUseCase,
|
|
46
69
|
} = require('./integrations/index');
|
|
70
|
+
const {
|
|
71
|
+
ReportBase,
|
|
72
|
+
IntegrationsReport,
|
|
73
|
+
BUILTIN_REPORTS,
|
|
74
|
+
createReportCommands,
|
|
75
|
+
} = require('./reporting/index');
|
|
76
|
+
const {
|
|
77
|
+
createTelemetry,
|
|
78
|
+
getTelemetry,
|
|
79
|
+
CANONICAL_COUNTERS,
|
|
80
|
+
} = require('./telemetry/index');
|
|
81
|
+
const { createUsageRepository } = require('./usage/index');
|
|
47
82
|
const { TimeoutCatcher } = require('./lambda/index');
|
|
48
|
-
const {
|
|
83
|
+
const {
|
|
84
|
+
getLogger,
|
|
85
|
+
createMemorySink,
|
|
86
|
+
resetLoggerForTests,
|
|
87
|
+
serializeError,
|
|
88
|
+
redactValue,
|
|
89
|
+
toSanitizedSurrogate,
|
|
90
|
+
debug,
|
|
91
|
+
initDebugLog,
|
|
92
|
+
flushDebugLog,
|
|
93
|
+
} = require('./logs/index');
|
|
49
94
|
const {
|
|
50
95
|
Credential,
|
|
51
|
-
EntityManager,
|
|
52
96
|
Entity,
|
|
53
|
-
ModuleManager,
|
|
54
97
|
ApiKeyRequester,
|
|
55
98
|
BasicAuthRequester,
|
|
56
99
|
OAuth2Requester,
|
|
57
100
|
Requester,
|
|
58
101
|
ModuleConstants,
|
|
59
102
|
ModuleFactory,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// const {Sync } = require('./syncs/model');
|
|
103
|
+
} = require('./modules/index');
|
|
104
|
+
const application = require('./application');
|
|
105
|
+
const utils = require('./utils');
|
|
64
106
|
|
|
65
107
|
const { QueuerUtil } = require('./queues');
|
|
66
108
|
|
|
67
109
|
module.exports = {
|
|
68
110
|
// assertions
|
|
69
|
-
expectShallowEqualDbObject,
|
|
70
111
|
get,
|
|
71
112
|
getAll,
|
|
72
113
|
verifyType,
|
|
@@ -79,21 +120,23 @@ module.exports = {
|
|
|
79
120
|
Worker,
|
|
80
121
|
loadInstalledModules,
|
|
81
122
|
createHandler,
|
|
123
|
+
runInvocationScope,
|
|
82
124
|
|
|
83
125
|
// database
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
126
|
+
prisma,
|
|
127
|
+
connectPrisma,
|
|
128
|
+
disconnectPrisma,
|
|
129
|
+
TokenRepository,
|
|
130
|
+
WebsocketConnectionRepository,
|
|
131
|
+
createUserRepository,
|
|
132
|
+
UserRepositoryMongo,
|
|
133
|
+
UserRepositoryPostgres,
|
|
134
|
+
GetUserFromXFriggHeaders,
|
|
135
|
+
GetUserFromAdopterJwt,
|
|
136
|
+
AuthenticateUser,
|
|
137
|
+
CredentialRepository,
|
|
138
|
+
ModuleRepository,
|
|
139
|
+
IntegrationMappingRepository,
|
|
97
140
|
Cryptor,
|
|
98
141
|
|
|
99
142
|
// errors
|
|
@@ -102,39 +145,72 @@ module.exports = {
|
|
|
102
145
|
HaltError,
|
|
103
146
|
RequiredPropertyError,
|
|
104
147
|
ParameterTypeError,
|
|
148
|
+
MappingAlreadyExistsError,
|
|
105
149
|
|
|
106
150
|
// integrations
|
|
107
151
|
IntegrationBase,
|
|
108
|
-
IntegrationModel,
|
|
109
152
|
Options,
|
|
110
|
-
IntegrationMapping,
|
|
111
|
-
IntegrationFactory,
|
|
112
|
-
IntegrationHelper,
|
|
113
153
|
checkRequiredParams,
|
|
114
154
|
createIntegrationRouter,
|
|
115
|
-
|
|
155
|
+
getModulesDefinitionFromIntegrationClasses,
|
|
156
|
+
LoadIntegrationContextUseCase,
|
|
157
|
+
CreateProcess,
|
|
158
|
+
UpdateProcessState,
|
|
159
|
+
UpdateProcessMetrics,
|
|
160
|
+
GetProcess,
|
|
161
|
+
|
|
162
|
+
// reporting
|
|
163
|
+
ReportBase,
|
|
164
|
+
IntegrationsReport,
|
|
165
|
+
BUILTIN_REPORTS,
|
|
166
|
+
createReportCommands,
|
|
167
|
+
|
|
168
|
+
// telemetry
|
|
169
|
+
createTelemetry,
|
|
170
|
+
getTelemetry,
|
|
171
|
+
CANONICAL_COUNTERS,
|
|
172
|
+
createUsageRepository,
|
|
173
|
+
|
|
174
|
+
// application - Command factories for integration developers
|
|
175
|
+
application,
|
|
176
|
+
createFriggCommands: application.createFriggCommands,
|
|
177
|
+
createIntegrationCommands: application.createIntegrationCommands,
|
|
178
|
+
createUserCommands: application.createUserCommands,
|
|
179
|
+
createEntityCommands: application.createEntityCommands,
|
|
180
|
+
createCredentialCommands: application.createCredentialCommands,
|
|
181
|
+
createProcessCommands: application.createProcessCommands,
|
|
182
|
+
createSchedulerCommands: application.createSchedulerCommands,
|
|
183
|
+
createUsageCommands: application.createUsageCommands,
|
|
184
|
+
findIntegrationContextByExternalEntityId:
|
|
185
|
+
application.findIntegrationContextByExternalEntityId,
|
|
186
|
+
integrationCommands: application.integrationCommands,
|
|
116
187
|
|
|
117
188
|
// lambda
|
|
118
189
|
TimeoutCatcher,
|
|
119
190
|
|
|
120
191
|
// logs
|
|
192
|
+
getLogger,
|
|
193
|
+
createMemorySink,
|
|
194
|
+
resetLoggerForTests,
|
|
195
|
+
serializeError,
|
|
196
|
+
redactValue,
|
|
197
|
+
toSanitizedSurrogate,
|
|
121
198
|
debug,
|
|
122
199
|
initDebugLog,
|
|
123
200
|
flushDebugLog,
|
|
124
201
|
|
|
125
202
|
// module plugin
|
|
126
203
|
Credential,
|
|
127
|
-
EntityManager,
|
|
128
204
|
Entity,
|
|
129
|
-
ModuleManager,
|
|
130
205
|
ApiKeyRequester,
|
|
131
206
|
BasicAuthRequester,
|
|
132
207
|
OAuth2Requester,
|
|
133
208
|
Requester,
|
|
134
209
|
ModuleConstants,
|
|
135
210
|
ModuleFactory,
|
|
136
|
-
Auther,
|
|
137
|
-
|
|
138
211
|
// queues
|
|
139
212
|
QueuerUtil,
|
|
213
|
+
|
|
214
|
+
// utils
|
|
215
|
+
...utils,
|
|
140
216
|
};
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventBridge Scheduler Adapter
|
|
3
|
+
*
|
|
4
|
+
* Infrastructure Layer - Hexagonal Architecture
|
|
5
|
+
*
|
|
6
|
+
* Responsible for:
|
|
7
|
+
* - Creating one-time EventBridge Scheduler schedules
|
|
8
|
+
* - Deleting schedules when no longer needed
|
|
9
|
+
* - Checking schedule status
|
|
10
|
+
*
|
|
11
|
+
* This adapter implements SchedulerServiceInterface for AWS EventBridge Scheduler.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const { SchedulerServiceInterface } = require('./scheduler-service-interface');
|
|
15
|
+
|
|
16
|
+
const SCHEDULER_SDK = '@aws-sdk/client-scheduler';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Lazily load the AWS EventBridge Scheduler SDK.
|
|
20
|
+
*
|
|
21
|
+
* Requiring `@aws-sdk/client-scheduler` at module top level would put the AWS
|
|
22
|
+
* SDK on the load path of every consumer of `@friggframework/core`, including
|
|
23
|
+
* those using the mock scheduler or no scheduler at all. Loading it here, on
|
|
24
|
+
* construction of the EventBridge adapter, keeps it out of the module-load
|
|
25
|
+
* path. The adapter calls it exactly once, in its constructor, and keeps the
|
|
26
|
+
* classes its methods need on the instance.
|
|
27
|
+
*
|
|
28
|
+
* Only a MODULE_NOT_FOUND for the scheduler SDK itself is rewritten into an
|
|
29
|
+
* actionable message; any other failure (including a missing transitive
|
|
30
|
+
* dependency) is rethrown unchanged so the real cause is not masked.
|
|
31
|
+
*
|
|
32
|
+
* @returns {object} The relevant exports from `@aws-sdk/client-scheduler`.
|
|
33
|
+
*/
|
|
34
|
+
function loadSchedulerSdk() {
|
|
35
|
+
try {
|
|
36
|
+
// Keep the literal specifier so bundlers (esbuild) can resolve it.
|
|
37
|
+
return require('@aws-sdk/client-scheduler');
|
|
38
|
+
} catch (error) {
|
|
39
|
+
const isSchedulerSdkMissing =
|
|
40
|
+
error &&
|
|
41
|
+
error.code === 'MODULE_NOT_FOUND' &&
|
|
42
|
+
typeof error.message === 'string' &&
|
|
43
|
+
error.message.includes(SCHEDULER_SDK);
|
|
44
|
+
if (isSchedulerSdkMissing) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`The EventBridge scheduler requires the "${SCHEDULER_SDK}" package, ` +
|
|
47
|
+
`which is not installed. Install it (\`npm install ${SCHEDULER_SDK}\`) ` +
|
|
48
|
+
'to use the EventBridge scheduler provider, or use the mock scheduler provider ' +
|
|
49
|
+
'(SCHEDULER_PROVIDER=mock) for local development.',
|
|
50
|
+
{ cause: error }
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
class EventBridgeSchedulerAdapter extends SchedulerServiceInterface {
|
|
58
|
+
constructor({ region } = {}) {
|
|
59
|
+
super();
|
|
60
|
+
const {
|
|
61
|
+
SchedulerClient,
|
|
62
|
+
CreateScheduleCommand,
|
|
63
|
+
DeleteScheduleCommand,
|
|
64
|
+
GetScheduleCommand,
|
|
65
|
+
ResourceNotFoundException,
|
|
66
|
+
} = loadSchedulerSdk();
|
|
67
|
+
this.sdk = {
|
|
68
|
+
CreateScheduleCommand,
|
|
69
|
+
DeleteScheduleCommand,
|
|
70
|
+
GetScheduleCommand,
|
|
71
|
+
ResourceNotFoundException,
|
|
72
|
+
};
|
|
73
|
+
this.client = new SchedulerClient({
|
|
74
|
+
region: region || process.env.AWS_REGION || 'us-east-1',
|
|
75
|
+
});
|
|
76
|
+
this.scheduleGroupName =
|
|
77
|
+
process.env.SCHEDULE_GROUP_NAME || 'frigg-integration-schedules';
|
|
78
|
+
this.roleArn = process.env.SCHEDULER_ROLE_ARN;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Create a one-time schedule that sends a message to SQS
|
|
83
|
+
*
|
|
84
|
+
* @param {Object} params
|
|
85
|
+
* @param {string} params.scheduleName - Unique name for the schedule
|
|
86
|
+
* @param {Date} params.scheduleAt - When to trigger the schedule
|
|
87
|
+
* @param {string} params.queueResourceId - Queue resource identifier (ARN) to send message to
|
|
88
|
+
* @param {Object} params.payload - Message payload
|
|
89
|
+
* @returns {Promise<{scheduledJobId: string, scheduledAt: string}>}
|
|
90
|
+
*/
|
|
91
|
+
async scheduleOneTime({
|
|
92
|
+
scheduleName,
|
|
93
|
+
scheduleAt,
|
|
94
|
+
queueResourceId,
|
|
95
|
+
payload,
|
|
96
|
+
}) {
|
|
97
|
+
if (!scheduleName) {
|
|
98
|
+
throw new Error('scheduleName is required');
|
|
99
|
+
}
|
|
100
|
+
if (!scheduleAt || !(scheduleAt instanceof Date)) {
|
|
101
|
+
throw new Error('scheduleAt must be a valid Date object');
|
|
102
|
+
}
|
|
103
|
+
if (!queueResourceId) {
|
|
104
|
+
throw new Error('queueResourceId is required');
|
|
105
|
+
}
|
|
106
|
+
if (!this.roleArn) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
'SCHEDULER_ROLE_ARN environment variable is not set'
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Format date to AWS schedule expression (at(yyyy-mm-ddThh:mm:ss))
|
|
113
|
+
const scheduleExpression = `at(${scheduleAt
|
|
114
|
+
.toISOString()
|
|
115
|
+
.replace(/\.\d{3}Z$/, '')})`;
|
|
116
|
+
|
|
117
|
+
const { CreateScheduleCommand } = this.sdk;
|
|
118
|
+
const command = new CreateScheduleCommand({
|
|
119
|
+
Name: scheduleName,
|
|
120
|
+
GroupName: this.scheduleGroupName,
|
|
121
|
+
ScheduleExpression: scheduleExpression,
|
|
122
|
+
ScheduleExpressionTimezone: 'UTC',
|
|
123
|
+
FlexibleTimeWindow: {
|
|
124
|
+
Mode: 'OFF',
|
|
125
|
+
},
|
|
126
|
+
Target: {
|
|
127
|
+
Arn: queueResourceId,
|
|
128
|
+
RoleArn: this.roleArn,
|
|
129
|
+
Input: JSON.stringify(payload),
|
|
130
|
+
},
|
|
131
|
+
ActionAfterCompletion: 'DELETE', // Auto-cleanup after execution
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const response = await this.client.send(command);
|
|
136
|
+
console.log(
|
|
137
|
+
`[Scheduler] Created schedule ${scheduleName} for ${scheduleAt.toISOString()}`
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
scheduledJobId: response.ScheduleArn,
|
|
142
|
+
scheduledAt: scheduleAt.toISOString(),
|
|
143
|
+
};
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error(
|
|
146
|
+
`[Scheduler] Failed to create schedule ${scheduleName}:`,
|
|
147
|
+
error.message
|
|
148
|
+
);
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Delete a schedule
|
|
155
|
+
*
|
|
156
|
+
* @param {string} scheduleName - Name of the schedule to delete
|
|
157
|
+
* @returns {Promise<void>}
|
|
158
|
+
*/
|
|
159
|
+
async deleteSchedule(scheduleName) {
|
|
160
|
+
if (!scheduleName) {
|
|
161
|
+
throw new Error('scheduleName is required');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const { DeleteScheduleCommand, ResourceNotFoundException } = this.sdk;
|
|
165
|
+
const command = new DeleteScheduleCommand({
|
|
166
|
+
Name: scheduleName,
|
|
167
|
+
GroupName: this.scheduleGroupName,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
await this.client.send(command);
|
|
172
|
+
console.log(`[Scheduler] Deleted schedule ${scheduleName}`);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
if (error instanceof ResourceNotFoundException) {
|
|
175
|
+
console.log(
|
|
176
|
+
`[Scheduler] Schedule ${scheduleName} not found (already deleted or executed)`
|
|
177
|
+
);
|
|
178
|
+
return; // Graceful handling - schedule doesn't exist
|
|
179
|
+
}
|
|
180
|
+
console.error(
|
|
181
|
+
`[Scheduler] Failed to delete schedule ${scheduleName}:`,
|
|
182
|
+
error.message
|
|
183
|
+
);
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Get schedule status
|
|
190
|
+
*
|
|
191
|
+
* @param {string} scheduleName - Name of the schedule
|
|
192
|
+
* @returns {Promise<{exists: boolean, scheduledAt?: string, state?: string}>}
|
|
193
|
+
*/
|
|
194
|
+
async getScheduleStatus(scheduleName) {
|
|
195
|
+
if (!scheduleName) {
|
|
196
|
+
throw new Error('scheduleName is required');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const { GetScheduleCommand, ResourceNotFoundException } = this.sdk;
|
|
200
|
+
const command = new GetScheduleCommand({
|
|
201
|
+
Name: scheduleName,
|
|
202
|
+
GroupName: this.scheduleGroupName,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
const response = await this.client.send(command);
|
|
207
|
+
|
|
208
|
+
// Parse the schedule expression to get the scheduled time
|
|
209
|
+
// Format: at(yyyy-mm-ddThh:mm:ss)
|
|
210
|
+
let scheduledAt = null;
|
|
211
|
+
if (response.ScheduleExpression) {
|
|
212
|
+
const match = response.ScheduleExpression.match(/^at\((.+)\)$/);
|
|
213
|
+
if (match) {
|
|
214
|
+
scheduledAt = new Date(match[1] + 'Z').toISOString();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
exists: true,
|
|
220
|
+
scheduledAt,
|
|
221
|
+
state: response.State,
|
|
222
|
+
};
|
|
223
|
+
} catch (error) {
|
|
224
|
+
if (error instanceof ResourceNotFoundException) {
|
|
225
|
+
return {
|
|
226
|
+
exists: false,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
console.error(
|
|
230
|
+
`[Scheduler] Failed to get schedule ${scheduleName}:`,
|
|
231
|
+
error.message
|
|
232
|
+
);
|
|
233
|
+
throw error;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
module.exports = { EventBridgeSchedulerAdapter };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduler Infrastructure
|
|
3
|
+
*
|
|
4
|
+
* Provides scheduling capabilities for one-time jobs.
|
|
5
|
+
* Follows hexagonal architecture with interface + adapters pattern.
|
|
6
|
+
*
|
|
7
|
+
* Providers:
|
|
8
|
+
* - eventbridge: AWS EventBridge Scheduler (production)
|
|
9
|
+
* - mock: In-memory mock scheduler (local development)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { SchedulerServiceInterface } = require('./scheduler-service-interface');
|
|
13
|
+
const { EventBridgeSchedulerAdapter } = require('./eventbridge-scheduler-adapter');
|
|
14
|
+
const { MockSchedulerAdapter } = require('./mock-scheduler-adapter');
|
|
15
|
+
const {
|
|
16
|
+
createSchedulerService,
|
|
17
|
+
SCHEDULER_PROVIDERS,
|
|
18
|
+
determineProvider,
|
|
19
|
+
} = require('./scheduler-service-factory');
|
|
20
|
+
|
|
21
|
+
module.exports = {
|
|
22
|
+
// Interface (Port)
|
|
23
|
+
SchedulerServiceInterface,
|
|
24
|
+
|
|
25
|
+
// Adapters
|
|
26
|
+
EventBridgeSchedulerAdapter,
|
|
27
|
+
MockSchedulerAdapter,
|
|
28
|
+
|
|
29
|
+
// Factory
|
|
30
|
+
createSchedulerService,
|
|
31
|
+
SCHEDULER_PROVIDERS,
|
|
32
|
+
determineProvider,
|
|
33
|
+
};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock Scheduler Adapter for Local Development
|
|
3
|
+
*
|
|
4
|
+
* Stores schedules in memory and logs instead of creating real EventBridge schedules.
|
|
5
|
+
* Used when SCHEDULER_PROVIDER=mock or in local/dev/test environments.
|
|
6
|
+
*
|
|
7
|
+
* This adapter implements SchedulerServiceInterface for local development and testing.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const { SchedulerServiceInterface } = require('./scheduler-service-interface');
|
|
11
|
+
|
|
12
|
+
class MockSchedulerAdapter extends SchedulerServiceInterface {
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
super();
|
|
15
|
+
this.verbose = options.verbose || false;
|
|
16
|
+
this.schedules = new Map();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Schedule a one-time job to be executed at a specific time
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} params
|
|
23
|
+
* @param {string} params.scheduleName - Unique name for the schedule
|
|
24
|
+
* @param {Date} params.scheduleAt - When to trigger the schedule
|
|
25
|
+
* @param {string} params.queueResourceId - Queue resource identifier to send message to
|
|
26
|
+
* @param {Object} params.payload - JSON payload to send
|
|
27
|
+
* @returns {Promise<{scheduledJobId: string, scheduledAt: string}>}
|
|
28
|
+
*/
|
|
29
|
+
async scheduleOneTime({ scheduleName, scheduleAt, queueResourceId, payload }) {
|
|
30
|
+
if (!scheduleName) {
|
|
31
|
+
throw new Error('scheduleName is required');
|
|
32
|
+
}
|
|
33
|
+
if (!scheduleAt || !(scheduleAt instanceof Date)) {
|
|
34
|
+
throw new Error('scheduleAt must be a valid Date object');
|
|
35
|
+
}
|
|
36
|
+
if (!queueResourceId) {
|
|
37
|
+
throw new Error('queueResourceId is required');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const scheduleData = {
|
|
41
|
+
scheduleName,
|
|
42
|
+
scheduledAt: scheduleAt.toISOString(),
|
|
43
|
+
queueResourceId,
|
|
44
|
+
payload,
|
|
45
|
+
createdAt: new Date().toISOString(),
|
|
46
|
+
state: 'ENABLED',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
this.schedules.set(scheduleName, scheduleData);
|
|
50
|
+
|
|
51
|
+
console.log(`[MockScheduler] Created schedule: ${scheduleName}`);
|
|
52
|
+
console.log(`[MockScheduler] Scheduled for: ${scheduleAt.toISOString()}`);
|
|
53
|
+
console.log(`[MockScheduler] Target: ${queueResourceId}`);
|
|
54
|
+
if (this.verbose) {
|
|
55
|
+
console.log(`[MockScheduler] Payload:`, JSON.stringify(payload, null, 2));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
scheduledJobId: `mock-job-${scheduleName}`,
|
|
60
|
+
scheduledAt: scheduleAt.toISOString(),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Delete a scheduled job
|
|
66
|
+
*
|
|
67
|
+
* @param {string} scheduleName - Name of the schedule to delete
|
|
68
|
+
* @returns {Promise<void>}
|
|
69
|
+
*/
|
|
70
|
+
async deleteSchedule(scheduleName) {
|
|
71
|
+
if (!scheduleName) {
|
|
72
|
+
throw new Error('scheduleName is required');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const existed = this.schedules.has(scheduleName);
|
|
76
|
+
this.schedules.delete(scheduleName);
|
|
77
|
+
|
|
78
|
+
console.log(`[MockScheduler] Deleted schedule: ${scheduleName} (existed: ${existed})`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get the status of a scheduled job
|
|
83
|
+
*
|
|
84
|
+
* @param {string} scheduleName - Name of the schedule
|
|
85
|
+
* @returns {Promise<{exists: boolean, scheduledAt?: string, state?: string}>}
|
|
86
|
+
*/
|
|
87
|
+
async getScheduleStatus(scheduleName) {
|
|
88
|
+
if (!scheduleName) {
|
|
89
|
+
throw new Error('scheduleName is required');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const schedule = this.schedules.get(scheduleName);
|
|
93
|
+
|
|
94
|
+
if (!schedule) {
|
|
95
|
+
return { exists: false };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
exists: true,
|
|
100
|
+
scheduledAt: schedule.scheduledAt,
|
|
101
|
+
state: schedule.state,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get all scheduled jobs (helper for testing)
|
|
107
|
+
*
|
|
108
|
+
* @returns {Object} Map of all schedules as plain object
|
|
109
|
+
*/
|
|
110
|
+
_getSchedules() {
|
|
111
|
+
return Object.fromEntries(this.schedules);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Clear all schedules (helper for testing)
|
|
116
|
+
*/
|
|
117
|
+
_clearSchedules() {
|
|
118
|
+
const count = this.schedules.size;
|
|
119
|
+
this.schedules.clear();
|
|
120
|
+
console.log(`[MockScheduler] Cleared ${count} schedules`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Simulate triggering a schedule (helper for testing)
|
|
125
|
+
*
|
|
126
|
+
* @param {string} scheduleName - Name of the schedule to trigger
|
|
127
|
+
* @returns {Object|null} The payload that would be sent, or null if not found
|
|
128
|
+
*/
|
|
129
|
+
_simulateTrigger(scheduleName) {
|
|
130
|
+
const schedule = this.schedules.get(scheduleName);
|
|
131
|
+
if (!schedule) {
|
|
132
|
+
console.log(`[MockScheduler] Cannot trigger - schedule not found: ${scheduleName}`);
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
console.log(`[MockScheduler] Simulating trigger for: ${scheduleName}`);
|
|
137
|
+
console.log(`[MockScheduler] Payload:`, JSON.stringify(schedule.payload, null, 2));
|
|
138
|
+
|
|
139
|
+
return schedule.payload;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = { MockSchedulerAdapter };
|