@pdtf/schemas 3.4.1-6 → 3.4.1-8

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.
@@ -8,7 +8,12 @@
8
8
  "Bash(jq:*)",
9
9
  "Bash(grep:*)",
10
10
  "Bash(rm:*)",
11
- "Bash(npm test:*)"
11
+ "Bash(npm test:*)",
12
+ "Bash(npm install:*)",
13
+ "Bash(git merge:*)",
14
+ "Bash(git add:*)",
15
+ "Bash(git commit:*)",
16
+ "Bash(git push:*)"
12
17
  ],
13
18
  "deny": []
14
19
  }
package/index.js CHANGED
@@ -13,6 +13,14 @@ addFormats(ajv);
13
13
  // Enhanced caching structure for subschemas and validators
14
14
  const schemaCache = new Map();
15
15
 
16
+ // Cache performance tracking
17
+ const cacheStats = {
18
+ hits: 0,
19
+ misses: 0,
20
+ totalQueries: 0,
21
+ cacheStartTime: Date.now()
22
+ };
23
+
16
24
  const verifiedClaimsSchema = require("./src/schemas/verifiedClaims/pdtf-verified-claims.json");
17
25
  const v2CoreSchema = require("./src/schemas/v2/pdtf-transaction.json");
18
26
  const v3CoreSchema = require("./src/schemas/v3/pdtf-transaction.json");
