@friggframework/core 2.0.0--canary.690.08cd07e.0 → 2.0.0--canary.693.d8859c2.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/CLAUDE.md +0 -28
- package/README.md +0 -105
- package/application/commands/integration-commands.js +10 -20
- package/application/commands/scheduler-commands.js +7 -11
- package/application/commands/user-commands.js +5 -17
- package/application/index.js +2 -6
- package/core/Worker.js +7 -31
- package/core/create-handler.js +0 -9
- package/credential/repositories/credential-repository-documentdb.js +0 -34
- package/credential/repositories/credential-repository-interface.js +0 -15
- package/credential/repositories/credential-repository-mongo.js +0 -23
- package/credential/repositories/credential-repository-postgres.js +0 -28
- package/database/config.js +24 -48
- package/database/documentdb-utils.js +0 -2
- package/database/encryption/encryption-schema-registry.js +12 -93
- package/database/prisma.js +2 -4
- package/errors/index.js +4 -0
- package/errors/mapping-already-exists-error.js +14 -0
- package/generated/prisma-mongodb/edge.js +38 -33
- package/generated/prisma-mongodb/index-browser.js +35 -30
- package/generated/prisma-mongodb/index.d.ts +1880 -3191
- package/generated/prisma-mongodb/index.js +38 -33
- package/generated/prisma-mongodb/package.json +1 -1
- package/generated/prisma-mongodb/schema.prisma +50 -86
- package/generated/prisma-mongodb/wasm.js +38 -33
- package/generated/prisma-postgresql/edge.js +38 -33
- package/generated/prisma-postgresql/index-browser.js +35 -30
- package/generated/prisma-postgresql/index.d.ts +2050 -3390
- package/generated/prisma-postgresql/index.js +38 -33
- package/generated/prisma-postgresql/package.json +1 -1
- package/generated/prisma-postgresql/schema.prisma +48 -81
- package/generated/prisma-postgresql/wasm.js +38 -33
- package/handlers/WEBHOOKS.md +29 -0
- package/handlers/app-definition-loader.js +19 -128
- package/handlers/app-handler-helpers.js +3 -25
- package/handlers/backend-utils.js +25 -31
- package/handlers/middleware/admin-auth.js +1 -14
- package/handlers/routers/auth.js +10 -46
- package/handlers/routers/health.js +4 -13
- package/handlers/routers/integration-defined-routers.js +92 -144
- package/handlers/routers/integration-webhook-routers.js +64 -102
- package/handlers/workers/integration-defined-workers.js +2 -5
- package/index.js +3 -65
- package/infrastructure/scheduler/index.js +6 -19
- package/infrastructure/scheduler/scheduler-service-factory.js +7 -55
- package/integrations/data-defined/README.md +169 -0
- package/integrations/data-defined/canonical.js +11 -0
- package/integrations/data-defined/capabilities/acmeerp.capabilities.json +608 -0
- package/integrations/data-defined/capabilities/asana.capabilities.json +265 -0
- package/integrations/data-defined/capabilities/calendly.capabilities.json +385 -0
- package/integrations/data-defined/capabilities/docusign.capabilities.json +314 -0
- package/integrations/data-defined/capabilities/fathom.capabilities.json +228 -0
- package/integrations/data-defined/capabilities/github.capabilities.json +563 -0
- package/integrations/data-defined/capabilities/hubspot.capabilities.json +715 -0
- package/integrations/data-defined/capabilities/jira.capabilities.json +376 -0
- package/integrations/data-defined/capabilities/klaviyo.capabilities.json +475 -0
- package/integrations/data-defined/capabilities/linear.capabilities.json +324 -0
- package/integrations/data-defined/capabilities/netsuite.capabilities.json +491 -0
- package/integrations/data-defined/capabilities/notion.capabilities.json +208 -0
- package/integrations/data-defined/capabilities/phone.capabilities.json +470 -0
- package/integrations/data-defined/capabilities/pipedrive.capabilities.json +388 -0
- package/integrations/data-defined/capabilities/quickbooks.capabilities.json +615 -0
- package/integrations/data-defined/capabilities/salesforce.capabilities.json +507 -0
- package/integrations/data-defined/capabilities/shopify.capabilities.json +1082 -0
- package/integrations/data-defined/capabilities/slack.capabilities.json +363 -0
- package/integrations/data-defined/capabilities/stripe.capabilities.json +580 -0
- package/integrations/data-defined/capabilities/webflow.capabilities.json +196 -0
- package/integrations/data-defined/capabilities/zendesk.capabilities.json +409 -0
- package/integrations/data-defined/compile.js +77 -0
- package/integrations/data-defined/config-form.js +110 -0
- package/integrations/data-defined/data-defined-integration.js +366 -0
- package/integrations/data-defined/examples/acme-erp-quickbooks.definition.json +467 -0
- package/integrations/data-defined/examples/asana-slack.definition.json +220 -0
- package/integrations/data-defined/examples/calendly-salesforce.definition.json +459 -0
- package/integrations/data-defined/examples/docusign-salesforce.definition.json +305 -0
- package/integrations/data-defined/examples/fathom-hubspot-notion.definition.json +575 -0
- package/integrations/data-defined/examples/github-linear.definition.json +316 -0
- package/integrations/data-defined/examples/hubspot-slack.definition.json +409 -0
- package/integrations/data-defined/examples/klaviyo-hubspot.definition.json +339 -0
- package/integrations/data-defined/examples/phone-hubspot.definition.json +637 -0
- package/integrations/data-defined/examples/pipedrive-hubspot.definition.json +136 -0
- package/integrations/data-defined/examples/pipedrive-phone.definition.json +340 -0
- package/integrations/data-defined/examples/records/phone-hubspot.definition-version.json +652 -0
- package/integrations/data-defined/examples/records/phone-hubspot.integration.json +86 -0
- package/integrations/data-defined/examples/records/phone-hubspot.mappings.json +39 -0
- package/integrations/data-defined/examples/records/phone-hubspot.workflow-run.json +62 -0
- package/integrations/data-defined/examples/shopify-klaviyo.definition.json +488 -0
- package/integrations/data-defined/examples/shopify-netsuite.definition.json +622 -0
- package/integrations/data-defined/examples/stripe-quickbooks.definition.json +476 -0
- package/integrations/data-defined/examples/webflow-hubspot-slack.definition.json +262 -0
- package/integrations/data-defined/examples/zendesk-jira.definition.json +604 -0
- package/integrations/data-defined/expressions.js +225 -0
- package/integrations/data-defined/index.js +39 -0
- package/integrations/data-defined/interpreter.js +89 -0
- package/integrations/data-defined/manifests.js +125 -0
- package/integrations/data-defined/repositories/definition-version-repository.js +67 -0
- package/integrations/data-defined/repositories/workflow-run-repository.js +59 -0
- package/integrations/data-defined/router.js +97 -0
- package/integrations/data-defined/runtime.js +208 -0
- package/integrations/data-defined/schema/capability-manifest.v0.1.schema.json +377 -0
- package/integrations/data-defined/schema/installation.v0.1.schema.json +83 -0
- package/integrations/data-defined/schema/integration-definition.v0.1.schema.json +848 -0
- package/integrations/data-defined/schema/records.md +98 -0
- package/integrations/data-defined/schema-check.js +58 -0
- package/integrations/data-defined/scripts/validate.js +66 -0
- package/integrations/data-defined/steps.js +89 -0
- package/integrations/data-defined/transforms.js +91 -0
- package/integrations/data-defined/use-cases/definition-use-cases.js +187 -0
- package/integrations/data-defined/validate.js +370 -0
- package/integrations/data-defined/versioning.js +161 -0
- package/integrations/data-defined/webhooks.js +119 -0
- package/integrations/index.js +0 -1
- package/integrations/integration-base.js +29 -0
- package/integrations/integration-router.js +101 -131
- package/integrations/repositories/integration-mapping-repository-documentdb.js +50 -0
- package/integrations/repositories/integration-mapping-repository-interface.js +15 -0
- package/integrations/repositories/integration-mapping-repository-mongo.js +29 -0
- package/integrations/repositories/integration-mapping-repository-postgres.js +30 -0
- package/integrations/repositories/integration-mapping-repository.js +29 -0
- package/integrations/repositories/integration-repository-documentdb.js +3 -35
- package/integrations/repositories/integration-repository-interface.js +1 -17
- package/integrations/repositories/integration-repository-mongo.js +77 -60
- package/integrations/repositories/integration-repository-postgres.js +76 -62
- package/integrations/repositories/process-repository-mongo.js +1 -1
- package/integrations/tests/doubles/test-integration-repository.js +1 -12
- package/integrations/use-cases/create-integration.js +20 -55
- package/integrations/use-cases/get-integrations-for-user.js +40 -80
- package/integrations/use-cases/index.js +1 -7
- package/integrations/utils/map-integration-dto.js +14 -43
- package/modules/index.js +0 -14
- package/modules/module-factory.js +0 -12
- package/modules/module.js +2 -53
- package/modules/repositories/module-repository-documentdb.js +6 -51
- package/modules/repositories/module-repository-interface.js +2 -19
- package/modules/repositories/module-repository-mongo.js +74 -67
- package/modules/repositories/module-repository-postgres.js +74 -66
- package/modules/repositories/module-repository.js +1 -2
- package/modules/requester/requester.js +5 -35
- package/modules/use-cases/get-entities-for-user.js +13 -26
- package/modules/use-cases/get-entity-options-by-id.js +4 -10
- package/modules/use-cases/get-entity-options-by-type.js +1 -1
- package/modules/use-cases/get-module-instance-from-type.js +1 -1
- package/modules/use-cases/get-module.js +4 -10
- package/modules/use-cases/process-authorization-callback.js +19 -53
- package/modules/use-cases/refresh-entity-options.js +4 -10
- package/modules/use-cases/test-module-auth.js +4 -10
- package/package.json +6 -6
- package/prisma-mongodb/schema.prisma +50 -86
- package/prisma-postgresql/migrations/20261018000000_add_data_defined_integrations/migration.sql +66 -0
- package/prisma-postgresql/schema.prisma +48 -81
- package/queues/index.js +0 -25
- package/types/index.d.ts +0 -2
- package/user/repositories/user-repository-documentdb.js +2 -27
- package/user/repositories/user-repository-interface.js +0 -18
- package/user/repositories/user-repository-mongo.js +0 -24
- package/user/repositories/user-repository-postgres.js +0 -18
- package/user/use-cases/authenticate-user.js +1 -7
- package/user/use-cases/get-user-from-adopter-jwt.js +124 -95
- package/user/use-cases/get-user-from-x-frigg-headers.js +80 -83
- package/user/user.js +1 -64
- package/credential/use-cases/credential-operations-for-user.js +0 -202
- package/credential/use-cases/reauthorize-credential-for-user.js +0 -73
- package/database/organization-where.js +0 -18
- package/database/unique-violation.js +0 -25
- package/extensions/bootstrap-runner.js +0 -43
- package/extensions/extension-loader.js +0 -187
- package/extensions/index.js +0 -41
- package/extensions/initialize-app.js +0 -123
- package/extensions/route-mounter.js +0 -103
- package/extensions/schema-composer.js +0 -188
- package/infrastructure/scheduler/netlify-scheduler-adapter.js +0 -216
- package/infrastructure/scheduler/scheduled-job-repository.js +0 -118
- package/integrations/repositories/integration-not-found.js +0 -14
- package/integrations/schedule-config.js +0 -80
- package/integrations/use-cases/dispatch-ongoing-syncs.js +0 -100
- package/integrations/use-cases/integration-operations-for-user.js +0 -256
- package/integrations/use-cases/resolve-integration-ownership.js +0 -177
- package/management-api/create-management-api-router.js +0 -49
- package/management-api/error-response.js +0 -116
- package/management-api/management-api-config.js +0 -151
- package/management-api/meta-router.js +0 -76
- package/management-api/openapi/build-openapi.js +0 -144
- package/management-api/openapi/components.js +0 -415
- package/management-api/openapi/v1-operations.js +0 -83
- package/management-api/openapi/v2-operations.js +0 -264
- package/management-api/route-registry.js +0 -411
- package/management-api/test-support/http-client.js +0 -39
- package/management-api/use-cases/get-management-api-meta.js +0 -57
- package/management-api/v1-deprecation.js +0 -120
- package/management-api/v2/create-v2-router.js +0 -85
- package/management-api/v2/dependencies.js +0 -281
- package/management-api/v2/dto.js +0 -143
- package/management-api/v2/handlers/authorization.js +0 -94
- package/management-api/v2/handlers/credentials.js +0 -33
- package/management-api/v2/handlers/entities.js +0 -77
- package/management-api/v2/handlers/integrations.js +0 -128
- package/management-api/v2/handlers/proxy.js +0 -34
- package/management-api/v2/request.js +0 -85
- package/management-api/v2/test-support/fake-dependencies.js +0 -103
- package/modules/domain/authorization-session.js +0 -144
- package/modules/entity-scope.js +0 -15
- package/modules/entity-type-registry.js +0 -311
- package/modules/proxy/proxy-bases.js +0 -169
- package/modules/proxy/proxy-errors.js +0 -31
- package/modules/proxy/proxy-path.js +0 -183
- package/modules/proxy/proxy-policy.js +0 -277
- package/modules/repositories/authorization-session-repository-documentdb.js +0 -112
- package/modules/repositories/authorization-session-repository-factory.js +0 -31
- package/modules/repositories/authorization-session-repository-interface.js +0 -47
- package/modules/repositories/authorization-session-repository-prisma.js +0 -87
- package/modules/repositories/entity-not-found.js +0 -18
- package/modules/requester/proxy-request.js +0 -245
- package/modules/scope-config.js +0 -192
- package/modules/scope-policy.js +0 -112
- package/modules/scope-resolution.js +0 -288
- package/modules/scope-visibility.js +0 -247
- package/modules/tests/doubles/in-memory-authorization-session-repository.js +0 -45
- package/modules/tests/doubles/ownership-matching.js +0 -18
- package/modules/use-cases/authorize-entity-for-user.js +0 -61
- package/modules/use-cases/create-entity-from-credential.js +0 -113
- package/modules/use-cases/entity-operations-for-user.js +0 -162
- package/modules/use-cases/entity-types.js +0 -139
- package/modules/use-cases/execute-entity-proxy-request.js +0 -331
- package/modules/use-cases/get-authorization-requirements.js +0 -100
- package/modules/use-cases/get-entity-module-for-user.js +0 -113
- package/modules/use-cases/manage-access.js +0 -21
- package/modules/use-cases/multi-step-authorization.js +0 -329
- package/prisma-postgresql/migrations/20261003000000_add_authorization_session/migration.sql +0 -28
- package/prisma-postgresql/migrations/20261015000000_add_organization_membership/migration.sql +0 -26
- package/prisma-postgresql/migrations/20261016000000_add_entity_integration_organization/migration.sql +0 -25
- package/prisma-postgresql/migrations/20261017000000_add_scheduled_job/migration.sql +0 -28
- package/providers/index.js +0 -23
- package/providers/resolve-provider.js +0 -93
- package/providers/runtime-detection.js +0 -124
- package/queues/providers/index.js +0 -11
- package/queues/providers/netlify-background-provider.js +0 -150
- package/queues/providers/qstash-queue-provider.js +0 -219
- package/queues/providers/sqs-queue-provider.js +0 -70
- package/queues/queue-client-interface.js +0 -55
- package/queues/queue-message-auth.js +0 -193
- package/queues/queue-provider-factory.js +0 -101
- package/queues/queue-provider.js +0 -65
- package/queues/sqs-queue-client.js +0 -81
- package/types/modules/index.d.ts +0 -214
- package/types/user/index.d.ts +0 -134
- package/user/adopter-jwt-config.js +0 -177
- package/user/adopter-jwt-errors.js +0 -59
- package/user/adopter-token-verifier.js +0 -122
- package/user/app-user-helpers.js +0 -97
- package/user/create-user-authentication.js +0 -64
- package/user/membership.js +0 -51
- package/user/repositories/organization-membership-record.js +0 -19
- package/user/repositories/organization-membership-repository-documentdb.js +0 -106
- package/user/repositories/organization-membership-repository-factory.js +0 -42
- package/user/repositories/organization-membership-repository-interface.js +0 -57
- package/user/repositories/organization-membership-repository-mongo.js +0 -13
- package/user/repositories/organization-membership-repository-postgres.js +0 -29
- package/user/repositories/organization-membership-repository-prisma.js +0 -81
- package/user/tests/doubles/adopter-jwt-fixtures.js +0 -220
- package/user/use-cases/ensure-organization-membership.js +0 -92
- package/user/use-cases/find-individual-users-by-organization.js +0 -54
|
@@ -2,27 +2,21 @@ const { findNearestBackendPackageJson } = require('@friggframework/core/utils');
|
|
|
2
2
|
const path = require('node:path');
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const { resolveTelemetryConfig } = require('../telemetry/telemetry-config');
|
|
5
|
-
const { assertAdopterJwtConfig } = require('../user/adopter-jwt-config');
|
|
6
5
|
const { registerDeniedKeys } = require('../logs/denied-keys');
|
|
7
6
|
const {
|
|
8
7
|
extractCredentialFieldsFromModules,
|
|
9
8
|
} = require('../database/encryption/encryption-schema-registry');
|
|
10
9
|
const {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} = require('../modules/entity-type-registry');
|
|
14
|
-
const { resolveOwnershipConfig } = require('../modules/entity-scope');
|
|
15
|
-
const { assertProxyConfig } = require('../modules/proxy/proxy-bases');
|
|
16
|
-
const {
|
|
17
|
-
resolveManagementApiConfig,
|
|
18
|
-
} = require('../management-api/management-api-config');
|
|
19
|
-
const { resolveScheduleConfig } = require('../integrations/schedule-config');
|
|
10
|
+
getModulesDefinitionFromIntegrationClasses,
|
|
11
|
+
} = require('../integrations/utils/map-integration-dto');
|
|
20
12
|
|
|
21
13
|
// Handlers without a database never load the encryption registry, so the
|
|
22
14
|
// credential leaf keys are registered for redaction here too.
|
|
23
|
-
function registerCredentialLogKeys(appDefinition,
|
|
15
|
+
function registerCredentialLogKeys(appDefinition, integrations) {
|
|
24
16
|
try {
|
|
25
|
-
extractCredentialFieldsFromModules(
|
|
17
|
+
extractCredentialFieldsFromModules(
|
|
18
|
+
getModulesDefinitionFromIntegrationClasses(integrations)
|
|
19
|
+
);
|
|
26
20
|
} catch {
|
|
27
21
|
// An odd integration shape must not stop the app from loading.
|
|
28
22
|
}
|
|
@@ -35,53 +29,18 @@ function registerCredentialLogKeys(appDefinition, moduleDefinitions) {
|
|
|
35
29
|
}
|
|
36
30
|
|
|
37
31
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* only traces static require() calls, and at runtime process.cwd() is the
|
|
49
|
-
* function root, not the backend. A generated function entry point therefore
|
|
50
|
-
* requires the backend's index.js statically and passes its Definition here.
|
|
51
|
-
*
|
|
52
|
-
* The preset definition is validated and derived exactly like a discovered
|
|
53
|
-
* one: adopter-JWT config, the entity registry, ownership and the Management
|
|
54
|
-
* API config all apply, so a Netlify function and an AWS Lambda load the
|
|
55
|
-
* same app the same way. Pass null to clear it.
|
|
56
|
-
*
|
|
57
|
-
* @param {Object|null} definition - the backend's `Definition` export
|
|
58
|
-
*/
|
|
59
|
-
function setAppDefinition(definition) {
|
|
60
|
-
if (
|
|
61
|
-
definition !== null &&
|
|
62
|
-
(typeof definition !== 'object' || Array.isArray(definition))
|
|
63
|
-
) {
|
|
64
|
-
throw new TypeError(
|
|
65
|
-
'setAppDefinition expects the app Definition object (or null)'
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
presetDefinition = definition;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* The definition preset with setAppDefinition(), unvalidated, or null.
|
|
73
|
-
*
|
|
74
|
-
* For low-level readers that only need one raw field before the app is
|
|
75
|
-
* fully loaded (the database type, the custom encryption schema) and keep
|
|
76
|
-
* their own process.cwd() discovery as the fallback.
|
|
77
|
-
*
|
|
78
|
-
* @returns {Object|null}
|
|
32
|
+
* Loads the App definition from the nearest backend package
|
|
33
|
+
* @function loadAppDefinition
|
|
34
|
+
* @description Searches for the nearest backend package.json, loads the corresponding index.js file,
|
|
35
|
+
* and extracts the application definition containing integrations and user configuration.
|
|
36
|
+
* @returns {{integrations: Array<object>, userConfig: object | null, adminScripts: Array<object>, reports: Array<object>, admin: object, telemetry: object, logging: object | null}} An object containing the application definition.
|
|
37
|
+
* @throws {Error} Throws error if backend package.json cannot be found.
|
|
38
|
+
* @throws {Error} Throws error if index.js file cannot be found in the backend directory.
|
|
39
|
+
* @example
|
|
40
|
+
* const { integrations, userConfig, telemetry } = loadAppDefinition();
|
|
41
|
+
* console.log(`Found ${integrations.length} integrations`);
|
|
79
42
|
*/
|
|
80
|
-
function
|
|
81
|
-
return presetDefinition;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function discoverAppDefinition() {
|
|
43
|
+
function loadAppDefinition() {
|
|
85
44
|
const backendPath = findNearestBackendPackageJson();
|
|
86
45
|
if (!backendPath) {
|
|
87
46
|
throw new Error('Could not find backend package.json');
|
|
@@ -94,78 +53,18 @@ function discoverAppDefinition() {
|
|
|
94
53
|
}
|
|
95
54
|
|
|
96
55
|
const backendJsFile = require(backendFilePath);
|
|
97
|
-
|
|
98
|
-
}
|
|
56
|
+
const appDefinition = backendJsFile.Definition;
|
|
99
57
|
|
|
100
|
-
/**
|
|
101
|
-
* Loads the App definition: the one preset with setAppDefinition(), or the
|
|
102
|
-
* nearest backend package's index.js.
|
|
103
|
-
* @function loadAppDefinition
|
|
104
|
-
* @description Uses the definition preset by setAppDefinition() when there is one; otherwise searches for the nearest backend package.json, loads the corresponding index.js file,
|
|
105
|
-
* and extracts the application definition containing integrations and user configuration.
|
|
106
|
-
* @returns {{appDefinition: object, integrations: Array<object>, entities: object | null, entityTypeRegistry: Map<string, object>, moduleDefinitions: Array<object>, ownership: {scope: ({default: string, allow: string[]}|null), individualAcross: string}, userConfig: object | null, adminScripts: Array<object>, reports: Array<object>, admin: object, telemetry: object, logging: object | null, managementApi: object}} An object containing the application definition. `appDefinition` is the raw Definition object.
|
|
107
|
-
* @throws {Error} Throws error if backend package.json cannot be found.
|
|
108
|
-
* @throws {Error} Throws error if index.js file cannot be found in the backend directory.
|
|
109
|
-
* @throws {Error} Throws error if user.authModes.adopterJwt is enabled without a usable user.jwtConfig.
|
|
110
|
-
* @throws {OwnershipConfigError} Throws if an ownership or scope setting is invalid (ADR-056 §3.1).
|
|
111
|
-
* @throws {ManagementApiConfigError} Throws if `managementApi.proxy.scopes` is invalid (ADR-056 §3.5).
|
|
112
|
-
* @throws {ProxyConfigError} Throws if a module's `proxy.baseUrls` or an allow rule's `base` is invalid (ADR-052).
|
|
113
|
-
* @throws {ScheduleConfigError} Throws if an integration's `Definition.schedule` is invalid.
|
|
114
|
-
* @example
|
|
115
|
-
* const { integrations, userConfig, telemetry } = loadAppDefinition();
|
|
116
|
-
* console.log(`Found ${integrations.length} integrations`);
|
|
117
|
-
*/
|
|
118
|
-
function loadAppDefinition() {
|
|
119
|
-
const appDefinition = presetDefinition || discoverAppDefinition();
|
|
120
|
-
return resolveAppDefinition(appDefinition);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function resolveAppDefinition(appDefinition) {
|
|
124
58
|
const {
|
|
125
59
|
integrations = [],
|
|
126
|
-
entities = null,
|
|
127
60
|
user: userConfig = null,
|
|
128
61
|
adminScripts = [],
|
|
129
62
|
reports = [],
|
|
130
63
|
admin = {},
|
|
131
64
|
logging = null,
|
|
132
|
-
managementApi = {},
|
|
133
65
|
} = appDefinition;
|
|
134
66
|
|
|
135
|
-
|
|
136
|
-
// key source would otherwise start cleanly and answer every login with 500.
|
|
137
|
-
assertAdopterJwtConfig(userConfig);
|
|
138
|
-
|
|
139
|
-
// Fail fast: a bad `entities` registry (key/name mismatch, conflicting
|
|
140
|
-
// definitions, `$infer: false` with an unregistered module) must stop the
|
|
141
|
-
// app at load, not on the first request that needs a module.
|
|
142
|
-
const entityTypeRegistry = getEntityTypeRegistry(appDefinition);
|
|
143
|
-
const moduleDefinitions = getEntityTypeDefinitions(entityTypeRegistry);
|
|
144
|
-
|
|
145
|
-
// Same reason for entity scopes (ADR-056 §3.1): a mistyped scope, an unknown
|
|
146
|
-
// `individualAcross`, or an organization-owned integration that binds an
|
|
147
|
-
// individual entity stops the app at load.
|
|
148
|
-
const ownership = resolveOwnershipConfig(appDefinition, entityTypeRegistry);
|
|
149
|
-
|
|
150
|
-
// And for the Management API: `managementApi.proxy.scopes` decides whose
|
|
151
|
-
// credentials the entity proxy may act through (ADR-056 §3.5), so an
|
|
152
|
-
// unknown scope stops the app here rather than being read as a default.
|
|
153
|
-
const managementApiConfig = resolveManagementApiConfig(managementApi);
|
|
154
|
-
|
|
155
|
-
// Named proxy bases (ADR-052 amendment): a module that declares both
|
|
156
|
-
// `baseUrl` and `baseUrls`, a bad base URL or name, or an allow rule for a
|
|
157
|
-
// base the module lacks, stops the app here.
|
|
158
|
-
assertProxyConfig(moduleDefinitions, managementApiConfig.proxy);
|
|
159
|
-
|
|
160
|
-
// And for each integration's `Definition.schedule`: a mistyped scope would
|
|
161
|
-
// otherwise tick ONGOING_SYNC per class when per installation was meant.
|
|
162
|
-
for (const IntegrationClass of integrations) {
|
|
163
|
-
if (IntegrationClass?.Definition) {
|
|
164
|
-
resolveScheduleConfig(IntegrationClass.Definition);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
registerCredentialLogKeys(appDefinition, moduleDefinitions);
|
|
67
|
+
registerCredentialLogKeys(appDefinition, integrations);
|
|
169
68
|
|
|
170
69
|
// Degrade consistently: an invalid telemetry block must never take down a
|
|
171
70
|
// router bundle that loads the app definition at module scope (telemetry is
|
|
@@ -189,24 +88,16 @@ function resolveAppDefinition(appDefinition) {
|
|
|
189
88
|
}
|
|
190
89
|
|
|
191
90
|
return {
|
|
192
|
-
appDefinition,
|
|
193
91
|
integrations,
|
|
194
|
-
entities,
|
|
195
|
-
entityTypeRegistry,
|
|
196
|
-
moduleDefinitions,
|
|
197
|
-
ownership,
|
|
198
92
|
userConfig,
|
|
199
93
|
adminScripts,
|
|
200
94
|
reports,
|
|
201
95
|
admin,
|
|
202
96
|
telemetry,
|
|
203
97
|
logging,
|
|
204
|
-
managementApi,
|
|
205
98
|
};
|
|
206
99
|
}
|
|
207
100
|
|
|
208
101
|
module.exports = {
|
|
209
102
|
loadAppDefinition,
|
|
210
|
-
setAppDefinition,
|
|
211
|
-
getPresetAppDefinition,
|
|
212
103
|
};
|
|
@@ -6,12 +6,6 @@ const bodyParser = require('body-parser');
|
|
|
6
6
|
const cors = require('cors');
|
|
7
7
|
const Boom = require('@hapi/boom');
|
|
8
8
|
const serverlessHttp = require('serverless-http');
|
|
9
|
-
const {
|
|
10
|
-
API_VERSION_HEADER,
|
|
11
|
-
isVersionedManagementApiPath,
|
|
12
|
-
toBoom,
|
|
13
|
-
toV2ErrorBody,
|
|
14
|
-
} = require('../management-api/error-response');
|
|
15
9
|
|
|
16
10
|
const log = getLogger('frigg.http');
|
|
17
11
|
|
|
@@ -32,15 +26,11 @@ const createApp = (applyMiddleware) => {
|
|
|
32
26
|
if (applyMiddleware) applyMiddleware(app);
|
|
33
27
|
|
|
34
28
|
// The express boundary: send the error response and log it one time.
|
|
35
|
-
// A Boom error keeps its status; other errors keep theirs only when they
|
|
36
|
-
// mark a 4xx safe to expose (body-parser's 400/413 via http-errors), so a
|
|
37
|
-
// malformed body is a 400, not a 500.
|
|
38
29
|
app.use((err, req, res, next) => {
|
|
39
|
-
const boomError =
|
|
30
|
+
const boomError = err.isBoom ? err : Boom.boomify(err);
|
|
40
31
|
const {
|
|
41
32
|
output: { statusCode = 500 },
|
|
42
33
|
} = boomError;
|
|
43
|
-
const versioned = isVersionedManagementApiPath(req.path);
|
|
44
34
|
|
|
45
35
|
if (statusCode >= 500) {
|
|
46
36
|
log.error('Request failed', {
|
|
@@ -49,6 +39,7 @@ const createApp = (applyMiddleware) => {
|
|
|
49
39
|
invocation: summarizeExpressRequest(req),
|
|
50
40
|
error: boomError,
|
|
51
41
|
});
|
|
42
|
+
res.status(statusCode).json({ error: 'Internal Server Error' });
|
|
52
43
|
} else {
|
|
53
44
|
// A client error needs no stack; the logger scrubs the reason.
|
|
54
45
|
log.warn('Request rejected', {
|
|
@@ -56,21 +47,8 @@ const createApp = (applyMiddleware) => {
|
|
|
56
47
|
statusCode,
|
|
57
48
|
reason: boomError.message,
|
|
58
49
|
});
|
|
50
|
+
res.status(statusCode).json({ error: err.message });
|
|
59
51
|
}
|
|
60
|
-
|
|
61
|
-
if (versioned) {
|
|
62
|
-
// Management API v2 / meta: { error: { code, message, details? } }.
|
|
63
|
-
if (req.path.startsWith('/api/v2')) {
|
|
64
|
-
res.set(API_VERSION_HEADER, '2');
|
|
65
|
-
}
|
|
66
|
-
return res.status(statusCode).json(toV2ErrorBody(boomError));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// v1 and other routes keep their historical body.
|
|
70
|
-
if (statusCode >= 500) {
|
|
71
|
-
return res.status(statusCode).json({ error: 'Internal Server Error' });
|
|
72
|
-
}
|
|
73
|
-
return res.status(statusCode).json({ error: err.message });
|
|
74
52
|
});
|
|
75
53
|
|
|
76
54
|
return app;
|
|
@@ -18,9 +18,8 @@ const {
|
|
|
18
18
|
createModuleRepository,
|
|
19
19
|
} = require('../modules/repositories/module-repository-factory');
|
|
20
20
|
const {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} = require('../modules/entity-type-registry');
|
|
21
|
+
getModulesDefinitionFromIntegrationClasses,
|
|
22
|
+
} = require('../integrations/utils/map-integration-dto');
|
|
24
23
|
const { processNotFound } = require('../integrations/use-cases/process-errors');
|
|
25
24
|
|
|
26
25
|
const loadRouterFromObject = (IntegrationClass, routerObject) => {
|
|
@@ -62,18 +61,30 @@ const initializeRepositories = () => {
|
|
|
62
61
|
return { processRepository, integrationRepository, moduleRepository };
|
|
63
62
|
};
|
|
64
63
|
|
|
64
|
+
const createModuleFactoryWithDefinitions = (
|
|
65
|
+
moduleRepository,
|
|
66
|
+
integrationClasses
|
|
67
|
+
) => {
|
|
68
|
+
const moduleDefinitions =
|
|
69
|
+
getModulesDefinitionFromIntegrationClasses(integrationClasses);
|
|
70
|
+
|
|
71
|
+
return new ModuleFactory({
|
|
72
|
+
moduleRepository,
|
|
73
|
+
moduleDefinitions,
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
|
|
65
77
|
const loadIntegrationForWebhook = async (integrationId) => {
|
|
66
78
|
const { loadAppDefinition } = require('./app-definition-loader');
|
|
67
|
-
const { integrations: integrationClasses
|
|
68
|
-
loadAppDefinition();
|
|
79
|
+
const { integrations: integrationClasses } = loadAppDefinition();
|
|
69
80
|
|
|
70
81
|
const { integrationRepository, moduleRepository } =
|
|
71
82
|
initializeRepositories();
|
|
72
83
|
|
|
73
|
-
const moduleFactory =
|
|
84
|
+
const moduleFactory = createModuleFactoryWithDefinitions(
|
|
74
85
|
moduleRepository,
|
|
75
|
-
|
|
76
|
-
|
|
86
|
+
integrationClasses
|
|
87
|
+
);
|
|
77
88
|
|
|
78
89
|
const getIntegrationInstance = new GetIntegrationInstance({
|
|
79
90
|
integrationRepository,
|
|
@@ -118,23 +129,13 @@ const integrationExists = async (integrationId) => {
|
|
|
118
129
|
}
|
|
119
130
|
};
|
|
120
131
|
|
|
121
|
-
const loadIntegrationForProcess = async (
|
|
122
|
-
processId,
|
|
123
|
-
integrationClass,
|
|
124
|
-
moduleDefinitions
|
|
125
|
-
) => {
|
|
132
|
+
const loadIntegrationForProcess = async (processId, integrationClass) => {
|
|
126
133
|
const { processRepository, integrationRepository, moduleRepository } =
|
|
127
134
|
initializeRepositories();
|
|
128
135
|
|
|
129
|
-
const moduleFactory =
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
moduleDefinitions ??
|
|
133
|
-
// No app definition handed in: this integration's own modules only.
|
|
134
|
-
getEntityTypeDefinitions(
|
|
135
|
-
getEntityTypeRegistry({ integrations: [integrationClass] })
|
|
136
|
-
),
|
|
137
|
-
});
|
|
136
|
+
const moduleFactory = createModuleFactoryWithDefinitions(moduleRepository, [
|
|
137
|
+
integrationClass,
|
|
138
|
+
]);
|
|
138
139
|
|
|
139
140
|
const getIntegrationInstance = new GetIntegrationInstance({
|
|
140
141
|
integrationRepository,
|
|
@@ -160,13 +161,7 @@ const loadIntegrationForProcess = async (
|
|
|
160
161
|
return instance;
|
|
161
162
|
};
|
|
162
163
|
|
|
163
|
-
|
|
164
|
-
* @param {Function} integrationClass
|
|
165
|
-
* @param {{moduleDefinitions?: Array<object>}} [options] - the app's offered
|
|
166
|
-
* module definitions (`loadAppDefinition().moduleDefinitions`). When omitted
|
|
167
|
-
* the worker hydrates with this integration's own modules only.
|
|
168
|
-
*/
|
|
169
|
-
const createQueueWorker = (integrationClass, { moduleDefinitions } = {}) => {
|
|
164
|
+
const createQueueWorker = (integrationClass) => {
|
|
170
165
|
const integrationName = integrationClass.Definition.name;
|
|
171
166
|
|
|
172
167
|
class QueueWorker extends Worker {
|
|
@@ -188,8 +183,7 @@ const createQueueWorker = (integrationClass, { moduleDefinitions } = {}) => {
|
|
|
188
183
|
console.log(`[QueueWorker] hydrating by processId`, logCtx);
|
|
189
184
|
integrationInstance = await loadIntegrationForProcess(
|
|
190
185
|
params.data.processId,
|
|
191
|
-
integrationClass
|
|
192
|
-
moduleDefinitions
|
|
186
|
+
integrationClass
|
|
193
187
|
);
|
|
194
188
|
console.log(`[QueueWorker] hydrated`, {
|
|
195
189
|
...logCtx,
|
|
@@ -29,19 +29,6 @@ function secretsMatch(provided, expected) {
|
|
|
29
29
|
return crypto.timingSafeEqual(providedHash, expectedHash);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
/**
|
|
33
|
-
* True when `provided` matches the configured ADMIN_API_KEY. False when no
|
|
34
|
-
* key is configured or none was provided. For callers that change a response
|
|
35
|
-
* for admins rather than reject everyone else (GET /api/meta).
|
|
36
|
-
* @param {string|undefined} provided
|
|
37
|
-
* @returns {boolean}
|
|
38
|
-
*/
|
|
39
|
-
function isValidAdminApiKey(provided) {
|
|
40
|
-
const expectedKey = process.env.ADMIN_API_KEY;
|
|
41
|
-
if (!expectedKey || !provided) return false;
|
|
42
|
-
return secretsMatch(provided, expectedKey);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
32
|
/**
|
|
46
33
|
* Validate admin API key from request header
|
|
47
34
|
* @param {import('express').Request} req
|
|
@@ -83,4 +70,4 @@ function validateAdminApiKey(req, res, next) {
|
|
|
83
70
|
next();
|
|
84
71
|
}
|
|
85
72
|
|
|
86
|
-
module.exports = { validateAdminApiKey
|
|
73
|
+
module.exports = { validateAdminApiKey };
|
package/handlers/routers/auth.js
CHANGED
|
@@ -1,51 +1,15 @@
|
|
|
1
|
-
const
|
|
2
|
-
const {
|
|
3
|
-
createManagementApiRouter,
|
|
4
|
-
} = require('../../management-api/create-management-api-router');
|
|
5
|
-
const {
|
|
6
|
-
createExtensionRoutesRouter,
|
|
7
|
-
} = require('../../extensions/route-mounter');
|
|
1
|
+
const { createIntegrationRouter } = require('@friggframework/core');
|
|
8
2
|
const { createAppHandler } = require('./../app-handler-helpers');
|
|
9
3
|
|
|
10
|
-
|
|
11
|
-
// unprefixed paths (or 410 when managementApi.v1 is false).
|
|
12
|
-
//
|
|
13
|
-
// Built on first access, not at require time (friggframework/frigg#545,
|
|
14
|
-
// c40eca49): a host that presets the app definition (setAppDefinition, as
|
|
15
|
-
// provider-netlify's function entry points do) can require this module
|
|
16
|
-
// before or after doing so.
|
|
17
|
-
let router;
|
|
18
|
-
let handler;
|
|
4
|
+
const router = createIntegrationRouter();
|
|
19
5
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
+
});
|
|
23
12
|
|
|
24
|
-
|
|
25
|
-
// of v1 nor v2, so it is never deprecated or disabled.
|
|
26
|
-
built.route('/api/integrations/redirect/:appId').get((req, res) => {
|
|
27
|
-
res.redirect(
|
|
28
|
-
`${process.env.FRONTEND_URI}/redirect/${req.params.appId
|
|
29
|
-
}?${new URLSearchParams(req.query)}`
|
|
30
|
-
);
|
|
31
|
-
});
|
|
13
|
+
const handler = createAppHandler('HTTP Event: Auth', router);
|
|
32
14
|
|
|
33
|
-
|
|
34
|
-
// behind the admin API key.
|
|
35
|
-
built.use(createExtensionRoutesRouter());
|
|
36
|
-
|
|
37
|
-
return built;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
module.exports = {
|
|
41
|
-
get router() {
|
|
42
|
-
if (!router) router = buildRouter();
|
|
43
|
-
return router;
|
|
44
|
-
},
|
|
45
|
-
get handler() {
|
|
46
|
-
if (!handler) {
|
|
47
|
-
handler = createAppHandler('HTTP Event: Auth', module.exports.router);
|
|
48
|
-
}
|
|
49
|
-
return handler;
|
|
50
|
-
},
|
|
51
|
-
};
|
|
15
|
+
module.exports = { handler };
|
|
@@ -2,6 +2,9 @@ const { Router } = require('express');
|
|
|
2
2
|
const { createAppHandler } = require('./../app-handler-helpers');
|
|
3
3
|
const { loadAppDefinition } = require('./../app-definition-loader');
|
|
4
4
|
const { ModuleFactory } = require('../../modules/module-factory');
|
|
5
|
+
const {
|
|
6
|
+
getModulesDefinitionFromIntegrationClasses,
|
|
7
|
+
} = require('../../integrations/utils/map-integration-dto');
|
|
5
8
|
const {
|
|
6
9
|
createModuleRepository,
|
|
7
10
|
} = require('../../modules/repositories/module-repository-factory');
|
|
@@ -25,25 +28,18 @@ const {
|
|
|
25
28
|
CheckIntegrationsHealthUseCase,
|
|
26
29
|
} = require('../use-cases/check-integrations-health-use-case');
|
|
27
30
|
|
|
28
|
-
const {
|
|
29
|
-
createManagementApiMetaRouter,
|
|
30
|
-
createDocsRedirectRouter,
|
|
31
|
-
} = require('../../management-api/meta-router');
|
|
32
|
-
|
|
33
31
|
const router = Router();
|
|
34
32
|
const healthCheckRepository = createHealthCheckRepository({ prismaClient: prisma });
|
|
35
33
|
|
|
36
34
|
// Load integrations and create factories just like auth router does
|
|
37
35
|
// This verifies the system can properly load integrations
|
|
38
36
|
let moduleFactory, integrationClasses;
|
|
39
|
-
let appDefinition = {};
|
|
40
37
|
try {
|
|
41
38
|
const appDef = loadAppDefinition();
|
|
42
|
-
appDefinition = appDef;
|
|
43
39
|
integrationClasses = appDef.integrations || [];
|
|
44
40
|
|
|
45
41
|
const moduleRepository = createModuleRepository();
|
|
46
|
-
const
|
|
42
|
+
const moduleDefinitions = getModulesDefinitionFromIntegrationClasses(integrationClasses);
|
|
47
43
|
|
|
48
44
|
moduleFactory = new ModuleFactory({
|
|
49
45
|
moduleRepository,
|
|
@@ -89,11 +85,6 @@ const validateApiKey = (req, res, next) => {
|
|
|
89
85
|
next();
|
|
90
86
|
};
|
|
91
87
|
|
|
92
|
-
// Management API discovery (ADR-053 §4) and the /api/docs redirect to it are
|
|
93
|
-
// public and DB-free, so they are mounted ahead of the health API key check.
|
|
94
|
-
router.use(createManagementApiMetaRouter({ appDefinition }));
|
|
95
|
-
router.use(createDocsRedirectRouter());
|
|
96
|
-
|
|
97
88
|
router.use(validateApiKey);
|
|
98
89
|
|
|
99
90
|
// Helper to detect VPC configuration
|