@luvio/environments 0.160.2 → 0.160.3
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/dist/environments.js +253 -56
- package/dist/types/utils/language.d.ts +2 -2
- package/package.json +5 -5
package/dist/environments.js
CHANGED
|
@@ -22,7 +22,7 @@ const RedirectDurableSegment = 'REDIRECT_KEYS';
|
|
|
22
22
|
const MessagingDurableSegment = 'MESSAGING';
|
|
23
23
|
const MessageNotifyStoreUpdateAvailable = 'notifyStoreUpdateAvailable';
|
|
24
24
|
|
|
25
|
-
const { keys, create, assign, freeze } = Object;
|
|
25
|
+
const { keys, create, assign, freeze, isFrozen } = Object;
|
|
26
26
|
|
|
27
27
|
//Durable store error instrumentation key
|
|
28
28
|
const DURABLE_STORE_ERROR = 'durable-store-error';
|
|
@@ -109,6 +109,74 @@ function publishDurableStoreEntries(durableRecords, put, publishMetadata) {
|
|
|
109
109
|
}
|
|
110
110
|
return { revivedKeys, hadUnexpectedShape };
|
|
111
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Extracts field filtering configuration from the selection.
|
|
114
|
+
*/
|
|
115
|
+
function extractFieldFilteringConfig(select, recordId, baseEnvironment) {
|
|
116
|
+
const rootRecordKey = serializeStructuredKey(baseEnvironment.storeGetCanonicalKey(recordId));
|
|
117
|
+
let topLevelFields;
|
|
118
|
+
let nestedFieldRequirements;
|
|
119
|
+
if (select &&
|
|
120
|
+
select.node.kind === 'Fragment' &&
|
|
121
|
+
'selections' in select.node &&
|
|
122
|
+
select.node.selections) {
|
|
123
|
+
topLevelFields = extractRequestedFieldNames(select.node.selections);
|
|
124
|
+
nestedFieldRequirements = extractNestedFieldRequirements(select.node.selections);
|
|
125
|
+
}
|
|
126
|
+
// Merge all nested field requirements into a single set
|
|
127
|
+
let nestedFields;
|
|
128
|
+
if (nestedFieldRequirements && nestedFieldRequirements.size > 0) {
|
|
129
|
+
nestedFields = new Set();
|
|
130
|
+
for (const fieldSet of nestedFieldRequirements.values()) {
|
|
131
|
+
for (const field of fieldSet) {
|
|
132
|
+
nestedFields.add(field);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return { rootRecordKey, topLevelFields, nestedFields };
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Categorizes keys into different fetch strategies based on filtering requirements.
|
|
140
|
+
*/
|
|
141
|
+
function categorizeKeysForL2Fetch(keysToRevive, config, baseEnvironment, shouldFilterFields) {
|
|
142
|
+
const unfilteredKeys = [];
|
|
143
|
+
const rootKeysWithTopLevelFields = [];
|
|
144
|
+
const nestedKeysWithNestedFields = [];
|
|
145
|
+
const canFilter = config.topLevelFields !== undefined && config.topLevelFields.size > 0;
|
|
146
|
+
for (let i = 0, len = keysToRevive.length; i < len; i += 1) {
|
|
147
|
+
const canonicalKey = serializeStructuredKey(baseEnvironment.storeGetCanonicalKey(keysToRevive[i]));
|
|
148
|
+
if (!shouldFilterFields(canonicalKey) || !canFilter) {
|
|
149
|
+
unfilteredKeys.push(canonicalKey);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const isRootRecord = canonicalKey === config.rootRecordKey;
|
|
153
|
+
if (isRootRecord) {
|
|
154
|
+
rootKeysWithTopLevelFields.push(canonicalKey);
|
|
155
|
+
}
|
|
156
|
+
else if (config.nestedFields !== undefined && config.nestedFields.size > 0) {
|
|
157
|
+
nestedKeysWithNestedFields.push(canonicalKey);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
unfilteredKeys.push(canonicalKey);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return { unfilteredKeys, rootKeysWithTopLevelFields, nestedKeysWithNestedFields };
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Builds L2 fetch promises for different key categories.
|
|
167
|
+
*/
|
|
168
|
+
function buildL2FetchPromises(categorizedKeys, config, durableStore) {
|
|
169
|
+
const promises = [
|
|
170
|
+
durableStore.getEntries(categorizedKeys.unfilteredKeys, DefaultDurableSegment),
|
|
171
|
+
];
|
|
172
|
+
if (config.topLevelFields && categorizedKeys.rootKeysWithTopLevelFields.length > 0) {
|
|
173
|
+
promises.push(durableStore.getEntriesWithSpecificFields(categorizedKeys.rootKeysWithTopLevelFields, config.topLevelFields, DefaultDurableSegment));
|
|
174
|
+
}
|
|
175
|
+
if (config.nestedFields && categorizedKeys.nestedKeysWithNestedFields.length > 0) {
|
|
176
|
+
promises.push(durableStore.getEntriesWithSpecificFields(categorizedKeys.nestedKeysWithNestedFields, config.nestedFields, DefaultDurableSegment));
|
|
177
|
+
}
|
|
178
|
+
return promises;
|
|
179
|
+
}
|
|
112
180
|
/**
|
|
113
181
|
* This method returns a Promise to a snapshot that is revived from L2 cache. If
|
|
114
182
|
* L2 does not have the entries necessary to fulfill the snapshot then this method
|
|
@@ -144,53 +212,41 @@ function reviveSnapshot(baseEnvironment, durableStore, unavailableSnapshot, dura
|
|
|
144
212
|
const keysToRevive = keysToReviveSet.keysAsArray();
|
|
145
213
|
const start = Date.now();
|
|
146
214
|
const { l2Trips } = reviveMetrics;
|
|
147
|
-
// Extract
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (requestedFields !== undefined &&
|
|
158
|
-
requestedFields.size > 0 &&
|
|
159
|
-
shouldFilterFields(canonicalKey)) {
|
|
160
|
-
filteredCanonicalKeys.push(canonicalKey);
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
canonicalKeys.push(canonicalKey);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
const fetchPromises = [
|
|
167
|
-
durableStore.getEntries(canonicalKeys, DefaultDurableSegment),
|
|
168
|
-
];
|
|
169
|
-
if (requestedFields !== undefined &&
|
|
170
|
-
requestedFields.size > 0 &&
|
|
171
|
-
filteredCanonicalKeys.length > 0) {
|
|
172
|
-
fetchPromises.push(durableStore.getEntriesWithSpecificFields(filteredCanonicalKeys, requestedFields, DefaultDurableSegment));
|
|
173
|
-
}
|
|
174
|
-
return Promise.all(fetchPromises).then(([durableRecords, filteredDurableRecords]) => {
|
|
215
|
+
// Extract field filtering requirements from the selection
|
|
216
|
+
const fieldFilteringConfig = extractFieldFilteringConfig(select, recordId, baseEnvironment);
|
|
217
|
+
// Categorize keys by how they should be fetched from L2
|
|
218
|
+
const categorizedKeys = categorizeKeysForL2Fetch(keysToRevive, fieldFilteringConfig, baseEnvironment, shouldFilterFields);
|
|
219
|
+
// Build fetch promises for each category
|
|
220
|
+
const fetchPromises = buildL2FetchPromises(categorizedKeys, fieldFilteringConfig, durableStore);
|
|
221
|
+
return Promise.all(fetchPromises).then(([durableRecords, filteredDurableRecords, nestedFilteredDurableRecords]) => {
|
|
222
|
+
const totalKeysRequested = categorizedKeys.unfilteredKeys.length +
|
|
223
|
+
categorizedKeys.rootKeysWithTopLevelFields.length +
|
|
224
|
+
categorizedKeys.nestedKeysWithNestedFields.length;
|
|
175
225
|
l2Trips.push({
|
|
176
226
|
duration: Date.now() - start,
|
|
177
|
-
keysRequestedCount:
|
|
227
|
+
keysRequestedCount: totalKeysRequested,
|
|
178
228
|
});
|
|
179
|
-
// Process
|
|
229
|
+
// Process all three categories of records
|
|
180
230
|
const revivedKeys = new StoreKeySet();
|
|
181
231
|
let hadUnexpectedShape = false;
|
|
182
|
-
// Process normal records
|
|
232
|
+
// Process normal records (all fields)
|
|
183
233
|
if (durableRecords !== undefined) {
|
|
184
234
|
const normalResult = publishDurableStoreEntries(durableRecords, baseEnvironment.storePut.bind(baseEnvironment), baseEnvironment.publishStoreMetadata.bind(baseEnvironment));
|
|
185
235
|
revivedKeys.merge(normalResult.revivedKeys);
|
|
186
236
|
hadUnexpectedShape = hadUnexpectedShape || normalResult.hadUnexpectedShape;
|
|
187
237
|
}
|
|
188
|
-
// Process filtered records with merging
|
|
238
|
+
// Process filtered records (root with top-level fields) with merging
|
|
189
239
|
if (filteredDurableRecords !== undefined) {
|
|
190
240
|
const filteredResult = publishDurableStoreEntries(filteredDurableRecords, createMergeFilteredPut((key) => baseEnvironment.store.readEntry(key), baseEnvironment.storePut.bind(baseEnvironment)), baseEnvironment.publishStoreMetadata.bind(baseEnvironment));
|
|
191
241
|
revivedKeys.merge(filteredResult.revivedKeys);
|
|
192
242
|
hadUnexpectedShape = hadUnexpectedShape || filteredResult.hadUnexpectedShape;
|
|
193
243
|
}
|
|
244
|
+
// Process nested filtered records with merging
|
|
245
|
+
if (nestedFilteredDurableRecords !== undefined) {
|
|
246
|
+
const nestedFilteredResult = publishDurableStoreEntries(nestedFilteredDurableRecords, createMergeFilteredPut((key) => baseEnvironment.store.readEntry(key), baseEnvironment.storePut.bind(baseEnvironment)), baseEnvironment.publishStoreMetadata.bind(baseEnvironment));
|
|
247
|
+
revivedKeys.merge(nestedFilteredResult.revivedKeys);
|
|
248
|
+
hadUnexpectedShape = hadUnexpectedShape || nestedFilteredResult.hadUnexpectedShape;
|
|
249
|
+
}
|
|
194
250
|
// if the data coming back from DS had an unexpected shape then just
|
|
195
251
|
// return the L1 snapshot
|
|
196
252
|
if (hadUnexpectedShape === true) {
|
|
@@ -236,6 +292,54 @@ function reviveSnapshot(baseEnvironment, durableStore, unavailableSnapshot, dura
|
|
|
236
292
|
return { snapshot: unavailableSnapshot, metrics: reviveMetrics };
|
|
237
293
|
});
|
|
238
294
|
}
|
|
295
|
+
/**
|
|
296
|
+
* Filters out null fields from a fields object (null indicates field doesn't exist in L2).
|
|
297
|
+
* Returns a new object without null values, or the original if no filtering needed.
|
|
298
|
+
*/
|
|
299
|
+
function filterNullFields(fields) {
|
|
300
|
+
const keys$1 = keys(fields);
|
|
301
|
+
let hasNull = false;
|
|
302
|
+
// Check if any nulls exist before allocating new object
|
|
303
|
+
for (let i = 0, len = keys$1.length; i < len; i += 1) {
|
|
304
|
+
if (fields[keys$1[i]] === null) {
|
|
305
|
+
hasNull = true;
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (!hasNull) {
|
|
310
|
+
return fields;
|
|
311
|
+
}
|
|
312
|
+
const cleaned = {};
|
|
313
|
+
for (let i = 0, len = keys$1.length; i < len; i += 1) {
|
|
314
|
+
const key = keys$1[i];
|
|
315
|
+
if (fields[key] !== null) {
|
|
316
|
+
cleaned[key] = fields[key];
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return cleaned;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Merges new fields into existing fields object, skipping null values.
|
|
323
|
+
* Creates a new object to avoid mutations.
|
|
324
|
+
*/
|
|
325
|
+
function mergeFieldsObjects(existing, incoming) {
|
|
326
|
+
const merged = { ...existing };
|
|
327
|
+
const keys$1 = keys(incoming);
|
|
328
|
+
for (let i = 0, len = keys$1.length; i < len; i += 1) {
|
|
329
|
+
const key = keys$1[i];
|
|
330
|
+
// Skip null values - they indicate the field doesn't exist in L2
|
|
331
|
+
if (incoming[key] !== null) {
|
|
332
|
+
merged[key] = incoming[key];
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return merged;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Type guard to check if value is a non-null object.
|
|
339
|
+
*/
|
|
340
|
+
function isObject(value) {
|
|
341
|
+
return typeof value === 'object' && value !== null;
|
|
342
|
+
}
|
|
239
343
|
/**
|
|
240
344
|
* Creates a put function that merges filtered fields with existing L1 records instead of replacing them.
|
|
241
345
|
* This is used when reviving filtered fields from L2 to preserve existing data in L1.
|
|
@@ -243,28 +347,36 @@ function reviveSnapshot(baseEnvironment, durableStore, unavailableSnapshot, dura
|
|
|
243
347
|
function createMergeFilteredPut(readEntry, storePut) {
|
|
244
348
|
return (key, filteredData) => {
|
|
245
349
|
const existingRecord = readEntry(key);
|
|
246
|
-
if
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
350
|
+
// Merge with existing record if both are objects
|
|
351
|
+
if (isObject(existingRecord) && isObject(filteredData)) {
|
|
352
|
+
// Create target object (copy if frozen to avoid mutation errors)
|
|
353
|
+
const targetObj = isFrozen(existingRecord)
|
|
354
|
+
? { ...existingRecord }
|
|
355
|
+
: existingRecord;
|
|
356
|
+
const keys$1 = keys(filteredData);
|
|
357
|
+
for (let i = 0, len = keys$1.length; i < len; i += 1) {
|
|
358
|
+
const fieldKey = keys$1[i];
|
|
359
|
+
const incomingValue = filteredData[fieldKey];
|
|
360
|
+
// Special handling for 'fields' property to merge rather than replace
|
|
361
|
+
if (fieldKey === 'fields' &&
|
|
362
|
+
isObject(incomingValue) &&
|
|
363
|
+
isObject(targetObj[fieldKey])) {
|
|
364
|
+
targetObj[fieldKey] = mergeFieldsObjects(targetObj[fieldKey], incomingValue);
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
targetObj[fieldKey] = incomingValue;
|
|
368
|
+
}
|
|
263
369
|
}
|
|
264
370
|
storePut(key, targetObj);
|
|
265
371
|
}
|
|
266
372
|
else {
|
|
267
|
-
// No existing record
|
|
373
|
+
// No existing record - clean null fields before storing
|
|
374
|
+
if (isObject(filteredData) && 'fields' in filteredData) {
|
|
375
|
+
const fields = filteredData.fields;
|
|
376
|
+
if (isObject(fields)) {
|
|
377
|
+
filteredData.fields = filterNullFields(fields);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
268
380
|
storePut(key, filteredData);
|
|
269
381
|
}
|
|
270
382
|
};
|
|
@@ -278,16 +390,101 @@ function extractRequestedFieldNames(selections) {
|
|
|
278
390
|
return undefined;
|
|
279
391
|
}
|
|
280
392
|
// Find the 'fields' ObjectSelection
|
|
281
|
-
|
|
282
|
-
|
|
393
|
+
let fieldsSelection;
|
|
394
|
+
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
395
|
+
const sel = selections[i];
|
|
396
|
+
if (sel.kind === 'Object' && sel.name === 'fields') {
|
|
397
|
+
fieldsSelection = sel;
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (!fieldsSelection ||
|
|
402
|
+
!fieldsSelection.selections ||
|
|
403
|
+
fieldsSelection.selections.length === 0) {
|
|
283
404
|
return undefined;
|
|
284
405
|
}
|
|
285
406
|
// Extract all field names from the fields selections
|
|
407
|
+
const fieldSelections = fieldsSelection.selections;
|
|
286
408
|
const fieldNames = new Set();
|
|
287
|
-
for (
|
|
288
|
-
fieldNames.add(
|
|
409
|
+
for (let i = 0, len = fieldSelections.length; i < len; i += 1) {
|
|
410
|
+
fieldNames.add(fieldSelections[i].name);
|
|
411
|
+
}
|
|
412
|
+
return fieldNames;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Extracts nested field requirements for spanning fields.
|
|
416
|
+
* For spanning fields like Case.CreatedBy.Name, we need to extract what fields
|
|
417
|
+
* are requested from the nested record (User in this case).
|
|
418
|
+
* The structure is: fields { CreatedBy { value (Link with fragment) { fields { Name } } } }
|
|
419
|
+
*/
|
|
420
|
+
function extractNestedFieldRequirements(selections) {
|
|
421
|
+
if (!selections) {
|
|
422
|
+
return undefined;
|
|
423
|
+
}
|
|
424
|
+
// Find the 'fields' ObjectSelection
|
|
425
|
+
let fieldsSelection;
|
|
426
|
+
for (let i = 0, len = selections.length; i < len; i += 1) {
|
|
427
|
+
const sel = selections[i];
|
|
428
|
+
if (sel.kind === 'Object' && sel.name === 'fields') {
|
|
429
|
+
fieldsSelection = sel;
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (!fieldsSelection || !fieldsSelection.selections) {
|
|
434
|
+
return undefined;
|
|
435
|
+
}
|
|
436
|
+
let nestedFieldsMap;
|
|
437
|
+
// Look for ObjectSelections within fields (these are spanning fields)
|
|
438
|
+
const fieldSelections = fieldsSelection.selections;
|
|
439
|
+
for (let i = 0, len = fieldSelections.length; i < len; i += 1) {
|
|
440
|
+
const fieldSel = fieldSelections[i];
|
|
441
|
+
if (fieldSel.kind !== 'Object') {
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
const objSel = fieldSel;
|
|
445
|
+
if (!objSel.selections) {
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
// Look for the 'value' Link selection
|
|
449
|
+
let valueLinkSelection;
|
|
450
|
+
for (let j = 0, jlen = objSel.selections.length; j < jlen; j += 1) {
|
|
451
|
+
const sel = objSel.selections[j];
|
|
452
|
+
if (sel.kind === 'Link' && sel.name === 'value') {
|
|
453
|
+
valueLinkSelection = sel;
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if (!valueLinkSelection || !('fragment' in valueLinkSelection)) {
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
const fragment = valueLinkSelection.fragment;
|
|
461
|
+
if (!fragment || !fragment.selections) {
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
// Look for the 'fields' selection within the fragment
|
|
465
|
+
let nestedFieldsSelection;
|
|
466
|
+
for (let j = 0, jlen = fragment.selections.length; j < jlen; j += 1) {
|
|
467
|
+
const sel = fragment.selections[j];
|
|
468
|
+
if (sel.kind === 'Object' && sel.name === 'fields') {
|
|
469
|
+
nestedFieldsSelection = sel;
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
if (nestedFieldsSelection && nestedFieldsSelection.selections) {
|
|
474
|
+
const nestedFields = new Set();
|
|
475
|
+
for (const nestedFieldSel of nestedFieldsSelection.selections) {
|
|
476
|
+
nestedFields.add(nestedFieldSel.name);
|
|
477
|
+
}
|
|
478
|
+
if (nestedFields.size > 0) {
|
|
479
|
+
// Lazy initialize map only if we have nested fields
|
|
480
|
+
if (!nestedFieldsMap) {
|
|
481
|
+
nestedFieldsMap = new Map();
|
|
482
|
+
}
|
|
483
|
+
nestedFieldsMap.set(fieldSel.name, nestedFields);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
289
486
|
}
|
|
290
|
-
return
|
|
487
|
+
return nestedFieldsMap;
|
|
291
488
|
}
|
|
292
489
|
|
|
293
490
|
const TTL_DURABLE_SEGMENT = 'TTL_DURABLE_SEGMENT';
|
|
@@ -15,7 +15,7 @@ declare const keys: {
|
|
|
15
15
|
[idx: string]: object | U | null | undefined;
|
|
16
16
|
}, U extends string | number | bigint | boolean | symbol>(o: T_1): Readonly<T_1>;
|
|
17
17
|
<T_2>(o: T_2): Readonly<T_2>;
|
|
18
|
-
};
|
|
18
|
+
}, isFrozen: (o: any) => boolean;
|
|
19
19
|
declare const hasOwnProperty: (v: PropertyKey) => boolean;
|
|
20
20
|
declare const isArray: (arg: any) => arg is any[];
|
|
21
|
-
export { create as ObjectCreate, keys as ObjectKeys, assign as ObjectAssign, freeze as ObjectFreeze, hasOwnProperty as ObjectPrototypeHasOwnProperty, isArray as ArrayIsArray, };
|
|
21
|
+
export { create as ObjectCreate, keys as ObjectKeys, assign as ObjectAssign, freeze as ObjectFreeze, isFrozen as ObjectIsFrozen, hasOwnProperty as ObjectPrototypeHasOwnProperty, isArray as ArrayIsArray, };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luvio/environments",
|
|
3
|
-
"version": "0.160.
|
|
3
|
+
"version": "0.160.3",
|
|
4
4
|
"description": "Luvio Environments",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"watch": "yarn build --watch"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@luvio/engine": "^0.160.
|
|
30
|
+
"@luvio/engine": "^0.160.3"
|
|
31
31
|
},
|
|
32
32
|
"volta": {
|
|
33
33
|
"extends": "../../../package.json"
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
{
|
|
37
37
|
"path": "./dist/environments.js",
|
|
38
38
|
"maxSize": {
|
|
39
|
-
"none": "
|
|
40
|
-
"min": "
|
|
41
|
-
"compressed": "
|
|
39
|
+
"none": "62.0 kB",
|
|
40
|
+
"min": "18.0 kB",
|
|
41
|
+
"compressed": "11.5 kB"
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
],
|