@@ -188,8 +196,10 @@ const getCachedSchemaData = (path, schemaId, overlays) => {
188
196
  const overlayKey = generateOverlayKey(overlays);
189
197
  const cacheKey = `${path}-${schemaId}-${overlayKey}`;
190
198
 
199
+ cacheStats.totalQueries++;
191
200
  let cached = schemaCache.get(cacheKey);
192
201
  if (!cached) {
202
+ cacheStats.misses++;
193
203
  // Compute subschema using the original logic
194
204
  const sourceSchema = getTransactionSchema(schemaId, overlays);
195
205
  const pathArray = path.split("/").slice(1);
@@ -235,9 +245,12 @@ const getCachedSchemaData = (path, schemaId, overlays) => {
235
245
  cached = {
236
246
  subSchema,
237
247
  validator,
238
- cacheKey
248
+ cacheKey,
249
+ createdAt: Date.now()
239
250
  };
240
251
  schemaCache.set(cacheKey, cached);
252
+ } else {
253
+ cacheStats.hits++;
241
254
  }
242
255
 
243
256
  return cached;
@@ -348,17 +361,178 @@ const validateVerifiedClaims = (verifiedClaims, schemaId, overlays) => {
348
361
  };
349
362
 
350
363
  // Cache management functions
351
- const getCacheStats = () => ({
352
- totalEntries: schemaCache.size,
353
- cacheKeys: Array.from(schemaCache.keys())
354
- });
364
+ const getCacheStats = () => {
365
+ const runtime = Date.now() - cacheStats.cacheStartTime;
366
+ const hitRate = cacheStats.totalQueries > 0 ? (cacheStats.hits / cacheStats.totalQueries * 100) : 0;
367
+
368
+ return {
369
+ totalEntries: schemaCache.size,
370
+ hits: cacheStats.hits,
371
+ misses: cacheStats.misses,
372
+ totalQueries: cacheStats.totalQueries,
373
+ hitRate: parseFloat(hitRate.toFixed(2)),
374
+ runtimeMs: runtime,
375
+ cacheKeys: Array.from(schemaCache.keys()),
376
+ memoryUsage: {
377
+ entriesCount: schemaCache.size,
378
+ // Rough estimate of memory usage per entry
379
+ estimatedSizeKB: Math.round((schemaCache.size * 2) / 1024 * 100) / 100 // Rough estimate
380
+ }
381
+ };
382
+ };
383
+
384
+ const getDetailedCacheStats = () => {
385
+ const baseStats = getCacheStats();
386
+ const entries = Array.from(schemaCache.entries()).map(([key, value]) => ({
387
+ key,
388
+ createdAt: value.createdAt,
389
+ age: Date.now() - value.createdAt,
390
+ hasValidator: typeof value.validator === 'function',
391
+ hasSubSchema: value.subSchema !== undefined
392
+ }));
393
+
394
+ return {
395
+ ...baseStats,
396
+ entries: entries.sort((a, b) => b.createdAt - a.createdAt), // Most recent first
397
+ oldestEntry: entries.length > 0 ? Math.max(...entries.map(e => e.age)) : 0,
398
+ newestEntry: entries.length > 0 ? Math.min(...entries.map(e => e.age)) : 0
399
+ };
400
+ };
355
401
 
356
- const clearSchemaCache = () => {
357
- // Clear our cache
358
- schemaCache.clear();
359
- // Also clear AJV's internal cache to prevent duplicates
360
- // Note: This removes all schemas from AJV, which is what we want for testing
361
- ajv.removeSchema();
402
+ const clearSchemaCache = (pattern) => {
403
+ if (pattern) {
404
+ // Clear entries matching pattern
405
+ const keysToDelete = [];
406
+ schemaCache.forEach((value, key) => {
407
+ if (key.includes(pattern)) {
408
+ keysToDelete.push(key);
409
+ }
410
+ });
411
+ keysToDelete.forEach(key => schemaCache.delete(key));
412
+
413
+ // Also remove matching schemas from AJV
414
+ keysToDelete.forEach(key => {
415
+ try {
416
+ ajv.removeSchema(key);
417
+ } catch (e) {
418
+ // Schema might not exist in AJV, ignore
419
+ }
420
+ });
421
+
422
+ return keysToDelete.length;
423
+ } else {
424
+ // Clear all cache
425
+ const entriesCleared = schemaCache.size;
426
+ schemaCache.clear();
427
+ // Reset stats
428
+ cacheStats.hits = 0;
429
+ cacheStats.misses = 0;
430
+ cacheStats.totalQueries = 0;
431
+ cacheStats.cacheStartTime = Date.now();
432
+
433
+ // Also clear AJV's internal cache to prevent duplicates
434
+ ajv.removeSchema();
435
+
436
+ return entriesCleared;
437
+ }
438
+ };
439
+
440
+ const warmupCache = (paths, schemaId = "https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json", overlaysList = []) => {
441
+ const warmupStats = {
442
+ totalAttempted: 0,
443
+ successful: 0,
444
+ failed: 0,
445
+ errors: []
446
+ };
447
+
448
+ // Default common paths if none provided
449
+ const defaultPaths = [
450
+ "/propertyPack",
451
+ "/participants",
452
+ "/status",
453
+ "/propertyPack/surveys",
454
+ "/propertyPack/valuations",
455
+ "/propertyPack/waterAndDrainage",
456
+ "/propertyPack/ownership",
457
+ "/propertyPack/notices"
458
+ ];
459
+
460
+ // Default common overlays if none provided
461
+ const defaultOverlays = [
462
+ [],
463
+ ["baspiV5"],
464
+ ["ta6ed4"],
465
+ ["nts2023"],
466
+ ["baspiV5", "ta6ed4"]
467
+ ];
468
+
469
+ const pathsToWarm = paths || defaultPaths;
470
+ const overlaysToWarm = overlaysList.length > 0 ? overlaysList : defaultOverlays;
471
+
472
+ pathsToWarm.forEach(path => {
473
+ overlaysToWarm.forEach(overlays => {
474
+ warmupStats.totalAttempted++;
475
+ try {
476
+ // This will populate the cache
477
+ getSubschema(path, schemaId, overlays);
478
+ getSubschemaValidator(path, schemaId, overlays);
479
+ warmupStats.successful++;
480
+ } catch (error) {
481
+ warmupStats.failed++;
482
+ warmupStats.errors.push({
483
+ path,
484
+ overlays,
485
+ error: error.message
486
+ });
487
+ }
488
+ });
489
+ });
490
+
491
+ return warmupStats;
492
+ };
493
+
494
+ const pruneCacheByAge = (maxAgeMs) => {
495
+ const now = Date.now();
496
+ const keysToDelete = [];
497
+
498
+ schemaCache.forEach((value, key) => {
499
+ if (now - value.createdAt > maxAgeMs) {
500
+ keysToDelete.push(key);
501
+ }
502
+ });
503
+
504
+ keysToDelete.forEach(key => {
505
+ schemaCache.delete(key);
506
+ try {
507
+ ajv.removeSchema(key);
508
+ } catch (e) {
509
+ // Schema might not exist in AJV, ignore
510
+ }
511
+ });
512
+
513
+ return keysToDelete.length;
514
+ };
515
+
516
+ const setCacheMaxSize = (maxSize) => {
517
+ if (schemaCache.size <= maxSize) return 0;
518
+
519
+ // Get entries sorted by creation time (oldest first)
520
+ const entries = Array.from(schemaCache.entries())
521
+ .sort((a, b) => a[1].createdAt - b[1].createdAt);
522
+
523
+ const toRemove = schemaCache.size - maxSize;
524
+ const keysToDelete = entries.slice(0, toRemove).map(([key]) => key);
525
+
526
+ keysToDelete.forEach(key => {
527
+ schemaCache.delete(key);
528
+ try {
529
+ ajv.removeSchema(key);
530
+ } catch (e) {
531
+ // Schema might not exist in AJV, ignore
532
+ }
533
+ });
534
+
535
+ return keysToDelete.length;
362
536
  };
363
537
 
364
538
  module.exports = {
@@ -373,7 +547,11 @@ module.exports = {
373
547
  validateVerifiedClaims,
374
548
  overlaysMap,
375
549
  extensionOverlays,
376
- // New cache management functions
550
+ // Enhanced cache management functions
377
551
  getCacheStats,
552
+ getDetailedCacheStats,
378
553
  clearSchemaCache,
554
+ warmupCache,
555
+ pruneCacheByAge,
556
+ setCacheMaxSize,
379
557
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pdtf/schemas",
3
- "version": "3.4.1-6",
3
+ "version": "3.4.1-8",
4
4
  "description": "Property Data Trust Framework Schemas and Utilities",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -29,6 +29,7 @@
29
29
  "ajv": "^8.12.0",
30
30
  "ajv-formats": "^2.1.1",
31
31
  "deepmerge": "^4.3.1",
32
+ "gpt-3-encoder": "^1.1.4",
32
33
  "jsonpointer": "^5.0.0",
33
34
  "traverse": "^0.6.7"
34
35
  },
@@ -9228,6 +9228,12 @@
9228
9228
  "controlledParking",
9229
9229
  "electricVehicleChargingPoint"
9230
9230
  ],
9231
+ "ntsl2Required": [
9232
+ "parkingArrangements",
9233
+ "disabledParking",
9234
+ "controlledParking",
9235
+ "electricVehicleChargingPoint"
9236
+ ],
9231
9237
  "ta6Required": ["parkingArrangements", "controlledParking"],
9232
9238
  "properties": {
9233
9239
  "parkingArrangements": {
@@ -9456,6 +9462,11 @@
9456
9462
  "isConservationArea",
9457
9463
  "hasTreePreservationOrder"
9458
9464
  ],
9465
+ "ntsl2Required": [
9466
+ "isListed",
9467
+ "isConservationArea",
9468
+ "hasTreePreservationOrder"
9469
+ ],
9459
9470
  "baspi4Required": [
9460
9471
  "isListed",
9461
9472
  "isConservationArea",