@friggframework/core 2.0.0-next.5 → 2.0.0-next.50
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 +693 -0
- package/README.md +959 -50
- package/application/commands/README.md +421 -0
- package/application/commands/credential-commands.js +224 -0
- package/application/commands/entity-commands.js +315 -0
- package/application/commands/integration-commands.js +179 -0
- package/application/commands/user-commands.js +213 -0
- package/application/index.js +69 -0
- package/core/CLAUDE.md +690 -0
- package/core/Worker.js +8 -21
- package/core/create-handler.js +2 -7
- package/credential/repositories/credential-repository-factory.js +47 -0
- package/credential/repositories/credential-repository-interface.js +98 -0
- package/credential/repositories/credential-repository-mongo.js +307 -0
- package/credential/repositories/credential-repository-postgres.js +313 -0
- package/credential/repositories/credential-repository.js +302 -0
- package/credential/use-cases/get-credential-for-user.js +21 -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/encryption/README.md +684 -0
- package/database/encryption/encryption-schema-registry.js +141 -0
- package/database/encryption/field-encryption-service.js +226 -0
- package/database/encryption/logger.js +79 -0
- package/database/encryption/prisma-encryption-extension.js +222 -0
- package/database/index.js +25 -12
- package/database/models/WebsocketConnection.js +16 -10
- package/database/models/readme.md +1 -0
- package/database/prisma.js +222 -0
- package/database/repositories/health-check-repository-factory.js +43 -0
- package/database/repositories/health-check-repository-interface.js +87 -0
- package/database/repositories/health-check-repository-mongodb.js +91 -0
- package/database/repositories/health-check-repository-postgres.js +82 -0
- package/database/repositories/health-check-repository.js +108 -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 +137 -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 +91 -0
- package/database/utils/mongodb-schema-init.js +106 -0
- package/database/utils/prisma-runner.js +400 -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/encrypt/test-encrypt.js +0 -2
- package/generated/prisma-mongodb/client.d.ts +1 -0
- package/generated/prisma-mongodb/client.js +4 -0
- package/generated/prisma-mongodb/default.d.ts +1 -0
- package/generated/prisma-mongodb/default.js +4 -0
- package/generated/prisma-mongodb/edge.d.ts +1 -0
- package/generated/prisma-mongodb/edge.js +334 -0
- package/generated/prisma-mongodb/index-browser.js +316 -0
- package/generated/prisma-mongodb/index.d.ts +22898 -0
- package/generated/prisma-mongodb/index.js +359 -0
- package/generated/prisma-mongodb/package.json +183 -0
- package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
- package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
- package/generated/prisma-mongodb/runtime/binary.js +289 -0
- package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
- package/generated/prisma-mongodb/runtime/edge.js +34 -0
- package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
- package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
- package/generated/prisma-mongodb/runtime/react-native.js +83 -0
- package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-mongodb/schema.prisma +362 -0
- package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-mongodb/wasm.d.ts +1 -0
- package/generated/prisma-mongodb/wasm.js +341 -0
- package/generated/prisma-postgresql/client.d.ts +1 -0
- package/generated/prisma-postgresql/client.js +4 -0
- package/generated/prisma-postgresql/default.d.ts +1 -0
- package/generated/prisma-postgresql/default.js +4 -0
- package/generated/prisma-postgresql/edge.d.ts +1 -0
- package/generated/prisma-postgresql/edge.js +356 -0
- package/generated/prisma-postgresql/index-browser.js +338 -0
- package/generated/prisma-postgresql/index.d.ts +25072 -0
- package/generated/prisma-postgresql/index.js +381 -0
- package/generated/prisma-postgresql/package.json +183 -0
- package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
- package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -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/binary.d.ts +1 -0
- package/generated/prisma-postgresql/runtime/binary.js +289 -0
- package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
- package/generated/prisma-postgresql/runtime/edge.js +34 -0
- package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
- package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
- package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
- package/generated/prisma-postgresql/runtime/react-native.js +83 -0
- package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
- package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
- package/generated/prisma-postgresql/schema.prisma +345 -0
- package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
- package/generated/prisma-postgresql/wasm.d.ts +1 -0
- package/generated/prisma-postgresql/wasm.js +363 -0
- package/handlers/WEBHOOKS.md +653 -0
- package/handlers/app-definition-loader.js +38 -0
- package/handlers/app-handler-helpers.js +56 -0
- package/handlers/backend-utils.js +180 -0
- package/handlers/database-migration-handler.js +227 -0
- package/handlers/integration-event-dispatcher.js +54 -0
- package/handlers/routers/HEALTHCHECK.md +342 -0
- package/handlers/routers/auth.js +15 -0
- package/handlers/routers/db-migration.handler.js +29 -0
- package/handlers/routers/db-migration.js +256 -0
- package/handlers/routers/health.js +519 -0
- package/handlers/routers/integration-defined-routers.js +45 -0
- package/handlers/routers/integration-webhook-routers.js +67 -0
- package/handlers/routers/user.js +63 -0
- package/handlers/routers/websocket.js +57 -0
- 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/integration-defined-workers.js +27 -0
- package/index.js +77 -22
- package/integrations/WEBHOOK-QUICKSTART.md +151 -0
- package/integrations/index.js +12 -10
- package/integrations/integration-base.js +296 -54
- package/integrations/integration-router.js +381 -182
- package/integrations/options.js +1 -1
- package/integrations/repositories/integration-mapping-repository-factory.js +50 -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-factory.js +44 -0
- package/integrations/repositories/integration-repository-interface.js +127 -0
- package/integrations/repositories/integration-repository-mongo.js +303 -0
- package/integrations/repositories/integration-repository-postgres.js +352 -0
- package/integrations/repositories/process-repository-factory.js +46 -0
- package/integrations/repositories/process-repository-interface.js +90 -0
- package/integrations/repositories/process-repository-mongo.js +190 -0
- package/integrations/repositories/process-repository-postgres.js +217 -0
- package/integrations/tests/doubles/dummy-integration-class.js +83 -0
- package/integrations/tests/doubles/test-integration-repository.js +99 -0
- package/integrations/use-cases/create-integration.js +83 -0
- package/integrations/use-cases/create-process.js +128 -0
- package/integrations/use-cases/delete-integration-for-user.js +101 -0
- package/integrations/use-cases/find-integration-context-by-external-entity-id.js +72 -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 +87 -0
- package/integrations/use-cases/get-possible-integrations.js +27 -0
- package/integrations/use-cases/get-process.js +87 -0
- package/integrations/use-cases/index.js +19 -0
- package/integrations/use-cases/load-integration-context.js +71 -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 +93 -0
- package/integrations/use-cases/update-process-metrics.js +201 -0
- package/integrations/use-cases/update-process-state.js +119 -0
- package/integrations/utils/map-integration-dto.js +36 -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}/entity.js +1 -1
- package/{module-plugin → modules}/index.js +0 -8
- package/modules/module-factory.js +56 -0
- package/modules/module.js +221 -0
- package/modules/repositories/module-repository-factory.js +33 -0
- package/modules/repositories/module-repository-interface.js +129 -0
- package/modules/repositories/module-repository-mongo.js +377 -0
- package/modules/repositories/module-repository-postgres.js +426 -0
- package/modules/repositories/module-repository.js +316 -0
- package/{module-plugin → modules}/requester/requester.js +1 -0
- package/{module-plugin → modules}/test/mock-api/api.js +8 -3
- package/{module-plugin → modules}/test/mock-api/definition.js +12 -8
- 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 +59 -0
- package/modules/use-cases/get-entity-options-by-type.js +34 -0
- package/modules/use-cases/get-module-instance-from-type.js +31 -0
- package/modules/use-cases/get-module.js +55 -0
- package/modules/use-cases/process-authorization-callback.js +122 -0
- package/modules/use-cases/refresh-entity-options.js +59 -0
- package/modules/use-cases/test-module-auth.js +55 -0
- package/modules/utils/map-module-dto.js +18 -0
- package/package.json +82 -50
- package/prisma-mongodb/schema.prisma +362 -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/migration_lock.toml +3 -0
- package/prisma-postgresql/schema.prisma +345 -0
- package/queues/queuer-util.js +28 -15
- package/syncs/manager.js +468 -443
- package/syncs/repositories/sync-repository-factory.js +38 -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-factory.js +33 -0
- package/token/repositories/token-repository-interface.js +131 -0
- package/token/repositories/token-repository-mongo.js +212 -0
- package/token/repositories/token-repository-postgres.js +257 -0
- package/token/repositories/token-repository.js +219 -0
- package/types/core/index.d.ts +2 -2
- package/types/integrations/index.d.ts +2 -6
- package/types/module-plugin/index.d.ts +5 -59
- package/types/syncs/index.d.ts +0 -2
- package/user/repositories/user-repository-factory.js +46 -0
- package/user/repositories/user-repository-interface.js +198 -0
- package/user/repositories/user-repository-mongo.js +291 -0
- package/user/repositories/user-repository-postgres.js +350 -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 +106 -0
- package/user/use-cases/login-user.js +122 -0
- package/user/user.js +93 -0
- package/utils/backend-path.js +38 -0
- package/utils/index.js +6 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +37 -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/database/models/State.js +0 -9
- package/database/models/Token.js +0 -70
- package/database/mongo.js +0 -45
- package/encrypt/Cryptor.test.js +0 -32
- package/encrypt/encrypt.js +0 -132
- package/encrypt/encrypt.test.js +0 -1069
- 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/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/manager.js +0 -169
- package/module-plugin/module-factory.js +0 -61
- package/module-plugin/requester/requester.test.js +0 -28
- package/module-plugin/test/auther.test.js +0 -97
- /package/{module-plugin → modules}/ModuleConstants.js +0 -0
- /package/{module-plugin → modules}/requester/api-key.js +0 -0
- /package/{module-plugin → modules}/requester/basic.js +0 -0
- /package/{module-plugin → modules}/requester/oauth-2.js +0 -0
- /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
# Frigg Healthcheck Endpoint Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Frigg service includes comprehensive healthcheck endpoints to monitor service health, connectivity, and readiness. These endpoints follow industry best practices and are designed for use with monitoring systems, load balancers, and container orchestration platforms.
|
|
6
|
+
|
|
7
|
+
## Endpoints
|
|
8
|
+
|
|
9
|
+
### 1. Basic Health Check
|
|
10
|
+
**GET** `/health`
|
|
11
|
+
|
|
12
|
+
Simple health check endpoint that returns basic service information. No authentication required. This endpoint is rate-limited at the API Gateway level.
|
|
13
|
+
|
|
14
|
+
**Response:**
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"status": "ok",
|
|
18
|
+
"timestamp": "2024-01-10T12:00:00.000Z",
|
|
19
|
+
"service": "frigg-core-api"
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Status Codes:**
|
|
24
|
+
- `200 OK` - Service is running
|
|
25
|
+
|
|
26
|
+
### 2. Detailed Health Check
|
|
27
|
+
**GET** `/health/detailed`
|
|
28
|
+
|
|
29
|
+
Comprehensive health check that tests all service components and dependencies.
|
|
30
|
+
|
|
31
|
+
**Authentication Required:**
|
|
32
|
+
- Header: `x-api-key: YOUR_API_KEY`
|
|
33
|
+
- The API key must match the `HEALTH_API_KEY` environment variable
|
|
34
|
+
|
|
35
|
+
**Response:**
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"service": "frigg-core-api",
|
|
39
|
+
"status": "healthy", // "healthy" or "unhealthy"
|
|
40
|
+
"timestamp": "2024-01-10T12:00:00.000Z",
|
|
41
|
+
"checks": {
|
|
42
|
+
"database": {
|
|
43
|
+
"status": "healthy",
|
|
44
|
+
"state": "connected",
|
|
45
|
+
"responseTime": 5 // milliseconds
|
|
46
|
+
},
|
|
47
|
+
"externalApis": {
|
|
48
|
+
"github": {
|
|
49
|
+
"status": "healthy",
|
|
50
|
+
"statusCode": 200,
|
|
51
|
+
"responseTime": 150,
|
|
52
|
+
"reachable": true
|
|
53
|
+
},
|
|
54
|
+
"npm": {
|
|
55
|
+
"status": "healthy",
|
|
56
|
+
"statusCode": 200,
|
|
57
|
+
"responseTime": 200,
|
|
58
|
+
"reachable": true
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"integrations": {
|
|
62
|
+
"status": "healthy",
|
|
63
|
+
"modules": {
|
|
64
|
+
"count": 10,
|
|
65
|
+
"available": ["module1", "module2", "..."]
|
|
66
|
+
},
|
|
67
|
+
"integrations": {
|
|
68
|
+
"count": 5,
|
|
69
|
+
"available": ["integration1", "integration2", "..."]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"responseTime": 250 // total endpoint response time in milliseconds
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Status Codes:**
|
|
78
|
+
- `200 OK` - Service is healthy (all components operational)
|
|
79
|
+
- `503 Service Unavailable` - Service is unhealthy (any component failure)
|
|
80
|
+
- `401 Unauthorized` - Missing or invalid x-api-key header
|
|
81
|
+
|
|
82
|
+
### 3. Liveness Probe
|
|
83
|
+
**GET** `/health/live`
|
|
84
|
+
|
|
85
|
+
Kubernetes-style liveness probe. Returns whether the service process is alive.
|
|
86
|
+
|
|
87
|
+
**Authentication Required:**
|
|
88
|
+
- Header: `x-api-key: YOUR_API_KEY`
|
|
89
|
+
|
|
90
|
+
**Response:**
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"status": "alive",
|
|
94
|
+
"timestamp": "2024-01-10T12:00:00.000Z"
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Status Codes:**
|
|
99
|
+
- `200 OK` - Service process is alive
|
|
100
|
+
|
|
101
|
+
### 4. Readiness Probe
|
|
102
|
+
**GET** `/health/ready`
|
|
103
|
+
|
|
104
|
+
Kubernetes-style readiness probe. Returns whether the service is ready to receive traffic.
|
|
105
|
+
|
|
106
|
+
**Authentication Required:**
|
|
107
|
+
- Header: `x-api-key: YOUR_API_KEY`
|
|
108
|
+
|
|
109
|
+
**Response:**
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"ready": true,
|
|
113
|
+
"timestamp": "2024-01-10T12:00:00.000Z",
|
|
114
|
+
"checks": {
|
|
115
|
+
"database": true,
|
|
116
|
+
"modules": true
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Status Codes:**
|
|
122
|
+
- `200 OK` - Service is ready
|
|
123
|
+
- `503 Service Unavailable` - Service is not ready
|
|
124
|
+
|
|
125
|
+
## Health Status Definitions
|
|
126
|
+
|
|
127
|
+
- **healthy**: All components are functioning normally
|
|
128
|
+
- **unhealthy**: Any component is failing, service may not function properly
|
|
129
|
+
|
|
130
|
+
## Component Checks
|
|
131
|
+
|
|
132
|
+
### Database Connectivity
|
|
133
|
+
- Checks database connection state
|
|
134
|
+
- Performs ping test with 2-second timeout if connected
|
|
135
|
+
- Reports connection state and response time
|
|
136
|
+
- Database type is not exposed for security reasons
|
|
137
|
+
|
|
138
|
+
### External API Connectivity
|
|
139
|
+
- Tests connectivity to external services (GitHub, npm registry)
|
|
140
|
+
- Configurable timeout (default: 5 seconds)
|
|
141
|
+
- Reports reachability and response times
|
|
142
|
+
- Uses Promise.all for parallel checking
|
|
143
|
+
|
|
144
|
+
### Integration Status
|
|
145
|
+
- Verifies available modules and integrations are loaded
|
|
146
|
+
- Reports counts and lists of available components
|
|
147
|
+
|
|
148
|
+
## Usage Examples
|
|
149
|
+
|
|
150
|
+
### Monitoring Systems
|
|
151
|
+
Configure your monitoring system to poll `/health/detailed` every 30-60 seconds:
|
|
152
|
+
```bash
|
|
153
|
+
curl -H "x-api-key: YOUR_API_KEY" https://your-frigg-instance.com/health/detailed
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Load Balancer Health Checks
|
|
157
|
+
Configure load balancers to use the simple `/health` endpoint:
|
|
158
|
+
```bash
|
|
159
|
+
curl https://your-frigg-instance.com/health
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Kubernetes Configuration
|
|
163
|
+
```yaml
|
|
164
|
+
livenessProbe:
|
|
165
|
+
httpGet:
|
|
166
|
+
path: /health/live
|
|
167
|
+
port: 8080
|
|
168
|
+
httpHeaders:
|
|
169
|
+
- name: x-api-key
|
|
170
|
+
value: YOUR_API_KEY
|
|
171
|
+
periodSeconds: 10
|
|
172
|
+
timeoutSeconds: 5
|
|
173
|
+
|
|
174
|
+
readinessProbe:
|
|
175
|
+
httpGet:
|
|
176
|
+
path: /health/ready
|
|
177
|
+
port: 8080
|
|
178
|
+
httpHeaders:
|
|
179
|
+
- name: x-api-key
|
|
180
|
+
value: YOUR_API_KEY
|
|
181
|
+
initialDelaySeconds: 30
|
|
182
|
+
periodSeconds: 10
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Customization
|
|
186
|
+
|
|
187
|
+
### Adding External API Checks
|
|
188
|
+
To add more external API checks, modify the `externalAPIs` array in the health router:
|
|
189
|
+
```javascript
|
|
190
|
+
const externalAPIs = [
|
|
191
|
+
{ name: 'github', url: 'https://api.github.com/status' },
|
|
192
|
+
{ name: 'npm', url: 'https://registry.npmjs.org' },
|
|
193
|
+
{ name: 'your-api', url: 'https://your-api.com/health' }
|
|
194
|
+
];
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Adjusting Timeouts
|
|
198
|
+
The default timeout for external API checks is 5 seconds. Database ping timeout is set to 2 seconds:
|
|
199
|
+
```javascript
|
|
200
|
+
const checkExternalAPI = (url, timeout = 5000) => {
|
|
201
|
+
// ...
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
await mongoose.connection.db.admin().ping({ maxTimeMS: 2000 });
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Best Practices
|
|
208
|
+
|
|
209
|
+
1. **Authentication**: Basic `/health` endpoint requires no authentication, but detailed endpoints require `x-api-key` header
|
|
210
|
+
2. **Rate Limiting**: Configure rate limiting at the API Gateway level to prevent abuse
|
|
211
|
+
3. **Fast Response**: Health checks should respond quickly (< 1 second)
|
|
212
|
+
4. **Strict Status Codes**: Return 503 for any non-healthy state to ensure proper alerting
|
|
213
|
+
5. **Detailed Logging**: Failed health checks are logged for debugging
|
|
214
|
+
6. **Security**: No sensitive information (DB types, versions) exposed in responses
|
|
215
|
+
7. **Lambda Considerations**: Uptime and memory metrics not included as they're not relevant in serverless
|
|
216
|
+
|
|
217
|
+
## Troubleshooting
|
|
218
|
+
|
|
219
|
+
### Database Connection Issues
|
|
220
|
+
- Check `MONGO_URI` environment variable
|
|
221
|
+
- Verify network connectivity to MongoDB
|
|
222
|
+
- Check MongoDB server status
|
|
223
|
+
|
|
224
|
+
### External API Failures
|
|
225
|
+
- May indicate network issues or external service downtime
|
|
226
|
+
- Service reports "unhealthy" status if any external API is unreachable
|
|
227
|
+
|
|
228
|
+
## Security Considerations
|
|
229
|
+
|
|
230
|
+
- Basic health endpoint requires no authentication for monitoring compatibility
|
|
231
|
+
- Detailed endpoints require `x-api-key` header authentication
|
|
232
|
+
- Health endpoints do not expose sensitive information
|
|
233
|
+
- Database connection strings and credentials are never included in responses
|
|
234
|
+
- External API checks use read-only endpoints
|
|
235
|
+
- Rate limiting should be configured at the API Gateway level
|
|
236
|
+
- Consider IP whitelisting for health endpoints in production
|
|
237
|
+
|
|
238
|
+
## Environment Variables
|
|
239
|
+
|
|
240
|
+
- `HEALTH_API_KEY`: Required API key for accessing detailed health endpoints
|
|
241
|
+
|
|
242
|
+
## TODO: DDD/Hexagonal Architecture Refactoring
|
|
243
|
+
|
|
244
|
+
### Current Architecture Issues
|
|
245
|
+
|
|
246
|
+
The health router (health.js, 677 lines) currently violates DDD/Hexagonal Architecture principles:
|
|
247
|
+
|
|
248
|
+
**✅ What's Good:**
|
|
249
|
+
- Database access properly abstracted through `HealthCheckRepository`
|
|
250
|
+
- `CheckDatabaseHealthUseCase` and `TestEncryptionUseCase` correctly implement use case pattern
|
|
251
|
+
- All tests passing, no breaking changes
|
|
252
|
+
|
|
253
|
+
**❌ Architecture Violations:**
|
|
254
|
+
1. **Handler contains significant business logic** - Functions like `getEncryptionConfiguration()`, `checkEncryptionHealth()`, `checkKmsDecryptCapability()`, `detectVpcConfiguration()`, `checkExternalAPIs()`, and `checkIntegrations()` contain business logic that should be in use cases
|
|
255
|
+
2. **Direct infrastructure dependencies** - Handler directly uses `https`, `http`, Node.js `dns`, and factory modules instead of accessing through repositories
|
|
256
|
+
3. **Mixed concerns** - Single file handles HTTP routing, business logic, infrastructure detection, and response formatting
|
|
257
|
+
4. **Violates dependency rule** - Handler should only call use cases, never repositories or contain business logic
|
|
258
|
+
|
|
259
|
+
### Proposed Refactoring Plan
|
|
260
|
+
|
|
261
|
+
#### Priority 1: Extract Core Health Check Use Cases (Immediate)
|
|
262
|
+
|
|
263
|
+
**New Use Cases:**
|
|
264
|
+
1. `CheckEncryptionHealthUseCase` - Orchestrate encryption testing with configuration checks (from health.js:122-181)
|
|
265
|
+
2. `CheckKmsConnectivityUseCase` - Test KMS decrypt capability (from health.js:339-490)
|
|
266
|
+
3. `DetectNetworkConfigurationUseCase` - VPC and network detection (from health.js:244-336)
|
|
267
|
+
|
|
268
|
+
**New Repositories:**
|
|
269
|
+
1. `EncryptionConfigRepository` - Get encryption mode, bypass rules (from health.js:98-120)
|
|
270
|
+
2. `KmsRepository` - KMS connectivity testing, decrypt capability checks
|
|
271
|
+
3. `NetworkRepository` - DNS resolution, VPC detection, TCP connectivity tests
|
|
272
|
+
|
|
273
|
+
#### Priority 2: Extract External Service Checks
|
|
274
|
+
|
|
275
|
+
**New Use Cases:**
|
|
276
|
+
4. `CheckExternalServicesUseCase` - Check external API availability (from health.js:183-209)
|
|
277
|
+
|
|
278
|
+
**New Repositories:**
|
|
279
|
+
4. `ExternalServiceRepository` - HTTP-based service health checking with timeout handling
|
|
280
|
+
|
|
281
|
+
#### Priority 3: Extract Integration Checks
|
|
282
|
+
|
|
283
|
+
**New Use Cases:**
|
|
284
|
+
5. `CheckIntegrationAvailabilityUseCase` - Verify integrations and modules loaded (from health.js:211-231)
|
|
285
|
+
|
|
286
|
+
**Extend Existing:**
|
|
287
|
+
- Add `getAvailableIntegrations()` and `getAvailableModules()` methods to existing `IntegrationRepository`
|
|
288
|
+
|
|
289
|
+
### Architectural Principles to Follow
|
|
290
|
+
|
|
291
|
+
**The Handler Should Only:**
|
|
292
|
+
- Define routes
|
|
293
|
+
- Call use cases
|
|
294
|
+
- Map use case results to HTTP responses
|
|
295
|
+
- Handle HTTP-specific concerns (status codes, headers)
|
|
296
|
+
|
|
297
|
+
**The Rule:**
|
|
298
|
+
> "Handlers (adapters) should only call use cases, never repositories or business logic directly"
|
|
299
|
+
|
|
300
|
+
**Dependency Direction:**
|
|
301
|
+
```
|
|
302
|
+
Handler (Adapter Layer)
|
|
303
|
+
↓ calls
|
|
304
|
+
Use Cases (Application Layer)
|
|
305
|
+
↓ calls
|
|
306
|
+
Repositories (Infrastructure Layer)
|
|
307
|
+
↓ calls
|
|
308
|
+
External Systems (Database, APIs, AWS Services)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Expected Outcome
|
|
312
|
+
|
|
313
|
+
- Reduce health.js from **677 lines to ~100-150 lines**
|
|
314
|
+
- All business logic moved to use cases
|
|
315
|
+
- All infrastructure access moved to repositories
|
|
316
|
+
- Handler becomes thin HTTP adapter
|
|
317
|
+
- Improved testability (use cases testable without HTTP context)
|
|
318
|
+
- Better reusability (use cases usable in CLI tools, background jobs, etc.)
|
|
319
|
+
|
|
320
|
+
### Implementation Status
|
|
321
|
+
|
|
322
|
+
- [ ] P1: Extract `CheckEncryptionHealthUseCase`
|
|
323
|
+
- [ ] P1: Create `EncryptionConfigRepository`
|
|
324
|
+
- [ ] P1: Extract `CheckKmsConnectivityUseCase`
|
|
325
|
+
- [ ] P1: Create `KmsRepository`
|
|
326
|
+
- [ ] P1: Extract `DetectNetworkConfigurationUseCase`
|
|
327
|
+
- [ ] P1: Create `NetworkRepository`
|
|
328
|
+
- [ ] P2: Extract `CheckExternalServicesUseCase`
|
|
329
|
+
- [ ] P2: Create `ExternalServiceRepository`
|
|
330
|
+
- [ ] P3: Extract `CheckIntegrationAvailabilityUseCase`
|
|
331
|
+
- [ ] P3: Extend existing `IntegrationRepository`
|
|
332
|
+
|
|
333
|
+
### Future Considerations (Optional)
|
|
334
|
+
|
|
335
|
+
**Domain Models (Value Objects):**
|
|
336
|
+
- `HealthCheckResult` - Overall health check result with status, checks, timestamp
|
|
337
|
+
- `DatabaseHealth` - Database-specific health information
|
|
338
|
+
- `EncryptionHealth` - Encryption-specific health information
|
|
339
|
+
- `ServiceHealth` - Generic external service health
|
|
340
|
+
- `NetworkConfiguration` - VPC and network detection results
|
|
341
|
+
|
|
342
|
+
These would replace plain objects and provide type safety and business logic encapsulation.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { createIntegrationRouter } = require('@friggframework/core');
|
|
2
|
+
const { createAppHandler } = require('./../app-handler-helpers');
|
|
3
|
+
|
|
4
|
+
const router = createIntegrationRouter();
|
|
5
|
+
|
|
6
|
+
router.route('/api/integrations/redirect/:appId').get((req, res) => {
|
|
7
|
+
res.redirect(
|
|
8
|
+
`${process.env.FRONTEND_URI}/redirect/${req.params.appId
|
|
9
|
+
}?${new URLSearchParams(req.query)}`
|
|
10
|
+
);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const handler = createAppHandler('HTTP Event: Auth', router);
|
|
14
|
+
|
|
15
|
+
module.exports = { handler };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Migration Router Lambda Handler
|
|
3
|
+
*
|
|
4
|
+
* Minimal Lambda wrapper that avoids loading core/index.js
|
|
5
|
+
* (which would try to load user/** modules excluded from migration packages)
|
|
6
|
+
*
|
|
7
|
+
* This handler is intentionally simpler than health.handler.js to avoid dependencies.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const serverlessHttp = require('serverless-http');
|
|
11
|
+
const express = require('express');
|
|
12
|
+
const cors = require('cors');
|
|
13
|
+
const dbMigrationRouter = require('./db-migration');
|
|
14
|
+
|
|
15
|
+
// Create minimal Express app
|
|
16
|
+
const app = express();
|
|
17
|
+
app.use(cors());
|
|
18
|
+
app.use(express.json());
|
|
19
|
+
app.use(dbMigrationRouter);
|
|
20
|
+
|
|
21
|
+
// Error handler
|
|
22
|
+
app.use((err, req, res, next) => {
|
|
23
|
+
console.error('Error:', err);
|
|
24
|
+
res.status(500).json({ message: 'Internal Server Error' });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Export as .handler property (Lambda config: db-migration.handler)
|
|
28
|
+
module.exports.handler = serverlessHttp(app);
|
|
29
|
+
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Migration Router
|
|
3
|
+
*
|
|
4
|
+
* HTTP API for triggering and monitoring database migrations.
|
|
5
|
+
*
|
|
6
|
+
* Endpoints:
|
|
7
|
+
* - GET /db-migrate/status - Check if migrations are pending
|
|
8
|
+
* - POST /db-migrate - Trigger async migration (queues job)
|
|
9
|
+
* - GET /db-migrate/:processId - Check migration status
|
|
10
|
+
*
|
|
11
|
+
* Security:
|
|
12
|
+
* - Requires ADMIN_API_KEY header for all requests
|
|
13
|
+
*
|
|
14
|
+
* Architecture:
|
|
15
|
+
* - Router (Adapter Layer) → Use Cases (Domain) → Repositories (Infrastructure)
|
|
16
|
+
* - Follows DDD/Hexagonal architecture
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const { Router } = require('express');
|
|
20
|
+
const catchAsyncError = require('express-async-handler');
|
|
21
|
+
const { MigrationStatusRepositoryS3 } = require('../../database/repositories/migration-status-repository-s3');
|
|
22
|
+
const {
|
|
23
|
+
TriggerDatabaseMigrationUseCase,
|
|
24
|
+
ValidationError: TriggerValidationError,
|
|
25
|
+
} = require('../../database/use-cases/trigger-database-migration-use-case');
|
|
26
|
+
const {
|
|
27
|
+
GetMigrationStatusUseCase,
|
|
28
|
+
ValidationError: GetValidationError,
|
|
29
|
+
NotFoundError,
|
|
30
|
+
} = require('../../database/use-cases/get-migration-status-use-case');
|
|
31
|
+
const { LambdaInvoker } = require('../../database/adapters/lambda-invoker');
|
|
32
|
+
const {
|
|
33
|
+
GetDatabaseStateViaWorkerUseCase,
|
|
34
|
+
} = require('../../database/use-cases/get-database-state-via-worker-use-case');
|
|
35
|
+
|
|
36
|
+
const router = Router();
|
|
37
|
+
|
|
38
|
+
// Dependency injection
|
|
39
|
+
// Use S3 repository to avoid User table dependency (chicken-and-egg problem)
|
|
40
|
+
const bucketName = process.env.S3_BUCKET_NAME || process.env.MIGRATION_STATUS_BUCKET;
|
|
41
|
+
const migrationStatusRepository = new MigrationStatusRepositoryS3(bucketName);
|
|
42
|
+
|
|
43
|
+
const triggerMigrationUseCase = new TriggerDatabaseMigrationUseCase({
|
|
44
|
+
migrationStatusRepository,
|
|
45
|
+
// Note: QueuerUtil is used directly in the use case (static utility)
|
|
46
|
+
});
|
|
47
|
+
const getStatusUseCase = new GetMigrationStatusUseCase({ migrationStatusRepository });
|
|
48
|
+
|
|
49
|
+
// Lambda invocation for database state check (keeps router lightweight)
|
|
50
|
+
const lambdaInvoker = new LambdaInvoker();
|
|
51
|
+
const workerFunctionName = process.env.WORKER_FUNCTION_NAME ||
|
|
52
|
+
`${process.env.SERVICE || 'unknown'}-${process.env.STAGE || 'production'}-dbMigrationWorker`;
|
|
53
|
+
|
|
54
|
+
const getDatabaseStateUseCase = new GetDatabaseStateViaWorkerUseCase({
|
|
55
|
+
lambdaInvoker,
|
|
56
|
+
workerFunctionName,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Admin API key validation middleware
|
|
61
|
+
* Matches pattern from health.js:72-88
|
|
62
|
+
*/
|
|
63
|
+
const validateApiKey = (req, res, next) => {
|
|
64
|
+
const apiKey = req.headers['x-frigg-admin-api-key'];
|
|
65
|
+
|
|
66
|
+
if (!apiKey || apiKey !== process.env.ADMIN_API_KEY) {
|
|
67
|
+
console.error('Unauthorized access attempt to db-migrate endpoint');
|
|
68
|
+
return res.status(401).json({
|
|
69
|
+
status: 'error',
|
|
70
|
+
message: 'Unauthorized - x-frigg-admin-api-key header required',
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
next();
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Apply API key validation to all routes
|
|
78
|
+
router.use(validateApiKey);
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* POST /db-migrate
|
|
82
|
+
*
|
|
83
|
+
* Trigger database migration (async via SQS queue)
|
|
84
|
+
*
|
|
85
|
+
* Request body:
|
|
86
|
+
* {
|
|
87
|
+
* userId: string (optional, defaults to 'admin'),
|
|
88
|
+
* dbType: 'postgresql' | 'mongodb',
|
|
89
|
+
* stage: string (e.g., 'production', 'dev')
|
|
90
|
+
* }
|
|
91
|
+
*
|
|
92
|
+
* Response (202 Accepted):
|
|
93
|
+
* {
|
|
94
|
+
* success: true,
|
|
95
|
+
* processId: string,
|
|
96
|
+
* state: 'INITIALIZING',
|
|
97
|
+
* statusUrl: string,
|
|
98
|
+
* message: string
|
|
99
|
+
* }
|
|
100
|
+
*/
|
|
101
|
+
router.post(
|
|
102
|
+
'/db-migrate',
|
|
103
|
+
catchAsyncError(async (req, res) => {
|
|
104
|
+
// Migration infrastructure is PostgreSQL-only, so hardcode dbType
|
|
105
|
+
const dbType = 'postgresql';
|
|
106
|
+
const { stage } = req.body;
|
|
107
|
+
// TODO: Extract userId from JWT token when auth is implemented
|
|
108
|
+
const userId = req.body.userId || 'admin';
|
|
109
|
+
|
|
110
|
+
console.log(`Migration trigger request: dbType=${dbType}, stage=${stage || 'auto-detect'}, userId=${userId}`);
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const result = await triggerMigrationUseCase.execute({
|
|
114
|
+
userId,
|
|
115
|
+
dbType,
|
|
116
|
+
stage,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// 202 Accepted - request accepted but not completed
|
|
120
|
+
res.status(202).json(result);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
// Handle validation errors (400 Bad Request)
|
|
123
|
+
if (error instanceof TriggerValidationError) {
|
|
124
|
+
return res.status(400).json({
|
|
125
|
+
success: false,
|
|
126
|
+
error: error.message,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Re-throw other errors for global error handler
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
})
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* GET /db-migrate/status
|
|
138
|
+
*
|
|
139
|
+
* Check if database has pending migrations
|
|
140
|
+
*
|
|
141
|
+
* Query params:
|
|
142
|
+
* - stage: string (optional, defaults to STAGE env var or 'production')
|
|
143
|
+
*
|
|
144
|
+
* Response (200 OK):
|
|
145
|
+
* {
|
|
146
|
+
* upToDate: boolean,
|
|
147
|
+
* pendingMigrations: number,
|
|
148
|
+
* dbType: 'postgresql',
|
|
149
|
+
* stage: string,
|
|
150
|
+
* recommendation?: string (if migrations pending),
|
|
151
|
+
* error?: string (if database check failed)
|
|
152
|
+
* }
|
|
153
|
+
*/
|
|
154
|
+
router.get(
|
|
155
|
+
'/db-migrate/status',
|
|
156
|
+
catchAsyncError(async (req, res) => {
|
|
157
|
+
const stage = req.query.stage || process.env.STAGE || 'production';
|
|
158
|
+
|
|
159
|
+
console.log(`Checking database state: stage=${stage}, worker=${workerFunctionName}`);
|
|
160
|
+
|
|
161
|
+
try {
|
|
162
|
+
// Invoke worker Lambda to check database state
|
|
163
|
+
const status = await getDatabaseStateUseCase.execute(stage);
|
|
164
|
+
|
|
165
|
+
res.status(200).json(status);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
// Log full error for debugging
|
|
168
|
+
console.error('Database state check failed:', error);
|
|
169
|
+
|
|
170
|
+
// Return sanitized error to client
|
|
171
|
+
return res.status(500).json({
|
|
172
|
+
success: false,
|
|
173
|
+
error: 'Failed to check database state',
|
|
174
|
+
details: error.message,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* GET /db-migrate/:migrationId
|
|
182
|
+
*
|
|
183
|
+
* Get migration status by migration ID
|
|
184
|
+
*
|
|
185
|
+
* Response (200 OK):
|
|
186
|
+
* {
|
|
187
|
+
* processId: string,
|
|
188
|
+
* type: 'DATABASE_MIGRATION',
|
|
189
|
+
* state: 'INITIALIZING' | 'RUNNING' | 'COMPLETED' | 'FAILED',
|
|
190
|
+
* context: {
|
|
191
|
+
* dbType: string,
|
|
192
|
+
* stage: string,
|
|
193
|
+
* migrationCommand: string (if started)
|
|
194
|
+
* },
|
|
195
|
+
* results: {
|
|
196
|
+
* success: boolean (if completed),
|
|
197
|
+
* duration: string (if completed),
|
|
198
|
+
* error: string (if failed)
|
|
199
|
+
* },
|
|
200
|
+
* createdAt: string,
|
|
201
|
+
* updatedAt: string
|
|
202
|
+
* }
|
|
203
|
+
*/
|
|
204
|
+
router.get(
|
|
205
|
+
'/db-migrate/:migrationId',
|
|
206
|
+
catchAsyncError(async (req, res) => {
|
|
207
|
+
const { migrationId } = req.params;
|
|
208
|
+
const stage = req.query.stage || process.env.STAGE || 'production';
|
|
209
|
+
|
|
210
|
+
console.log(`Migration status request: migrationId=${migrationId}, stage=${stage}`);
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
const status = await getStatusUseCase.execute(migrationId, stage);
|
|
214
|
+
|
|
215
|
+
res.status(200).json(status);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
// Handle not found errors (404 Not Found)
|
|
218
|
+
if (error instanceof NotFoundError) {
|
|
219
|
+
return res.status(404).json({
|
|
220
|
+
success: false,
|
|
221
|
+
error: error.message,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Handle validation errors (400 Bad Request)
|
|
226
|
+
if (error instanceof GetValidationError) {
|
|
227
|
+
return res.status(400).json({
|
|
228
|
+
success: false,
|
|
229
|
+
error: error.message,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Re-throw other errors for global error handler
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
236
|
+
})
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
// Minimal Lambda handler (avoids app-handler-helpers which loads core/index.js → user/**)
|
|
240
|
+
const serverlessHttp = require('serverless-http');
|
|
241
|
+
const express = require('express');
|
|
242
|
+
const cors = require('cors');
|
|
243
|
+
|
|
244
|
+
const app = express();
|
|
245
|
+
app.use(cors());
|
|
246
|
+
app.use(express.json());
|
|
247
|
+
app.use(router);
|
|
248
|
+
app.use((err, req, res, next) => {
|
|
249
|
+
console.error('Migration Router Error:', err);
|
|
250
|
+
res.status(500).json({ message: 'Internal Server Error' });
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const handler = serverlessHttp(app);
|
|
254
|
+
|
|
255
|
+
module.exports = { handler, router };
|
|
256
|
+
|