@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,7 +1,5 @@
|
|
|
1
1
|
const { prisma } = require('../../database/prisma');
|
|
2
|
-
const { organizationWhere } = require('../../database/organization-where');
|
|
3
2
|
const { ModuleRepositoryInterface } = require('./module-repository-interface');
|
|
4
|
-
const { entityNotFoundError } = require('./entity-not-found');
|
|
5
3
|
|
|
6
4
|
/**
|
|
7
5
|
* MongoDB Module Repository Adapter
|
|
@@ -78,26 +76,6 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
78
76
|
return credentialMap;
|
|
79
77
|
}
|
|
80
78
|
|
|
81
|
-
/**
|
|
82
|
-
* The one place a stored entity row becomes the entity the application sees.
|
|
83
|
-
* The provider's `data` is spread FIRST and every column is pinned after it:
|
|
84
|
-
* a stored `id`, `userId` or `organizationId` in `data` must not decide who
|
|
85
|
-
* owns the entity or who sees it.
|
|
86
|
-
* @private
|
|
87
|
-
*/
|
|
88
|
-
_mapEntity(row, credential) {
|
|
89
|
-
return {
|
|
90
|
-
...(row.data || {}),
|
|
91
|
-
id: row.id,
|
|
92
|
-
credential,
|
|
93
|
-
userId: row.userId,
|
|
94
|
-
name: row.name,
|
|
95
|
-
externalId: row.externalId,
|
|
96
|
-
moduleName: row.moduleName,
|
|
97
|
-
organizationId: row.organizationId ?? null,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
|
|
101
79
|
/**
|
|
102
80
|
* Find entity by ID with credential
|
|
103
81
|
* Replaces: Entity.findById(entityId).populate('credential')
|
|
@@ -112,12 +90,20 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
112
90
|
});
|
|
113
91
|
|
|
114
92
|
if (!entity) {
|
|
115
|
-
throw
|
|
93
|
+
throw new Error(`Entity ${entityId} not found`);
|
|
116
94
|
}
|
|
117
95
|
|
|
118
96
|
const credential = await this._fetchCredential(entity.credentialId);
|
|
119
97
|
|
|
120
|
-
return
|
|
98
|
+
return {
|
|
99
|
+
id: entity.id,
|
|
100
|
+
credential,
|
|
101
|
+
userId: entity.userId,
|
|
102
|
+
name: entity.name,
|
|
103
|
+
externalId: entity.externalId,
|
|
104
|
+
moduleName: entity.moduleName,
|
|
105
|
+
...(entity.data || {}),
|
|
106
|
+
};
|
|
121
107
|
}
|
|
122
108
|
|
|
123
109
|
/**
|
|
@@ -135,7 +121,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
135
121
|
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
136
122
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
137
123
|
|
|
138
|
-
return entities.map((e) => (
|
|
124
|
+
return entities.map((e) => ({
|
|
125
|
+
id: e.id,
|
|
126
|
+
credential: credentialMap.get(e.credentialId) || null,
|
|
127
|
+
userId: e.userId,
|
|
128
|
+
name: e.name,
|
|
129
|
+
externalId: e.externalId,
|
|
130
|
+
moduleName: e.moduleName,
|
|
131
|
+
...(e.data || {}),
|
|
132
|
+
}));
|
|
139
133
|
}
|
|
140
134
|
|
|
141
135
|
/**
|
|
@@ -153,7 +147,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
153
147
|
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
154
148
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
155
149
|
|
|
156
|
-
return entities.map((e) => (
|
|
150
|
+
return entities.map((e) => ({
|
|
151
|
+
id: e.id,
|
|
152
|
+
credential: credentialMap.get(e.credentialId) || null,
|
|
153
|
+
userId: e.userId,
|
|
154
|
+
name: e.name,
|
|
155
|
+
externalId: e.externalId,
|
|
156
|
+
moduleName: e.moduleName,
|
|
157
|
+
...(e.data || {}),
|
|
158
|
+
}));
|
|
157
159
|
}
|
|
158
160
|
|
|
159
161
|
/**
|
|
@@ -175,32 +177,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
175
177
|
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
176
178
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
177
179
|
|
|
178
|
-
return entities.map((e) => (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
* @returns {Promise<Array>} Array of entity objects with string IDs
|
|
188
|
-
*/
|
|
189
|
-
async findEntitiesByOwnership(clauses) {
|
|
190
|
-
if (!Array.isArray(clauses) || clauses.length === 0) return [];
|
|
191
|
-
const entities = await this.prisma.entity.findMany({
|
|
192
|
-
where: {
|
|
193
|
-
OR: clauses.map(({ userId, organizationId }) => ({
|
|
194
|
-
userId,
|
|
195
|
-
...organizationWhere(organizationId),
|
|
196
|
-
})),
|
|
197
|
-
},
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
201
|
-
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
202
|
-
|
|
203
|
-
return entities.map((e) => (this._mapEntity(e, credentialMap.get(e.credentialId) || null)));
|
|
180
|
+
return entities.map((e) => ({
|
|
181
|
+
id: e.id,
|
|
182
|
+
credential: credentialMap.get(e.credentialId) || null,
|
|
183
|
+
userId: e.userId,
|
|
184
|
+
name: e.name,
|
|
185
|
+
externalId: e.externalId,
|
|
186
|
+
moduleName: e.moduleName,
|
|
187
|
+
...(e.data || {}),
|
|
188
|
+
}));
|
|
204
189
|
}
|
|
205
190
|
|
|
206
191
|
/**
|
|
@@ -238,7 +223,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
238
223
|
|
|
239
224
|
const credential = await this._fetchCredential(entity.credentialId);
|
|
240
225
|
|
|
241
|
-
return
|
|
226
|
+
return {
|
|
227
|
+
id: entity.id,
|
|
228
|
+
credential,
|
|
229
|
+
userId: entity.userId,
|
|
230
|
+
name: entity.name,
|
|
231
|
+
externalId: entity.externalId,
|
|
232
|
+
moduleName: entity.moduleName,
|
|
233
|
+
...(entity.data || {}),
|
|
234
|
+
};
|
|
242
235
|
}
|
|
243
236
|
|
|
244
237
|
/**
|
|
@@ -258,7 +251,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
258
251
|
.filter(Boolean);
|
|
259
252
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
260
253
|
|
|
261
|
-
return entities.map((e) => (
|
|
254
|
+
return entities.map((e) => ({
|
|
255
|
+
id: e.id,
|
|
256
|
+
credential: credentialMap.get(e.credentialId) || null,
|
|
257
|
+
userId: e.userId,
|
|
258
|
+
name: e.name,
|
|
259
|
+
externalId: e.externalId,
|
|
260
|
+
moduleName: e.moduleName,
|
|
261
|
+
...(e.data || {}),
|
|
262
|
+
}));
|
|
262
263
|
}
|
|
263
264
|
|
|
264
265
|
/**
|
|
@@ -266,13 +267,9 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
266
267
|
* Replaces: Entity.create(entityData)
|
|
267
268
|
*
|
|
268
269
|
* @param {Object} entityData - Entity data
|
|
269
|
-
* @param {{organizationId?: (string|null)}} [tenancy] - the organization the entity
|
|
270
|
-
* belongs to (ADR-056 §3.6). A separate argument, not a field of `entityData`,
|
|
271
|
-
* because `entityData` carries provider fields and one named `organizationId`
|
|
272
|
-
* must not be taken for ours.
|
|
273
270
|
* @returns {Promise<Object>} Created entity object with string IDs
|
|
274
271
|
*/
|
|
275
|
-
async createEntity(entityData
|
|
272
|
+
async createEntity(entityData) {
|
|
276
273
|
const {
|
|
277
274
|
user,
|
|
278
275
|
userId,
|
|
@@ -290,7 +287,6 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
290
287
|
name,
|
|
291
288
|
moduleName,
|
|
292
289
|
externalId,
|
|
293
|
-
organizationId: tenancy.organizationId ?? null,
|
|
294
290
|
data: dynamicData,
|
|
295
291
|
};
|
|
296
292
|
|
|
@@ -300,7 +296,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
300
296
|
|
|
301
297
|
const credentialObj = await this._fetchCredential(entity.credentialId);
|
|
302
298
|
|
|
303
|
-
return
|
|
299
|
+
return {
|
|
300
|
+
id: entity.id,
|
|
301
|
+
credential: credentialObj,
|
|
302
|
+
userId: entity.userId,
|
|
303
|
+
name: entity.name,
|
|
304
|
+
externalId: entity.externalId,
|
|
305
|
+
moduleName: entity.moduleName,
|
|
306
|
+
...(entity.data || {}),
|
|
307
|
+
};
|
|
304
308
|
}
|
|
305
309
|
|
|
306
310
|
/**
|
|
@@ -354,7 +358,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
354
358
|
|
|
355
359
|
const credentialObj = await this._fetchCredential(entity.credentialId);
|
|
356
360
|
|
|
357
|
-
return
|
|
361
|
+
return {
|
|
362
|
+
id: entity.id,
|
|
363
|
+
credential: credentialObj,
|
|
364
|
+
userId: entity.userId,
|
|
365
|
+
name: entity.name,
|
|
366
|
+
externalId: entity.externalId,
|
|
367
|
+
moduleName: entity.moduleName,
|
|
368
|
+
...(entity.data || {}),
|
|
369
|
+
};
|
|
358
370
|
} catch (error) {
|
|
359
371
|
if (error.code === 'P2025') {
|
|
360
372
|
return null;
|
|
@@ -417,11 +429,6 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
417
429
|
if (filter.moduleName) where.moduleName = filter.moduleName;
|
|
418
430
|
if (filter.externalId) where.externalId = this._toString(filter.externalId);
|
|
419
431
|
|
|
420
|
-
// `null` means "no organization"; absent means "any".
|
|
421
|
-
if (filter.organizationId !== undefined) {
|
|
422
|
-
Object.assign(where, organizationWhere(filter.organizationId));
|
|
423
|
-
}
|
|
424
|
-
|
|
425
432
|
return where;
|
|
426
433
|
}
|
|
427
434
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const { prisma } = require('../../database/prisma');
|
|
2
2
|
const { ModuleRepositoryInterface } = require('./module-repository-interface');
|
|
3
|
-
const { entityNotFoundError } = require('./entity-not-found');
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* PostgreSQL Module Repository Adapter
|
|
@@ -109,26 +108,6 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
109
108
|
return credentialMap;
|
|
110
109
|
}
|
|
111
110
|
|
|
112
|
-
/**
|
|
113
|
-
* The one place a stored entity row becomes the entity the application sees.
|
|
114
|
-
* The provider's `data` is spread FIRST and every column is pinned after it:
|
|
115
|
-
* a stored `id`, `userId` or `organizationId` in `data` must not decide who
|
|
116
|
-
* owns the entity or who sees it.
|
|
117
|
-
* @private
|
|
118
|
-
*/
|
|
119
|
-
_mapEntity(row, credential) {
|
|
120
|
-
return {
|
|
121
|
-
...(row.data || {}),
|
|
122
|
-
id: row.id.toString(),
|
|
123
|
-
credential,
|
|
124
|
-
userId: row.userId?.toString(),
|
|
125
|
-
name: row.name,
|
|
126
|
-
externalId: row.externalId,
|
|
127
|
-
moduleName: row.moduleName,
|
|
128
|
-
organizationId: row.organizationId?.toString() ?? null,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
|
|
132
111
|
/**
|
|
133
112
|
* Find entity by ID with credential
|
|
134
113
|
* Replaces: Entity.findById(entityId).populate('credential')
|
|
@@ -145,12 +124,20 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
145
124
|
});
|
|
146
125
|
|
|
147
126
|
if (!entity) {
|
|
148
|
-
throw
|
|
127
|
+
throw new Error(`Entity ${entityId} not found`);
|
|
149
128
|
}
|
|
150
129
|
|
|
151
130
|
const credential = await this._fetchCredential(entity.credentialId);
|
|
152
131
|
|
|
153
|
-
return
|
|
132
|
+
return {
|
|
133
|
+
id: entity.id.toString(),
|
|
134
|
+
credential,
|
|
135
|
+
userId: entity.userId?.toString(),
|
|
136
|
+
name: entity.name,
|
|
137
|
+
externalId: entity.externalId,
|
|
138
|
+
moduleName: entity.moduleName,
|
|
139
|
+
...(entity.data || {}),
|
|
140
|
+
};
|
|
154
141
|
}
|
|
155
142
|
|
|
156
143
|
/**
|
|
@@ -170,7 +157,15 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
170
157
|
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
171
158
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
172
159
|
|
|
173
|
-
return entities.map((e) => (
|
|
160
|
+
return entities.map((e) => ({
|
|
161
|
+
id: e.id.toString(),
|
|
162
|
+
credential: credentialMap.get(e.credentialId) || null,
|
|
163
|
+
userId: e.userId?.toString(),
|
|
164
|
+
name: e.name,
|
|
165
|
+
externalId: e.externalId,
|
|
166
|
+
moduleName: e.moduleName,
|
|
167
|
+
...(e.data || {}),
|
|
168
|
+
}));
|
|
174
169
|
}
|
|
175
170
|
|
|
176
171
|
/**
|
|
@@ -190,7 +185,15 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
190
185
|
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
191
186
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
192
187
|
|
|
193
|
-
return entities.map((e) => (
|
|
188
|
+
return entities.map((e) => ({
|
|
189
|
+
id: e.id.toString(),
|
|
190
|
+
credential: credentialMap.get(e.credentialId) || null,
|
|
191
|
+
userId: e.userId?.toString(),
|
|
192
|
+
name: e.name,
|
|
193
|
+
externalId: e.externalId,
|
|
194
|
+
moduleName: e.moduleName,
|
|
195
|
+
...(e.data || {}),
|
|
196
|
+
}));
|
|
194
197
|
}
|
|
195
198
|
|
|
196
199
|
/**
|
|
@@ -214,32 +217,15 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
214
217
|
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
215
218
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
216
219
|
|
|
217
|
-
return entities.map((e) => (
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
* @returns {Promise<Array>} Array of entity objects with string IDs
|
|
227
|
-
*/
|
|
228
|
-
async findEntitiesByOwnership(clauses) {
|
|
229
|
-
if (!Array.isArray(clauses) || clauses.length === 0) return [];
|
|
230
|
-
const entities = await this.prisma.entity.findMany({
|
|
231
|
-
where: {
|
|
232
|
-
OR: clauses.map(({ userId, organizationId }) => ({
|
|
233
|
-
userId: this._convertId(userId),
|
|
234
|
-
organizationId: this._convertId(organizationId),
|
|
235
|
-
})),
|
|
236
|
-
},
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
240
|
-
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
241
|
-
|
|
242
|
-
return entities.map((e) => (this._mapEntity(e, credentialMap.get(e.credentialId) || null)));
|
|
220
|
+
return entities.map((e) => ({
|
|
221
|
+
id: e.id.toString(),
|
|
222
|
+
credential: credentialMap.get(e.credentialId) || null,
|
|
223
|
+
userId: e.userId?.toString(),
|
|
224
|
+
name: e.name,
|
|
225
|
+
externalId: e.externalId,
|
|
226
|
+
moduleName: e.moduleName,
|
|
227
|
+
...(e.data || {}),
|
|
228
|
+
}));
|
|
243
229
|
}
|
|
244
230
|
|
|
245
231
|
/**
|
|
@@ -278,7 +264,15 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
278
264
|
|
|
279
265
|
const credential = await this._fetchCredential(entity.credentialId);
|
|
280
266
|
|
|
281
|
-
return
|
|
267
|
+
return {
|
|
268
|
+
id: entity.id.toString(),
|
|
269
|
+
credential,
|
|
270
|
+
userId: entity.userId?.toString(),
|
|
271
|
+
name: entity.name,
|
|
272
|
+
externalId: entity.externalId,
|
|
273
|
+
moduleName: entity.moduleName,
|
|
274
|
+
...(entity.data || {}),
|
|
275
|
+
};
|
|
282
276
|
}
|
|
283
277
|
|
|
284
278
|
/**
|
|
@@ -298,7 +292,15 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
298
292
|
.filter(Boolean);
|
|
299
293
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
300
294
|
|
|
301
|
-
return entities.map((e) => (
|
|
295
|
+
return entities.map((e) => ({
|
|
296
|
+
id: e.id.toString(),
|
|
297
|
+
credential: credentialMap.get(e.credentialId) || null,
|
|
298
|
+
userId: e.userId?.toString(),
|
|
299
|
+
name: e.name,
|
|
300
|
+
externalId: e.externalId,
|
|
301
|
+
moduleName: e.moduleName,
|
|
302
|
+
...(e.data || {}),
|
|
303
|
+
}));
|
|
302
304
|
}
|
|
303
305
|
|
|
304
306
|
/**
|
|
@@ -306,13 +308,9 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
306
308
|
* Replaces: Entity.create(entityData)
|
|
307
309
|
*
|
|
308
310
|
* @param {Object} entityData - Entity data (with string IDs from application layer)
|
|
309
|
-
* @param {{organizationId?: (string|null)}} [tenancy] - the organization the entity
|
|
310
|
-
* belongs to (ADR-056 §3.6). A separate argument, not a field of `entityData`,
|
|
311
|
-
* because `entityData` carries provider fields and one named `organizationId`
|
|
312
|
-
* must not be taken for ours.
|
|
313
311
|
* @returns {Promise<Object>} Created entity object with string IDs
|
|
314
312
|
*/
|
|
315
|
-
async createEntity(entityData
|
|
313
|
+
async createEntity(entityData) {
|
|
316
314
|
const {
|
|
317
315
|
user,
|
|
318
316
|
userId,
|
|
@@ -330,7 +328,6 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
330
328
|
name,
|
|
331
329
|
moduleName,
|
|
332
330
|
externalId,
|
|
333
|
-
organizationId: this._convertId(tenancy.organizationId ?? null),
|
|
334
331
|
data: dynamicData,
|
|
335
332
|
};
|
|
336
333
|
|
|
@@ -340,7 +337,15 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
340
337
|
|
|
341
338
|
const credentialObj = await this._fetchCredential(entity.credentialId);
|
|
342
339
|
|
|
343
|
-
return
|
|
340
|
+
return {
|
|
341
|
+
id: entity.id.toString(),
|
|
342
|
+
credential: credentialObj,
|
|
343
|
+
userId: entity.userId?.toString(),
|
|
344
|
+
name: entity.name,
|
|
345
|
+
externalId: entity.externalId,
|
|
346
|
+
moduleName: entity.moduleName,
|
|
347
|
+
...(entity.data || {}),
|
|
348
|
+
};
|
|
344
349
|
}
|
|
345
350
|
|
|
346
351
|
/**
|
|
@@ -396,7 +401,15 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
396
401
|
|
|
397
402
|
const credentialObj = await this._fetchCredential(entity.credentialId);
|
|
398
403
|
|
|
399
|
-
return
|
|
404
|
+
return {
|
|
405
|
+
id: entity.id.toString(),
|
|
406
|
+
credential: credentialObj,
|
|
407
|
+
userId: entity.userId?.toString(),
|
|
408
|
+
name: entity.name,
|
|
409
|
+
externalId: entity.externalId,
|
|
410
|
+
moduleName: entity.moduleName,
|
|
411
|
+
...(entity.data || {}),
|
|
412
|
+
};
|
|
400
413
|
} catch (error) {
|
|
401
414
|
if (error.code === 'P2025') {
|
|
402
415
|
return null;
|
|
@@ -461,11 +474,6 @@ class ModuleRepositoryPostgres extends ModuleRepositoryInterface {
|
|
|
461
474
|
if (filter.moduleName) where.moduleName = filter.moduleName;
|
|
462
475
|
if (filter.externalId) where.externalId = this._toString(filter.externalId);
|
|
463
476
|
|
|
464
|
-
// `null` means "no organization"; absent means "any".
|
|
465
|
-
if (filter.organizationId !== undefined) {
|
|
466
|
-
where.organizationId = this._convertId(filter.organizationId);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
477
|
return where;
|
|
470
478
|
}
|
|
471
479
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const { prisma } = require('../../database/prisma');
|
|
2
2
|
const { ModuleRepositoryInterface } = require('./module-repository-interface');
|
|
3
|
-
const { entityNotFoundError } = require('./entity-not-found');
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Prisma-based Module Repository
|
|
@@ -38,7 +37,7 @@ class ModuleRepository extends ModuleRepositoryInterface {
|
|
|
38
37
|
});
|
|
39
38
|
|
|
40
39
|
if (!entity) {
|
|
41
|
-
throw
|
|
40
|
+
throw new Error(`Entity ${entityId} not found`);
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
return {
|
|
@@ -8,7 +8,6 @@ const { getLogger } = require('../../logs');
|
|
|
8
8
|
const { redactUrl } = require('../../logs/redact');
|
|
9
9
|
const { toSanitizedSurrogate } = require('../../logs/serialize');
|
|
10
10
|
const { getLoggerScope } = require('../../logs/context');
|
|
11
|
-
const { proxyRequest } = require('./proxy-request');
|
|
12
11
|
|
|
13
12
|
const DEFAULT_REQUEST_TIMEOUT_MS = 60_000;
|
|
14
13
|
|
|
@@ -238,9 +237,7 @@ class Requester extends Delegate {
|
|
|
238
237
|
// recursion (with its own backoff sleeps) always gets a clean
|
|
239
238
|
// signal. Timer is cleared in the finally block regardless of
|
|
240
239
|
// outcome.
|
|
241
|
-
|
|
242
|
-
// Management API proxy passes what is left of its deadline).
|
|
243
|
-
const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;
|
|
240
|
+
const timeoutMs = this.requestTimeoutMs;
|
|
244
241
|
const controller = timeoutMs > 0 ? new AbortController() : null;
|
|
245
242
|
const timeoutHandle = controller
|
|
246
243
|
? setTimeout(() => controller.abort(), timeoutMs)
|
|
@@ -278,11 +275,7 @@ class Requester extends Delegate {
|
|
|
278
275
|
// stall at batch scale.
|
|
279
276
|
const isTimeout =
|
|
280
277
|
e?.name === 'AbortError' || e?.type === 'aborted';
|
|
281
|
-
if (
|
|
282
|
-
e?.code === 'ECONNRESET' &&
|
|
283
|
-
!options.noRetry &&
|
|
284
|
-
attempt < this.backOff.length
|
|
285
|
-
) {
|
|
278
|
+
if (e?.code === 'ECONNRESET' && attempt < this.backOff.length) {
|
|
286
279
|
clearRequestTimer();
|
|
287
280
|
const delay = this.backOff[attempt] * 1000;
|
|
288
281
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
@@ -308,7 +301,6 @@ class Requester extends Delegate {
|
|
|
308
301
|
// If the status is retriable and there are back off requests left, retry the request
|
|
309
302
|
if (
|
|
310
303
|
(status === 429 || status >= 500) &&
|
|
311
|
-
!options.noRetry &&
|
|
312
304
|
attempt < this.backOff.length
|
|
313
305
|
) {
|
|
314
306
|
clearRequestTimer();
|
|
@@ -394,12 +386,6 @@ class Requester extends Delegate {
|
|
|
394
386
|
// If the error wasn't retried, throw. FetchError.create reads
|
|
395
387
|
// the response body (response.text()) — timer must still be
|
|
396
388
|
// alive to catch a stalled body stream.
|
|
397
|
-
// The proxy relays upstream errors to its caller instead of
|
|
398
|
-
// throwing; 401 keeps the refresh / invalidate handling above.
|
|
399
|
-
if (status >= 400 && options.returnErrorResponses) {
|
|
400
|
-
return response;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
389
|
if (status >= 400) {
|
|
404
390
|
this._logRequestFailed(encodedUrl, options, status);
|
|
405
391
|
const fetchError = await FetchError.create({
|
|
@@ -542,17 +528,6 @@ class Requester extends Delegate {
|
|
|
542
528
|
return res;
|
|
543
529
|
}
|
|
544
530
|
|
|
545
|
-
/**
|
|
546
|
-
* Generic, path-checked request for the Management API entity proxy
|
|
547
|
-
* (ADR-052 §8). The URL is always the module base URL plus a validated
|
|
548
|
-
* path; see ./proxy-request.js. Module methods are not involved.
|
|
549
|
-
*
|
|
550
|
-
* @param {Object} params - see proxyRequest()
|
|
551
|
-
*/
|
|
552
|
-
async _proxyRequest(params) {
|
|
553
|
-
return proxyRequest(this, params);
|
|
554
|
-
}
|
|
555
|
-
|
|
556
531
|
async _delete(options) {
|
|
557
532
|
const fetchOptions = {
|
|
558
533
|
method: 'DELETE',
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
const { Module } = require('../module');
|
|
2
2
|
const { mapModuleClassToModuleDTO } = require('../utils/map-module-dto');
|
|
3
|
-
const { describeRecord, visibilityClauses } = require('../scope-visibility');
|
|
4
|
-
const { DEFAULT_SCOPE_POLICY } = require('../scope-policy');
|
|
5
3
|
|
|
6
4
|
class GetEntitiesForUser {
|
|
7
|
-
constructor({ moduleRepository, moduleDefinitions
|
|
8
|
-
this.scopePolicy = scopePolicy || DEFAULT_SCOPE_POLICY;
|
|
5
|
+
constructor({ moduleRepository, moduleDefinitions }) {
|
|
9
6
|
this.moduleRepository = moduleRepository;
|
|
10
7
|
|
|
11
8
|
this.definitionMap = new Map();
|
|
@@ -14,31 +11,21 @@ class GetEntitiesForUser {
|
|
|
14
11
|
}
|
|
15
12
|
}
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
*/
|
|
21
|
-
async execute(user) {
|
|
22
|
-
const ctx = this.scopePolicy.accessContext(user);
|
|
23
|
-
const found = await this.moduleRepository.findEntitiesByOwnership(
|
|
24
|
-
visibilityClauses(ctx, 'entity')
|
|
25
|
-
);
|
|
26
|
-
const entities = (found || []).filter((entity) =>
|
|
27
|
-
describeRecord(entity, ctx, 'entity')
|
|
14
|
+
async execute(userId) {
|
|
15
|
+
const entities = await this.moduleRepository.findEntitiesByUserId(
|
|
16
|
+
userId
|
|
28
17
|
);
|
|
29
18
|
|
|
30
|
-
return
|
|
31
|
-
|
|
32
|
-
const definition = this.definitionMap.get(entity.moduleName);
|
|
19
|
+
return entities.map((entity) => {
|
|
20
|
+
const definition = this.definitionMap.get(entity.moduleName);
|
|
33
21
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
22
|
+
const moduleInstance = new Module({
|
|
23
|
+
userId,
|
|
24
|
+
definition: definition,
|
|
25
|
+
entity: entity,
|
|
26
|
+
});
|
|
27
|
+
return mapModuleClassToModuleDTO(moduleInstance);
|
|
28
|
+
});
|
|
42
29
|
}
|
|
43
30
|
}
|
|
44
31
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const { Module } = require('../module');
|
|
2
|
-
const { DEFAULT_SCOPE_POLICY } = require('../scope-policy');
|
|
3
2
|
|
|
4
3
|
class GetEntityOptionsById {
|
|
5
4
|
/**
|
|
@@ -7,11 +6,9 @@ class GetEntityOptionsById {
|
|
|
7
6
|
* @param {import('../repositories/module-repository-interface').ModuleRepositoryInterface} params.moduleRepository
|
|
8
7
|
* @param {} params.moduleDefinitions
|
|
9
8
|
*/
|
|
10
|
-
constructor({ moduleRepository, moduleDefinitions
|
|
9
|
+
constructor({ moduleRepository, moduleDefinitions }) {
|
|
11
10
|
this.moduleRepository = moduleRepository;
|
|
12
11
|
this.moduleDefinitions = moduleDefinitions;
|
|
13
|
-
// Who may load an entity follows its scope (ADR-056 §3.6).
|
|
14
|
-
this.scopePolicy = scopePolicy || DEFAULT_SCOPE_POLICY;
|
|
15
12
|
}
|
|
16
13
|
|
|
17
14
|
/**
|
|
@@ -38,7 +35,7 @@ class GetEntityOptionsById {
|
|
|
38
35
|
|
|
39
36
|
// Validate entity ownership
|
|
40
37
|
const isOwned = typeof userIdOrUser === 'object' && userIdOrUser?.ownsUserId
|
|
41
|
-
?
|
|
38
|
+
? userIdOrUser.ownsUserId(entity.userId)
|
|
42
39
|
: entity.userId?.toString() === userId?.toString();
|
|
43
40
|
|
|
44
41
|
if (!isOwned) {
|
|
@@ -60,11 +57,8 @@ class GetEntityOptionsById {
|
|
|
60
57
|
);
|
|
61
58
|
}
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// update the owner's credential, not create one under the caller.
|
|
66
|
-
const module = await Module.create({
|
|
67
|
-
userId: entity.userId ?? userId,
|
|
60
|
+
const module = new Module({
|
|
61
|
+
userId,
|
|
68
62
|
entity,
|
|
69
63
|
definition: moduleDefinition,
|
|
70
64
|
});
|
|
@@ -21,7 +21,7 @@ class GetEntityOptionsByType {
|
|
|
21
21
|
if (!moduleDefinition) {
|
|
22
22
|
throw new Error(`Module definition not found for type: ${type}`);
|
|
23
23
|
}
|
|
24
|
-
const moduleInstance =
|
|
24
|
+
const moduleInstance = new Module({
|
|
25
25
|
userId,
|
|
26
26
|
definition: moduleDefinition,
|
|
27
27
|
});
|