@friggframework/core 2.0.0-next.10 → 2.0.0-next.101
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/CLAUDE.md +702 -0
- package/README.md +959 -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 +166 -0
- package/admin-scripts/repositories/admin-script-execution-repository-mongo.js +228 -0
- package/admin-scripts/repositories/admin-script-execution-repository-postgres.js +268 -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 +358 -0
- package/application/commands/credential-commands.js +245 -0
- package/application/commands/entity-commands.js +336 -0
- package/application/commands/integration-commands.js +343 -0
- package/application/commands/process-commands.js +135 -0
- package/application/commands/scheduler-commands.js +263 -0
- package/application/commands/user-commands.js +312 -0
- package/application/index.js +82 -0
- package/assertions/index.js +0 -3
- package/core/CLAUDE.md +690 -0
- package/core/Worker.js +60 -24
- package/core/create-handler.js +84 -6
- package/credential/repositories/credential-repository-documentdb.js +304 -0
- package/credential/repositories/credential-repository-factory.js +54 -0
- package/credential/repositories/credential-repository-interface.js +98 -0
- package/credential/repositories/credential-repository-mongo.js +269 -0
- package/credential/repositories/credential-repository-postgres.js +287 -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 +154 -0
- package/database/documentdb-encryption-service.js +330 -0
- package/database/documentdb-utils.js +136 -0
- package/database/encryption/README.md +839 -0
- package/database/encryption/documentdb-encryption-service.md +3575 -0
- package/database/encryption/encryption-schema-registry.js +401 -0
- package/database/encryption/field-encryption-service.js +254 -0
- package/database/encryption/logger.js +79 -0
- package/database/encryption/prisma-encryption-extension.js +230 -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/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 +477 -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 +15 -7
- package/errors/index.js +2 -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 +374 -0
- package/generated/prisma-mongodb/index-browser.js +356 -0
- package/generated/prisma-mongodb/index.d.ts +25667 -0
- package/generated/prisma-mongodb/index.js +399 -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 +432 -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 +381 -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 +395 -0
- package/generated/prisma-postgresql/index-browser.js +377 -0
- package/generated/prisma-postgresql/index.d.ts +28455 -0
- package/generated/prisma-postgresql/index.js +420 -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 +414 -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 +402 -0
- package/handlers/WEBHOOKS.md +653 -0
- package/handlers/app-definition-loader.js +43 -0
- package/handlers/app-handler-helpers.js +3 -3
- package/handlers/backend-utils.js +271 -42
- package/handlers/database-migration-handler.js +227 -0
- package/handlers/integration-event-dispatcher.js +54 -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 +311 -0
- package/handlers/routers/health.js +518 -0
- package/handlers/routers/integration-defined-routers.js +85 -10
- package/handlers/routers/integration-webhook-routers.js +67 -0
- package/handlers/routers/reporting.js +9 -0
- package/handlers/routers/user.js +27 -5
- package/handlers/routers/websocket.js +5 -3
- 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 +352 -0
- package/handlers/workers/dlq-processor.js +63 -0
- package/handlers/workers/integration-defined-workers.js +13 -7
- package/index.js +91 -46
- package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +184 -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 +633 -72
- package/integrations/integration-router.js +398 -180
- package/integrations/options.js +1 -1
- package/integrations/repositories/config-patch-shared.js +43 -0
- package/integrations/repositories/integration-mapping-repository-documentdb.js +280 -0
- package/integrations/repositories/integration-mapping-repository-factory.js +57 -0
- package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
- package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
- package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
- package/integrations/repositories/integration-mapping-repository.js +156 -0
- package/integrations/repositories/integration-repository-documentdb.js +284 -0
- package/integrations/repositories/integration-repository-factory.js +51 -0
- package/integrations/repositories/integration-repository-interface.js +173 -0
- package/integrations/repositories/integration-repository-mongo.js +414 -0
- package/integrations/repositories/integration-repository-postgres.js +452 -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/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/create-integration.js +215 -0
- package/integrations/use-cases/create-process.js +130 -0
- package/integrations/use-cases/delete-integration-for-user.js +119 -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/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 +216 -0
- package/integrations/use-cases/update-process-state.js +163 -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/logs/logger.js +0 -4
- package/{module-plugin → modules}/index.js +0 -10
- package/modules/module-factory.js +56 -0
- package/modules/module.js +287 -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 +396 -0
- package/modules/requester/requester.js +334 -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 +243 -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 +18 -0
- package/package.json +82 -50
- package/prisma-mongodb/schema.prisma +432 -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/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 +414 -0
- package/queues/queuer-util.js +103 -21
- package/reporting/README.md +86 -0
- package/reporting/index.js +17 -0
- package/reporting/reporting-router.js +77 -0
- package/reporting/repositories/reporting-repository-documentdb.js +127 -0
- package/reporting/repositories/reporting-repository-factory.js +35 -0
- package/reporting/repositories/reporting-repository-interface.js +16 -0
- package/reporting/repositories/reporting-repository-mongo.js +54 -0
- package/reporting/repositories/reporting-repository-postgres.js +70 -0
- package/reporting/use-cases/index.js +6 -0
- package/reporting/use-cases/list-integrations-report.js +142 -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/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/integrations/index.d.ts +3 -8
- package/types/module-plugin/index.d.ts +17 -69
- package/types/syncs/index.d.ts +0 -17
- package/user/repositories/user-repository-documentdb.js +458 -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 +127 -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 +77 -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
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tier 3 — Integration Extensions
|
|
3
|
+
*
|
|
4
|
+
* An Integration Extension is a reusable bundle exported by an API module (or a
|
|
5
|
+
* shared extensions library) that contributes routes, events, queues, and workers
|
|
6
|
+
* to a consumer integration. The integration binds the bundle declaratively via
|
|
7
|
+
* `static Definition.extensions` and the framework merges its contributions into
|
|
8
|
+
* the integration's effective definition at instantiation time.
|
|
9
|
+
*
|
|
10
|
+
* Extension bundle shape:
|
|
11
|
+
*
|
|
12
|
+
* {
|
|
13
|
+
* name: string, // required, unique within the API module
|
|
14
|
+
* routes?: Array<{ // optional, mounted alongside Definition.routes
|
|
15
|
+
* path: string,
|
|
16
|
+
* method: 'GET' | 'POST' | 'PUT' | 'DELETE' | ...,
|
|
17
|
+
* event: string // must exist in `events` below
|
|
18
|
+
* }>,
|
|
19
|
+
* events?: { // optional, merged into instance.events
|
|
20
|
+
* [eventName]: {
|
|
21
|
+
* type?: string, // e.g. 'LIFE_CYCLE_EVENT'
|
|
22
|
+
* handler: Function // default handler; integration may override per-binding
|
|
23
|
+
* }
|
|
24
|
+
* },
|
|
25
|
+
* queues?: Array<Object>, // reserved — Phase 2
|
|
26
|
+
* workers?: Array<Object> // reserved — Phase 2
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* Integration binding shape (on the integration's static Definition.extensions):
|
|
30
|
+
*
|
|
31
|
+
* extensions: {
|
|
32
|
+
* hubspotWebhooks: { // local binding name (developer's choice)
|
|
33
|
+
* extension: hubspot.extensions.webhooks,
|
|
34
|
+
* handlers: { // optional override map
|
|
35
|
+
* HUBSPOT_WEBHOOK: 'onHubSpotEvent' // event → method name on the integration
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* The same extension may be bound multiple times under different local names; the
|
|
41
|
+
* binding key is the developer-controlled local handle, not a global registry key.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
const KNOWN_HTTP_METHODS = new Set([
|
|
45
|
+
'get',
|
|
46
|
+
'post',
|
|
47
|
+
'put',
|
|
48
|
+
'patch',
|
|
49
|
+
'delete',
|
|
50
|
+
'options',
|
|
51
|
+
'head',
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Validate the shape of an extension bundle and its binding.
|
|
56
|
+
*
|
|
57
|
+
* @param {Object} extension - The extension bundle to validate.
|
|
58
|
+
* @param {string} bindingName - The local binding key (for error context).
|
|
59
|
+
* @param {string} integrationName - The integration's Definition.name (for error context).
|
|
60
|
+
* @param {Object} [binding] - Optional full binding object; if provided, also validates binding.handlers.
|
|
61
|
+
* @throws {Error} If the extension is missing required fields or is internally inconsistent.
|
|
62
|
+
*/
|
|
63
|
+
function validateExtensionBinding(extension, bindingName, integrationName, binding) {
|
|
64
|
+
const ctx = `Integration "${integrationName}" extension binding "${bindingName}"`;
|
|
65
|
+
|
|
66
|
+
if (!extension || typeof extension !== 'object') {
|
|
67
|
+
throw new Error(`${ctx}: extension must be an object`);
|
|
68
|
+
}
|
|
69
|
+
if (!extension.name || typeof extension.name !== 'string') {
|
|
70
|
+
throw new Error(`${ctx}: extension is missing required "name" field`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (
|
|
74
|
+
extension.useDatabase !== undefined &&
|
|
75
|
+
typeof extension.useDatabase !== 'boolean'
|
|
76
|
+
) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`${ctx}: extension "${extension.name}" "useDatabase" must be a boolean`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (
|
|
82
|
+
binding &&
|
|
83
|
+
binding.useDatabase !== undefined &&
|
|
84
|
+
typeof binding.useDatabase !== 'boolean'
|
|
85
|
+
) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`${ctx}: binding "useDatabase" must be a boolean`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const events = extension.events || {};
|
|
92
|
+
if (typeof events !== 'object' || Array.isArray(events)) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`${ctx}: extension "${extension.name}" "events" must be an object keyed by event name`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Validate each event's shape — handler, when present, must be a function.
|
|
99
|
+
for (const [eventName, eventDef] of Object.entries(events)) {
|
|
100
|
+
if (!eventDef || typeof eventDef !== 'object') {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`${ctx}: extension "${extension.name}" event "${eventName}" must be an object`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
if (
|
|
106
|
+
eventDef.handler !== undefined &&
|
|
107
|
+
typeof eventDef.handler !== 'function'
|
|
108
|
+
) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
`${ctx}: extension "${extension.name}" event "${eventName}" "handler" must be a function`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const routes = extension.routes || [];
|
|
116
|
+
if (!Array.isArray(routes)) {
|
|
117
|
+
throw new Error(
|
|
118
|
+
`${ctx}: extension "${extension.name}" "routes" must be an array`
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
for (const route of routes) {
|
|
123
|
+
if (!route || typeof route !== 'object') {
|
|
124
|
+
throw new Error(
|
|
125
|
+
`${ctx}: extension "${extension.name}" has a malformed route entry`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
if (typeof route.path !== 'string' || route.path.length === 0) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`${ctx}: extension "${extension.name}" route is missing "path"`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
if (typeof route.method !== 'string') {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`${ctx}: extension "${extension.name}" route "${route.path}" is missing "method"`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
if (!KNOWN_HTTP_METHODS.has(route.method.toLowerCase())) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
`${ctx}: extension "${extension.name}" route "${route.path}" has unsupported method "${route.method}"`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
if (typeof route.event !== 'string' || route.event.length === 0) {
|
|
144
|
+
throw new Error(
|
|
145
|
+
`${ctx}: extension "${extension.name}" route "${route.path}" is missing "event"`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
if (!Object.prototype.hasOwnProperty.call(events, route.event)) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`${ctx}: extension "${extension.name}" route "${route.path}" references event "${route.event}" which is not declared in extension.events`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Validate binding.handlers if a binding was supplied.
|
|
156
|
+
if (binding && binding.handlers !== undefined) {
|
|
157
|
+
if (
|
|
158
|
+
typeof binding.handlers !== 'object' ||
|
|
159
|
+
Array.isArray(binding.handlers) ||
|
|
160
|
+
binding.handlers === null
|
|
161
|
+
) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`${ctx}: "handlers" must be an object keyed by event name`
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
for (const [eventName, methodRef] of Object.entries(binding.handlers)) {
|
|
167
|
+
if (typeof methodRef !== 'string' || methodRef.length === 0) {
|
|
168
|
+
throw new Error(
|
|
169
|
+
`${ctx}: handler for event "${eventName}" must be a non-empty method name string (got ${typeof methodRef})`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
if (!Object.prototype.hasOwnProperty.call(events, eventName)) {
|
|
173
|
+
throw new Error(
|
|
174
|
+
`${ctx}: binding.handlers references event "${eventName}" which is not declared in extension "${extension.name}".events — check for typos`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get the flattened list of extension-contributed routes for an integration class.
|
|
183
|
+
* Each route carries the binding name and extension name alongside the route fields
|
|
184
|
+
* so the router builder can produce useful boot-time logs.
|
|
185
|
+
*
|
|
186
|
+
* @param {Function} IntegrationClass - A class extending IntegrationBase.
|
|
187
|
+
* @returns {Array<{bindingName: string, extensionName: string, path: string, method: string, event: string}>}
|
|
188
|
+
*/
|
|
189
|
+
function getExtensionRoutes(IntegrationClass) {
|
|
190
|
+
const extensions = IntegrationClass?.Definition?.extensions || {};
|
|
191
|
+
const integrationName = IntegrationClass?.Definition?.name;
|
|
192
|
+
const flat = [];
|
|
193
|
+
for (const [bindingName, binding] of Object.entries(extensions)) {
|
|
194
|
+
// Fail fast: surface bad bindings at boot, not at first request.
|
|
195
|
+
// Mirrors the validation that _mergeExtensions does at instance time.
|
|
196
|
+
validateExtensionBinding(
|
|
197
|
+
binding && binding.extension,
|
|
198
|
+
bindingName,
|
|
199
|
+
integrationName,
|
|
200
|
+
binding
|
|
201
|
+
);
|
|
202
|
+
const useDatabase =
|
|
203
|
+
binding.useDatabase ?? binding.extension.useDatabase ?? false;
|
|
204
|
+
const routes = binding.extension.routes || [];
|
|
205
|
+
for (const route of routes) {
|
|
206
|
+
flat.push({
|
|
207
|
+
bindingName,
|
|
208
|
+
extensionName: binding.extension.name,
|
|
209
|
+
path: route.path,
|
|
210
|
+
method: route.method,
|
|
211
|
+
event: route.event,
|
|
212
|
+
useDatabase,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return flat;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get the flattened list of extension-contributed workers for an integration class.
|
|
221
|
+
* Reserved for Phase 2 — today the per-integration QueueWorker handles all events
|
|
222
|
+
* by name, so extension-contributed events flow through it without a dedicated worker.
|
|
223
|
+
*
|
|
224
|
+
* @param {Function} IntegrationClass - A class extending IntegrationBase.
|
|
225
|
+
* @returns {Array<Object>}
|
|
226
|
+
*/
|
|
227
|
+
function getExtensionWorkers(IntegrationClass) {
|
|
228
|
+
const extensions = IntegrationClass?.Definition?.extensions || {};
|
|
229
|
+
const integrationName = IntegrationClass?.Definition?.name;
|
|
230
|
+
const flat = [];
|
|
231
|
+
for (const [bindingName, binding] of Object.entries(extensions)) {
|
|
232
|
+
validateExtensionBinding(
|
|
233
|
+
binding && binding.extension,
|
|
234
|
+
bindingName,
|
|
235
|
+
integrationName,
|
|
236
|
+
binding
|
|
237
|
+
);
|
|
238
|
+
const workers = binding.extension.workers || [];
|
|
239
|
+
for (const worker of workers) {
|
|
240
|
+
flat.push({
|
|
241
|
+
bindingName,
|
|
242
|
+
extensionName: binding.extension.name,
|
|
243
|
+
...worker,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return flat;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
module.exports = {
|
|
251
|
+
validateExtensionBinding,
|
|
252
|
+
getExtensionRoutes,
|
|
253
|
+
getExtensionWorkers,
|
|
254
|
+
};
|
package/integrations/index.js
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
const { IntegrationBase } = require('./integration-base');
|
|
2
|
-
const { IntegrationModel } = require('./integration-model');
|
|
3
2
|
const { Options } = require('./options');
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
const {
|
|
4
|
+
createIntegrationRouter,
|
|
5
|
+
checkRequiredParams,
|
|
6
|
+
} = require('./integration-router');
|
|
7
|
+
const {
|
|
8
|
+
getModulesDefinitionFromIntegrationClasses,
|
|
9
|
+
} = require('./utils/map-integration-dto');
|
|
10
|
+
const {
|
|
11
|
+
LoadIntegrationContextUseCase,
|
|
12
|
+
} = require('./use-cases/load-integration-context');
|
|
13
|
+
const {
|
|
14
|
+
validateExtensionBinding,
|
|
15
|
+
getExtensionRoutes,
|
|
16
|
+
getExtensionWorkers,
|
|
17
|
+
} = require('./extension');
|
|
8
18
|
|
|
9
19
|
module.exports = {
|
|
10
20
|
IntegrationBase,
|
|
11
|
-
IntegrationModel,
|
|
12
21
|
Options,
|
|
13
|
-
IntegrationMapping,
|
|
14
|
-
IntegrationFactory,
|
|
15
|
-
IntegrationHelper,
|
|
16
22
|
createIntegrationRouter,
|
|
17
23
|
checkRequiredParams,
|
|
18
|
-
|
|
24
|
+
getModulesDefinitionFromIntegrationClasses,
|
|
25
|
+
LoadIntegrationContextUseCase,
|
|
26
|
+
validateExtensionBinding,
|
|
27
|
+
getExtensionRoutes,
|
|
28
|
+
getExtensionWorkers,
|
|
19
29
|
};
|