@friggframework/core 2.0.0--canary.499.2ef107f.0 → 2.0.0--canary.499.4c64a49.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.
|
@@ -21,7 +21,7 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
21
21
|
const objectId = toObjectId(id);
|
|
22
22
|
if (!objectId) return null;
|
|
23
23
|
const doc = await findOne(this.prisma, 'Credential', { _id: objectId });
|
|
24
|
-
return doc ? this.
|
|
24
|
+
return doc ? this._mapCredentialById(doc) : null;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
async updateAuthenticationStatus(credentialId, authIsValid) {
|
|
@@ -95,8 +95,8 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
const document = {
|
|
98
|
-
userId: toObjectId(userId || user
|
|
99
|
-
externalId,
|
|
98
|
+
userId: toObjectId(userId || user || identifiers.user),
|
|
99
|
+
externalId: externalId !== undefined ? externalId : identifiers.externalId,
|
|
100
100
|
authIsValid: authIsValid ?? null,
|
|
101
101
|
data: oauthData,
|
|
102
102
|
createdAt: now,
|
|
@@ -183,7 +183,32 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
|
183
183
|
return query;
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
/**
|
|
187
|
+
* Map credential document to application format (without legacy fields)
|
|
188
|
+
* Used by findCredential, upsertCredential, updateCredential
|
|
189
|
+
* Matches MongoDB repository format
|
|
190
|
+
* @private
|
|
191
|
+
*/
|
|
186
192
|
_mapCredential(doc) {
|
|
193
|
+
const data = doc?.data || {};
|
|
194
|
+
const id = fromObjectId(doc?._id);
|
|
195
|
+
const userId = fromObjectId(doc?.userId);
|
|
196
|
+
return {
|
|
197
|
+
id,
|
|
198
|
+
userId,
|
|
199
|
+
externalId: doc?.externalId ?? null,
|
|
200
|
+
authIsValid: doc?.authIsValid ?? null,
|
|
201
|
+
...data,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Map credential document with legacy fields for findCredentialById
|
|
207
|
+
* Includes _id and user fields for backward compatibility
|
|
208
|
+
* Matches MongoDB repository format
|
|
209
|
+
* @private
|
|
210
|
+
*/
|
|
211
|
+
_mapCredentialById(doc) {
|
|
187
212
|
const data = doc?.data || {};
|
|
188
213
|
const id = fromObjectId(doc?._id);
|
|
189
214
|
const userId = fromObjectId(doc?.userId);
|
|
@@ -35,19 +35,16 @@ async function findOne(client, collection, filter = {}, options = {}) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async function insertOne(client, collection, document) {
|
|
38
|
-
|
|
38
|
+
// Generate ObjectId if not present (MongoDB raw insert doesn't return insertedIds)
|
|
39
|
+
const _id = document._id || new ObjectId();
|
|
40
|
+
const docWithId = { ...document, _id };
|
|
41
|
+
|
|
42
|
+
await client.$runCommandRaw({
|
|
39
43
|
insert: collection,
|
|
40
|
-
documents: [
|
|
44
|
+
documents: [docWithId],
|
|
41
45
|
});
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const firstKey = Object.keys(result.insertedIds)[0];
|
|
45
|
-
if (firstKey !== undefined) {
|
|
46
|
-
return result.insertedIds[firstKey];
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
if (result?.insertedId) return result.insertedId;
|
|
50
|
-
return null;
|
|
46
|
+
|
|
47
|
+
return _id;
|
|
51
48
|
}
|
|
52
49
|
|
|
53
50
|
async function updateOne(client, collection, filter, update, options = {}) {
|
|
@@ -9,11 +9,111 @@ const {
|
|
|
9
9
|
deleteOne,
|
|
10
10
|
} = require('../../database/documentdb-utils');
|
|
11
11
|
const { ModuleRepositoryInterface } = require('./module-repository-interface');
|
|
12
|
+
const { Cryptor } = require('../../encrypt/Cryptor');
|
|
13
|
+
const { getEncryptedFields } = require('../../database/encryption/encryption-schema-registry');
|
|
12
14
|
|
|
13
15
|
class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
14
16
|
constructor() {
|
|
15
17
|
super();
|
|
16
18
|
this.prisma = prisma;
|
|
19
|
+
this._initializeCryptor();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
_initializeCryptor() {
|
|
23
|
+
// Match logic from @friggframework/core/database/prisma.js
|
|
24
|
+
const stage = process.env.STAGE || process.env.NODE_ENV || 'development';
|
|
25
|
+
const bypassEncryption = ['dev', 'test', 'local'].includes(stage.toLowerCase());
|
|
26
|
+
|
|
27
|
+
if (bypassEncryption) {
|
|
28
|
+
this.cryptor = null;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Determine encryption method
|
|
33
|
+
const hasKMS = process.env.KMS_KEY_ARN && process.env.KMS_KEY_ARN.trim() !== '';
|
|
34
|
+
const hasAES = process.env.AES_KEY_ID && process.env.AES_KEY_ID.trim() !== '';
|
|
35
|
+
|
|
36
|
+
if (!hasKMS && !hasAES) {
|
|
37
|
+
console.warn('No encryption keys configured. Encryption disabled.');
|
|
38
|
+
this.cryptor = null;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const shouldUseAws = hasKMS;
|
|
43
|
+
this.cryptor = new Cryptor({ shouldUseAws });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_isEncryptedValue(value) {
|
|
47
|
+
// Envelope encryption format: "keyId:encryptedPart1:encryptedPart2:encryptedKey"
|
|
48
|
+
// Must be string with at least 4 colon-separated parts
|
|
49
|
+
if (typeof value !== 'string') {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const parts = value.split(':');
|
|
54
|
+
return parts.length >= 4;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async _decryptField(encryptedValue, context = '') {
|
|
58
|
+
// If encryption is disabled, return as-is
|
|
59
|
+
if (!this.cryptor) {
|
|
60
|
+
return encryptedValue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// If not encrypted format, return as-is
|
|
64
|
+
if (!this._isEncryptedValue(encryptedValue)) {
|
|
65
|
+
return encryptedValue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
// Decrypt using Cryptor
|
|
70
|
+
const decryptedString = await this.cryptor.decrypt(encryptedValue);
|
|
71
|
+
|
|
72
|
+
// Try to parse as JSON (for objects/arrays)
|
|
73
|
+
try {
|
|
74
|
+
return JSON.parse(decryptedString);
|
|
75
|
+
} catch {
|
|
76
|
+
// Not JSON, return as string
|
|
77
|
+
return decryptedString;
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error(`Failed to decrypt field${context ? ` (${context})` : ''}:`, error.message);
|
|
81
|
+
// Return null on decryption failure to avoid exposing encrypted data
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async _decryptCredentialData(rawData) {
|
|
87
|
+
if (!rawData || typeof rawData !== 'object') {
|
|
88
|
+
return rawData;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Get encrypted fields from registry
|
|
92
|
+
const encryptedFieldsConfig = getEncryptedFields('Credential');
|
|
93
|
+
if (!encryptedFieldsConfig || !encryptedFieldsConfig.fields) {
|
|
94
|
+
return rawData;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const decrypted = {};
|
|
98
|
+
|
|
99
|
+
for (const [key, value] of Object.entries(rawData)) {
|
|
100
|
+
// Check if this field is in the encrypted fields list
|
|
101
|
+
const isEncrypted = encryptedFieldsConfig.fields.some(field => {
|
|
102
|
+
// Support both top-level and nested fields (e.g., 'data.access_token')
|
|
103
|
+
const fieldPath = field.split('.');
|
|
104
|
+
return fieldPath[fieldPath.length - 1] === key;
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
if (isEncrypted) {
|
|
108
|
+
// Decrypt encrypted fields
|
|
109
|
+
decrypted[key] = await this._decryptField(value, `Credential.data.${key}`);
|
|
110
|
+
} else {
|
|
111
|
+
// Pass through non-encrypted fields
|
|
112
|
+
decrypted[key] = value;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return decrypted;
|
|
17
117
|
}
|
|
18
118
|
|
|
19
119
|
async findEntityById(entityId) {
|
|
@@ -31,10 +131,13 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
31
131
|
|
|
32
132
|
async findEntitiesByUserId(userId) {
|
|
33
133
|
const objectId = toObjectId(userId);
|
|
34
|
-
|
|
134
|
+
if (!objectId) {
|
|
135
|
+
throw new Error(`Invalid userId: ${userId}`);
|
|
136
|
+
}
|
|
137
|
+
const filter = { userId: objectId };
|
|
35
138
|
const docs = await findMany(this.prisma, 'Entity', filter);
|
|
36
139
|
const credentialMap = await this._fetchCredentialsBulk(docs.map((doc) => doc.credentialId));
|
|
37
|
-
return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) ||
|
|
140
|
+
return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) || null));
|
|
38
141
|
}
|
|
39
142
|
|
|
40
143
|
async findEntitiesByIds(entitiesIds) {
|
|
@@ -42,18 +145,21 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
42
145
|
if (ids.length === 0) return [];
|
|
43
146
|
const docs = await findMany(this.prisma, 'Entity', { _id: { $in: ids } });
|
|
44
147
|
const credentialMap = await this._fetchCredentialsBulk(docs.map((doc) => doc.credentialId));
|
|
45
|
-
return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) ||
|
|
148
|
+
return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) || null));
|
|
46
149
|
}
|
|
47
150
|
|
|
48
151
|
async findEntitiesByUserIdAndModuleName(userId, moduleName) {
|
|
49
152
|
const objectId = toObjectId(userId);
|
|
153
|
+
if (!objectId) {
|
|
154
|
+
throw new Error(`Invalid userId: ${userId}`);
|
|
155
|
+
}
|
|
50
156
|
const filter = {
|
|
51
|
-
|
|
157
|
+
userId: objectId,
|
|
52
158
|
moduleName,
|
|
53
159
|
};
|
|
54
160
|
const docs = await findMany(this.prisma, 'Entity', filter);
|
|
55
161
|
const credentialMap = await this._fetchCredentialsBulk(docs.map((doc) => doc.credentialId));
|
|
56
|
-
return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) ||
|
|
162
|
+
return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) || null));
|
|
57
163
|
}
|
|
58
164
|
|
|
59
165
|
async unsetCredential(entityId) {
|
|
@@ -66,7 +172,6 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
66
172
|
{
|
|
67
173
|
$set: {
|
|
68
174
|
credentialId: null,
|
|
69
|
-
updatedAt: new Date(),
|
|
70
175
|
},
|
|
71
176
|
}
|
|
72
177
|
);
|
|
@@ -82,7 +187,6 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
82
187
|
}
|
|
83
188
|
|
|
84
189
|
async createEntity(entityData) {
|
|
85
|
-
const now = new Date();
|
|
86
190
|
const document = {
|
|
87
191
|
userId: toObjectId(entityData.user || entityData.userId),
|
|
88
192
|
credentialId: toObjectId(entityData.credential || entityData.credentialId) || null,
|
|
@@ -90,10 +194,6 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
90
194
|
moduleName: entityData.moduleName ?? null,
|
|
91
195
|
externalId: entityData.externalId ?? null,
|
|
92
196
|
accountId: entityData.accountId ?? null,
|
|
93
|
-
integrationIds: (entityData.integrationIds || []).map((id) => toObjectId(id)).filter(Boolean),
|
|
94
|
-
syncIds: (entityData.syncIds || []).map((id) => toObjectId(id)).filter(Boolean),
|
|
95
|
-
createdAt: now,
|
|
96
|
-
updatedAt: now,
|
|
97
197
|
};
|
|
98
198
|
const insertedId = await insertOne(this.prisma, 'Entity', document);
|
|
99
199
|
const created = await findOne(this.prisma, 'Entity', { _id: insertedId });
|
|
@@ -117,13 +217,6 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
117
217
|
if (updates.moduleName !== undefined) updatePayload.moduleName = updates.moduleName;
|
|
118
218
|
if (updates.externalId !== undefined) updatePayload.externalId = updates.externalId;
|
|
119
219
|
if (updates.accountId !== undefined) updatePayload.accountId = updates.accountId;
|
|
120
|
-
if (updates.integrationIds !== undefined) {
|
|
121
|
-
updatePayload.integrationIds = (updates.integrationIds || []).map((id) => toObjectId(id)).filter(Boolean);
|
|
122
|
-
}
|
|
123
|
-
if (updates.syncIds !== undefined) {
|
|
124
|
-
updatePayload.syncIds = (updates.syncIds || []).map((id) => toObjectId(id)).filter(Boolean);
|
|
125
|
-
}
|
|
126
|
-
updatePayload.updatedAt = new Date();
|
|
127
220
|
const result = await updateOne(
|
|
128
221
|
this.prisma,
|
|
129
222
|
'Entity',
|
|
@@ -148,9 +241,40 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
148
241
|
async _fetchCredential(credentialId) {
|
|
149
242
|
const id = fromObjectId(credentialId);
|
|
150
243
|
if (!id) return null;
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
// Convert to ObjectId for raw query
|
|
247
|
+
const objectId = toObjectId(id);
|
|
248
|
+
if (!objectId) return null;
|
|
249
|
+
|
|
250
|
+
// Use raw findOne to bypass Prisma encryption extension
|
|
251
|
+
const rawCredential = await findOne(this.prisma, 'Credential', {
|
|
252
|
+
_id: objectId
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
if (!rawCredential) return null;
|
|
256
|
+
|
|
257
|
+
// Manually decrypt data field
|
|
258
|
+
const decryptedData = await this._decryptCredentialData(
|
|
259
|
+
rawCredential.data || {}
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
// Return in same format
|
|
263
|
+
const credential = {
|
|
264
|
+
id: fromObjectId(rawCredential._id),
|
|
265
|
+
userId: fromObjectId(rawCredential.userId),
|
|
266
|
+
externalId: rawCredential.externalId ?? null,
|
|
267
|
+
authIsValid: rawCredential.authIsValid ?? null,
|
|
268
|
+
createdAt: rawCredential.createdAt,
|
|
269
|
+
updatedAt: rawCredential.updatedAt,
|
|
270
|
+
data: decryptedData
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
return this._convertCredentialIds(credential);
|
|
274
|
+
} catch (error) {
|
|
275
|
+
console.error(`Failed to fetch/decrypt credential ${id}:`, error.message);
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
154
278
|
}
|
|
155
279
|
|
|
156
280
|
async _fetchCredentialsBulk(credentialIds) {
|
|
@@ -158,14 +282,76 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
158
282
|
.map((value) => fromObjectId(value))
|
|
159
283
|
.filter((value) => value !== null && value !== undefined);
|
|
160
284
|
if (ids.length === 0) return new Map();
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
285
|
+
|
|
286
|
+
try {
|
|
287
|
+
// Convert string IDs to ObjectIds for bulk query
|
|
288
|
+
const objectIds = ids.map(id => toObjectId(id)).filter(Boolean);
|
|
289
|
+
if (objectIds.length === 0) return new Map();
|
|
290
|
+
|
|
291
|
+
// Use raw findMany to bypass Prisma encryption extension
|
|
292
|
+
const rawCredentials = await findMany(this.prisma, 'Credential', {
|
|
293
|
+
_id: { $in: objectIds }
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// Decrypt all credentials in parallel
|
|
297
|
+
const decryptionPromises = rawCredentials.map(async (rawCredential) => {
|
|
298
|
+
try {
|
|
299
|
+
// Manually decrypt the data field
|
|
300
|
+
const decryptedData = await this._decryptCredentialData(
|
|
301
|
+
rawCredential.data || {}
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
// Build credential object in same format as Prisma would return
|
|
305
|
+
const credential = {
|
|
306
|
+
id: fromObjectId(rawCredential._id),
|
|
307
|
+
userId: fromObjectId(rawCredential.userId),
|
|
308
|
+
externalId: rawCredential.externalId ?? null,
|
|
309
|
+
authIsValid: rawCredential.authIsValid ?? null,
|
|
310
|
+
createdAt: rawCredential.createdAt,
|
|
311
|
+
updatedAt: rawCredential.updatedAt,
|
|
312
|
+
data: decryptedData
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
return this._convertCredentialIds(credential);
|
|
316
|
+
} catch (error) {
|
|
317
|
+
const credId = fromObjectId(rawCredential._id);
|
|
318
|
+
console.error(`Failed to decrypt credential ${credId}:`, error.message);
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// Wait for all decryptions to complete
|
|
324
|
+
const decryptedCredentials = await Promise.all(decryptionPromises);
|
|
325
|
+
|
|
326
|
+
// Build Map from results, filtering out nulls
|
|
327
|
+
const map = new Map();
|
|
328
|
+
decryptedCredentials.forEach(credential => {
|
|
329
|
+
if (credential) {
|
|
330
|
+
map.set(credential.id, credential);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
return map;
|
|
335
|
+
} catch (error) {
|
|
336
|
+
console.error('Failed to fetch credentials bulk:', error.message);
|
|
337
|
+
return new Map();
|
|
167
338
|
}
|
|
168
|
-
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Convert credential object IDs to strings for application layer
|
|
343
|
+
* Ensures consistent credential format across database adapters
|
|
344
|
+
* @private
|
|
345
|
+
* @param {Object|null} credential - Credential object from database
|
|
346
|
+
* @returns {Object|null} Credential with properly formatted IDs
|
|
347
|
+
*/
|
|
348
|
+
_convertCredentialIds(credential) {
|
|
349
|
+
if (!credential) return credential;
|
|
350
|
+
return {
|
|
351
|
+
...credential,
|
|
352
|
+
id: credential.id ? String(credential.id) : null,
|
|
353
|
+
userId: credential.userId ? String(credential.userId) : null,
|
|
354
|
+
};
|
|
169
355
|
}
|
|
170
356
|
|
|
171
357
|
_buildFilter(filter) {
|
|
@@ -183,10 +369,9 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
|
|
|
183
369
|
const credObj = toObjectId(filter.credential || filter.credentialId);
|
|
184
370
|
if (credObj) query.credentialId = credObj;
|
|
185
371
|
}
|
|
186
|
-
if (filter.name
|
|
187
|
-
if (filter.moduleName
|
|
188
|
-
if (filter.externalId
|
|
189
|
-
if (filter.accountId !== undefined) query.accountId = filter.accountId;
|
|
372
|
+
if (filter.name) query.name = filter.name;
|
|
373
|
+
if (filter.moduleName) query.moduleName = filter.moduleName;
|
|
374
|
+
if (filter.externalId) query.externalId = filter.externalId;
|
|
190
375
|
return query;
|
|
191
376
|
}
|
|
192
377
|
|
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.499.
|
|
4
|
+
"version": "2.0.0--canary.499.4c64a49.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.499.
|
|
42
|
-
"@friggframework/prettier-config": "2.0.0--canary.499.
|
|
43
|
-
"@friggframework/test": "2.0.0--canary.499.
|
|
41
|
+
"@friggframework/eslint-config": "2.0.0--canary.499.4c64a49.0",
|
|
42
|
+
"@friggframework/prettier-config": "2.0.0--canary.499.4c64a49.0",
|
|
43
|
+
"@friggframework/test": "2.0.0--canary.499.4c64a49.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": "4c64a49a369d67e2c2fb831e134db33c6d4cc6ca"
|
|
84
84
|
}
|