@pdtf/schemas 3.6.0-dev.3 → 3.6.0-dev.32

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.
Files changed (193) hide show
  1. package/docs/ta6-certificate-permit-contract.md +51 -0
  2. package/docs/v4-mapping-and-recomposition.md +476 -0
  3. package/index.js +212 -0
  4. package/package.json +10 -1
  5. package/src/schemas/v3/combined.json +2267 -658
  6. package/src/schemas/v3/compactSkeleton.txt +120 -51
  7. package/src/schemas/v3/overlays/baspi4.json +54 -74
  8. package/src/schemas/v3/overlays/baspi5.json +54 -74
  9. package/src/schemas/v3/overlays/extensions/ac.json +2 -1
  10. package/src/schemas/v3/overlays/extensions/dk.json +3 -2
  11. package/src/schemas/v3/overlays/extensions/fd.json +2 -1
  12. package/src/schemas/v3/overlays/extensions/ic.json +44 -9
  13. package/src/schemas/v3/overlays/extensions/lc.json +3 -2
  14. package/src/schemas/v3/overlays/extensions/mi.json +2 -1
  15. package/src/schemas/v3/overlays/extensions/nd.json +3 -2
  16. package/src/schemas/v3/overlays/extensions/pc.json +3 -2
  17. package/src/schemas/v3/overlays/extensions/ph.json +2 -1
  18. package/src/schemas/v3/overlays/extensions/rw.json +4 -3
  19. package/src/schemas/v3/overlays/extensions/sc.json +8 -4
  20. package/src/schemas/v3/overlays/extensions/sd.json +3 -2
  21. package/src/schemas/v3/overlays/extensions/tr.json +3 -2
  22. package/src/schemas/v3/overlays/extensions/wg.json +2 -1
  23. package/src/schemas/v3/overlays/llc1.json +1 -2
  24. package/src/schemas/v3/overlays/lpe1.json +3 -2
  25. package/src/schemas/v3/overlays/nts.json +7 -3
  26. package/src/schemas/v3/overlays/nts2.json +9 -4
  27. package/src/schemas/v3/overlays/ntsl.json +5 -2
  28. package/src/schemas/v3/overlays/ntsl2.json +7 -3
  29. package/src/schemas/v3/overlays/piq.json +34 -25
  30. package/src/schemas/v3/overlays/rds.json +24 -50
  31. package/src/schemas/v3/overlays/sef25.json +16 -2
  32. package/src/schemas/v3/overlays/ta10.json +0 -9
  33. package/src/schemas/v3/overlays/ta6.json +39 -70
  34. package/src/schemas/v3/overlays/ta6ed6.json +331 -307
  35. package/{pensive-tesla-d0d355/src/schemas/v3/overlays/ta6.json → src/schemas/v3/overlays/ta6ed6v2.json} +1574 -1464
  36. package/src/schemas/v3/overlays/ta7.json +2 -1
  37. package/src/schemas/v3/overlays/ta7ed5.json +77 -21
  38. package/src/schemas/v3/pdtf-transaction.json +1030 -492
  39. package/src/schemas/v3/skeleton.json +163 -57
  40. package/src/schemas/v4/Gift.json +88 -0
  41. package/src/schemas/v4/Offer.json +425 -0
  42. package/src/schemas/v4/Organisation.json +167 -0
  43. package/src/schemas/v4/Person.json +321 -0
  44. package/src/schemas/v4/Property.json +27813 -0
  45. package/src/schemas/v4/PropertyTitleLink.json +183 -0
  46. package/src/schemas/v4/Representation.json +67 -0
  47. package/src/schemas/v4/SellerCapacity.json +193 -0
  48. package/src/schemas/v4/Title.json +14675 -0
  49. package/src/schemas/v4/Transaction.json +1612 -0
  50. package/src/schemas/v4/TransactionRole.json +59 -0
  51. package/src/schemas/v4/mapping.json +1188 -0
  52. package/src/utils/checkTa6OmissionCompatibility.js +146 -0
  53. package/src/utils/extractExtensionOverlays.js +11 -2
  54. package/src/utils/extractOverlay.js +21 -0
  55. package/src/utils/generateV4Schemas.js +1561 -0
  56. package/src/utils/syncTa6ed6v2Markers.js +92 -0
  57. package/src/utils/v4.js +956 -0
  58. package/CLAUDE.md +0 -101
  59. package/pensive-tesla-d0d355/CLAUDE.md +0 -101
  60. package/pensive-tesla-d0d355/LICENSE +0 -21
  61. package/pensive-tesla-d0d355/README.md +0 -435
  62. package/pensive-tesla-d0d355/docs/branch-release-workflow.md +0 -138
  63. package/pensive-tesla-d0d355/docs/sef25-extensions-ui-spec.md +0 -355
  64. package/pensive-tesla-d0d355/index.js +0 -654
  65. package/pensive-tesla-d0d355/package-lock.json +0 -7297
  66. package/pensive-tesla-d0d355/package.json +0 -44
  67. package/pensive-tesla-d0d355/src/examples/v1/exampleAddParticipantVouch.json +0 -32
  68. package/pensive-tesla-d0d355/src/examples/v1/exampleDocumentedVouch.json +0 -40
  69. package/pensive-tesla-d0d355/src/examples/v1/exampleElectronicRecord.json +0 -30
  70. package/pensive-tesla-d0d355/src/examples/v1/exampleTransaction.json +0 -878
  71. package/pensive-tesla-d0d355/src/examples/v1/exampleVouch.json +0 -25
  72. package/pensive-tesla-d0d355/src/examples/v2/exampleTransaction.json +0 -901
  73. package/pensive-tesla-d0d355/src/examples/v3/exampleAddParticipantVouch.json +0 -38
  74. package/pensive-tesla-d0d355/src/examples/v3/exampleCustomOverlay.json +0 -55
  75. package/pensive-tesla-d0d355/src/examples/v3/exampleCustomOverlay2.json +0 -93
  76. package/pensive-tesla-d0d355/src/examples/v3/exampleDocumentedVouch.json +0 -47
  77. package/pensive-tesla-d0d355/src/examples/v3/exampleElectronicRecord.json +0 -36
  78. package/pensive-tesla-d0d355/src/examples/v3/exampleTransaction.json +0 -1038
  79. package/pensive-tesla-d0d355/src/examples/v3/exampleVouch.json +0 -32
  80. package/pensive-tesla-d0d355/src/mappings/SendPropertyDetailsRequestSchema.json +0 -1588
  81. package/pensive-tesla-d0d355/src/mappings/adf.js +0 -198
  82. package/pensive-tesla-d0d355/src/schemas/v1/GeoJSON.json +0 -1279
  83. package/pensive-tesla-d0d355/src/schemas/v1/baspiNotes.html +0 -102
  84. package/pensive-tesla-d0d355/src/schemas/v1/energy-performance-certificate.json +0 -124
  85. package/pensive-tesla-d0d355/src/schemas/v1/freehold-information.json +0 -2051
  86. package/pensive-tesla-d0d355/src/schemas/v1/leasehold-information.json +0 -2064
  87. package/pensive-tesla-d0d355/src/schemas/v1/legal-information.json +0 -1045
  88. package/pensive-tesla-d0d355/src/schemas/v1/material-facts.json +0 -2109
  89. package/pensive-tesla-d0d355/src/schemas/v1/pdtf-transaction-search-results.json +0 -40
  90. package/pensive-tesla-d0d355/src/schemas/v1/pdtf-transaction.json +0 -191
  91. package/pensive-tesla-d0d355/src/schemas/v1/searches/drainage-and-water.json +0 -261
  92. package/pensive-tesla-d0d355/src/schemas/v1/searches/local-land-charges.json +0 -69
  93. package/pensive-tesla-d0d355/src/schemas/v1/searches/local-searches-required.json +0 -857
  94. package/pensive-tesla-d0d355/src/schemas/v1/searches.json +0 -237
  95. package/pensive-tesla-d0d355/src/schemas/v1/title-deed.json +0 -841
  96. package/pensive-tesla-d0d355/src/schemas/v2/baspiNotes.html +0 -102
  97. package/pensive-tesla-d0d355/src/schemas/v2/combined.json +0 -37731
  98. package/pensive-tesla-d0d355/src/schemas/v2/overlays/baspi.json +0 -8132
  99. package/pensive-tesla-d0d355/src/schemas/v2/overlays/con29DW.json +0 -705
  100. package/pensive-tesla-d0d355/src/schemas/v2/overlays/con29R.json +0 -2956
  101. package/pensive-tesla-d0d355/src/schemas/v2/overlays/fme1.json +0 -1259
  102. package/pensive-tesla-d0d355/src/schemas/v2/overlays/llc1.json +0 -25
  103. package/pensive-tesla-d0d355/src/schemas/v2/overlays/lpe1.json +0 -2171
  104. package/pensive-tesla-d0d355/src/schemas/v2/overlays/nts.json +0 -326
  105. package/pensive-tesla-d0d355/src/schemas/v2/overlays/oc1.json +0 -2799
  106. package/pensive-tesla-d0d355/src/schemas/v2/overlays/piq.json +0 -3419
  107. package/pensive-tesla-d0d355/src/schemas/v2/overlays/rds.json +0 -3736
  108. package/pensive-tesla-d0d355/src/schemas/v2/overlays/ta10.json +0 -5306
  109. package/pensive-tesla-d0d355/src/schemas/v2/overlays/ta6.json +0 -4533
  110. package/pensive-tesla-d0d355/src/schemas/v2/overlays/ta7.json +0 -1045
  111. package/pensive-tesla-d0d355/src/schemas/v2/pdtf-transaction.json +0 -34351
  112. package/pensive-tesla-d0d355/src/schemas/v2/skeleton.json +0 -3973
  113. package/pensive-tesla-d0d355/src/schemas/v3/combined.json +0 -48469
  114. package/pensive-tesla-d0d355/src/schemas/v3/compactSkeleton.txt +0 -4519
  115. package/pensive-tesla-d0d355/src/schemas/v3/overlays/README.md +0 -299
  116. package/pensive-tesla-d0d355/src/schemas/v3/overlays/baspi4.json +0 -8025
  117. package/pensive-tesla-d0d355/src/schemas/v3/overlays/baspi5.json +0 -8175
  118. package/pensive-tesla-d0d355/src/schemas/v3/overlays/con29DW.json +0 -716
  119. package/pensive-tesla-d0d355/src/schemas/v3/overlays/con29R.json +0 -2981
  120. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/ac.json +0 -333
  121. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/as.json +0 -74
  122. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/dk.json +0 -32
  123. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/dr.json +0 -73
  124. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/er.json +0 -85
  125. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/fd.json +0 -75
  126. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/hi.json +0 -51
  127. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/hs.json +0 -73
  128. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/ic.json +0 -59
  129. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/jk.json +0 -96
  130. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/la.json +0 -85
  131. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/lc.json +0 -75
  132. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/ma.json +0 -90
  133. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/mc.json +0 -38
  134. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/mi.json +0 -69
  135. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/nd.json +0 -43
  136. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/oa.json +0 -24
  137. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/oc.json +0 -57
  138. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/pc.json +0 -37
  139. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/ph.json +0 -194
  140. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/rw.json +0 -68
  141. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/sb.json +0 -73
  142. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/sc.json +0 -129
  143. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/sd.json +0 -63
  144. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/sf.json +0 -74
  145. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/sl.json +0 -68
  146. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/ta.json +0 -252
  147. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/tf.json +0 -103
  148. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/tr.json +0 -73
  149. package/pensive-tesla-d0d355/src/schemas/v3/overlays/extensions/wg.json +0 -350
  150. package/pensive-tesla-d0d355/src/schemas/v3/overlays/fme1.json +0 -1266
  151. package/pensive-tesla-d0d355/src/schemas/v3/overlays/llc1.json +0 -25
  152. package/pensive-tesla-d0d355/src/schemas/v3/overlays/lpe1.json +0 -2199
  153. package/pensive-tesla-d0d355/src/schemas/v3/overlays/nts.json +0 -2157
  154. package/pensive-tesla-d0d355/src/schemas/v3/overlays/nts2.json +0 -2742
  155. package/pensive-tesla-d0d355/src/schemas/v3/overlays/ntsl.json +0 -1813
  156. package/pensive-tesla-d0d355/src/schemas/v3/overlays/ntsl2.json +0 -2217
  157. package/pensive-tesla-d0d355/src/schemas/v3/overlays/oc1.json +0 -2817
  158. package/pensive-tesla-d0d355/src/schemas/v3/overlays/piq.json +0 -3322
  159. package/pensive-tesla-d0d355/src/schemas/v3/overlays/rds.json +0 -3665
  160. package/pensive-tesla-d0d355/src/schemas/v3/overlays/sef25.json +0 -1639
  161. package/pensive-tesla-d0d355/src/schemas/v3/overlays/sr24.json +0 -38
  162. package/pensive-tesla-d0d355/src/schemas/v3/overlays/ta10.json +0 -4654
  163. package/pensive-tesla-d0d355/src/schemas/v3/overlays/ta6ed6.json +0 -6534
  164. package/pensive-tesla-d0d355/src/schemas/v3/overlays/ta7.json +0 -1537
  165. package/pensive-tesla-d0d355/src/schemas/v3/overlays/ta7ed5.json +0 -1551
  166. package/pensive-tesla-d0d355/src/schemas/v3/pdtf-transaction.json +0 -41573
  167. package/pensive-tesla-d0d355/src/schemas/v3/skeleton.json +0 -5767
  168. package/pensive-tesla-d0d355/src/schemas/verifiedClaims/README.md +0 -21
  169. package/pensive-tesla-d0d355/src/schemas/verifiedClaims/pdtf-verified-claims.json +0 -447
  170. package/pensive-tesla-d0d355/src/utils/compactSkeleton.js +0 -84
  171. package/pensive-tesla-d0d355/src/utils/countTokens.js +0 -67
  172. package/pensive-tesla-d0d355/src/utils/extractExtensionOverlays.js +0 -624
  173. package/pensive-tesla-d0d355/src/utils/extractOverlay.js +0 -381
  174. package/pensive-tesla-d0d355/src/utils/extractProperties.js +0 -44
  175. package/pensive-tesla-d0d355/src/utils/listPathTitles.js +0 -36
  176. package/pensive-tesla-d0d355/src/utils/minimalSkeleton.js +0 -85
  177. package/pensive-tesla-d0d355/src/utils/pathList.csv +0 -903
  178. package/pensive-tesla-d0d355/src/utils/pathSkeleton.js +0 -181
  179. package/src/examples/v1/exampleAddParticipantVouch.json +0 -32
  180. package/src/examples/v1/exampleDocumentedVouch.json +0 -40
  181. package/src/examples/v1/exampleElectronicRecord.json +0 -30
  182. package/src/examples/v1/exampleTransaction.json +0 -878
  183. package/src/examples/v1/exampleVouch.json +0 -25
  184. package/src/examples/v2/exampleTransaction.json +0 -901
  185. package/src/examples/v3/exampleAddParticipantVouch.json +0 -38
  186. package/src/examples/v3/exampleCustomOverlay.json +0 -55
  187. package/src/examples/v3/exampleCustomOverlay2.json +0 -93
  188. package/src/examples/v3/exampleDocumentedVouch.json +0 -47
  189. package/src/examples/v3/exampleElectronicRecord.json +0 -36
  190. package/src/examples/v3/exampleTransaction.json +0 -1038
  191. package/src/examples/v3/exampleVouch.json +0 -32
  192. package/src/mappings/SendPropertyDetailsRequestSchema.json +0 -1588
  193. package/src/mappings/adf.js +0 -198
