@friggframework/core 2.0.0--canary.684.0da024b.0 → 2.0.0--canary.679.a2bcc2f.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 -2
- package/README.md +0 -105
- package/application/commands/integration-commands.js +2 -2
- package/application/commands/user-commands.js +5 -17
- package/credential/use-cases/credential-operations-for-user.js +25 -110
- package/credential/use-cases/reauthorize-credential-for-user.js +8 -15
- package/database/documentdb-utils.js +1 -6
- package/generated/prisma-mongodb/edge.js +4 -15
- package/generated/prisma-mongodb/index-browser.js +1 -12
- package/generated/prisma-mongodb/index.d.ts +86 -2027
- package/generated/prisma-mongodb/index.js +4 -15
- package/generated/prisma-mongodb/package.json +1 -1
- package/generated/prisma-mongodb/schema.prisma +0 -47
- package/generated/prisma-mongodb/wasm.js +4 -15
- package/generated/prisma-postgresql/edge.js +4 -15
- package/generated/prisma-postgresql/index-browser.js +1 -12
- package/generated/prisma-postgresql/index.d.ts +63 -2162
- package/generated/prisma-postgresql/index.js +4 -15
- package/generated/prisma-postgresql/package.json +1 -1
- package/generated/prisma-postgresql/schema.prisma +0 -44
- package/generated/prisma-postgresql/wasm.js +4 -15
- package/handlers/app-definition-loader.js +1 -15
- package/index.js +0 -18
- package/integrations/integration-router.js +73 -115
- 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 -5
- package/integrations/use-cases/integration-operations-for-user.js +24 -55
- package/management-api/management-api-config.js +0 -3
- package/management-api/openapi/components.js +0 -40
- package/management-api/openapi/v2-operations.js +1 -13
- package/management-api/v2/dependencies.js +15 -40
- package/management-api/v2/dto.js +0 -20
- package/management-api/v2/handlers/authorization.js +0 -1
- package/management-api/v2/handlers/credentials.js +2 -6
- package/management-api/v2/handlers/entities.js +7 -10
- package/management-api/v2/handlers/integrations.js +3 -6
- package/management-api/v2/request.js +1 -32
- package/modules/index.js +0 -8
- package/modules/repositories/module-repository-documentdb.js +4 -48
- package/modules/repositories/module-repository-interface.js +2 -19
- package/modules/repositories/module-repository-mongo.js +73 -65
- package/modules/repositories/module-repository-postgres.js +73 -64
- package/modules/use-cases/entity-operations-for-user.js +13 -50
- package/modules/use-cases/entity-types.js +7 -31
- package/modules/use-cases/execute-entity-proxy-request.js +0 -15
- package/modules/use-cases/get-entities-for-user.js +5 -16
- package/modules/use-cases/get-entity-module-for-user.js +3 -23
- package/modules/use-cases/get-entity-options-by-id.js +3 -9
- package/modules/use-cases/get-module.js +3 -9
- package/modules/use-cases/multi-step-authorization.js +12 -39
- package/modules/use-cases/process-authorization-callback.js +18 -52
- package/modules/use-cases/refresh-entity-options.js +3 -9
- package/modules/use-cases/test-module-auth.js +3 -9
- package/package.json +5 -6
- package/prisma-mongodb/schema.prisma +0 -47
- package/prisma-postgresql/schema.prisma +0 -44
- package/types/index.d.ts +0 -1
- package/types/modules/index.d.ts +0 -87
- 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/database/organization-where.js +0 -18
- package/database/unique-violation.js +0 -25
- package/integrations/repositories/integration-not-found.js +0 -14
- package/integrations/use-cases/resolve-integration-ownership.js +0 -177
- package/modules/entity-scope.js +0 -15
- 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 -239
- 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/manage-access.js +0 -21
- 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/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,5 +1,4 @@
|
|
|
1
1
|
const { maskCredential } = require('../dto');
|
|
2
|
-
const { parseListFilters } = require('../request');
|
|
3
2
|
|
|
4
3
|
/** Management API v2 credential handlers, keyed by operationId. */
|
|
5
4
|
function createCredentialHandlers(useCases) {
|
|
@@ -7,11 +6,8 @@ function createCredentialHandlers(useCases) {
|
|
|
7
6
|
useCases;
|
|
8
7
|
|
|
9
8
|
return {
|
|
10
|
-
async listCredentials(
|
|
11
|
-
const credentials = await listCredentialsForUser.execute(
|
|
12
|
-
user,
|
|
13
|
-
parseListFilters(req.query)
|
|
14
|
-
);
|
|
9
|
+
async listCredentials(_req, res, user) {
|
|
10
|
+
const credentials = await listCredentialsForUser.execute(user);
|
|
15
11
|
res.json({ credentials: credentials.map(maskCredential) });
|
|
16
12
|
},
|
|
17
13
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { toEntityDto } = require('../dto');
|
|
2
|
-
const { objectBody, parseStep
|
|
2
|
+
const { objectBody, parseStep } = require('../request');
|
|
3
3
|
|
|
4
4
|
/** Management API v2 entity and entity-type handlers, keyed by operationId. */
|
|
5
5
|
function createEntityHandlers(useCases) {
|
|
@@ -16,20 +16,17 @@ function createEntityHandlers(useCases) {
|
|
|
16
16
|
} = useCases;
|
|
17
17
|
|
|
18
18
|
return {
|
|
19
|
-
async listEntities(
|
|
20
|
-
const entities = await listEntitiesForUser.execute(
|
|
21
|
-
user,
|
|
22
|
-
parseListFilters(req.query)
|
|
23
|
-
);
|
|
19
|
+
async listEntities(_req, res, user) {
|
|
20
|
+
const entities = await listEntitiesForUser.execute(user);
|
|
24
21
|
res.json({ entities: entities.map(toEntityDto) });
|
|
25
22
|
},
|
|
26
23
|
|
|
27
|
-
async listEntityTypes(_req, res
|
|
28
|
-
res.json({ types: await listEntityTypes.execute(
|
|
24
|
+
async listEntityTypes(_req, res) {
|
|
25
|
+
res.json({ types: await listEntityTypes.execute() });
|
|
29
26
|
},
|
|
30
27
|
|
|
31
|
-
async getEntityType(req, res
|
|
32
|
-
res.json(await getEntityType.execute(req.params.entityType
|
|
28
|
+
async getEntityType(req, res) {
|
|
29
|
+
res.json(await getEntityType.execute(req.params.entityType));
|
|
33
30
|
},
|
|
34
31
|
|
|
35
32
|
// Describes a step's requirements without starting an authorization
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { toIntegrationDto } = require('../dto');
|
|
2
|
-
const { objectBody, optionalString
|
|
2
|
+
const { objectBody, optionalString } = require('../request');
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Management API v2 integration handlers, keyed by registry operationId.
|
|
@@ -27,11 +27,8 @@ function createIntegrationHandlers(useCases) {
|
|
|
27
27
|
);
|
|
28
28
|
|
|
29
29
|
return {
|
|
30
|
-
async listIntegrations(
|
|
31
|
-
const integrations = await getIntegrationsForUser.execute(
|
|
32
|
-
user,
|
|
33
|
-
parseListFilters(req.query)
|
|
34
|
-
);
|
|
30
|
+
async listIntegrations(_req, res, user) {
|
|
31
|
+
const integrations = await getIntegrationsForUser.execute(user.getId());
|
|
35
32
|
res.json({ integrations: integrations.map(toIntegrationDto) });
|
|
36
33
|
},
|
|
37
34
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const Boom = require('@hapi/boom');
|
|
2
|
-
const { LIST_OWNERS } = require('../../modules/scope-visibility');
|
|
3
2
|
|
|
4
3
|
/** The JSON body as an object, or a 400 VALIDATION_ERROR. */
|
|
5
4
|
function objectBody(req) {
|
|
@@ -52,34 +51,4 @@ function optionalString(value, name) {
|
|
|
52
51
|
return value;
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* `?scope=individual|organization` and `?owner=me|org` on a list (ADR-056
|
|
59
|
-
* §3.4). Anything else is a 400.
|
|
60
|
-
*/
|
|
61
|
-
function parseListFilters(query = {}) {
|
|
62
|
-
const scope = optionalString(query.scope, 'scope');
|
|
63
|
-
const owner = optionalString(query.owner, 'owner');
|
|
64
|
-
if (scope !== undefined && !LIST_SCOPES.includes(scope)) {
|
|
65
|
-
throw Boom.badRequest(`scope must be one of ${LIST_SCOPES.join(', ')}`, {
|
|
66
|
-
code: 'VALIDATION_ERROR',
|
|
67
|
-
details: { field: 'scope' },
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
if (owner !== undefined && !Object.hasOwn(LIST_OWNERS, owner)) {
|
|
71
|
-
throw Boom.badRequest('owner must be me or org', {
|
|
72
|
-
code: 'VALIDATION_ERROR',
|
|
73
|
-
details: { field: 'owner' },
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
return { scope, owner };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
module.exports = {
|
|
80
|
-
objectBody,
|
|
81
|
-
requireFields,
|
|
82
|
-
parseStep,
|
|
83
|
-
optionalString,
|
|
84
|
-
parseListFilters,
|
|
85
|
-
};
|
|
54
|
+
module.exports = { objectBody, requireFields, parseStep, optionalString };
|
package/modules/index.js
CHANGED
|
@@ -8,11 +8,6 @@ const {
|
|
|
8
8
|
getEntityTypeRegistry,
|
|
9
9
|
EntityRegistryError,
|
|
10
10
|
} = require('./entity-type-registry');
|
|
11
|
-
const {
|
|
12
|
-
resolveScope,
|
|
13
|
-
listBindingScopes,
|
|
14
|
-
OwnershipConfigError,
|
|
15
|
-
} = require('./entity-scope');
|
|
16
11
|
|
|
17
12
|
module.exports = {
|
|
18
13
|
ApiKeyRequester,
|
|
@@ -23,7 +18,4 @@ module.exports = {
|
|
|
23
18
|
ModuleFactory,
|
|
24
19
|
getEntityTypeRegistry,
|
|
25
20
|
EntityRegistryError,
|
|
26
|
-
resolveScope,
|
|
27
|
-
listBindingScopes,
|
|
28
|
-
OwnershipConfigError,
|
|
29
21
|
};
|
|
@@ -3,7 +3,6 @@ const {
|
|
|
3
3
|
toObjectId,
|
|
4
4
|
fromObjectId,
|
|
5
5
|
findMany,
|
|
6
|
-
findManyDrained,
|
|
7
6
|
findOne,
|
|
8
7
|
insertOne,
|
|
9
8
|
updateOne,
|
|
@@ -77,29 +76,6 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
77
76
|
return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) || null));
|
|
78
77
|
}
|
|
79
78
|
|
|
80
|
-
/**
|
|
81
|
-
* Find entities matching any of the owner/organization pairs, in one query.
|
|
82
|
-
* `organizationId: null` matches rows with no organization (a raw MongoDB
|
|
83
|
-
* `null` also matches a missing field). The caller (a use case) decides
|
|
84
|
-
* which pairs; this only runs them.
|
|
85
|
-
*
|
|
86
|
-
* @param {Array<{userId: string, organizationId: (string|null)}>} clauses
|
|
87
|
-
* @returns {Promise<Array>}
|
|
88
|
-
*/
|
|
89
|
-
async findEntitiesByOwnership(clauses) {
|
|
90
|
-
if (!Array.isArray(clauses) || clauses.length === 0) return [];
|
|
91
|
-
// Drained: a list can hold more than the first cursor batch (~101).
|
|
92
|
-
const docs = await findManyDrained(this.prisma, 'Entity', {
|
|
93
|
-
$or: clauses.map(({ userId, organizationId }) => ({
|
|
94
|
-
userId: toObjectId(userId),
|
|
95
|
-
organizationId:
|
|
96
|
-
organizationId === null ? null : toObjectId(organizationId),
|
|
97
|
-
})),
|
|
98
|
-
});
|
|
99
|
-
const credentialMap = await this._fetchCredentialsBulk(docs.map((doc) => doc.credentialId));
|
|
100
|
-
return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) || null));
|
|
101
|
-
}
|
|
102
|
-
|
|
103
79
|
async unsetCredential(entityId) {
|
|
104
80
|
const objectId = toObjectId(entityId);
|
|
105
81
|
if (!objectId) return false;
|
|
@@ -139,14 +115,7 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
139
115
|
);
|
|
140
116
|
}
|
|
141
117
|
|
|
142
|
-
|
|
143
|
-
* @param {Object} entityData
|
|
144
|
-
* @param {{organizationId?: (string|null)}} [tenancy] - the organization the entity
|
|
145
|
-
* belongs to (ADR-056 §3.6). A separate argument, not a field of `entityData`,
|
|
146
|
-
* because `entityData` carries provider fields and one named `organizationId`
|
|
147
|
-
* must not be taken for ours.
|
|
148
|
-
*/
|
|
149
|
-
async createEntity(entityData, tenancy = {}) {
|
|
118
|
+
async createEntity(entityData) {
|
|
150
119
|
const {
|
|
151
120
|
user,
|
|
152
121
|
userId,
|
|
@@ -164,7 +133,6 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
164
133
|
name: name ?? null,
|
|
165
134
|
moduleName: moduleName ?? null,
|
|
166
135
|
externalId: externalId ?? null,
|
|
167
|
-
organizationId: toObjectId(tenancy.organizationId) || null,
|
|
168
136
|
data: dynamicData,
|
|
169
137
|
};
|
|
170
138
|
const insertedId = await insertOne(this.prisma, 'Entity', document);
|
|
@@ -279,9 +247,8 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
279
247
|
const objectIds = ids.map(id => toObjectId(id)).filter(Boolean);
|
|
280
248
|
if (objectIds.length === 0) return new Map();
|
|
281
249
|
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
const rawCredentials = await findManyDrained(this.prisma, 'Credential', {
|
|
250
|
+
// Use raw findMany to bypass Prisma encryption extension
|
|
251
|
+
const rawCredentials = await findMany(this.prisma, 'Credential', {
|
|
285
252
|
_id: { $in: objectIds }
|
|
286
253
|
});
|
|
287
254
|
|
|
@@ -362,30 +329,19 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
362
329
|
if (filter.name) query.name = filter.name;
|
|
363
330
|
if (filter.moduleName) query.moduleName = filter.moduleName;
|
|
364
331
|
if (filter.externalId) query.externalId = filter.externalId;
|
|
365
|
-
// `null` means "no organization"; absent means "any". A raw MongoDB
|
|
366
|
-
// `{ field: null }` matches both a null value and a missing field.
|
|
367
|
-
if (filter.organizationId !== undefined) {
|
|
368
|
-
query.organizationId =
|
|
369
|
-
filter.organizationId === null
|
|
370
|
-
? null
|
|
371
|
-
: toObjectId(filter.organizationId);
|
|
372
|
-
}
|
|
373
332
|
return query;
|
|
374
333
|
}
|
|
375
334
|
|
|
376
335
|
_mapEntity(doc, credential) {
|
|
377
336
|
const dynamicData = doc?.data || {};
|
|
378
337
|
return {
|
|
379
|
-
// First, so no stored provider field can replace a column below
|
|
380
|
-
// (identity, owner or organization decide who sees the entity).
|
|
381
|
-
...dynamicData,
|
|
382
338
|
id: fromObjectId(doc?._id),
|
|
383
339
|
credential,
|
|
384
340
|
userId: fromObjectId(doc?.userId),
|
|
385
341
|
name: doc?.name ?? null,
|
|
386
342
|
externalId: doc?.externalId ?? null,
|
|
387
343
|
moduleName: doc?.moduleName ?? null,
|
|
388
|
-
|
|
344
|
+
...dynamicData,
|
|
389
345
|
};
|
|
390
346
|
}
|
|
391
347
|
}
|
|
@@ -67,21 +67,6 @@ class ModuleRepositoryInterface {
|
|
|
67
67
|
);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
/**
|
|
71
|
-
* Find entities matching any of the owner/organization pairs, in one query
|
|
72
|
-
* (ADR-056 §3.6). `organizationId: null` matches rows with no organization.
|
|
73
|
-
* Which pairs is decided by the caller (modules/entity-scope.js), not here.
|
|
74
|
-
*
|
|
75
|
-
* @param {Array<{userId: string|number, organizationId: (string|number|null)}>} clauses
|
|
76
|
-
* @returns {Promise<Array>} Array of entity objects
|
|
77
|
-
* @abstract
|
|
78
|
-
*/
|
|
79
|
-
async findEntitiesByOwnership(clauses) {
|
|
80
|
-
throw new Error(
|
|
81
|
-
'Method findEntitiesByOwnership must be implemented by subclass'
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
70
|
/**
|
|
86
71
|
* Unset credential from entity
|
|
87
72
|
*
|
|
@@ -125,13 +110,11 @@ class ModuleRepositoryInterface {
|
|
|
125
110
|
/**
|
|
126
111
|
* Create a new entity
|
|
127
112
|
*
|
|
128
|
-
* @param {Object} entityData - Entity data
|
|
129
|
-
* @param {{organizationId?: (string|number|null)}} [tenancy] - the organization
|
|
130
|
-
* the entity belongs to (ADR-056 §3.6), kept apart from `entityData`
|
|
113
|
+
* @param {Object} entityData - Entity data
|
|
131
114
|
* @returns {Promise<Object>} Created entity object
|
|
132
115
|
* @abstract
|
|
133
116
|
*/
|
|
134
|
-
async createEntity(entityData
|
|
117
|
+
async createEntity(entityData) {
|
|
135
118
|
throw new Error('Method createEntity must be implemented by subclass');
|
|
136
119
|
}
|
|
137
120
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const { prisma } = require('../../database/prisma');
|
|
2
|
-
const { organizationWhere } = require('../../database/organization-where');
|
|
3
2
|
const { ModuleRepositoryInterface } = require('./module-repository-interface');
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -77,26 +76,6 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
77
76
|
return credentialMap;
|
|
78
77
|
}
|
|
79
78
|
|
|
80
|
-
/**
|
|
81
|
-
* The one place a stored entity row becomes the entity the application sees.
|
|
82
|
-
* The provider's `data` is spread FIRST and every column is pinned after it:
|
|
83
|
-
* a stored `id`, `userId` or `organizationId` in `data` must not decide who
|
|
84
|
-
* owns the entity or who sees it.
|
|
85
|
-
* @private
|
|
86
|
-
*/
|
|
87
|
-
_mapEntity(row, credential) {
|
|
88
|
-
return {
|
|
89
|
-
...(row.data || {}),
|
|
90
|
-
id: row.id,
|
|
91
|
-
credential,
|
|
92
|
-
userId: row.userId,
|
|
93
|
-
name: row.name,
|
|
94
|
-
externalId: row.externalId,
|
|
95
|
-
moduleName: row.moduleName,
|
|
96
|
-
organizationId: row.organizationId ?? null,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
79
|
/**
|
|
101
80
|
* Find entity by ID with credential
|
|
102
81
|
* Replaces: Entity.findById(entityId).populate('credential')
|
|
@@ -116,7 +95,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
116
95
|
|
|
117
96
|
const credential = await this._fetchCredential(entity.credentialId);
|
|
118
97
|
|
|
119
|
-
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
|
+
};
|
|
120
107
|
}
|
|
121
108
|
|
|
122
109
|
/**
|
|
@@ -134,7 +121,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
134
121
|
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
135
122
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
136
123
|
|
|
137
|
-
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
|
+
}));
|
|
138
133
|
}
|
|
139
134
|
|
|
140
135
|
/**
|
|
@@ -152,7 +147,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
152
147
|
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
153
148
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
154
149
|
|
|
155
|
-
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
|
+
}));
|
|
156
159
|
}
|
|
157
160
|
|
|
158
161
|
/**
|
|
@@ -174,32 +177,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
174
177
|
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
175
178
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
176
179
|
|
|
177
|
-
return entities.map((e) => (
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
* @returns {Promise<Array>} Array of entity objects with string IDs
|
|
187
|
-
*/
|
|
188
|
-
async findEntitiesByOwnership(clauses) {
|
|
189
|
-
if (!Array.isArray(clauses) || clauses.length === 0) return [];
|
|
190
|
-
const entities = await this.prisma.entity.findMany({
|
|
191
|
-
where: {
|
|
192
|
-
OR: clauses.map(({ userId, organizationId }) => ({
|
|
193
|
-
userId,
|
|
194
|
-
...organizationWhere(organizationId),
|
|
195
|
-
})),
|
|
196
|
-
},
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
|
|
200
|
-
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
201
|
-
|
|
202
|
-
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
|
+
}));
|
|
203
189
|
}
|
|
204
190
|
|
|
205
191
|
/**
|
|
@@ -237,7 +223,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
237
223
|
|
|
238
224
|
const credential = await this._fetchCredential(entity.credentialId);
|
|
239
225
|
|
|
240
|
-
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
|
+
};
|
|
241
235
|
}
|
|
242
236
|
|
|
243
237
|
/**
|
|
@@ -257,7 +251,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
257
251
|
.filter(Boolean);
|
|
258
252
|
const credentialMap = await this._fetchCredentialsBulk(credentialIds);
|
|
259
253
|
|
|
260
|
-
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
|
+
}));
|
|
261
263
|
}
|
|
262
264
|
|
|
263
265
|
/**
|
|
@@ -265,13 +267,9 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
265
267
|
* Replaces: Entity.create(entityData)
|
|
266
268
|
*
|
|
267
269
|
* @param {Object} entityData - Entity data
|
|
268
|
-
* @param {{organizationId?: (string|null)}} [tenancy] - the organization the entity
|
|
269
|
-
* belongs to (ADR-056 §3.6). A separate argument, not a field of `entityData`,
|
|
270
|
-
* because `entityData` carries provider fields and one named `organizationId`
|
|
271
|
-
* must not be taken for ours.
|
|
272
270
|
* @returns {Promise<Object>} Created entity object with string IDs
|
|
273
271
|
*/
|
|
274
|
-
async createEntity(entityData
|
|
272
|
+
async createEntity(entityData) {
|
|
275
273
|
const {
|
|
276
274
|
user,
|
|
277
275
|
userId,
|
|
@@ -289,7 +287,6 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
289
287
|
name,
|
|
290
288
|
moduleName,
|
|
291
289
|
externalId,
|
|
292
|
-
organizationId: tenancy.organizationId ?? null,
|
|
293
290
|
data: dynamicData,
|
|
294
291
|
};
|
|
295
292
|
|
|
@@ -299,7 +296,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
299
296
|
|
|
300
297
|
const credentialObj = await this._fetchCredential(entity.credentialId);
|
|
301
298
|
|
|
302
|
-
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
|
+
};
|
|
303
308
|
}
|
|
304
309
|
|
|
305
310
|
/**
|
|
@@ -353,7 +358,15 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
353
358
|
|
|
354
359
|
const credentialObj = await this._fetchCredential(entity.credentialId);
|
|
355
360
|
|
|
356
|
-
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
|
+
};
|
|
357
370
|
} catch (error) {
|
|
358
371
|
if (error.code === 'P2025') {
|
|
359
372
|
return null;
|
|
@@ -416,11 +429,6 @@ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
|
|
|
416
429
|
if (filter.moduleName) where.moduleName = filter.moduleName;
|
|
417
430
|
if (filter.externalId) where.externalId = this._toString(filter.externalId);
|
|
418
431
|
|
|
419
|
-
// `null` means "no organization"; absent means "any".
|
|
420
|
-
if (filter.organizationId !== undefined) {
|
|
421
|
-
Object.assign(where, organizationWhere(filter.organizationId));
|
|
422
|
-
}
|
|
423
|
-
|
|
424
432
|
return where;
|
|
425
433
|
}
|
|
426
434
|
}
|