@friggframework/core 2.0.0--canary.548.c8ae0ca.0 → 2.0.0--canary.545.c40eca4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -67
- package/CLAUDE.md +148 -124
- package/README.md +165 -130
- package/admin-scripts/index.js +52 -0
- package/admin-scripts/repositories/admin-api-key-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/admin-api-key-repository-factory.js +51 -0
- package/admin-scripts/repositories/admin-api-key-repository-interface.js +121 -0
- package/admin-scripts/repositories/admin-api-key-repository-mongo.js +155 -0
- package/admin-scripts/repositories/admin-api-key-repository-postgres.js +189 -0
- package/admin-scripts/repositories/admin-process-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/admin-process-repository-factory.js +49 -0
- package/admin-scripts/repositories/admin-process-repository-interface.js +150 -0
- package/admin-scripts/repositories/admin-process-repository-mongo.js +213 -0
- package/admin-scripts/repositories/admin-process-repository-postgres.js +251 -0
- package/admin-scripts/repositories/script-execution-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/script-execution-repository-factory.js +51 -0
- package/admin-scripts/repositories/script-execution-repository-interface.js +193 -0
- package/admin-scripts/repositories/script-execution-repository-mongo.js +278 -0
- package/admin-scripts/repositories/script-execution-repository-postgres.js +320 -0
- package/admin-scripts/repositories/script-schedule-repository-documentdb.js +21 -0
- package/admin-scripts/repositories/script-schedule-repository-factory.js +49 -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/admin-script-commands.js +348 -0
- package/application/commands/integration-commands.js +12 -6
- package/application/index.js +5 -3
- package/assertions/get.js +17 -7
- package/associations/association.js +59 -57
- package/core/CLAUDE.md +222 -156
- package/core/Worker.js +33 -12
- package/credential/credential-router.js +262 -0
- package/credential/repositories/credential-repository-documentdb.js +71 -1
- package/credential/repositories/credential-repository-factory.js +4 -6
- package/credential/repositories/credential-repository-interface.js +8 -2
- package/credential/repositories/credential-repository-mongo.js +45 -4
- package/credential/repositories/credential-repository-postgres.js +44 -3
- package/credential/repositories/credential-repository.js +3 -1
- package/credential/use-cases/delete-credential-for-user.js +50 -0
- package/credential/use-cases/get-credential-for-user.js +21 -3
- package/credential/use-cases/list-credentials-for-user.js +31 -0
- package/credential/use-cases/reauthorize-credential.js +103 -0
- package/credential/use-cases/update-authentication-status.js +5 -2
- package/database/MONGODB_TRANSACTION_FIX.md +72 -52
- package/database/config.js +13 -59
- package/database/documentdb-encryption-service.js +29 -13
- package/database/documentdb-utils.js +21 -12
- package/database/encryption/README.md +53 -36
- package/database/encryption/encryption-schema-registry.js +29 -23
- package/database/encryption/field-encryption-service.js +15 -4
- package/database/encryption/logger.js +3 -2
- package/database/encryption/prisma-encryption-extension.js +5 -8
- package/database/prisma.js +22 -14
- package/database/repositories/health-check-repository-factory.js +7 -5
- package/database/repositories/health-check-repository-interface.js +15 -5
- package/database/repositories/health-check-repository-postgres.js +1 -1
- package/database/use-cases/check-database-health-use-case.js +3 -2
- package/database/use-cases/check-database-state-use-case.js +8 -7
- package/database/use-cases/get-database-state-via-worker-use-case.js +15 -12
- package/database/use-cases/get-migration-status-use-case.js +4 -2
- package/database/use-cases/run-database-migration-use-case.js +41 -9
- package/database/use-cases/test-encryption-use-case.js +4 -5
- package/database/use-cases/trigger-database-migration-use-case.js +9 -8
- package/database/utils/mongodb-collection-utils.js +11 -3
- package/database/utils/mongodb-schema-init.js +10 -4
- package/database/utils/prisma-runner.js +144 -74
- package/database/utils/prisma-schema-parser.js +2 -2
- package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +135 -80
- package/encrypt/Cryptor.js +54 -49
- package/encrypt/aes-encryption-key-provider.js +82 -0
- package/encrypt/encryption-key-provider-interface.js +50 -0
- package/errors/fetch-error.js +1 -1
- package/generated/prisma-mongodb/edge.js +59 -4
- package/generated/prisma-mongodb/index-browser.js +49 -1
- package/generated/prisma-mongodb/index.d.ts +4023 -61
- package/generated/prisma-mongodb/index.js +59 -4
- package/generated/prisma-mongodb/package.json +1 -1
- package/generated/prisma-mongodb/schema.prisma +87 -0
- package/generated/prisma-mongodb/wasm.js +59 -4
- package/generated/prisma-postgresql/edge.js +58 -4
- package/generated/prisma-postgresql/index-browser.js +48 -1
- package/generated/prisma-postgresql/index.d.ts +4738 -54
- package/generated/prisma-postgresql/index.js +58 -4
- package/generated/prisma-postgresql/package.json +1 -1
- package/generated/prisma-postgresql/schema.prisma +85 -0
- package/generated/prisma-postgresql/wasm.js +58 -4
- package/handlers/WEBHOOKS.md +104 -81
- package/handlers/app-definition-loader.js +53 -10
- package/handlers/app-handler-helpers.js +14 -3
- package/handlers/backend-utils.js +0 -1
- package/handlers/database-migration-handler.js +64 -45
- package/handlers/middleware/admin-auth.js +53 -0
- package/handlers/routers/HEALTHCHECK.md +170 -135
- package/handlers/routers/admin.js +474 -0
- package/handlers/routers/auth.js +51 -9
- package/handlers/routers/db-migration.handler.js +2 -3
- package/handlers/routers/db-migration.js +102 -66
- package/handlers/routers/docs.js +180 -0
- package/handlers/routers/health.js +84 -283
- package/handlers/routers/integration-defined-routers.js +44 -33
- package/handlers/routers/integration-webhook-routers.js +73 -52
- package/handlers/routers/middleware/loadUser.js +39 -0
- package/handlers/routers/middleware/requireAdmin.js +43 -0
- package/handlers/routers/middleware/requireLoggedInUser.js +19 -0
- package/handlers/routers/user.js +30 -14
- package/handlers/routers/websocket.js +18 -4
- package/handlers/use-cases/check-integrations-health-use-case.js +13 -6
- package/handlers/workers/db-migration.js +74 -35
- package/handlers/workers/integration-defined-workers.js +31 -20
- package/index.js +50 -16
- package/infrastructure/scheduler/index.js +15 -11
- package/infrastructure/scheduler/netlify-scheduler-adapter.js +185 -0
- package/infrastructure/scheduler/scheduler-service-factory.js +38 -31
- package/integrations/WEBHOOK-QUICKSTART.md +21 -14
- package/integrations/index.js +4 -0
- package/integrations/integration-base.js +9 -6
- package/integrations/integration-router.js +1828 -157
- package/integrations/options.js +47 -20
- package/integrations/repositories/integration-mapping-repository-factory.js +4 -8
- package/integrations/repositories/integration-repository-documentdb.js +53 -24
- package/integrations/repositories/integration-repository-factory.js +6 -6
- package/integrations/repositories/integration-repository-interface.js +27 -9
- package/integrations/repositories/integration-repository-postgres.js +3 -3
- package/integrations/repositories/process-repository-factory.js +4 -7
- package/integrations/repositories/process-repository-interface.js +9 -5
- package/integrations/repositories/process-repository-mongo.js +7 -3
- package/integrations/repositories/process-repository-postgres.js +2 -2
- package/integrations/tests/doubles/config-capturing-integration.js +9 -8
- package/integrations/tests/doubles/dummy-integration-class.js +81 -8
- package/integrations/tests/doubles/test-integration-repository.js +51 -11
- package/integrations/use-cases/create-integration.js +36 -32
- package/integrations/use-cases/create-process.js +20 -9
- package/integrations/use-cases/delete-integration-for-user.js +5 -4
- package/integrations/use-cases/execute-proxy-request.js +564 -0
- package/integrations/use-cases/get-integration-for-user.js +25 -10
- package/integrations/use-cases/get-integration-instance-by-definition.js +13 -7
- package/integrations/use-cases/get-integrations-for-user.js +4 -1
- package/integrations/use-cases/get-possible-integrations.js +1 -1
- package/integrations/use-cases/get-process.js +5 -6
- package/integrations/use-cases/index.js +3 -1
- package/integrations/use-cases/load-integration-context.js +1 -5
- package/integrations/use-cases/update-process-state.js +10 -8
- package/integrations/utils/map-integration-dto.js +9 -3
- package/jest-setup.js +1 -1
- package/jest-teardown.js +1 -1
- package/lambda/TimeoutCatcher.js +32 -30
- package/lambda/index.js +1 -1
- package/logs/index.js +3 -3
- package/modules/domain/entities/AuthorizationSession.js +131 -0
- package/modules/domain/entities/index.js +10 -0
- package/modules/module.js +4 -9
- package/modules/repositories/authorization-session-repository-factory.js +53 -0
- package/modules/repositories/authorization-session-repository-interface.js +75 -0
- package/modules/repositories/authorization-session-repository-mongo.js +169 -0
- package/modules/repositories/authorization-session-repository-postgres.js +170 -0
- package/modules/repositories/module-repository-documentdb.js +89 -41
- package/modules/repositories/module-repository-factory.js +4 -6
- package/modules/repositories/module-repository-interface.js +13 -0
- package/modules/repositories/module-repository-mongo.js +40 -5
- package/modules/repositories/module-repository-postgres.js +42 -5
- package/modules/repositories/module-repository.js +28 -0
- package/modules/requester/api-key.js +0 -2
- package/modules/requester/basic.js +0 -1
- package/modules/requester/oauth-2.js +3 -14
- package/modules/test/mock-api/definition.js +15 -10
- package/modules/test/mock-api/mocks/hubspot.js +36 -36
- package/modules/tests/doubles/test-module-factory.js +10 -4
- package/modules/tests/doubles/test-module-repository.js +1 -1
- package/modules/use-cases/delete-module-entity.js +23 -0
- package/modules/use-cases/get-authorization-requirements.js +110 -0
- package/modules/use-cases/get-entities-for-user.js +1 -1
- package/modules/use-cases/get-entity-options-by-id.js +8 -6
- package/modules/use-cases/get-module-entity-by-id.js +16 -0
- package/modules/use-cases/get-module.js +12 -9
- package/modules/use-cases/process-authorization-callback.js +12 -6
- package/modules/use-cases/process-authorization-step.js +160 -0
- package/modules/use-cases/refresh-entity-options.js +8 -6
- package/modules/use-cases/start-authorization-session.js +86 -0
- package/modules/use-cases/test-module-auth.js +8 -6
- package/modules/use-cases/update-module-entity.js +27 -0
- package/modules/utils/map-module-dto.js +2 -2
- package/openapi/openapi-spec-generator.js +370 -0
- package/openapi/openapi-v1.yaml +1360 -0
- package/openapi/openapi-v2.yaml +1535 -0
- package/package.json +7 -9
- package/prisma-mongodb/schema.prisma +87 -0
- package/prisma-postgresql/migrations/20260222000000_add_admin_process_and_script_schedule/migration.sql +55 -0
- package/prisma-postgresql/schema.prisma +85 -0
- package/providers/index.js +13 -0
- package/providers/resolve-provider.js +93 -0
- package/queues/index.js +19 -0
- package/queues/providers/index.js +7 -0
- package/queues/providers/netlify-background-provider.js +76 -0
- package/queues/providers/qstash-queue-provider.js +122 -0
- package/queues/queue-client-interface.js +55 -0
- package/queues/queue-provider-factory.js +93 -0
- package/queues/queue-provider.js +46 -0
- package/queues/queuer-util.js +33 -25
- package/syncs/repositories/sync-repository-documentdb.js +39 -19
- package/syncs/repositories/sync-repository-factory.js +4 -4
- package/syncs/repositories/sync-repository-interface.js +6 -2
- package/syncs/repositories/sync-repository-postgres.js +19 -13
- package/syncs/sync.js +104 -100
- package/token/repositories/token-repository-factory.js +4 -6
- package/types/assertions/index.d.ts +72 -72
- package/types/core/index.d.ts +98 -53
- package/types/errors/index.d.ts +61 -54
- package/types/eslint-config/index.d.ts +40 -40
- package/types/lambda/index.d.ts +26 -26
- package/types/logs/index.d.ts +4 -4
- package/types/prettier-config/index.d.ts +5 -5
- package/types/test-environment/index.d.ts +14 -14
- package/types/tsconfig.json +95 -93
- package/user/repositories/user-repository-factory.js +4 -4
- package/user/tests/doubles/test-user-repository.js +5 -2
- package/user/use-cases/authenticate-user.js +2 -4
- package/user/use-cases/authenticate-with-shared-secret.js +1 -1
- package/user/use-cases/create-individual-user.js +8 -7
- package/user/use-cases/create-organization-user.js +1 -1
- package/user/use-cases/create-token-for-user-id.js +1 -1
- package/user/use-cases/delete-user.js +47 -0
- package/user/use-cases/get-user-from-adopter-jwt.js +0 -2
- package/user/use-cases/get-user-from-bearer-token.js +7 -3
- package/user/use-cases/get-user-from-x-frigg-headers.js +14 -11
- package/user/use-cases/login-user.js +8 -8
- package/user/user.js +18 -4
- package/utils/backend-path.js +2 -2
- package/utils/index.js +4 -1
- package/websocket/repositories/websocket-connection-repository-documentdb.js +46 -21
- package/websocket/repositories/websocket-connection-repository-factory.js +4 -8
- package/websocket/repositories/websocket-connection-repository-mongo.js +26 -16
- package/websocket/repositories/websocket-connection-repository-postgres.js +26 -15
- package/websocket/repositories/websocket-connection-repository.js +26 -20
- package/websocket/websocket-message-sender-interface.js +38 -0
- package/database/adapters/lambda-invoker.js +0 -97
- package/database/repositories/migration-status-repository-s3.js +0 -137
- package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +0 -184
|
@@ -3,18 +3,60 @@ const path = require('node:path');
|
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Cached app definition, set via setAppDefinition().
|
|
7
|
+
* When set, loadAppDefinition() returns this instead of discovering
|
|
8
|
+
* the backend via process.cwd().
|
|
9
|
+
*/
|
|
10
|
+
let cachedAppDefinition = null;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Pre-set the app definition so loadAppDefinition() can return it
|
|
14
|
+
* without needing process.cwd()-based discovery.
|
|
15
|
+
*
|
|
16
|
+
* This is critical for platforms like Netlify where:
|
|
17
|
+
* - nft/esbuild traces static require() calls to determine bundle contents
|
|
18
|
+
* - process.cwd() at runtime points to /var/task/, not the backend directory
|
|
19
|
+
* - The caller can use a static require('../../backend/index.js') to make
|
|
20
|
+
* the backend traceable, then pass the definition here
|
|
21
|
+
*
|
|
22
|
+
* @param {Object} definition - The app definition object (backend's Definition export)
|
|
23
|
+
*/
|
|
24
|
+
function setAppDefinition(definition) {
|
|
25
|
+
cachedAppDefinition = definition;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Loads the App definition from the nearest backend package.
|
|
30
|
+
*
|
|
31
|
+
* If setAppDefinition() was called, returns the cached definition
|
|
32
|
+
* immediately (no filesystem discovery needed).
|
|
33
|
+
*
|
|
34
|
+
* Otherwise, discovers the backend via process.cwd() traversal.
|
|
35
|
+
*
|
|
36
|
+
* Returns the full appDefinition object plus convenience destructured fields
|
|
37
|
+
* for backward compatibility (integrations, userConfig).
|
|
38
|
+
*
|
|
7
39
|
* @function loadAppDefinition
|
|
8
|
-
* @
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
40
|
+
* @returns {{
|
|
41
|
+
* integrations: Array<object>,
|
|
42
|
+
* userConfig: object | null,
|
|
43
|
+
* appDefinition: object
|
|
44
|
+
* }}
|
|
45
|
+
* @throws {Error} If backend package.json or index.js cannot be found.
|
|
13
46
|
* @example
|
|
14
|
-
*
|
|
15
|
-
*
|
|
47
|
+
* // Existing callers still work:
|
|
48
|
+
* const { integrations, userConfig } = loadAppDefinition();
|
|
49
|
+
*
|
|
50
|
+
* // New callers can access the full definition:
|
|
51
|
+
* const { appDefinition } = loadAppDefinition();
|
|
52
|
+
* console.log(appDefinition.provider); // 'aws' | 'netlify'
|
|
16
53
|
*/
|
|
17
54
|
function loadAppDefinition() {
|
|
55
|
+
if (cachedAppDefinition) {
|
|
56
|
+
const { integrations = [], user: userConfig = null } = cachedAppDefinition;
|
|
57
|
+
return { integrations, userConfig, appDefinition: cachedAppDefinition };
|
|
58
|
+
}
|
|
59
|
+
|
|
18
60
|
const backendPath = findNearestBackendPackageJson();
|
|
19
61
|
if (!backendPath) {
|
|
20
62
|
throw new Error('Could not find backend package.json');
|
|
@@ -30,9 +72,10 @@ function loadAppDefinition() {
|
|
|
30
72
|
const appDefinition = backendJsFile.Definition;
|
|
31
73
|
|
|
32
74
|
const { integrations = [], user: userConfig = null } = appDefinition;
|
|
33
|
-
return { integrations, userConfig };
|
|
75
|
+
return { integrations, userConfig, appDefinition };
|
|
34
76
|
}
|
|
35
77
|
|
|
36
78
|
module.exports = {
|
|
37
79
|
loadAppDefinition,
|
|
38
|
-
|
|
80
|
+
setAppDefinition,
|
|
81
|
+
};
|
|
@@ -3,6 +3,7 @@ const express = require('express');
|
|
|
3
3
|
const bodyParser = require('body-parser');
|
|
4
4
|
const cors = require('cors');
|
|
5
5
|
const Boom = require('@hapi/boom');
|
|
6
|
+
const loadUserManager = require('./routers/middleware/loadUser');
|
|
6
7
|
const serverlessHttp = require('serverless-http');
|
|
7
8
|
|
|
8
9
|
const createApp = (applyMiddleware) => {
|
|
@@ -19,6 +20,8 @@ const createApp = (applyMiddleware) => {
|
|
|
19
20
|
})
|
|
20
21
|
);
|
|
21
22
|
|
|
23
|
+
app.use(loadUserManager);
|
|
24
|
+
|
|
22
25
|
if (applyMiddleware) applyMiddleware(app);
|
|
23
26
|
|
|
24
27
|
// Handle sending error response and logging server errors to console
|
|
@@ -32,7 +35,6 @@ const createApp = (applyMiddleware) => {
|
|
|
32
35
|
flushDebugLog(boomError);
|
|
33
36
|
res.status(statusCode).json({ error: 'Internal Server Error' });
|
|
34
37
|
} else {
|
|
35
|
-
console.warn(`[Frigg] ${req.method} ${req.path} -> ${statusCode}: ${err.message}`);
|
|
36
38
|
res.status(statusCode).json({ error: err.message });
|
|
37
39
|
}
|
|
38
40
|
});
|
|
@@ -40,9 +42,18 @@ const createApp = (applyMiddleware) => {
|
|
|
40
42
|
return app;
|
|
41
43
|
};
|
|
42
44
|
|
|
43
|
-
function createAppHandler(
|
|
45
|
+
function createAppHandler(
|
|
46
|
+
eventName,
|
|
47
|
+
router,
|
|
48
|
+
shouldUseDatabase = true,
|
|
49
|
+
basePath = null
|
|
50
|
+
) {
|
|
44
51
|
const app = createApp((app) => {
|
|
45
|
-
|
|
52
|
+
if (basePath) {
|
|
53
|
+
app.use(basePath, router);
|
|
54
|
+
} else {
|
|
55
|
+
app.use(router);
|
|
56
|
+
}
|
|
46
57
|
});
|
|
47
58
|
return createHandler({
|
|
48
59
|
eventName,
|
|
@@ -101,7 +101,6 @@ const loadIntegrationForWebhook = async (integrationId) => {
|
|
|
101
101
|
};
|
|
102
102
|
|
|
103
103
|
const loadIntegrationForProcess = async (processId, integrationClass) => {
|
|
104
|
-
|
|
105
104
|
const { processRepository, integrationRepository, moduleRepository } =
|
|
106
105
|
initializeRepositories();
|
|
107
106
|
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Database Migration Handler for AWS Lambda
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Executes Prisma migrations in a Lambda environment.
|
|
5
5
|
* Based on AWS best practices for running migrations in serverless environments.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Supported Commands:
|
|
8
8
|
* - deploy: Apply pending migrations to the database (production-safe)
|
|
9
9
|
* - reset: Reset database and apply all migrations (DANGEROUS - dev only)
|
|
10
|
-
*
|
|
10
|
+
*
|
|
11
11
|
* Usage:
|
|
12
12
|
* // Via Lambda invoke
|
|
13
13
|
* {
|
|
14
14
|
* "command": "deploy" // or "reset"
|
|
15
15
|
* }
|
|
16
|
-
*
|
|
16
|
+
*
|
|
17
17
|
* Requirements:
|
|
18
18
|
* - Prisma CLI must be included in deployment or Lambda layer
|
|
19
19
|
* - DATABASE_URL environment variable must be set
|
|
20
20
|
* - VPC configuration for Aurora access
|
|
21
|
-
*
|
|
21
|
+
*
|
|
22
22
|
* Reference: https://www.prisma.io/docs/guides/deployment/deployment-guides/deploying-to-aws-lambda
|
|
23
23
|
*/
|
|
24
24
|
|
|
@@ -27,7 +27,7 @@ const path = require('path');
|
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Execute Prisma migration command
|
|
30
|
-
*
|
|
30
|
+
*
|
|
31
31
|
* @param {string} command - Migration command ('deploy' or 'reset')
|
|
32
32
|
* @param {string} schemaPath - Path to Prisma schema file
|
|
33
33
|
* @returns {Promise<number>} Exit code
|
|
@@ -35,16 +35,18 @@ const path = require('path');
|
|
|
35
35
|
async function executePrismaMigration(command, schemaPath) {
|
|
36
36
|
console.log(`Executing Prisma migration: ${command}`);
|
|
37
37
|
console.log(`Schema path: ${schemaPath}`);
|
|
38
|
-
console.log(
|
|
38
|
+
console.log(
|
|
39
|
+
`Database URL: ${process.env.DATABASE_URL ? '[SET]' : '[NOT SET]'}`
|
|
40
|
+
);
|
|
39
41
|
|
|
40
42
|
return new Promise((resolve, reject) => {
|
|
41
43
|
// Build command arguments
|
|
42
44
|
const args = ['migrate', command];
|
|
43
|
-
|
|
45
|
+
|
|
44
46
|
// Add command-specific options
|
|
45
47
|
if (command === 'reset') {
|
|
46
|
-
args.push('--force');
|
|
47
|
-
args.push('--skip-generate');
|
|
48
|
+
args.push('--force'); // Skip confirmation prompt
|
|
49
|
+
args.push('--skip-generate'); // Skip client generation (already done in layer)
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
// Add schema path if provided
|
|
@@ -53,7 +55,7 @@ async function executePrismaMigration(command, schemaPath) {
|
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
console.log(`Running: prisma ${args.join(' ')}`);
|
|
56
|
-
|
|
58
|
+
|
|
57
59
|
// Execute Prisma CLI
|
|
58
60
|
execFile(
|
|
59
61
|
path.resolve('./node_modules/prisma/build/index.js'),
|
|
@@ -63,7 +65,7 @@ async function executePrismaMigration(command, schemaPath) {
|
|
|
63
65
|
...process.env,
|
|
64
66
|
// Ensure Prisma uses the correct binary target
|
|
65
67
|
PRISMA_CLI_BINARY_TARGETS: 'rhel-openssl-3.0.x',
|
|
66
|
-
}
|
|
68
|
+
},
|
|
67
69
|
},
|
|
68
70
|
(error, stdout, stderr) => {
|
|
69
71
|
// Log all output
|
|
@@ -75,7 +77,10 @@ async function executePrismaMigration(command, schemaPath) {
|
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
if (error) {
|
|
78
|
-
console.error(
|
|
80
|
+
console.error(
|
|
81
|
+
`Migration ${command} exited with error:`,
|
|
82
|
+
error.message
|
|
83
|
+
);
|
|
79
84
|
console.error(`Exit code: ${error.code || 1}`);
|
|
80
85
|
resolve(error.code || 1);
|
|
81
86
|
} else {
|
|
@@ -92,11 +97,11 @@ async function executePrismaMigration(command, schemaPath) {
|
|
|
92
97
|
*/
|
|
93
98
|
function validateCommand(command) {
|
|
94
99
|
const validCommands = ['deploy', 'reset'];
|
|
95
|
-
|
|
100
|
+
|
|
96
101
|
if (!validCommands.includes(command)) {
|
|
97
102
|
throw new Error(
|
|
98
103
|
`Invalid migration command: "${command}". ` +
|
|
99
|
-
|
|
104
|
+
`Valid commands are: ${validCommands.join(', ')}`
|
|
100
105
|
);
|
|
101
106
|
}
|
|
102
107
|
|
|
@@ -106,10 +111,12 @@ function validateCommand(command) {
|
|
|
106
111
|
if (stage === 'production' || stage === 'prod') {
|
|
107
112
|
throw new Error(
|
|
108
113
|
'BLOCKED: "reset" command is not allowed in production environment. ' +
|
|
109
|
-
|
|
114
|
+
'This command would delete all data. Use "deploy" instead.'
|
|
110
115
|
);
|
|
111
116
|
}
|
|
112
|
-
console.warn(
|
|
117
|
+
console.warn(
|
|
118
|
+
'⚠️ WARNING: "reset" will DELETE all data and reset the database!'
|
|
119
|
+
);
|
|
113
120
|
}
|
|
114
121
|
}
|
|
115
122
|
|
|
@@ -119,14 +126,17 @@ function validateCommand(command) {
|
|
|
119
126
|
function getSchemaPath() {
|
|
120
127
|
// In Lambda, schemas are in @friggframework/core/generated/
|
|
121
128
|
const baseSchemaPath = './node_modules/@friggframework/core/generated';
|
|
122
|
-
|
|
129
|
+
|
|
123
130
|
// Check if Postgres is enabled
|
|
124
|
-
if (
|
|
131
|
+
if (
|
|
132
|
+
process.env.DATABASE_URL?.includes('postgresql') ||
|
|
133
|
+
process.env.DATABASE_URL?.includes('postgres')
|
|
134
|
+
) {
|
|
125
135
|
const schemaPath = `${baseSchemaPath}/prisma-postgresql/schema.prisma`;
|
|
126
136
|
console.log(`Using PostgreSQL schema: ${schemaPath}`);
|
|
127
137
|
return schemaPath;
|
|
128
138
|
}
|
|
129
|
-
|
|
139
|
+
|
|
130
140
|
// Check if MongoDB is enabled
|
|
131
141
|
if (process.env.DATABASE_URL?.includes('mongodb')) {
|
|
132
142
|
const schemaPath = `${baseSchemaPath}/prisma-mongodb/schema.prisma`;
|
|
@@ -135,13 +145,15 @@ function getSchemaPath() {
|
|
|
135
145
|
}
|
|
136
146
|
|
|
137
147
|
// Default to PostgreSQL
|
|
138
|
-
console.log(
|
|
148
|
+
console.log(
|
|
149
|
+
'DATABASE_URL not set or database type unknown, defaulting to PostgreSQL'
|
|
150
|
+
);
|
|
139
151
|
return `${baseSchemaPath}/prisma-postgresql/schema.prisma`;
|
|
140
152
|
}
|
|
141
153
|
|
|
142
154
|
/**
|
|
143
155
|
* Lambda handler for database migrations
|
|
144
|
-
*
|
|
156
|
+
*
|
|
145
157
|
* @param {Object} event - Lambda event
|
|
146
158
|
* @param {string} event.command - Migration command ('deploy' or 'reset')
|
|
147
159
|
* @param {Object} context - Lambda context
|
|
@@ -149,41 +161,48 @@ function getSchemaPath() {
|
|
|
149
161
|
*/
|
|
150
162
|
exports.handler = async (event, context) => {
|
|
151
163
|
const startTime = Date.now();
|
|
152
|
-
|
|
164
|
+
|
|
153
165
|
console.log('='.repeat(60));
|
|
154
166
|
console.log('Database Migration Handler');
|
|
155
167
|
console.log('='.repeat(60));
|
|
156
168
|
console.log('Event:', JSON.stringify(event, null, 2));
|
|
157
|
-
console.log(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
169
|
+
console.log(
|
|
170
|
+
'Context:',
|
|
171
|
+
JSON.stringify(
|
|
172
|
+
{
|
|
173
|
+
functionName: context.functionName,
|
|
174
|
+
functionVersion: context.functionVersion,
|
|
175
|
+
memoryLimitInMB: context.memoryLimitInMB,
|
|
176
|
+
logGroupName: context.logGroupName,
|
|
177
|
+
},
|
|
178
|
+
null,
|
|
179
|
+
2
|
|
180
|
+
)
|
|
181
|
+
);
|
|
182
|
+
|
|
164
183
|
try {
|
|
165
184
|
// Get migration command (default to 'deploy')
|
|
166
185
|
const command = event.command || 'deploy';
|
|
167
|
-
|
|
186
|
+
|
|
168
187
|
// Validate command
|
|
169
188
|
validateCommand(command);
|
|
170
|
-
|
|
189
|
+
|
|
171
190
|
// Check required environment variables
|
|
172
191
|
if (!process.env.DATABASE_URL) {
|
|
173
192
|
throw new Error(
|
|
174
193
|
'DATABASE_URL environment variable is not set. ' +
|
|
175
|
-
|
|
194
|
+
'Cannot connect to database for migrations.'
|
|
176
195
|
);
|
|
177
196
|
}
|
|
178
|
-
|
|
197
|
+
|
|
179
198
|
// Determine schema path
|
|
180
199
|
const schemaPath = getSchemaPath();
|
|
181
|
-
|
|
200
|
+
|
|
182
201
|
// Execute migration
|
|
183
202
|
const exitCode = await executePrismaMigration(command, schemaPath);
|
|
184
|
-
|
|
203
|
+
|
|
185
204
|
const duration = Date.now() - startTime;
|
|
186
|
-
|
|
205
|
+
|
|
187
206
|
if (exitCode === 0) {
|
|
188
207
|
const result = {
|
|
189
208
|
success: true,
|
|
@@ -192,26 +211,27 @@ exports.handler = async (event, context) => {
|
|
|
192
211
|
duration: `${duration}ms`,
|
|
193
212
|
timestamp: new Date().toISOString(),
|
|
194
213
|
};
|
|
195
|
-
|
|
214
|
+
|
|
196
215
|
console.log('='.repeat(60));
|
|
197
216
|
console.log('Migration completed successfully');
|
|
198
217
|
console.log(JSON.stringify(result, null, 2));
|
|
199
218
|
console.log('='.repeat(60));
|
|
200
|
-
|
|
219
|
+
|
|
201
220
|
return result;
|
|
202
221
|
} else {
|
|
203
|
-
throw new Error(
|
|
222
|
+
throw new Error(
|
|
223
|
+
`Migration ${command} failed with exit code ${exitCode}`
|
|
224
|
+
);
|
|
204
225
|
}
|
|
205
|
-
|
|
206
226
|
} catch (error) {
|
|
207
227
|
const duration = Date.now() - startTime;
|
|
208
|
-
|
|
228
|
+
|
|
209
229
|
console.error('='.repeat(60));
|
|
210
230
|
console.error('Migration failed');
|
|
211
231
|
console.error('Error:', error.message);
|
|
212
232
|
console.error('Stack:', error.stack);
|
|
213
233
|
console.error('='.repeat(60));
|
|
214
|
-
|
|
234
|
+
|
|
215
235
|
const errorResult = {
|
|
216
236
|
success: false,
|
|
217
237
|
command: event.command || 'unknown',
|
|
@@ -219,9 +239,8 @@ exports.handler = async (event, context) => {
|
|
|
219
239
|
duration: `${duration}ms`,
|
|
220
240
|
timestamp: new Date().toISOString(),
|
|
221
241
|
};
|
|
222
|
-
|
|
242
|
+
|
|
223
243
|
// Return error (don't throw) so Lambda doesn't retry
|
|
224
244
|
return errorResult;
|
|
225
245
|
}
|
|
226
246
|
};
|
|
227
|
-
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin Auth Middleware
|
|
3
|
+
*
|
|
4
|
+
* Shared authentication middleware for all admin endpoints:
|
|
5
|
+
* - /admin/db-migrate/*
|
|
6
|
+
* - /admin/scripts/*
|
|
7
|
+
*
|
|
8
|
+
* Uses simple ENV-based API key validation.
|
|
9
|
+
* Expects: x-frigg-admin-api-key header
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Validate admin API key from request header
|
|
14
|
+
* @param {import('express').Request} req
|
|
15
|
+
* @param {import('express').Response} res
|
|
16
|
+
* @param {import('express').NextFunction} next
|
|
17
|
+
*/
|
|
18
|
+
function validateAdminApiKey(req, res, next) {
|
|
19
|
+
const expectedKey = process.env.ADMIN_API_KEY;
|
|
20
|
+
|
|
21
|
+
// Check if admin API key is configured
|
|
22
|
+
if (!expectedKey) {
|
|
23
|
+
console.error('ADMIN_API_KEY environment variable not configured');
|
|
24
|
+
return res.status(401).json({
|
|
25
|
+
error: 'Unauthorized',
|
|
26
|
+
message: 'Admin API key not configured'
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const apiKey = req.headers['x-frigg-admin-api-key'];
|
|
31
|
+
|
|
32
|
+
// Check if header is present
|
|
33
|
+
if (!apiKey) {
|
|
34
|
+
console.error('Missing x-frigg-admin-api-key header');
|
|
35
|
+
return res.status(401).json({
|
|
36
|
+
error: 'Unauthorized',
|
|
37
|
+
message: 'x-frigg-admin-api-key header required'
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Validate key
|
|
42
|
+
if (apiKey !== expectedKey) {
|
|
43
|
+
console.error('Invalid admin API key provided');
|
|
44
|
+
return res.status(401).json({
|
|
45
|
+
error: 'Unauthorized',
|
|
46
|
+
message: 'Invalid admin API key'
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
next();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = { validateAdminApiKey };
|