@friggframework/core 2.0.0--canary.686.3e27a92.0 → 2.0.0--canary.663.8de669c.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 +1 -6
- package/database/encryption/encryption-config.js +31 -10
- package/database/encryption/encryption-schema-registry.js +12 -93
- package/database/prisma.js +2 -4
- package/generated/prisma-mongodb/edge.js +4 -43
- package/generated/prisma-mongodb/index-browser.js +1 -40
- package/generated/prisma-mongodb/index.d.ts +111 -4739
- package/generated/prisma-mongodb/index.js +4 -43
- package/generated/prisma-mongodb/package.json +1 -1
- package/generated/prisma-mongodb/schema.prisma +0 -92
- package/generated/prisma-mongodb/wasm.js +4 -43
- package/generated/prisma-postgresql/edge.js +4 -43
- package/generated/prisma-postgresql/index-browser.js +1 -40
- package/generated/prisma-postgresql/index.d.ts +33 -4966
- package/generated/prisma-postgresql/index.js +4 -43
- package/generated/prisma-postgresql/package.json +1 -1
- package/generated/prisma-postgresql/schema.prisma +0 -87
- package/generated/prisma-postgresql/wasm.js +4 -43
- package/handlers/app-definition-loader.js +19 -121
- 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 +1 -65
- package/infrastructure/scheduler/index.js +6 -19
- package/infrastructure/scheduler/scheduler-service-factory.js +7 -55
- package/integrations/index.js +0 -1
- package/integrations/integration-router.js +96 -131
- 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 +76 -59
- package/integrations/repositories/integration-repository-postgres.js +76 -62
- 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 +2 -27
- 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 +5 -6
- package/prisma-mongodb/schema.prisma +0 -92
- package/prisma-postgresql/schema.prisma +0 -87
- 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 -408
- 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-errors.js +0 -20
- package/modules/proxy/proxy-path.js +0 -179
- package/modules/proxy/proxy-policy.js +0 -248
- 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 -244
- 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 -286
- 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 -197
- 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
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
const Boom = require('@hapi/boom');
|
|
2
|
-
const { FetchError } = require('../../errors/fetch-error');
|
|
3
|
-
const { getLogger } = require('../../logs');
|
|
4
|
-
const { AuthorizationSession } = require('../domain/authorization-session');
|
|
5
|
-
const { findDefinition, getAuthStepCount } = require('./entity-types');
|
|
6
|
-
const { describeRecord } = require('../scope-visibility');
|
|
7
|
-
const { DEFAULT_SCOPE_POLICY } = require('../scope-policy');
|
|
8
|
-
|
|
9
|
-
const log = getLogger('frigg.api.authorize');
|
|
10
|
-
|
|
11
|
-
const defaultCreateModule = (params) => {
|
|
12
|
-
const { Module } = require('../module');
|
|
13
|
-
return Module.create(params);
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const isMultiStep = (definition) =>
|
|
17
|
-
getAuthStepCount(definition) > 1 ||
|
|
18
|
-
typeof definition.processAuthorizationStep === 'function';
|
|
19
|
-
|
|
20
|
-
const sessionNotFound = () =>
|
|
21
|
-
Boom.notFound('Authorization session not found or expired', {
|
|
22
|
-
code: 'AUTHORIZATION_SESSION_NOT_FOUND',
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Maps a failure from the module or the provider to a client-facing error.
|
|
27
|
-
* Boom errors pass through. A provider HTTP failure is a 502; a failed auth
|
|
28
|
-
* test or a ClientSafeError is a 400. Anything else stays a 500.
|
|
29
|
-
*/
|
|
30
|
-
function toAuthorizationError(error, { passMessage = false } = {}) {
|
|
31
|
-
if (error?.isBoom) return error;
|
|
32
|
-
if (error instanceof FetchError) {
|
|
33
|
-
return Boom.badGateway('The provider rejected the authorization request', {
|
|
34
|
-
code: 'UPSTREAM_ERROR',
|
|
35
|
-
expose: true,
|
|
36
|
-
details: { upstreamStatus: error.statusCode ?? null },
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
if (error?.isClientSafe || passMessage) {
|
|
40
|
-
return Boom.badRequest(error?.message || 'Authorization failed', {
|
|
41
|
-
code: 'AUTHORIZATION_FAILED',
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
if (error?.message === 'Authorization failed') {
|
|
45
|
-
return Boom.badRequest(
|
|
46
|
-
'Authorization failed: the credentials did not pass the module auth test',
|
|
47
|
-
{ code: 'AUTHORIZATION_FAILED' }
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
return error;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Loads the session a caller continues, checking it belongs to them, to the
|
|
55
|
-
* entity type and (for re-authorization) to the credential.
|
|
56
|
-
*/
|
|
57
|
-
async function loadSession(repository, sessionId, binding) {
|
|
58
|
-
if (typeof sessionId !== 'string' || !sessionId) throw sessionNotFound();
|
|
59
|
-
const session = await repository.findBySessionId(sessionId);
|
|
60
|
-
if (!session || session.isExpired() || !session.belongsTo(binding)) {
|
|
61
|
-
throw sessionNotFound();
|
|
62
|
-
}
|
|
63
|
-
if (session.completed) {
|
|
64
|
-
throw Boom.conflict('Authorization session is already complete', {
|
|
65
|
-
code: 'AUTHORIZATION_SESSION_COMPLETED',
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
return session;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async function startSession(repository, binding, maxSteps) {
|
|
72
|
-
// Expired sessions are removed opportunistically; PostgreSQL has no TTL.
|
|
73
|
-
Promise.resolve()
|
|
74
|
-
.then(() => repository.deleteExpired())
|
|
75
|
-
.catch((error) =>
|
|
76
|
-
log.warn('Expired authorization sessions were not removed', {
|
|
77
|
-
eventName: `${log.name}.session_cleanup_failed`,
|
|
78
|
-
error,
|
|
79
|
-
})
|
|
80
|
-
);
|
|
81
|
-
return repository.create(AuthorizationSession.start({ ...binding, maxSteps }));
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* GET /api/v2/authorize (and GET /api/v2/credentials/:id/reauthorize): what
|
|
86
|
-
* the caller must submit next. A multi-step flow gets a session on step 1;
|
|
87
|
-
* later steps need that sessionId and must be the session's current step.
|
|
88
|
-
*/
|
|
89
|
-
class GetAuthorizationStep {
|
|
90
|
-
/**
|
|
91
|
-
* @param {Object} params
|
|
92
|
-
* @param {Array<Object>} params.moduleDefinitions
|
|
93
|
-
* @param {import('./get-authorization-requirements').GetAuthorizationRequirements} params.getAuthorizationRequirements
|
|
94
|
-
* @param {import('../repositories/authorization-session-repository-interface').AuthorizationSessionRepositoryInterface} params.authorizationSessionRepository
|
|
95
|
-
*/
|
|
96
|
-
constructor({ moduleDefinitions, getAuthorizationRequirements, authorizationSessionRepository }) {
|
|
97
|
-
this.moduleDefinitions = moduleDefinitions || [];
|
|
98
|
-
this.getAuthorizationRequirements = getAuthorizationRequirements;
|
|
99
|
-
this.sessions = authorizationSessionRepository;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async execute({ user, entityType, step = 1, sessionId, credentialId = null, state }) {
|
|
103
|
-
const definition = findDefinition(this.moduleDefinitions, entityType);
|
|
104
|
-
const userId = user.getId();
|
|
105
|
-
const requirementsFor = (n) =>
|
|
106
|
-
this.getAuthorizationRequirements.execute({ entityType, step: n, userId, state });
|
|
107
|
-
|
|
108
|
-
if (!isMultiStep(definition)) return requirementsFor(step);
|
|
109
|
-
|
|
110
|
-
const binding = { userId, entityType, credentialId };
|
|
111
|
-
let session;
|
|
112
|
-
if (sessionId) {
|
|
113
|
-
session = await loadSession(this.sessions, sessionId, binding);
|
|
114
|
-
if (step !== session.currentStep) {
|
|
115
|
-
throw Boom.conflict(
|
|
116
|
-
`This session expects step ${session.currentStep}`,
|
|
117
|
-
{ code: 'STEP_OUT_OF_ORDER', details: { expectedStep: session.currentStep } }
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
} else {
|
|
121
|
-
if (step !== 1) {
|
|
122
|
-
throw Boom.badRequest('sessionId is required after step 1', {
|
|
123
|
-
code: 'SESSION_REQUIRED',
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
session = await startSession(this.sessions, binding, getAuthStepCount(definition));
|
|
127
|
-
}
|
|
128
|
-
return { ...(await requirementsFor(step)), sessionId: session.sessionId };
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* POST /api/v2/authorize (and POST /api/v2/credentials/:id/reauthorize).
|
|
134
|
-
*
|
|
135
|
-
* Single-step modules complete at once through ProcessAuthorizationCallback
|
|
136
|
-
* (the v1 authorize logic). Multi-step modules run
|
|
137
|
-
* definition.processAuthorizationStep(api, step, data, stepData) per step;
|
|
138
|
-
* when it reports `completed`, its `authData` goes through the same
|
|
139
|
-
* callback. Returns either
|
|
140
|
-
* `{ status: 'complete', entity, credential }` (domain records; the handler
|
|
141
|
-
* masks them) or
|
|
142
|
-
* `{ status: 'pending', step, totalSteps, sessionId, requirements, message? }`.
|
|
143
|
-
*/
|
|
144
|
-
class SubmitAuthorizationStep {
|
|
145
|
-
constructor({
|
|
146
|
-
moduleDefinitions,
|
|
147
|
-
getAuthorizationRequirements,
|
|
148
|
-
authorizationSessionRepository,
|
|
149
|
-
authorizeEntityForUser,
|
|
150
|
-
moduleRepository,
|
|
151
|
-
credentialRepository,
|
|
152
|
-
createModule,
|
|
153
|
-
scopePolicy,
|
|
154
|
-
}) {
|
|
155
|
-
this.scopePolicy = scopePolicy || DEFAULT_SCOPE_POLICY;
|
|
156
|
-
this.moduleDefinitions = moduleDefinitions || [];
|
|
157
|
-
this.getAuthorizationRequirements = getAuthorizationRequirements;
|
|
158
|
-
this.sessions = authorizationSessionRepository;
|
|
159
|
-
this.authorizeEntityForUser = authorizeEntityForUser;
|
|
160
|
-
this.moduleRepository = moduleRepository;
|
|
161
|
-
this.credentialRepository = credentialRepository;
|
|
162
|
-
this.createModule = createModule || defaultCreateModule;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* @param {Object} params
|
|
167
|
-
* @param {string} [params.scope] - the scope the caller asks for, from the
|
|
168
|
-
* deciding level's allow list (ADR-056 §3.1). Never `global`.
|
|
169
|
-
* @param {string} [params.fixedScope] - re-authorization keeps the scope the
|
|
170
|
-
* credential already has, whatever the config says now.
|
|
171
|
-
*/
|
|
172
|
-
async execute({ user, entityType, data, step = 1, sessionId, credentialId = null, scope, fixedScope }) {
|
|
173
|
-
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
174
|
-
throw Boom.badRequest('data must be an object', {
|
|
175
|
-
code: 'VALIDATION_ERROR',
|
|
176
|
-
details: { field: 'data' },
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
const definition = findDefinition(this.moduleDefinitions, entityType);
|
|
180
|
-
// `userId` binds a session to the caller and is what GET /authorize
|
|
181
|
-
// computes too. The owner of the entity this creates is decided by
|
|
182
|
-
// scope (§3.2), not by user.primary, and is `ownership.ownerId`.
|
|
183
|
-
const userId = user.getId();
|
|
184
|
-
const ownership = this.authorizeEntityForUser.resolveOwnership({
|
|
185
|
-
user,
|
|
186
|
-
entityType,
|
|
187
|
-
scope,
|
|
188
|
-
fixedScope,
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
if (!isMultiStep(definition)) {
|
|
192
|
-
if (step !== 1) {
|
|
193
|
-
throw Boom.badRequest(`${entityType} has a single authorization step`, {
|
|
194
|
-
code: 'INVALID_STEP',
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
return this.complete({ ownership, user, entityType, params: data, credentialId });
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const totalSteps = getAuthStepCount(definition);
|
|
201
|
-
const binding = { userId, entityType, credentialId };
|
|
202
|
-
let session;
|
|
203
|
-
if (sessionId) {
|
|
204
|
-
session = await loadSession(this.sessions, sessionId, binding);
|
|
205
|
-
if (step === 1 && session.currentStep !== 1) {
|
|
206
|
-
session.restart();
|
|
207
|
-
} else if (step !== session.currentStep) {
|
|
208
|
-
throw Boom.conflict(`This session expects step ${session.currentStep}`, {
|
|
209
|
-
code: 'STEP_OUT_OF_ORDER',
|
|
210
|
-
details: { expectedStep: session.currentStep },
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
} else {
|
|
214
|
-
if (step !== 1) {
|
|
215
|
-
throw Boom.badRequest('sessionId is required after step 1', {
|
|
216
|
-
code: 'SESSION_REQUIRED',
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
session = await startSession(this.sessions, binding, totalSteps);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
if (typeof definition.processAuthorizationStep !== 'function') {
|
|
223
|
-
throw Boom.badImplementation(
|
|
224
|
-
`Module ${entityType} declares ${totalSteps} steps but no processAuthorizationStep`
|
|
225
|
-
);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const module = await this.createModule({ userId: ownership.ownerId, definition });
|
|
229
|
-
let result;
|
|
230
|
-
try {
|
|
231
|
-
result = await definition.processAuthorizationStep(
|
|
232
|
-
module.api,
|
|
233
|
-
step,
|
|
234
|
-
data,
|
|
235
|
-
session.stepData
|
|
236
|
-
);
|
|
237
|
-
} catch (error) {
|
|
238
|
-
// processAuthorizationStep errors are written for the end user
|
|
239
|
-
// (docs/MULTI_STEP_AUTH_MIGRATION_GUIDE.md), e.g. "Invalid code".
|
|
240
|
-
throw toAuthorizationError(error, { passMessage: true });
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (result?.completed) {
|
|
244
|
-
session.markComplete();
|
|
245
|
-
await this.sessions.update(session);
|
|
246
|
-
const outcome = await this.complete({
|
|
247
|
-
ownership,
|
|
248
|
-
user,
|
|
249
|
-
entityType,
|
|
250
|
-
params: result.authData || {},
|
|
251
|
-
credentialId,
|
|
252
|
-
});
|
|
253
|
-
// The collected data is no longer needed once the credential exists.
|
|
254
|
-
await Promise.resolve()
|
|
255
|
-
.then(() => this.sessions.deleteBySessionId(session.sessionId))
|
|
256
|
-
.catch(() => {});
|
|
257
|
-
return outcome;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const nextStep = result?.nextStep ?? step + 1;
|
|
261
|
-
try {
|
|
262
|
-
session.advanceTo(nextStep, result?.stepData);
|
|
263
|
-
} catch (error) {
|
|
264
|
-
throw Boom.badImplementation(
|
|
265
|
-
`Module ${entityType} returned an invalid next step: ${error.message}`
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
await this.sessions.update(session);
|
|
269
|
-
|
|
270
|
-
const requirements = await this.getAuthorizationRequirements.execute({
|
|
271
|
-
entityType,
|
|
272
|
-
step: nextStep,
|
|
273
|
-
userId,
|
|
274
|
-
});
|
|
275
|
-
return {
|
|
276
|
-
status: 'pending',
|
|
277
|
-
step: nextStep,
|
|
278
|
-
totalSteps,
|
|
279
|
-
sessionId: session.sessionId,
|
|
280
|
-
requirements,
|
|
281
|
-
...(result?.message && { message: String(result.message) }),
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
async complete({ ownership, user, entityType, params, credentialId }) {
|
|
286
|
-
let callback;
|
|
287
|
-
try {
|
|
288
|
-
({ result: callback } = await this.authorizeEntityForUser.execute({
|
|
289
|
-
user,
|
|
290
|
-
entityType,
|
|
291
|
-
data: params,
|
|
292
|
-
ownership,
|
|
293
|
-
}));
|
|
294
|
-
} catch (error) {
|
|
295
|
-
throw toAuthorizationError(error);
|
|
296
|
-
}
|
|
297
|
-
const [entity, credential] = await Promise.all([
|
|
298
|
-
this.moduleRepository.findEntityById(callback.entity_id),
|
|
299
|
-
this.credentialRepository.findCredentialById(callback.credential_id),
|
|
300
|
-
]);
|
|
301
|
-
// What the new entity is to this caller (§3.4), so a client need not list again.
|
|
302
|
-
const tenancy = entity
|
|
303
|
-
? describeRecord(entity, this.scopePolicy.accessContext(user), 'entity')
|
|
304
|
-
: null;
|
|
305
|
-
const outcome = {
|
|
306
|
-
status: 'complete',
|
|
307
|
-
entity: entity && tenancy ? { ...entity, tenancy } : entity,
|
|
308
|
-
credential: credential && {
|
|
309
|
-
...credential,
|
|
310
|
-
type: entityType,
|
|
311
|
-
entityIds: entity ? [String(entity.id)] : [],
|
|
312
|
-
...(tenancy && { tenancy }),
|
|
313
|
-
},
|
|
314
|
-
};
|
|
315
|
-
if (credentialId && String(callback.credential_id) !== String(credentialId)) {
|
|
316
|
-
// The provider account differs from the one being re-authorized,
|
|
317
|
-
// so a separate credential was stored.
|
|
318
|
-
outcome.previousCredentialId = String(credentialId);
|
|
319
|
-
}
|
|
320
|
-
return outcome;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
module.exports = {
|
|
325
|
-
GetAuthorizationStep,
|
|
326
|
-
SubmitAuthorizationStep,
|
|
327
|
-
toAuthorizationError,
|
|
328
|
-
isMultiStep,
|
|
329
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
-- CreateTable
|
|
2
|
-
-- Multi-step authorization state for Management API v2 (/api/v2/authorize).
|
|
3
|
-
-- Short-lived rows; "stepData" is encrypted at rest by the application.
|
|
4
|
-
CREATE TABLE "AuthorizationSession" (
|
|
5
|
-
"id" SERIAL NOT NULL,
|
|
6
|
-
"sessionId" TEXT NOT NULL,
|
|
7
|
-
"userId" TEXT NOT NULL,
|
|
8
|
-
"entityType" TEXT NOT NULL,
|
|
9
|
-
"credentialId" TEXT,
|
|
10
|
-
"currentStep" INTEGER NOT NULL DEFAULT 1,
|
|
11
|
-
"maxSteps" INTEGER NOT NULL,
|
|
12
|
-
"stepData" JSONB NOT NULL DEFAULT '{}',
|
|
13
|
-
"expiresAt" TIMESTAMP(3) NOT NULL,
|
|
14
|
-
"completed" BOOLEAN NOT NULL DEFAULT false,
|
|
15
|
-
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
16
|
-
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
17
|
-
|
|
18
|
-
CONSTRAINT "AuthorizationSession_pkey" PRIMARY KEY ("id")
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
-- CreateIndex
|
|
22
|
-
CREATE UNIQUE INDEX "AuthorizationSession_sessionId_key" ON "AuthorizationSession"("sessionId");
|
|
23
|
-
|
|
24
|
-
-- CreateIndex
|
|
25
|
-
CREATE INDEX "AuthorizationSession_userId_entityType_idx" ON "AuthorizationSession"("userId", "entityType");
|
|
26
|
-
|
|
27
|
-
-- CreateIndex
|
|
28
|
-
CREATE INDEX "AuthorizationSession_expiresAt_idx" ON "AuthorizationSession"("expiresAt");
|
package/prisma-postgresql/migrations/20261015000000_add_organization_membership/migration.sql
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
-- CreateTable
|
|
2
|
-
-- Organization memberships (ADR-056 §3.6). One row per person per organization.
|
|
3
|
-
-- "User"."organizationId" stays as the legacy single-org pointer. It is NOT
|
|
4
|
-
-- backfilled into this table: the domain (user/membership.js) reads it as an
|
|
5
|
-
-- implicit membership when no row exists (see docs/guides/organization-memberships.md).
|
|
6
|
-
CREATE TABLE "OrganizationMembership" (
|
|
7
|
-
"id" SERIAL NOT NULL,
|
|
8
|
-
"individualUserId" INTEGER NOT NULL,
|
|
9
|
-
"organizationUserId" INTEGER NOT NULL,
|
|
10
|
-
"orgRole" TEXT NOT NULL DEFAULT 'MEMBER',
|
|
11
|
-
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
12
|
-
|
|
13
|
-
CONSTRAINT "OrganizationMembership_pkey" PRIMARY KEY ("id")
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
-- CreateIndex
|
|
17
|
-
CREATE INDEX "OrganizationMembership_organizationUserId_idx" ON "OrganizationMembership"("organizationUserId");
|
|
18
|
-
|
|
19
|
-
-- CreateIndex
|
|
20
|
-
CREATE UNIQUE INDEX "OrganizationMembership_individualUserId_organizationUserId_key" ON "OrganizationMembership"("individualUserId", "organizationUserId");
|
|
21
|
-
|
|
22
|
-
-- AddForeignKey
|
|
23
|
-
ALTER TABLE "OrganizationMembership" ADD CONSTRAINT "OrganizationMembership_individualUserId_fkey" FOREIGN KEY ("individualUserId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
|
|
24
|
-
|
|
25
|
-
-- AddForeignKey
|
|
26
|
-
ALTER TABLE "OrganizationMembership" ADD CONSTRAINT "OrganizationMembership_organizationUserId_fkey" FOREIGN KEY ("organizationUserId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE NO ACTION;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
-- Entity and Integration carry the organization they were created in (ADR-056 §3.6).
|
|
2
|
-
-- Nullable, no default and no backfill: a row written before this migration keeps
|
|
3
|
-
-- NULL, and the domain (modules/entity-scope.js) reads NULL as "predates scoping"
|
|
4
|
-
-- (docs/guides/entity-scopes.md). No scope column: the owner's user type says it.
|
|
5
|
-
-- Deliberately no foreign key: a deleted organization must leave its rows
|
|
6
|
-
-- invisible, and ON DELETE SET NULL would turn them into unscoped ones.
|
|
7
|
-
--
|
|
8
|
-
-- Release note: the two CREATE INDEX statements below are plain (not
|
|
9
|
-
-- CONCURRENTLY, which Prisma migrations cannot run inside a transaction). Each
|
|
10
|
-
-- takes a SHARE lock on its table while it builds, so writes to "Entity" and
|
|
11
|
-
-- "Integration" wait for it. Both tables are small in a typical Frigg
|
|
12
|
-
-- deployment; on a very large one, create the indexes by hand first with
|
|
13
|
-
-- CREATE INDEX CONCURRENTLY IF NOT EXISTS under the same names, then deploy.
|
|
14
|
-
|
|
15
|
-
-- AlterTable
|
|
16
|
-
ALTER TABLE "Entity" ADD COLUMN "organizationId" INTEGER;
|
|
17
|
-
|
|
18
|
-
-- AlterTable
|
|
19
|
-
ALTER TABLE "Integration" ADD COLUMN "organizationId" INTEGER;
|
|
20
|
-
|
|
21
|
-
-- CreateIndex
|
|
22
|
-
CREATE INDEX "Entity_userId_organizationId_idx" ON "Entity"("userId", "organizationId");
|
|
23
|
-
|
|
24
|
-
-- CreateIndex
|
|
25
|
-
CREATE INDEX "Integration_userId_organizationId_idx" ON "Integration"("userId", "organizationId");
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
-- One-time scheduled jobs for the poll-and-dispatch scheduler
|
|
2
|
-
-- (NetlifySchedulerAdapter, friggframework/frigg#545): a cron function reads
|
|
3
|
-
-- PENDING rows that are due and dispatches them to a queue.
|
|
4
|
-
--
|
|
5
|
-
-- IF NOT EXISTS on purpose: #545 shipped this model in the Prisma schema with
|
|
6
|
-
-- no migration, so an app that ran its canary may already have the table from
|
|
7
|
-
-- `prisma db push`. On such a database this migration is a no-op; on a fresh
|
|
8
|
-
-- one it is the SQL `prisma migrate diff` generates.
|
|
9
|
-
|
|
10
|
-
-- CreateTable
|
|
11
|
-
CREATE TABLE IF NOT EXISTS "ScheduledJob" (
|
|
12
|
-
"id" SERIAL NOT NULL,
|
|
13
|
-
"scheduleName" TEXT NOT NULL,
|
|
14
|
-
"scheduledAt" TIMESTAMP(3) NOT NULL,
|
|
15
|
-
"queueResourceId" TEXT NOT NULL,
|
|
16
|
-
"payload" JSONB,
|
|
17
|
-
"state" TEXT NOT NULL DEFAULT 'PENDING',
|
|
18
|
-
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
19
|
-
"updatedAt" TIMESTAMP(3) NOT NULL,
|
|
20
|
-
|
|
21
|
-
CONSTRAINT "ScheduledJob_pkey" PRIMARY KEY ("id")
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
-- CreateIndex
|
|
25
|
-
CREATE UNIQUE INDEX IF NOT EXISTS "ScheduledJob_scheduleName_key" ON "ScheduledJob"("scheduleName");
|
|
26
|
-
|
|
27
|
-
-- CreateIndex
|
|
28
|
-
CREATE INDEX IF NOT EXISTS "ScheduledJob_state_scheduledAt_idx" ON "ScheduledJob"("state", "scheduledAt");
|
package/providers/index.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
resolveProvider,
|
|
3
|
-
determineProviderName,
|
|
4
|
-
providerPackageName,
|
|
5
|
-
KNOWN_PROVIDERS,
|
|
6
|
-
} = require('./resolve-provider');
|
|
7
|
-
const {
|
|
8
|
-
isDeployedRuntime,
|
|
9
|
-
isAwsLambdaRuntime,
|
|
10
|
-
isLocalRun,
|
|
11
|
-
resolveActiveProvider,
|
|
12
|
-
} = require('./runtime-detection');
|
|
13
|
-
|
|
14
|
-
module.exports = {
|
|
15
|
-
resolveProvider,
|
|
16
|
-
determineProviderName,
|
|
17
|
-
providerPackageName,
|
|
18
|
-
KNOWN_PROVIDERS,
|
|
19
|
-
isDeployedRuntime,
|
|
20
|
-
isAwsLambdaRuntime,
|
|
21
|
-
isLocalRun,
|
|
22
|
-
resolveActiveProvider,
|
|
23
|
-
};
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provider Resolver
|
|
3
|
-
*
|
|
4
|
-
* Resolves a provider name from the appDefinition into the corresponding
|
|
5
|
-
* @friggframework/provider-{name} package. This is the bridge between
|
|
6
|
-
* `appDefinition.provider` and the provider plugin interface.
|
|
7
|
-
*
|
|
8
|
-
* Resolution order:
|
|
9
|
-
* 1. Explicit `providerName` argument
|
|
10
|
-
* 2. `appDefinition.provider`
|
|
11
|
-
* 3. `FRIGG_PROVIDER` environment variable
|
|
12
|
-
* 4. Default: 'aws'
|
|
13
|
-
*
|
|
14
|
-
* Package naming convention:
|
|
15
|
-
* provider: 'netlify' → require('@friggframework/provider-netlify')
|
|
16
|
-
* provider: 'aws' → require('@friggframework/provider-aws')
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* const provider = resolveProvider({ provider: 'netlify' });
|
|
20
|
-
* // provider.name === 'netlify'
|
|
21
|
-
* // provider.deploy(appDefinition, options)
|
|
22
|
-
* // provider.createHandler(options)
|
|
23
|
-
* // provider.QueueProvider (class)
|
|
24
|
-
* // etc.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
const KNOWN_PROVIDERS = ['aws', 'netlify'];
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Determine the provider name from available sources.
|
|
31
|
-
*
|
|
32
|
-
* @param {Object} [appDefinition] - Frigg app definition
|
|
33
|
-
* @param {string} [providerName] - Explicit override
|
|
34
|
-
* @returns {string} Provider name (e.g. 'netlify', 'aws')
|
|
35
|
-
*/
|
|
36
|
-
function determineProviderName(appDefinition, providerName) {
|
|
37
|
-
if (providerName) {
|
|
38
|
-
return providerName;
|
|
39
|
-
}
|
|
40
|
-
if (appDefinition?.provider) {
|
|
41
|
-
return appDefinition.provider;
|
|
42
|
-
}
|
|
43
|
-
if (process.env.FRIGG_PROVIDER) {
|
|
44
|
-
return process.env.FRIGG_PROVIDER;
|
|
45
|
-
}
|
|
46
|
-
return 'aws';
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Resolve a provider name to a package name.
|
|
51
|
-
*
|
|
52
|
-
* @param {string} name - Provider name (e.g. 'netlify')
|
|
53
|
-
* @returns {string} npm package name (e.g. '@friggframework/provider-netlify')
|
|
54
|
-
*/
|
|
55
|
-
function providerPackageName(name) {
|
|
56
|
-
return `@friggframework/provider-${name}`;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Resolve and load the provider plugin for the given app definition.
|
|
61
|
-
*
|
|
62
|
-
* @param {Object} [appDefinition] - Frigg app definition (reads .provider)
|
|
63
|
-
* @param {Object} [options]
|
|
64
|
-
* @param {string} [options.provider] - Explicit provider name override
|
|
65
|
-
* @returns {Object} Provider plugin (conforms to the provider plugin interface)
|
|
66
|
-
* @throws {Error} If the provider package is not installed
|
|
67
|
-
*/
|
|
68
|
-
function resolveProvider(appDefinition, options = {}) {
|
|
69
|
-
const name = determineProviderName(appDefinition, options.provider);
|
|
70
|
-
const packageName = providerPackageName(name);
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
return require(packageName);
|
|
74
|
-
} catch (error) {
|
|
75
|
-
if (error.code === 'MODULE_NOT_FOUND') {
|
|
76
|
-
const hint = KNOWN_PROVIDERS.includes(name)
|
|
77
|
-
? `Install it with: npm install ${packageName}`
|
|
78
|
-
: `Is '${name}' a valid Frigg provider? Known providers: ${KNOWN_PROVIDERS.join(', ')}`;
|
|
79
|
-
|
|
80
|
-
throw new Error(
|
|
81
|
-
`Provider '${name}' specified in appDefinition but package '${packageName}' is not installed.\n ${hint}`
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
throw error;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
module.exports = {
|
|
89
|
-
resolveProvider,
|
|
90
|
-
determineProviderName,
|
|
91
|
-
providerPackageName,
|
|
92
|
-
KNOWN_PROVIDERS,
|
|
93
|
-
};
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Deployed-runtime detection, provider-aware.
|
|
3
|
-
*
|
|
4
|
-
* "Deployed" decides whether a missing secret may be tolerated: a deployed
|
|
5
|
-
* function must fail closed whatever STAGE says, while a laptop, a test run or
|
|
6
|
-
* a local emulator may run in development mode. Reading only AWS Lambda's
|
|
7
|
-
* variables (AWS_LAMBDA_FUNCTION_NAME, LAMBDA_TASK_ROOT, AWS_EXECUTION_ENV)
|
|
8
|
-
* makes every other host look local: a Netlify Function with STAGE=dev would
|
|
9
|
-
* be treated like `frigg start`.
|
|
10
|
-
*
|
|
11
|
-
* So the active provider is asked as well. The provider is the app
|
|
12
|
-
* definition's `provider` or FRIGG_PROVIDER (which provider-netlify's
|
|
13
|
-
* generated function entry points set to 'netlify'), resolved to its
|
|
14
|
-
* @friggframework/provider-<name> package, and its `detect(env)` says whether
|
|
15
|
-
* the process runs on that platform.
|
|
16
|
-
*
|
|
17
|
-
* A local run is never deployed: serverless-offline / `serverless invoke
|
|
18
|
-
* local` (IS_OFFLINE, IS_LOCAL), `netlify dev` (NETLIFY_DEV=true) and Jest
|
|
19
|
-
* (JEST_WORKER_ID).
|
|
20
|
-
*/
|
|
21
|
-
const { resolveProvider } = require('./resolve-provider');
|
|
22
|
-
|
|
23
|
-
function isSet(value) {
|
|
24
|
-
return typeof value === 'string' && value.trim() !== '';
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function isTrue(value) {
|
|
28
|
-
if (typeof value !== 'string') return false;
|
|
29
|
-
const normalized = value.trim().toLowerCase();
|
|
30
|
-
return normalized === 'true' || normalized === '1';
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* @param {Object} [env=process.env]
|
|
35
|
-
* @returns {boolean} true under a local emulator or test runner
|
|
36
|
-
*/
|
|
37
|
-
function isLocalRun(env = process.env) {
|
|
38
|
-
return (
|
|
39
|
-
isTrue(env.IS_OFFLINE) ||
|
|
40
|
-
isTrue(env.IS_LOCAL) ||
|
|
41
|
-
isTrue(env.NETLIFY_DEV) ||
|
|
42
|
-
isSet(env.JEST_WORKER_ID)
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* The AWS Lambda runtime sets AWS_LAMBDA_FUNCTION_NAME, LAMBDA_TASK_ROOT and
|
|
48
|
-
* AWS_EXECUTION_ENV (AWS_Lambda_<runtime>).
|
|
49
|
-
*
|
|
50
|
-
* @param {Object} [env=process.env]
|
|
51
|
-
* @returns {boolean}
|
|
52
|
-
*/
|
|
53
|
-
function isAwsLambdaRuntime(env = process.env) {
|
|
54
|
-
return (
|
|
55
|
-
isSet(env.AWS_LAMBDA_FUNCTION_NAME) ||
|
|
56
|
-
isSet(env.LAMBDA_TASK_ROOT) ||
|
|
57
|
-
String(env.AWS_EXECUTION_ENV ?? '').startsWith('AWS_Lambda_')
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* The provider plugin of the running app, or null for AWS (covered by
|
|
63
|
-
* isAwsLambdaRuntime) or when no provider is named or its package is absent.
|
|
64
|
-
*
|
|
65
|
-
* @param {Object} [env=process.env]
|
|
66
|
-
* @param {Object} [options]
|
|
67
|
-
* @param {Object} [options.appDefinition]
|
|
68
|
-
* @param {Function} [options.resolve=resolveProvider]
|
|
69
|
-
* @returns {Object|null}
|
|
70
|
-
*/
|
|
71
|
-
function resolveActiveProvider(env = process.env, { appDefinition, resolve = resolveProvider } = {}) {
|
|
72
|
-
const name = appDefinition?.provider || env.FRIGG_PROVIDER;
|
|
73
|
-
if (!isSet(name) || name === 'aws') return null;
|
|
74
|
-
try {
|
|
75
|
-
return resolve(null, { provider: name });
|
|
76
|
-
} catch (_) {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* True when the process runs as a deployed function on AWS Lambda or on the
|
|
83
|
-
* active provider's platform, and not under a local emulator or test runner.
|
|
84
|
-
*
|
|
85
|
-
* @param {Object} [env=process.env]
|
|
86
|
-
* @param {Object} [options]
|
|
87
|
-
* @param {Object} [options.provider] - provider plugin to ask (default: the active one)
|
|
88
|
-
* @param {Object} [options.appDefinition] - reads `provider`
|
|
89
|
-
* @returns {boolean}
|
|
90
|
-
*/
|
|
91
|
-
function isDeployedRuntime(env = process.env, { provider, appDefinition } = {}) {
|
|
92
|
-
if (isLocalRun(env)) return false;
|
|
93
|
-
if (isAwsLambdaRuntime(env)) return true;
|
|
94
|
-
if (provider === undefined) {
|
|
95
|
-
// A named non-AWS provider whose package cannot be loaded (or has no
|
|
96
|
-
// detect()) cannot say where we run. Fail closed: provider-netlify's
|
|
97
|
-
// generated entry points set FRIGG_PROVIDER, so treating that as local
|
|
98
|
-
// would let a deployed function accept unsigned queue messages.
|
|
99
|
-
const name = appDefinition?.provider || env.FRIGG_PROVIDER;
|
|
100
|
-
if (isSet(name) && name !== 'aws') {
|
|
101
|
-
const active = resolveActiveProvider(env, { appDefinition });
|
|
102
|
-
if (!active || typeof active.detect !== 'function') return true;
|
|
103
|
-
return askProvider(active, env, true);
|
|
104
|
-
}
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
if (!provider || typeof provider.detect !== 'function') return false;
|
|
108
|
-
return askProvider(provider, env, false);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function askProvider(active, env, onError) {
|
|
112
|
-
try {
|
|
113
|
-
return active.detect(env) === true;
|
|
114
|
-
} catch (_) {
|
|
115
|
-
return onError;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
module.exports = {
|
|
120
|
-
isDeployedRuntime,
|
|
121
|
-
isAwsLambdaRuntime,
|
|
122
|
-
isLocalRun,
|
|
123
|
-
resolveActiveProvider,
|
|
124
|
-
};
|