@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 { DocumentDBEncryptionService } = require('../../database/documentdb-encryption-service');
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
- // Decrypt sensitive fields using service
50
- const decryptedMapping = await this.encryptionService.decryptFields('IntegrationMapping', doc);
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(this.prisma, 'IntegrationMapping', filter);
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
- // Decrypt existing mapping data first
61
- const decryptedExisting = await this.encryptionService.decryptFields('IntegrationMapping', existing);
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, // Plain text 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
- // Read back and decrypt
88
- const updated = await findOne(this.prisma, 'IntegrationMapping', { _id: existing._id });
75
+ const updated = await findOne(this.prisma, 'IntegrationMapping', {
76
+ _id: existing._id,
77
+ });
89
78
  if (!updated) {
90
- console.error('[IntegrationMappingRepositoryDocumentDB] Mapping not found after update', {
91
- mappingId: fromObjectId(existing._id),
92
- integrationId,
93
- sourceId,
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
- 'This indicates a database consistency issue.'
89
+ 'This indicates a database consistency issue.'
98
90
  );
99
91
  }
100
- const decryptedMapping = await this.encryptionService.decryptFields('IntegrationMapping', updated);
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: sourceId === null || sourceId === undefined ? null : String(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(this.prisma, 'IntegrationMapping', encryptedDocument);
115
+ const insertedId = await insertOne(
116
+ this.prisma,
117
+ 'IntegrationMapping',
118
+ encryptedDocument
119
+ );
120
120
 
121
- // Read back and decrypt
122
- const created = await findOne(this.prisma, 'IntegrationMapping', { _id: insertedId });
121
+ const created = await findOne(this.prisma, 'IntegrationMapping', {
122
+ _id: insertedId,
123
+ });
123
124
  if (!created) {
124
- console.error('[IntegrationMappingRepositoryDocumentDB] Mapping not found after insert', {
125
- insertedId: fromObjectId(insertedId),
126
- integrationId,
127
- sourceId,
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
- 'This indicates a database consistency issue.'
135
+ 'This indicates a database consistency issue.'
132
136
  );
133
137
  }
134
- const decryptedMapping = await this.encryptionService.decryptFields('IntegrationMapping', created);
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 => this.encryptionService.decryptFields('IntegrationMapping', 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(this.prisma, 'IntegrationMapping', filter);
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', { _id: objectId });
186
+ const doc = await findOne(this.prisma, 'IntegrationMapping', {
187
+ _id: objectId,
188
+ });
175
189
  if (!doc) return null;
176
190
 
177
- // Decrypt sensitive fields using service
178
- const decryptedMapping = await this.encryptionService.decryptFields('IntegrationMapping', doc);
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', { _id: objectId });
202
+ const existing = await findOne(this.prisma, 'IntegrationMapping', {
203
+ _id: objectId,
204
+ });
187
205
  if (!existing) return null;
188
206
 
189
- // Decrypt existing mapping data first
190
- const decryptedExisting = await this.encryptionService.decryptFields('IntegrationMapping', existing);
207
+ const decryptedExisting = await this.encryptionService.decryptFields(
208
+ 'IntegrationMapping',
209
+ existing
210
+ );
191
211
 
192
- // Merge updates - if mapping is provided, use it, otherwise keep existing
193
- const mergedMapping = updates.mapping !== undefined ? updates.mapping : decryptedExisting.mapping;
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
- // Read back and decrypt
220
- const updated = await findOne(this.prisma, 'IntegrationMapping', { _id: objectId });
239
+ const updated = await findOne(this.prisma, 'IntegrationMapping', {
240
+ _id: objectId,
241
+ });
221
242
  if (!updated) {
222
- console.error('[IntegrationMappingRepositoryDocumentDB] Mapping not found after update', {
223
- mappingId: fromObjectId(objectId),
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
- 'This indicates a database consistency issue.'
251
+ 'This indicates a database consistency issue.'
228
252
  );
229
253
  }
230
- const decryptedMapping = await this.encryptionService.decryptFields('IntegrationMapping', updated);
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.d72d514.0",
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.d72d514.0",
42
- "@friggframework/prettier-config": "2.0.0--canary.503.d72d514.0",
43
- "@friggframework/test": "2.0.0--canary.503.d72d514.0",
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": "d72d5146178da9d183e93525478ba84807399bcc"
83
+ "gitHead": "35bc02bb0d15ab3be40bac3d7b3bcf33cebb4382"
84
84
  }