@friggframework/core 2.0.0--canary.503.d72d514.0 → 2.0.0--canary.503.35bc02b.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.
|
@@ -12,28 +12,9 @@ const {
|
|
|
12
12
|
const {
|
|
13
13
|
IntegrationMappingRepositoryInterface,
|
|
14
14
|
} = require('./integration-mapping-repository-interface');
|
|
15
|
-
const {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
* IntegrationMapping repository for DocumentDB.
|
|
19
|
-
* Uses DocumentDBEncryptionService for field-level encryption.
|
|
20
|
-
*
|
|
21
|
-
* Encrypted fields:
|
|
22
|
-
* - IntegrationMapping.mapping
|
|
23
|
-
*
|
|
24
|
-
* SECURITY CRITICAL: Mapping data may contain API keys, secrets, and sensitive configuration.
|
|
25
|
-
*
|
|
26
|
-
* DEFENSIVE CHECK PATTERN:
|
|
27
|
-
* Methods that return documents (upsertMapping, updateMapping) include defensive checks
|
|
28
|
-
* to verify the document exists after write operations. This catches:
|
|
29
|
-
* - Race conditions (document deleted between write and read)
|
|
30
|
-
* - Silent write failures due to permissions or storage issues
|
|
31
|
-
* - DocumentDB replication consistency issues
|
|
32
|
-
*
|
|
33
|
-
* @see credential-repository-documentdb.js for the same pattern
|
|
34
|
-
* @see DocumentDBEncryptionService
|
|
35
|
-
* @see encryption-schema-registry.js
|
|
36
|
-
*/
|
|
15
|
+
const {
|
|
16
|
+
DocumentDBEncryptionService,
|
|
17
|
+
} = require('../../database/documentdb-encryption-service');
|
|
37
18
|
class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositoryInterface {
|
|
38
19
|
constructor() {
|
|
39
20
|
super();
|
|
@@ -46,27 +27,34 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
46
27
|
const doc = await findOne(this.prisma, 'IntegrationMapping', filter);
|
|
47
28
|
if (!doc) return null;
|
|
48
29
|
|
|
49
|
-
|
|
50
|
-
|
|
30
|
+
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
31
|
+
'IntegrationMapping',
|
|
32
|
+
doc
|
|
33
|
+
);
|
|
51
34
|
return this._mapMapping(decryptedMapping);
|
|
52
35
|
}
|
|
53
36
|
|
|
54
37
|
async upsertMapping(integrationId, sourceId, mapping) {
|
|
55
38
|
const filter = this._compositeFilter(integrationId, sourceId);
|
|
56
|
-
const existing = await findOne(
|
|
39
|
+
const existing = await findOne(
|
|
40
|
+
this.prisma,
|
|
41
|
+
'IntegrationMapping',
|
|
42
|
+
filter
|
|
43
|
+
);
|
|
57
44
|
const now = new Date();
|
|
58
45
|
|
|
59
46
|
if (existing) {
|
|
60
|
-
|
|
61
|
-
|
|
47
|
+
const decryptedExisting =
|
|
48
|
+
await this.encryptionService.decryptFields(
|
|
49
|
+
'IntegrationMapping',
|
|
50
|
+
existing
|
|
51
|
+
);
|
|
62
52
|
|
|
63
|
-
// Build update document
|
|
64
53
|
const updateDocument = {
|
|
65
|
-
mapping,
|
|
54
|
+
mapping,
|
|
66
55
|
updatedAt: now,
|
|
67
56
|
};
|
|
68
57
|
|
|
69
|
-
// Encrypt before storing
|
|
70
58
|
const encryptedUpdate = await this.encryptionService.encryptFields(
|
|
71
59
|
'IntegrationMapping',
|
|
72
60
|
{ mapping: updateDocument.mapping }
|
|
@@ -84,54 +72,73 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
84
72
|
}
|
|
85
73
|
);
|
|
86
74
|
|
|
87
|
-
|
|
88
|
-
|
|
75
|
+
const updated = await findOne(this.prisma, 'IntegrationMapping', {
|
|
76
|
+
_id: existing._id,
|
|
77
|
+
});
|
|
89
78
|
if (!updated) {
|
|
90
|
-
console.error(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
79
|
+
console.error(
|
|
80
|
+
'[IntegrationMappingRepositoryDocumentDB] Mapping not found after update',
|
|
81
|
+
{
|
|
82
|
+
mappingId: fromObjectId(existing._id),
|
|
83
|
+
integrationId,
|
|
84
|
+
sourceId,
|
|
85
|
+
}
|
|
86
|
+
);
|
|
95
87
|
throw new Error(
|
|
96
88
|
'Failed to update mapping: Document not found after update. ' +
|
|
97
|
-
|
|
89
|
+
'This indicates a database consistency issue.'
|
|
98
90
|
);
|
|
99
91
|
}
|
|
100
|
-
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
92
|
+
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
93
|
+
'IntegrationMapping',
|
|
94
|
+
updated
|
|
95
|
+
);
|
|
101
96
|
return this._mapMapping(decryptedMapping);
|
|
102
97
|
}
|
|
103
98
|
|
|
104
|
-
// Build plain text document
|
|
105
99
|
const plainDocument = {
|
|
106
100
|
integrationId: toObjectId(integrationId),
|
|
107
|
-
sourceId:
|
|
101
|
+
sourceId:
|
|
102
|
+
sourceId === null || sourceId === undefined
|
|
103
|
+
? null
|
|
104
|
+
: String(sourceId),
|
|
108
105
|
mapping,
|
|
109
106
|
createdAt: now,
|
|
110
107
|
updatedAt: now,
|
|
111
108
|
};
|
|
112
109
|
|
|
113
|
-
// Encrypt before storing
|
|
114
110
|
const encryptedDocument = await this.encryptionService.encryptFields(
|
|
115
111
|
'IntegrationMapping',
|
|
116
112
|
plainDocument
|
|
117
113
|
);
|
|
118
114
|
|
|
119
|
-
const insertedId = await insertOne(
|
|
115
|
+
const insertedId = await insertOne(
|
|
116
|
+
this.prisma,
|
|
117
|
+
'IntegrationMapping',
|
|
118
|
+
encryptedDocument
|
|
119
|
+
);
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
const created = await findOne(this.prisma, 'IntegrationMapping', {
|
|
122
|
+
_id: insertedId,
|
|
123
|
+
});
|
|
123
124
|
if (!created) {
|
|
124
|
-
console.error(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
console.error(
|
|
126
|
+
'[IntegrationMappingRepositoryDocumentDB] Mapping not found after insert',
|
|
127
|
+
{
|
|
128
|
+
insertedId: fromObjectId(insertedId),
|
|
129
|
+
integrationId,
|
|
130
|
+
sourceId,
|
|
131
|
+
}
|
|
132
|
+
);
|
|
129
133
|
throw new Error(
|
|
130
134
|
'Failed to create mapping: Document not found after insert. ' +
|
|
131
|
-
|
|
135
|
+
'This indicates a database consistency issue.'
|
|
132
136
|
);
|
|
133
137
|
}
|
|
134
|
-
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
138
|
+
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
139
|
+
'IntegrationMapping',
|
|
140
|
+
created
|
|
141
|
+
);
|
|
135
142
|
return this._mapMapping(decryptedMapping);
|
|
136
143
|
}
|
|
137
144
|
|
|
@@ -141,9 +148,10 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
141
148
|
if (integrationObjectId) filter.integrationId = integrationObjectId;
|
|
142
149
|
const docs = await findMany(this.prisma, 'IntegrationMapping', filter);
|
|
143
150
|
|
|
144
|
-
// Decrypt sensitive fields for each document
|
|
145
151
|
const decryptedDocs = await Promise.all(
|
|
146
|
-
docs.map(doc =>
|
|
152
|
+
docs.map((doc) =>
|
|
153
|
+
this.encryptionService.decryptFields('IntegrationMapping', doc)
|
|
154
|
+
)
|
|
147
155
|
);
|
|
148
156
|
|
|
149
157
|
return decryptedDocs.map((doc) => this._mapMapping(doc));
|
|
@@ -151,7 +159,11 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
151
159
|
|
|
152
160
|
async deleteMapping(integrationId, sourceId) {
|
|
153
161
|
const filter = this._compositeFilter(integrationId, sourceId);
|
|
154
|
-
const result = await deleteOne(
|
|
162
|
+
const result = await deleteOne(
|
|
163
|
+
this.prisma,
|
|
164
|
+
'IntegrationMapping',
|
|
165
|
+
filter
|
|
166
|
+
);
|
|
155
167
|
const deleted = result?.n ?? 0;
|
|
156
168
|
return { acknowledged: true, deletedCount: deleted };
|
|
157
169
|
}
|
|
@@ -171,11 +183,15 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
171
183
|
async findMappingById(id) {
|
|
172
184
|
const objectId = toObjectId(id);
|
|
173
185
|
if (!objectId) return null;
|
|
174
|
-
const doc = await findOne(this.prisma, 'IntegrationMapping', {
|
|
186
|
+
const doc = await findOne(this.prisma, 'IntegrationMapping', {
|
|
187
|
+
_id: objectId,
|
|
188
|
+
});
|
|
175
189
|
if (!doc) return null;
|
|
176
190
|
|
|
177
|
-
|
|
178
|
-
|
|
191
|
+
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
192
|
+
'IntegrationMapping',
|
|
193
|
+
doc
|
|
194
|
+
);
|
|
179
195
|
return this._mapMapping(decryptedMapping);
|
|
180
196
|
}
|
|
181
197
|
|
|
@@ -183,22 +199,26 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
183
199
|
const objectId = toObjectId(id);
|
|
184
200
|
if (!objectId) return null;
|
|
185
201
|
|
|
186
|
-
const existing = await findOne(this.prisma, 'IntegrationMapping', {
|
|
202
|
+
const existing = await findOne(this.prisma, 'IntegrationMapping', {
|
|
203
|
+
_id: objectId,
|
|
204
|
+
});
|
|
187
205
|
if (!existing) return null;
|
|
188
206
|
|
|
189
|
-
|
|
190
|
-
|
|
207
|
+
const decryptedExisting = await this.encryptionService.decryptFields(
|
|
208
|
+
'IntegrationMapping',
|
|
209
|
+
existing
|
|
210
|
+
);
|
|
191
211
|
|
|
192
|
-
|
|
193
|
-
|
|
212
|
+
const mergedMapping =
|
|
213
|
+
updates.mapping !== undefined
|
|
214
|
+
? updates.mapping
|
|
215
|
+
: decryptedExisting.mapping;
|
|
194
216
|
|
|
195
|
-
// Build update with other fields
|
|
196
217
|
const updateDocument = {
|
|
197
218
|
...updates,
|
|
198
219
|
updatedAt: new Date(),
|
|
199
220
|
};
|
|
200
221
|
|
|
201
|
-
// Encrypt mapping before storing
|
|
202
222
|
if (mergedMapping !== undefined) {
|
|
203
223
|
const encryptedUpdate = await this.encryptionService.encryptFields(
|
|
204
224
|
'IntegrationMapping',
|
|
@@ -216,18 +236,25 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
216
236
|
}
|
|
217
237
|
);
|
|
218
238
|
|
|
219
|
-
|
|
220
|
-
|
|
239
|
+
const updated = await findOne(this.prisma, 'IntegrationMapping', {
|
|
240
|
+
_id: objectId,
|
|
241
|
+
});
|
|
221
242
|
if (!updated) {
|
|
222
|
-
console.error(
|
|
223
|
-
|
|
224
|
-
|
|
243
|
+
console.error(
|
|
244
|
+
'[IntegrationMappingRepositoryDocumentDB] Mapping not found after update',
|
|
245
|
+
{
|
|
246
|
+
mappingId: fromObjectId(objectId),
|
|
247
|
+
}
|
|
248
|
+
);
|
|
225
249
|
throw new Error(
|
|
226
250
|
'Failed to update mapping: Document not found after update. ' +
|
|
227
|
-
|
|
251
|
+
'This indicates a database consistency issue.'
|
|
228
252
|
);
|
|
229
253
|
}
|
|
230
|
-
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
254
|
+
const decryptedMapping = await this.encryptionService.decryptFields(
|
|
255
|
+
'IntegrationMapping',
|
|
256
|
+
updated
|
|
257
|
+
);
|
|
231
258
|
return this._mapMapping(decryptedMapping);
|
|
232
259
|
}
|
|
233
260
|
|
|
@@ -254,5 +281,3 @@ class IntegrationMappingRepositoryDocumentDB extends IntegrationMappingRepositor
|
|
|
254
281
|
}
|
|
255
282
|
|
|
256
283
|
module.exports = { IntegrationMappingRepositoryDocumentDB };
|
|
257
|
-
|
|
258
|
-
|
|
@@ -15,11 +15,6 @@ const {
|
|
|
15
15
|
DocumentDBEncryptionService,
|
|
16
16
|
} = require('../../database/documentdb-encryption-service');
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* @see credential-repository-documentdb.js for the same pattern
|
|
20
|
-
* @see integration-mapping-repository-documentdb.js for the same pattern
|
|
21
|
-
* @see encryption-schema-registry.js for custom schema configuration
|
|
22
|
-
*/
|
|
23
18
|
class ProcessRepositoryDocumentDB extends ProcessRepositoryInterface {
|
|
24
19
|
constructor() {
|
|
25
20
|
super();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/core",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.503.
|
|
4
|
+
"version": "2.0.0--canary.503.35bc02b.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-apigatewaymanagementapi": "^3.588.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.588.0",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@friggframework/eslint-config": "2.0.0--canary.503.
|
|
42
|
-
"@friggframework/prettier-config": "2.0.0--canary.503.
|
|
43
|
-
"@friggframework/test": "2.0.0--canary.503.
|
|
41
|
+
"@friggframework/eslint-config": "2.0.0--canary.503.35bc02b.0",
|
|
42
|
+
"@friggframework/prettier-config": "2.0.0--canary.503.35bc02b.0",
|
|
43
|
+
"@friggframework/test": "2.0.0--canary.503.35bc02b.0",
|
|
44
44
|
"@prisma/client": "^6.17.0",
|
|
45
45
|
"@types/lodash": "4.17.15",
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"publishConfig": {
|
|
81
81
|
"access": "public"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "35bc02bb0d15ab3be40bac3d7b3bcf33cebb4382"
|
|
84
84
|
}
|