@friggframework/core 2.0.0--canary.419.f684df1.0 → 2.0.0--canary.419.6e5f240.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/handlers/routers/health.js +114 -87
- package/package.json +5 -5
|
@@ -9,18 +9,19 @@ const router = Router();
|
|
|
9
9
|
|
|
10
10
|
const validateApiKey = (req, res, next) => {
|
|
11
11
|
const apiKey = req.headers['x-api-key'];
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
if (req.path === '/health') {
|
|
14
14
|
return next();
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
if (!apiKey || apiKey !== process.env.HEALTH_API_KEY) {
|
|
18
|
+
console.log('Unauthorized access attempt to health endpoint');
|
|
18
19
|
return res.status(401).json({
|
|
19
20
|
status: 'error',
|
|
20
|
-
message: 'Unauthorized'
|
|
21
|
+
message: 'Unauthorized',
|
|
21
22
|
});
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
+
|
|
24
25
|
next();
|
|
25
26
|
};
|
|
26
27
|
|
|
@@ -30,7 +31,7 @@ const checkExternalAPI = (url, timeout = 5000) => {
|
|
|
30
31
|
return new Promise((resolve) => {
|
|
31
32
|
const protocol = url.startsWith('https:') ? https : http;
|
|
32
33
|
const startTime = Date.now();
|
|
33
|
-
|
|
34
|
+
|
|
34
35
|
try {
|
|
35
36
|
const request = protocol.get(url, { timeout }, (res) => {
|
|
36
37
|
const responseTime = Date.now() - startTime;
|
|
@@ -38,7 +39,7 @@ const checkExternalAPI = (url, timeout = 5000) => {
|
|
|
38
39
|
status: 'healthy',
|
|
39
40
|
statusCode: res.statusCode,
|
|
40
41
|
responseTime,
|
|
41
|
-
reachable: res.statusCode < 500
|
|
42
|
+
reachable: res.statusCode < 500,
|
|
42
43
|
});
|
|
43
44
|
});
|
|
44
45
|
|
|
@@ -47,7 +48,7 @@ const checkExternalAPI = (url, timeout = 5000) => {
|
|
|
47
48
|
status: 'unhealthy',
|
|
48
49
|
error: error.message,
|
|
49
50
|
responseTime: Date.now() - startTime,
|
|
50
|
-
reachable: false
|
|
51
|
+
reachable: false,
|
|
51
52
|
});
|
|
52
53
|
});
|
|
53
54
|
|
|
@@ -57,7 +58,7 @@ const checkExternalAPI = (url, timeout = 5000) => {
|
|
|
57
58
|
status: 'timeout',
|
|
58
59
|
error: 'Request timeout',
|
|
59
60
|
responseTime: timeout,
|
|
60
|
-
reachable: false
|
|
61
|
+
reachable: false,
|
|
61
62
|
});
|
|
62
63
|
});
|
|
63
64
|
} catch (error) {
|
|
@@ -65,7 +66,7 @@ const checkExternalAPI = (url, timeout = 5000) => {
|
|
|
65
66
|
status: 'error',
|
|
66
67
|
error: error.message,
|
|
67
68
|
responseTime: Date.now() - startTime,
|
|
68
|
-
reachable: false
|
|
69
|
+
reachable: false,
|
|
69
70
|
});
|
|
70
71
|
}
|
|
71
72
|
});
|
|
@@ -76,14 +77,14 @@ const getDatabaseState = () => {
|
|
|
76
77
|
0: 'disconnected',
|
|
77
78
|
1: 'connected',
|
|
78
79
|
2: 'connecting',
|
|
79
|
-
3: 'disconnecting'
|
|
80
|
+
3: 'disconnecting',
|
|
80
81
|
};
|
|
81
82
|
const readyState = mongoose.connection.readyState;
|
|
82
|
-
|
|
83
|
+
|
|
83
84
|
return {
|
|
84
85
|
readyState,
|
|
85
86
|
stateName: stateMap[readyState],
|
|
86
|
-
isConnected: readyState === 1
|
|
87
|
+
isConnected: readyState === 1,
|
|
87
88
|
};
|
|
88
89
|
};
|
|
89
90
|
|
|
@@ -91,7 +92,7 @@ const checkDatabaseHealth = async () => {
|
|
|
91
92
|
const { stateName, isConnected } = getDatabaseState();
|
|
92
93
|
const result = {
|
|
93
94
|
status: isConnected ? 'healthy' : 'unhealthy',
|
|
94
|
-
state: stateName
|
|
95
|
+
state: stateName,
|
|
95
96
|
};
|
|
96
97
|
|
|
97
98
|
if (isConnected) {
|
|
@@ -104,19 +105,20 @@ const checkDatabaseHealth = async () => {
|
|
|
104
105
|
};
|
|
105
106
|
|
|
106
107
|
const getEncryptionConfiguration = () => {
|
|
107
|
-
const { STAGE, BYPASS_ENCRYPTION_STAGE, KMS_KEY_ARN, AES_KEY_ID } =
|
|
108
|
-
|
|
108
|
+
const { STAGE, BYPASS_ENCRYPTION_STAGE, KMS_KEY_ARN, AES_KEY_ID } =
|
|
109
|
+
process.env;
|
|
110
|
+
|
|
109
111
|
const defaultBypassStages = ['dev', 'test', 'local'];
|
|
110
112
|
const useEnv = BYPASS_ENCRYPTION_STAGE !== undefined;
|
|
111
113
|
const bypassStages = useEnv
|
|
112
114
|
? BYPASS_ENCRYPTION_STAGE.split(',').map((s) => s.trim())
|
|
113
115
|
: defaultBypassStages;
|
|
114
|
-
|
|
116
|
+
|
|
115
117
|
const isBypassed = bypassStages.includes(STAGE);
|
|
116
118
|
const hasAES = AES_KEY_ID && AES_KEY_ID.trim() !== '';
|
|
117
119
|
const hasKMS = KMS_KEY_ARN && KMS_KEY_ARN.trim() !== '' && !hasAES;
|
|
118
120
|
const mode = hasAES ? 'aes' : hasKMS ? 'kms' : 'none';
|
|
119
|
-
|
|
121
|
+
|
|
120
122
|
return {
|
|
121
123
|
stage: STAGE || null,
|
|
122
124
|
isBypassed,
|
|
@@ -128,19 +130,24 @@ const getEncryptionConfiguration = () => {
|
|
|
128
130
|
|
|
129
131
|
const createTestEncryptionModel = () => {
|
|
130
132
|
const { Encrypt } = require('./../../encrypt');
|
|
131
|
-
|
|
132
|
-
const testSchema = new mongoose.Schema(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
|
|
134
|
+
const testSchema = new mongoose.Schema(
|
|
135
|
+
{
|
|
136
|
+
testSecret: { type: String, lhEncrypt: true },
|
|
137
|
+
normalField: { type: String },
|
|
138
|
+
nestedSecret: {
|
|
139
|
+
value: { type: String, lhEncrypt: true },
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
{ timestamps: false }
|
|
143
|
+
);
|
|
139
144
|
|
|
140
145
|
testSchema.plugin(Encrypt);
|
|
141
|
-
|
|
142
|
-
return
|
|
143
|
-
mongoose.
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
mongoose.models.TestEncryption ||
|
|
149
|
+
mongoose.model('TestEncryption', testSchema)
|
|
150
|
+
);
|
|
144
151
|
};
|
|
145
152
|
|
|
146
153
|
const createTestDocument = async (TestModel) => {
|
|
@@ -148,21 +155,23 @@ const createTestDocument = async (TestModel) => {
|
|
|
148
155
|
testSecret: 'This is a secret value that should be encrypted',
|
|
149
156
|
normalField: 'This is a normal field that should not be encrypted',
|
|
150
157
|
nestedSecret: {
|
|
151
|
-
value: 'This is a nested secret that should be encrypted'
|
|
152
|
-
}
|
|
158
|
+
value: 'This is a nested secret that should be encrypted',
|
|
159
|
+
},
|
|
153
160
|
};
|
|
154
161
|
|
|
155
162
|
const testDoc = new TestModel(testData);
|
|
156
163
|
await testDoc.save();
|
|
157
|
-
|
|
164
|
+
|
|
158
165
|
return { testDoc, testData };
|
|
159
166
|
};
|
|
160
167
|
|
|
161
168
|
const verifyDecryption = (retrievedDoc, originalData) => {
|
|
162
|
-
return
|
|
169
|
+
return (
|
|
170
|
+
retrievedDoc &&
|
|
163
171
|
retrievedDoc.testSecret === originalData.testSecret &&
|
|
164
172
|
retrievedDoc.normalField === originalData.normalField &&
|
|
165
|
-
retrievedDoc.nestedSecret?.value === originalData.nestedSecret.value
|
|
173
|
+
retrievedDoc.nestedSecret?.value === originalData.nestedSecret.value
|
|
174
|
+
);
|
|
166
175
|
};
|
|
167
176
|
|
|
168
177
|
const verifyEncryptionInDatabase = async (testDoc, originalData, TestModel) => {
|
|
@@ -171,70 +180,85 @@ const verifyEncryptionInDatabase = async (testDoc, originalData, TestModel) => {
|
|
|
171
180
|
.collection(collectionName)
|
|
172
181
|
.findOne({ _id: testDoc._id });
|
|
173
182
|
|
|
174
|
-
const secretIsEncrypted =
|
|
175
|
-
|
|
176
|
-
rawDoc.testSecret
|
|
183
|
+
const secretIsEncrypted =
|
|
184
|
+
rawDoc &&
|
|
185
|
+
typeof rawDoc.testSecret === 'string' &&
|
|
186
|
+
rawDoc.testSecret.includes(':') &&
|
|
177
187
|
rawDoc.testSecret !== originalData.testSecret;
|
|
178
|
-
|
|
179
|
-
const nestedIsEncrypted =
|
|
188
|
+
|
|
189
|
+
const nestedIsEncrypted =
|
|
190
|
+
rawDoc?.nestedSecret?.value &&
|
|
180
191
|
typeof rawDoc.nestedSecret.value === 'string' &&
|
|
181
|
-
rawDoc.nestedSecret.value.includes(':') &&
|
|
192
|
+
rawDoc.nestedSecret.value.includes(':') &&
|
|
182
193
|
rawDoc.nestedSecret.value !== originalData.nestedSecret.value;
|
|
183
|
-
|
|
184
|
-
const normalNotEncrypted =
|
|
185
|
-
rawDoc.normalField === originalData.normalField;
|
|
194
|
+
|
|
195
|
+
const normalNotEncrypted =
|
|
196
|
+
rawDoc && rawDoc.normalField === originalData.normalField;
|
|
186
197
|
|
|
187
198
|
return {
|
|
188
199
|
secretIsEncrypted,
|
|
189
200
|
nestedIsEncrypted,
|
|
190
|
-
normalNotEncrypted
|
|
201
|
+
normalNotEncrypted,
|
|
191
202
|
};
|
|
192
203
|
};
|
|
193
204
|
|
|
194
205
|
const evaluateEncryptionTestResults = (decryptionWorks, encryptionResults) => {
|
|
195
|
-
const { secretIsEncrypted, nestedIsEncrypted, normalNotEncrypted } =
|
|
196
|
-
|
|
197
|
-
|
|
206
|
+
const { secretIsEncrypted, nestedIsEncrypted, normalNotEncrypted } =
|
|
207
|
+
encryptionResults;
|
|
208
|
+
|
|
209
|
+
if (
|
|
210
|
+
decryptionWorks &&
|
|
211
|
+
secretIsEncrypted &&
|
|
212
|
+
nestedIsEncrypted &&
|
|
213
|
+
normalNotEncrypted
|
|
214
|
+
) {
|
|
198
215
|
return {
|
|
199
216
|
status: 'enabled',
|
|
200
|
-
testResult: 'Encryption and decryption verified successfully'
|
|
217
|
+
testResult: 'Encryption and decryption verified successfully',
|
|
201
218
|
};
|
|
202
219
|
}
|
|
203
|
-
|
|
220
|
+
|
|
204
221
|
if (decryptionWorks && (!secretIsEncrypted || !nestedIsEncrypted)) {
|
|
205
222
|
return {
|
|
206
223
|
status: 'unhealthy',
|
|
207
|
-
testResult: 'Fields are not being encrypted in database'
|
|
224
|
+
testResult: 'Fields are not being encrypted in database',
|
|
208
225
|
};
|
|
209
226
|
}
|
|
210
|
-
|
|
227
|
+
|
|
211
228
|
if (decryptionWorks && !normalNotEncrypted) {
|
|
212
229
|
return {
|
|
213
230
|
status: 'unhealthy',
|
|
214
|
-
testResult: 'Normal fields are being incorrectly encrypted'
|
|
231
|
+
testResult: 'Normal fields are being incorrectly encrypted',
|
|
215
232
|
};
|
|
216
233
|
}
|
|
217
|
-
|
|
234
|
+
|
|
218
235
|
return {
|
|
219
236
|
status: 'unhealthy',
|
|
220
|
-
testResult: 'Decryption failed or data mismatch'
|
|
237
|
+
testResult: 'Decryption failed or data mismatch',
|
|
221
238
|
};
|
|
222
239
|
};
|
|
223
240
|
|
|
224
241
|
const testEncryption = async () => {
|
|
225
242
|
const TestModel = createTestEncryptionModel();
|
|
226
243
|
const { testDoc, testData } = await createTestDocument(TestModel);
|
|
227
|
-
|
|
244
|
+
|
|
228
245
|
try {
|
|
229
246
|
const retrievedDoc = await TestModel.findById(testDoc._id);
|
|
230
247
|
const decryptionWorks = verifyDecryption(retrievedDoc, testData);
|
|
231
|
-
const encryptionResults = await verifyEncryptionInDatabase(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
248
|
+
const encryptionResults = await verifyEncryptionInDatabase(
|
|
249
|
+
testDoc,
|
|
250
|
+
testData,
|
|
251
|
+
TestModel
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const evaluation = evaluateEncryptionTestResults(
|
|
255
|
+
decryptionWorks,
|
|
256
|
+
encryptionResults
|
|
257
|
+
);
|
|
258
|
+
|
|
235
259
|
return {
|
|
236
260
|
...evaluation,
|
|
237
|
-
encryptionWorks: decryptionWorks
|
|
261
|
+
encryptionWorks: decryptionWorks,
|
|
238
262
|
};
|
|
239
263
|
} finally {
|
|
240
264
|
await TestModel.deleteOne({ _id: testDoc._id });
|
|
@@ -243,12 +267,12 @@ const testEncryption = async () => {
|
|
|
243
267
|
|
|
244
268
|
const checkEncryptionHealth = async () => {
|
|
245
269
|
const config = getEncryptionConfiguration();
|
|
246
|
-
|
|
270
|
+
|
|
247
271
|
if (config.isBypassed || config.mode === 'none') {
|
|
248
|
-
const testResult = config.isBypassed
|
|
249
|
-
? 'Encryption bypassed for this stage'
|
|
272
|
+
const testResult = config.isBypassed
|
|
273
|
+
? 'Encryption bypassed for this stage'
|
|
250
274
|
: 'No encryption keys configured';
|
|
251
|
-
|
|
275
|
+
|
|
252
276
|
return {
|
|
253
277
|
status: 'disabled',
|
|
254
278
|
mode: config.mode,
|
|
@@ -258,14 +282,14 @@ const checkEncryptionHealth = async () => {
|
|
|
258
282
|
encryptionWorks: false,
|
|
259
283
|
debug: {
|
|
260
284
|
hasKMS: config.hasKMS,
|
|
261
|
-
hasAES: config.hasAES
|
|
262
|
-
}
|
|
285
|
+
hasAES: config.hasAES,
|
|
286
|
+
},
|
|
263
287
|
};
|
|
264
288
|
}
|
|
265
289
|
|
|
266
290
|
try {
|
|
267
291
|
const testResults = await testEncryption();
|
|
268
|
-
|
|
292
|
+
|
|
269
293
|
return {
|
|
270
294
|
...testResults,
|
|
271
295
|
mode: config.mode,
|
|
@@ -273,8 +297,8 @@ const checkEncryptionHealth = async () => {
|
|
|
273
297
|
stage: config.stage,
|
|
274
298
|
debug: {
|
|
275
299
|
hasKMS: config.hasKMS,
|
|
276
|
-
hasAES: config.hasAES
|
|
277
|
-
}
|
|
300
|
+
hasAES: config.hasAES,
|
|
301
|
+
},
|
|
278
302
|
};
|
|
279
303
|
} catch (error) {
|
|
280
304
|
return {
|
|
@@ -286,8 +310,8 @@ const checkEncryptionHealth = async () => {
|
|
|
286
310
|
encryptionWorks: false,
|
|
287
311
|
debug: {
|
|
288
312
|
hasKMS: config.hasKMS,
|
|
289
|
-
hasAES: config.hasAES
|
|
290
|
-
}
|
|
313
|
+
hasAES: config.hasAES,
|
|
314
|
+
},
|
|
291
315
|
};
|
|
292
316
|
}
|
|
293
317
|
};
|
|
@@ -295,25 +319,28 @@ const checkEncryptionHealth = async () => {
|
|
|
295
319
|
const checkExternalAPIs = async () => {
|
|
296
320
|
const apis = [
|
|
297
321
|
{ name: 'github', url: 'https://api.github.com/status' },
|
|
298
|
-
{ name: 'npm', url: 'https://registry.npmjs.org' }
|
|
322
|
+
{ name: 'npm', url: 'https://registry.npmjs.org' },
|
|
299
323
|
];
|
|
300
324
|
|
|
301
325
|
const results = await Promise.all(
|
|
302
|
-
apis.map(api =>
|
|
303
|
-
checkExternalAPI(api.url).then(result => ({
|
|
326
|
+
apis.map((api) =>
|
|
327
|
+
checkExternalAPI(api.url).then((result) => ({
|
|
328
|
+
name: api.name,
|
|
329
|
+
...result,
|
|
330
|
+
}))
|
|
304
331
|
)
|
|
305
332
|
);
|
|
306
|
-
|
|
333
|
+
|
|
307
334
|
const apiStatuses = {};
|
|
308
335
|
let allReachable = true;
|
|
309
|
-
|
|
336
|
+
|
|
310
337
|
results.forEach(({ name, ...checkResult }) => {
|
|
311
338
|
apiStatuses[name] = checkResult;
|
|
312
339
|
if (!checkResult.reachable) {
|
|
313
340
|
allReachable = false;
|
|
314
341
|
}
|
|
315
342
|
});
|
|
316
|
-
|
|
343
|
+
|
|
317
344
|
return { apiStatuses, allReachable };
|
|
318
345
|
};
|
|
319
346
|
|
|
@@ -321,7 +348,7 @@ const checkIntegrations = () => {
|
|
|
321
348
|
const moduleTypes = Array.isArray(moduleFactory.moduleTypes)
|
|
322
349
|
? moduleFactory.moduleTypes
|
|
323
350
|
: [];
|
|
324
|
-
|
|
351
|
+
|
|
325
352
|
const integrationTypes = Array.isArray(integrationFactory.integrationTypes)
|
|
326
353
|
? integrationFactory.integrationTypes
|
|
327
354
|
: [];
|
|
@@ -345,7 +372,7 @@ const buildHealthCheckResponse = (startTime) => {
|
|
|
345
372
|
status: 'healthy',
|
|
346
373
|
timestamp: new Date().toISOString(),
|
|
347
374
|
checks: {},
|
|
348
|
-
calculateResponseTime: () => Date.now() - startTime
|
|
375
|
+
calculateResponseTime: () => Date.now() - startTime,
|
|
349
376
|
};
|
|
350
377
|
};
|
|
351
378
|
|
|
@@ -353,7 +380,7 @@ router.get('/health', async (_req, res) => {
|
|
|
353
380
|
const status = {
|
|
354
381
|
status: 'ok',
|
|
355
382
|
timestamp: new Date().toISOString(),
|
|
356
|
-
service: 'frigg-core-api'
|
|
383
|
+
service: 'frigg-core-api',
|
|
357
384
|
};
|
|
358
385
|
|
|
359
386
|
res.status(200).json(status);
|
|
@@ -372,7 +399,7 @@ router.get('/health/detailed', async (_req, res) => {
|
|
|
372
399
|
} catch (error) {
|
|
373
400
|
response.checks.database = {
|
|
374
401
|
status: 'unhealthy',
|
|
375
|
-
error: error.message
|
|
402
|
+
error: error.message,
|
|
376
403
|
};
|
|
377
404
|
response.status = 'unhealthy';
|
|
378
405
|
}
|
|
@@ -385,7 +412,7 @@ router.get('/health/detailed', async (_req, res) => {
|
|
|
385
412
|
} catch (error) {
|
|
386
413
|
response.checks.encryption = {
|
|
387
414
|
status: 'unhealthy',
|
|
388
|
-
error: error.message
|
|
415
|
+
error: error.message,
|
|
389
416
|
};
|
|
390
417
|
response.status = 'unhealthy';
|
|
391
418
|
}
|
|
@@ -401,7 +428,7 @@ router.get('/health/detailed', async (_req, res) => {
|
|
|
401
428
|
} catch (error) {
|
|
402
429
|
response.checks.integrations = {
|
|
403
430
|
status: 'unhealthy',
|
|
404
|
-
error: error.message
|
|
431
|
+
error: error.message,
|
|
405
432
|
};
|
|
406
433
|
response.status = 'unhealthy';
|
|
407
434
|
}
|
|
@@ -416,14 +443,14 @@ router.get('/health/detailed', async (_req, res) => {
|
|
|
416
443
|
router.get('/health/live', (_req, res) => {
|
|
417
444
|
res.status(200).json({
|
|
418
445
|
status: 'alive',
|
|
419
|
-
timestamp: new Date().toISOString()
|
|
446
|
+
timestamp: new Date().toISOString(),
|
|
420
447
|
});
|
|
421
448
|
});
|
|
422
449
|
|
|
423
450
|
router.get('/health/ready', async (_req, res) => {
|
|
424
451
|
const dbState = getDatabaseState();
|
|
425
452
|
const isDbReady = dbState.isConnected;
|
|
426
|
-
|
|
453
|
+
|
|
427
454
|
let areModulesReady = false;
|
|
428
455
|
try {
|
|
429
456
|
const moduleTypes = Array.isArray(moduleFactory.moduleTypes)
|
|
@@ -441,11 +468,11 @@ router.get('/health/ready', async (_req, res) => {
|
|
|
441
468
|
timestamp: new Date().toISOString(),
|
|
442
469
|
checks: {
|
|
443
470
|
database: isDbReady,
|
|
444
|
-
modules: areModulesReady
|
|
445
|
-
}
|
|
471
|
+
modules: areModulesReady,
|
|
472
|
+
},
|
|
446
473
|
});
|
|
447
474
|
});
|
|
448
475
|
|
|
449
476
|
const handler = createAppHandler('HTTP Event: Health', router);
|
|
450
477
|
|
|
451
|
-
module.exports = { handler, router };
|
|
478
|
+
module.exports = { handler, router };
|
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.419.
|
|
4
|
+
"version": "2.0.0--canary.419.6e5f240.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@hapi/boom": "^10.0.1",
|
|
7
7
|
"aws-sdk": "^2.1200.0",
|
|
@@ -22,9 +22,9 @@
|
|
|
22
22
|
"uuid": "^9.0.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@friggframework/eslint-config": "2.0.0--canary.419.
|
|
26
|
-
"@friggframework/prettier-config": "2.0.0--canary.419.
|
|
27
|
-
"@friggframework/test": "2.0.0--canary.419.
|
|
25
|
+
"@friggframework/eslint-config": "2.0.0--canary.419.6e5f240.0",
|
|
26
|
+
"@friggframework/prettier-config": "2.0.0--canary.419.6e5f240.0",
|
|
27
|
+
"@friggframework/test": "2.0.0--canary.419.6e5f240.0",
|
|
28
28
|
"@types/lodash": "4.17.15",
|
|
29
29
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
30
30
|
"chai": "^4.3.6",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"publishConfig": {
|
|
57
57
|
"access": "public"
|
|
58
58
|
},
|
|
59
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "6e5f240c068ad7882b6e30c6976419d24cb8e5c2"
|
|
60
60
|
}
|