@@ -1,654 +0,0 @@
1
- const merge = require("deepmerge");
2
- const Ajv = require("ajv");
3
- const addFormats = require("ajv-formats");
4
- const ajv = new Ajv({
5
- allErrors: true,
6
- // schema contains additional baspiRef and RDSRef metadata which is not strictly valid
7
- strictSchema: false,
8
- discriminator: true,
9
- });
10
- // Adds date formats among other types to the validator.
11
- addFormats(ajv);
12
-
13
- // Enhanced caching structure for subschemas and validators
14
- const schemaCache = new Map();
15
-
16
- // Cache performance tracking
17
- const cacheStats = {
18
- hits: 0,
19
- misses: 0,
20
- totalQueries: 0,
21
- cacheStartTime: Date.now(),
22
- };
23
-
24
- const verifiedClaimsSchema = require("./src/schemas/verifiedClaims/pdtf-verified-claims.json");
25
- const v2CoreSchema = require("./src/schemas/v2/pdtf-transaction.json");
26
- const v3CoreSchema = require("./src/schemas/v3/pdtf-transaction.json");
27
-
28
- // Extension overlays for v3
29
- const extensionOverlays = {
30
- // Specialist Issues Extensions
31
- as: require("./src/schemas/v3/overlays/extensions/as.json"),
32
- dr: require("./src/schemas/v3/overlays/extensions/dr.json"),
33
- jk: require("./src/schemas/v3/overlays/extensions/jk.json"),
34
- sb: require("./src/schemas/v3/overlays/extensions/sb.json"),
35
- hs: require("./src/schemas/v3/overlays/extensions/hs.json"),
36
-
37
- // Property Features Extensions
38
- oa: require("./src/schemas/v3/overlays/extensions/oa.json"),
39
- la: require("./src/schemas/v3/overlays/extensions/la.json"),
40
- sf: require("./src/schemas/v3/overlays/extensions/sf.json"),
41
- mc: require("./src/schemas/v3/overlays/extensions/mc.json"),
42
-
43
- // Ownership & Financial Extensions
44
- er: require("./src/schemas/v3/overlays/extensions/er.json"),
45
- ma: require("./src/schemas/v3/overlays/extensions/ma.json"),
46
- tf: require("./src/schemas/v3/overlays/extensions/tf.json"),
47
-
48
- // Utilities & Services Extensions
49
- sl: require("./src/schemas/v3/overlays/extensions/sl.json"),
50
- hi: require("./src/schemas/v3/overlays/extensions/hi.json"),
51
- fd: require("./src/schemas/v3/overlays/extensions/fd.json"),
52
-
53
- // Transaction Extensions
54
- oc: require("./src/schemas/v3/overlays/extensions/oc.json"),
55
-
56
- // SEF25 Extensions
57
- sc: require("./src/schemas/v3/overlays/extensions/sc.json"),
58
- pc: require("./src/schemas/v3/overlays/extensions/pc.json"),
59
- ph: require("./src/schemas/v3/overlays/extensions/ph.json"),
60
- dk: require("./src/schemas/v3/overlays/extensions/dk.json"),
61
- rw: require("./src/schemas/v3/overlays/extensions/rw.json"),
62
- sd: require("./src/schemas/v3/overlays/extensions/sd.json"),
63
- lc: require("./src/schemas/v3/overlays/extensions/lc.json"),
64
- wg: require("./src/schemas/v3/overlays/extensions/wg.json"),
65
- ic: require("./src/schemas/v3/overlays/extensions/ic.json"),
66
- nd: require("./src/schemas/v3/overlays/extensions/nd.json"),
67
- mi: require("./src/schemas/v3/overlays/extensions/mi.json"),
68
- tr: require("./src/schemas/v3/overlays/extensions/tr.json"),
69
- ac: require("./src/schemas/v3/overlays/extensions/ac.json"),
70
-
71
- // Compatibility Extensions
72
- ta: require("./src/schemas/v3/overlays/extensions/ta.json"),
73
- };
74
-
75
- const overlaysMap = {
76
- "https://trust.propdata.org.uk/schemas/v2/pdtf-transaction.json": {
77
- baspiV4: require("./src/schemas/v2/overlays/baspi.json"),
78
- ta6ed4: require("./src/schemas/v2/overlays/ta6.json"),
79
- ta7ed3: require("./src/schemas/v2/overlays/ta7.json"),
80
- ta10ed3: require("./src/schemas/v2/overlays/ta10.json"),
81
- lpe1ed4: require("./src/schemas/v2/overlays/lpe1.json"),
82
- fme1ed2: require("./src/schemas/v2/overlays/fme1.json"),
83
- llc1v2: require("./src/schemas/v2/overlays/llc1.json"),
84
- nts2023: require("./src/schemas/v2/overlays/nts.json"),
85
- con29R2019: require("./src/schemas/v2/overlays/con29R.json"),
86
- con29DW: require("./src/schemas/v2/overlays/con29DW.json"),
87
- rdsV333: require("./src/schemas/v2/overlays/rds.json"),
88
- oc1v21: require("./src/schemas/v2/overlays/oc1.json"),
89
- piqV3: require("./src/schemas/v2/overlays/piq.json"),
90
- null: {},
91
- },
92
- "https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json": {
93
- baspiV4: require("./src/schemas/v3/overlays/baspi4.json"),
94
- baspiV5: require("./src/schemas/v3/overlays/baspi5.json"),
95
- ta6ed4: require("./src/schemas/v3/overlays/ta6.json"),
96
- ta6ed6: require("./src/schemas/v3/overlays/ta6ed6.json"),
97
- ta7ed3: require("./src/schemas/v3/overlays/ta7.json"),
98
- ta7ed5: require("./src/schemas/v3/overlays/ta7ed5.json"),
99
- ta10ed3: require("./src/schemas/v3/overlays/ta10.json"),
100
- lpe1ed4: require("./src/schemas/v3/overlays/lpe1.json"),
101
- fme1ed2: require("./src/schemas/v3/overlays/fme1.json"),
102
- llc1v2: require("./src/schemas/v3/overlays/llc1.json"),
103
- nts2023: require("./src/schemas/v3/overlays/nts.json"),
104
- ntsl2023: require("./src/schemas/v3/overlays/ntsl.json"),
105
- nts2025: require("./src/schemas/v3/overlays/nts2.json"),
106
- ntsl2025: require("./src/schemas/v3/overlays/ntsl2.json"),
107
- con29R2019: require("./src/schemas/v3/overlays/con29R.json"),
108
- con29DW: require("./src/schemas/v3/overlays/con29DW.json"),
109
- rdsV333: require("./src/schemas/v3/overlays/rds.json"),
110
- oc1v21: require("./src/schemas/v3/overlays/oc1.json"),
111
- piqV3: require("./src/schemas/v3/overlays/piq.json"),
112
- sr24: require("./src/schemas/v3/overlays/sr24.json"),
113
- // Include extension overlays for v3
114
- ...extensionOverlays,
115
- null: {},
116
- },
117
- };
118
-
119
- const transactionSchemas = {
120
- "https://trust.propdata.org.uk/schemas/v2/pdtf-transaction.json":
121
- v2CoreSchema,
122
- "https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json":
123
- v3CoreSchema,
124
- };
125
-
126
- // Custom array merge function for oneOf arrays
127
- const arrayMerge = (target, source, options) => {
128
- // For string arrays (enum, required, etc.)
129
- if (
130
- target.length > 0 &&
131
- source.length > 0 &&
132
- target[0] &&
133
- typeof target[0] === "string" &&
134
- source[0] &&
135
- typeof source[0] === "string"
136
- ) {
137
- // Detect if this is a required array by checking the parent key
138
- // Required arrays are property names (camelCase, no spaces)
139
- // Enum arrays are values (can contain spaces, capitals, etc.)
140
- const isRequiredArray =
141
- target.every(
142
- (item) =>
143
- typeof item === "string" &&
144
- item.length > 0 &&
145
- // Required field names are typically camelCase without spaces
146
- !item.includes(" ") &&
147
- // First character is usually lowercase for field names
148
- (item[0] === item[0].toLowerCase() ||
149
- item.startsWith("is") ||
150
- item.startsWith("has")),
151
- ) &&
152
- source.every(
153
- (item) =>
154
- typeof item === "string" &&
155
- item.length > 0 &&
156
- !item.includes(" ") &&
157
- (item[0] === item[0].toLowerCase() ||
158
- item.startsWith("is") ||
159
- item.startsWith("has")),
160
- );
161
-
162
- if (isRequiredArray) {
163
- // Combine required arrays
164
- const combined = [...target];
165
- source.forEach((item) => {
166
- if (!combined.includes(item)) {
167
- combined.push(item);
168
- }
169
- });
170
- return combined;
171
- }
172
-
173
- // For other string arrays (like enum), replace with source
174
- return source.length > 0 ? source : target;
175
- }
176
-
177
- // If target is empty but source has values, use source
178
- if (target.length === 0 && source.length > 0) {
179
- return source;
180
- }
181
-
182
- // Ensure we only process arrays of the same length
183
- // If source is shorter, pad with nulls
184
- // If source is longer, truncate to target length
185
- const paddedSource = [...source];
186
- while (paddedSource.length < target.length) {
187
- paddedSource.push(null);
188
- }
189
- paddedSource.splice(target.length);
190
-
191
- return target.map((item, index) => {
192
- if (paddedSource[index] === null || paddedSource[index] === undefined) {
193
- return item;
194
- }
195
- if (item === null || item === undefined) {
196
- return paddedSource[index];
197
- }
198
- // Recursively merge nested objects and arrays
199
- return merge(item, paddedSource[index], { arrayMerge });
200
- });
201
- };
202
-
203
- const getTransactionSchema = (
204
- schemaId = "https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json",
205
- overlays,
206
- ) => {
207
- const sourceSchema = transactionSchemas[schemaId];
208
- if (!overlays || overlays.length < 1) return sourceSchema;
209
-
210
- let mergedSchema = JSON.parse(JSON.stringify(sourceSchema)); // Deep copy
211
- overlays.forEach((overlay) => {
212
- const overlaySchema = JSON.parse(
213
- JSON.stringify(overlaysMap[schemaId][overlay] || {}),
214
- ); // Deep copy
215
- mergedSchema = merge(mergedSchema, overlaySchema, { arrayMerge });
216
- });
217
-
218
- return mergedSchema;
219
- };
220
-
221
- // Add helper function to generate cache key
222
- const generateOverlayKey = (overlays) => {
223
- if (!overlays) return "";
224
- return overlays.join(".");
225
- };
226
-
227
- // Enhanced caching function that stores both subschemas and validators
228
- const getCachedSchemaData = (path, schemaId, overlays) => {
229
- const overlayKey = generateOverlayKey(overlays);
230
- const cacheKey = `${path}-${schemaId}-${overlayKey}`;
231
-
232
- cacheStats.totalQueries++;
233
- let cached = schemaCache.get(cacheKey);
234
- if (!cached) {
235
- cacheStats.misses++;
236
- // Compute subschema using the original logic
237
- const sourceSchema = getTransactionSchema(schemaId, overlays);
238
- const pathArray = path.split("/").slice(1);
239
- let subSchema = sourceSchema;
240
-
241
- if (pathArray.length >= 1) {
242
- subSchema = pathArray.reduce((schema, pathElement) => {
243
- if (!schema) return undefined;
244
- const { type, items, properties, patternProperties, oneOf } = schema;
245
-
246
- // Check array type
247
- if (type === "array") return items;
248
-
249
- // Check explicit properties first
250
- if (properties?.[pathElement]) return properties[pathElement];
251
-
252
- // Check patternProperties
253
- if (patternProperties) {
254
- for (const pattern in patternProperties) {
255
- try {
256
- const regex = new RegExp(pattern);
257
- if (regex.test(pathElement)) {
258
- return patternProperties[pattern];
259
- }
260
- } catch (e) {
261
- // Invalid regex pattern in schema - skip it
262
- console.warn(
263
- `Invalid regex pattern in patternProperties: ${pattern}`,
264
- e,
265
- );
266
- }
267
- }
268
- }
269
-
270
- // Check oneOf discriminators (recursively for nested oneOf)
271
- if (oneOf) {
272
- const findInOneOf = (branches) => {
273
- let arrayFallback;
274
- for (const branch of branches) {
275
- if (!branch) continue;
276
- // Track array matches as fallback (prefer property matches)
277
- if (
278
- branch.type === "array" &&
279
- !Number.isNaN(pathElement) &&
280
- !arrayFallback
281
- ) {
282
- arrayFallback = branch.items;
283
- }
284
- if (branch.properties?.[pathElement]) {
285
- return branch.properties[pathElement];
286
- }
287
- if (branch.patternProperties) {
288
- for (const pattern in branch.patternProperties) {
289
- try {
290
- const regex = new RegExp(pattern);
291
- if (regex.test(pathElement)) {
292
- return branch.patternProperties[pattern];
293
- }
294
- } catch (e) {
295
- // Invalid regex pattern - skip
296
- }
297
- }
298
- }
299
- // Recurse into nested oneOf branches
300
- if (branch.oneOf) {
301
- const nested = findInOneOf(branch.oneOf);
302
- if (nested) return nested;
303
- }
304
- }
305
- return arrayFallback;
306
- };
307
- const matchingProperty = findInOneOf(oneOf);
308
- if (matchingProperty) return matchingProperty;
309
- }
310
-
311
- return undefined;
312
- }, sourceSchema);
313
- }
314
-
315
- // Add schema to AJV and get validator
316
- // Only add valid schemas to AJV
317
- let validator;
318
- if (subSchema && typeof subSchema === "object") {
319
- // Check if schema already exists in AJV to avoid duplicates
320
- validator = ajv.getSchema(cacheKey);
321
- if (!validator) {
322
- ajv.addSchema(subSchema, cacheKey);
323
- validator = ajv.getSchema(cacheKey);
324
- }
325
- } else {
326
- // For invalid paths, create a validator that always fails
327
- validator = () => false;
328
- validator.errors = [`Invalid path: schema is ${subSchema}`];
329
- }
330
-
331
- cached = {
332
- subSchema,
333
- validator,
334
- cacheKey,
335
- createdAt: Date.now(),
336
- };
337
- schemaCache.set(cacheKey, cached);
338
- } else {
339
- cacheStats.hits++;
340
- }
341
-
342
- return cached;
343
- };
344
-
345
- const getValidator = (schemaId, overlays) => {
346
- return getSubschemaValidator("", schemaId, overlays);
347
- };
348
-
349
- // common functions for v1 and v2 - now with caching
350
- const getSubschema = (path, schemaId, overlays) => {
351
- const cached = getCachedSchemaData(path, schemaId, overlays);
352
- return cached.subSchema;
353
- };
354
-
355
- const isPathValid = (path, schemaId, overlays) => {
356
- try {
357
- return getSubschema(path, schemaId, overlays) !== undefined;
358
- } catch (err) {
359
- return false;
360
- }
361
- };
362
-
363
- const getSubschemaValidator = (path, schemaId, overlays) => {
364
- const cached = getCachedSchemaData(path, schemaId, overlays);
365
- return cached.validator;
366
- };
367
-
368
- // v1, deprecated
369
- const getTitleAtPath = (schema, path, rootPath = path) => {
370
- if (path === "") path = "/";
371
- let pathArray = path.split("/").slice(1);
372
- if (pathArray.length === 1 && pathArray[0] === "") {
373
- if (schema.title) return schema.title;
374
- if (schema.title === "") return ""; // deliberately blank
375
- // no 'title' property present, so we use the property name to create a readable descriptor
376
- const propertyName = rootPath
377
- .split("/")
378
- .pop()
379
- .replace(/([A-Z])/g, " $1")
380
- .toLowerCase()
381
- .trim();
382
- return propertyName.charAt(0).toUpperCase() + propertyName.slice(1);
383
- }
384
- const propertyName = pathArray.shift();
385
- const subPath = "/" + pathArray.join("/");
386
-
387
- let subSchema = schema.properties
388
- ? schema.properties[propertyName]
389
- : undefined;
390
- if (subSchema) {
391
- return getTitleAtPath(subSchema, subPath, rootPath);
392
- }
393
- if (schema.type === "array") {
394
- subSchema = schema.items;
395
- return getTitleAtPath(subSchema, subPath, rootPath);
396
- }
397
- const oneOfs = schema.oneOf;
398
- if (oneOfs) {
399
- // only single dependency discriminator, oneOf keyword is supported
400
- const matchingOneOf = oneOfs.find(
401
- (oneOf) => oneOf["properties"][propertyName],
402
- );
403
- if (matchingOneOf)
404
- return getTitleAtPath(
405
- matchingOneOf["properties"][propertyName],
406
- subPath,
407
- rootPath,
408
- );
409
- }
410
- };
411
-
412
- const validateVerifiedClaims = (verifiedClaims, schemaId, overlays) => {
413
- const validatorVClaims = ajv.compile(verifiedClaimsSchema);
414
-
415
- const validationErrorsArr = [];
416
- const vClaimSchValidation = validatorVClaims({
417
- verified_claims: verifiedClaims,
418
- });
419
-
420
- if (!vClaimSchValidation) {
421
- validationErrorsArr.push(validatorVClaims.errors);
422
- }
423
-
424
- const verifiedClaimsArray = Array.isArray(verifiedClaims)
425
- ? verifiedClaims
426
- : [verifiedClaims];
427
-
428
- verifiedClaimsArray.forEach((claim) => {
429
- const paths = Object.keys(claim.claims);
430
- for (const path of paths) {
431
- const validPath = isPathValid(path, schemaId, overlays);
432
- if (validPath) {
433
- const subValidator = getSubschemaValidator(path, schemaId, overlays);
434
- const isValid = subValidator(claim.claims[path]);
435
- if (!isValid) {
436
- validationErrorsArr.push(...subValidator.errors);
437
- }
438
- } else {
439
- validationErrorsArr.push(
440
- `Path ${path} is not a valid PDTF schema path`,
441
- );
442
- }
443
- }
444
- });
445
-
446
- return validationErrorsArr;
447
- };
448
-
449
- // Cache management functions
450
- const getCacheStats = () => {
451
- const runtime = Date.now() - cacheStats.cacheStartTime;
452
- const hitRate =
453
- cacheStats.totalQueries > 0
454
- ? (cacheStats.hits / cacheStats.totalQueries) * 100
455
- : 0;
456
-
457
- return {
458
- totalEntries: schemaCache.size,
459
- hits: cacheStats.hits,
460
- misses: cacheStats.misses,
461
- totalQueries: cacheStats.totalQueries,
462
- hitRate: parseFloat(hitRate.toFixed(2)),
463
- runtimeMs: runtime,
464
- cacheKeys: Array.from(schemaCache.keys()),
465
- memoryUsage: {
466
- entriesCount: schemaCache.size,
467
- // Rough estimate of memory usage per entry
468
- estimatedSizeKB: Math.round(((schemaCache.size * 2) / 1024) * 100) / 100, // Rough estimate
469
- },
470
- };
471
- };
472
-
473
- const getDetailedCacheStats = () => {
474
- const baseStats = getCacheStats();
475
- const entries = Array.from(schemaCache.entries()).map(([key, value]) => ({
476
- key,
477
- createdAt: value.createdAt,
478
- age: Date.now() - value.createdAt,
479
- hasValidator: typeof value.validator === "function",
480
- hasSubSchema: value.subSchema !== undefined,
481
- }));
482
-
483
- return {
484
- ...baseStats,
485
- entries: entries.sort((a, b) => b.createdAt - a.createdAt), // Most recent first
486
- oldestEntry:
487
- entries.length > 0 ? Math.max(...entries.map((e) => e.age)) : 0,
488
- newestEntry:
489
- entries.length > 0 ? Math.min(...entries.map((e) => e.age)) : 0,
490
- };
491
- };
492
-
493
- const clearSchemaCache = (pattern) => {
494
- if (pattern) {
495
- // Clear entries matching pattern
496
- const keysToDelete = [];
497
- schemaCache.forEach((value, key) => {
498
- if (key.includes(pattern)) {
499
- keysToDelete.push(key);
500
- }
501
- });
502
- keysToDelete.forEach((key) => schemaCache.delete(key));
503
-
504
- // Also remove matching schemas from AJV
505
- keysToDelete.forEach((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
- } else {
515
- // Clear all cache
516
- const entriesCleared = schemaCache.size;
517
- schemaCache.clear();
518
- // Reset stats
519
- cacheStats.hits = 0;
520
- cacheStats.misses = 0;
521
- cacheStats.totalQueries = 0;
522
- cacheStats.cacheStartTime = Date.now();
523
-
524
- // Also clear AJV's internal cache to prevent duplicates
525
- ajv.removeSchema();
526
-
527
- return entriesCleared;
528
- }
529
- };
530
-
531
- const warmupCache = (
532
- paths,
533
- schemaId = "https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json",
534
- overlaysList = [],
535
- ) => {
536
- const warmupStats = {
537
- totalAttempted: 0,
538
- successful: 0,
539
- failed: 0,
540
- errors: [],
541
- };
542
-
543
- // Default common paths if none provided
544
- const defaultPaths = [
545
- "/propertyPack",
546
- "/participants",
547
- "/status",
548
- "/propertyPack/surveys",
549
- "/propertyPack/valuations",
550
- "/propertyPack/waterAndDrainage",
551
- "/propertyPack/ownership",
552
- "/propertyPack/notices",
553
- ];
554
-
555
- // Default common overlays if none provided
556
- const defaultOverlays = [
557
- [],
558
- ["baspiV5"],
559
- ["ta6ed4"],
560
- ["nts2023"],
561
- ["baspiV5", "ta6ed4"],
562
- ];
563
-
564
- const pathsToWarm = paths || defaultPaths;
565
- const overlaysToWarm =
566
- overlaysList.length > 0 ? overlaysList : defaultOverlays;
567
-
568
- pathsToWarm.forEach((path) => {
569
- overlaysToWarm.forEach((overlays) => {
570
- warmupStats.totalAttempted++;
571
- try {
572
- // This will populate the cache
573
- getSubschema(path, schemaId, overlays);
574
- getSubschemaValidator(path, schemaId, overlays);
575
- warmupStats.successful++;
576
- } catch (error) {
577
- warmupStats.failed++;
578
- warmupStats.errors.push({
579
- path,
580
- overlays,
581
- error: error.message,
582
- });
583
- }
584
- });
585
- });
586
-
587
- return warmupStats;
588
- };
589
-
590
- const pruneCacheByAge = (maxAgeMs) => {
591
- const now = Date.now();
592
- const keysToDelete = [];
593
-
594
- schemaCache.forEach((value, key) => {
595
- if (now - value.createdAt > maxAgeMs) {
596
- keysToDelete.push(key);
597
- }
598
- });
599
-
600
- keysToDelete.forEach((key) => {
601
- schemaCache.delete(key);
602
- try {
603
- ajv.removeSchema(key);
604
- } catch (e) {
605
- // Schema might not exist in AJV, ignore
606
- }
607
- });
608
-
609
- return keysToDelete.length;
610
- };
611
-
612
- const setCacheMaxSize = (maxSize) => {
613
- if (schemaCache.size <= maxSize) return 0;
614
-
615
- // Get entries sorted by creation time (oldest first)
616
- const entries = Array.from(schemaCache.entries()).sort(
617
- (a, b) => a[1].createdAt - b[1].createdAt,
618
- );
619
-
620
- const toRemove = schemaCache.size - maxSize;
621
- const keysToDelete = entries.slice(0, toRemove).map(([key]) => key);
622
-
623
- keysToDelete.forEach((key) => {
624
- schemaCache.delete(key);
625
- try {
626
- ajv.removeSchema(key);
627
- } catch (e) {
628
- // Schema might not exist in AJV, ignore
629
- }
630
- });
631
-
632
- return keysToDelete.length;
633
- };
634
-
635
- module.exports = {
636
- ajv,
637
- getTransactionSchema,
638
- getValidator,
639
- getSubschema,
640
- isPathValid,
641
- getSubschemaValidator,
642
- getTitleAtPath,
643
- verifiedClaimsSchema,
644
- validateVerifiedClaims,
645
- overlaysMap,
646
- extensionOverlays,
647
- // Enhanced cache management functions
648
- getCacheStats,
649
- getDetailedCacheStats,
650
- clearSchemaCache,
651
- warmupCache,
652
- pruneCacheByAge,
653
- setCacheMaxSize,
654
- };