@aventara/core 1.0.0-rc.0 → 1.0.0-rc.10

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 (338) hide show
  1. package/CHANGELOG.md +2068 -1
  2. package/ERRORS.md +142 -0
  3. package/README.md +485 -60
  4. package/dist/adapters/adapter-discovery-diagnostic.d.ts +4 -4
  5. package/dist/adapters/adapter-discovery-diagnostic.guidance.d.ts +6 -0
  6. package/dist/adapters/adapter-discovery-diagnostic.guidance.js +7 -0
  7. package/dist/adapters/adapter-field.d.ts +33 -11
  8. package/dist/adapters/adapter-identifier.d.ts +15 -6
  9. package/dist/adapters/adapter-identifier.js +6 -1
  10. package/dist/adapters/adapter-model.d.ts +18 -9
  11. package/dist/adapters/adapter-operation-executor.interface.d.ts +4 -4
  12. package/dist/adapters/adapter-operation.d.ts +21 -6
  13. package/dist/adapters/adapter-resource.d.ts +23 -9
  14. package/dist/adapters/adapter-sql-statement.d.ts +19 -0
  15. package/dist/adapters/adapter-transaction-executor.interface.d.ts +19 -0
  16. package/dist/adapters/adapter.interface.d.ts +59 -29
  17. package/dist/avz/avz-check.factory.d.ts +83 -0
  18. package/dist/avz/avz-check.factory.js +116 -0
  19. package/dist/avz/avz-check.registry.d.ts +35 -0
  20. package/dist/avz/avz-check.registry.js +9 -0
  21. package/dist/avz/avz.d.ts +203 -0
  22. package/dist/{json → avz}/avz.js +150 -8
  23. package/dist/{json → avz}/index.d.ts +2 -1
  24. package/dist/{json → avz}/json-shape.registry.d.ts +9 -8
  25. package/dist/{json → avz}/zod-issue.translator.d.ts +8 -2
  26. package/dist/{json → avz}/zod-issue.translator.js +7 -0
  27. package/dist/compiler/contract-compiler-diagnostic.d.ts +31 -5
  28. package/dist/compiler/contract-compiler-diagnostic.guidance.d.ts +6 -0
  29. package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
  30. package/dist/compiler/contract.compiler.d.ts +23 -17
  31. package/dist/compiler/contract.compiler.js +753 -443
  32. package/dist/compiler/create-requirements.projector.d.ts +49 -0
  33. package/dist/compiler/create-requirements.projector.js +423 -0
  34. package/dist/compiler/field-validator.compiler.d.ts +47 -0
  35. package/dist/compiler/field-validator.compiler.js +238 -0
  36. package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
  37. package/dist/compiler/managed-elsewhere.projector.js +179 -0
  38. package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
  39. package/dist/compiler/managed-elsewhere.validator.js +74 -0
  40. package/dist/config/any-framework-config.d.ts +19 -12
  41. package/dist/config/computed-fields.d.ts +62 -0
  42. package/dist/config/computed-fields.js +73 -0
  43. package/dist/config/config-diagnostic.d.ts +11 -4
  44. package/dist/config/config-diagnostic.guidance.d.ts +6 -0
  45. package/dist/config/config-diagnostic.guidance.js +32 -0
  46. package/dist/config/config-layer.d.ts +15 -6
  47. package/dist/config/config.resolver.d.ts +98 -31
  48. package/dist/config/config.resolver.js +173 -44
  49. package/dist/config/config.validator.d.ts +7 -7
  50. package/dist/config/config.validator.js +792 -69
  51. package/dist/config/define-resource.d.ts +53 -0
  52. package/dist/config/define-resource.js +14 -0
  53. package/dist/config/effective-fields.d.ts +19 -23
  54. package/dist/config/entrypoint.normalizer.d.ts +4 -3
  55. package/dist/config/exact-framework-config.d.ts +325 -0
  56. package/dist/config/field-compute.resolver.d.ts +21 -0
  57. package/dist/config/field-compute.resolver.js +123 -0
  58. package/dist/config/field-pipeline-config.d.ts +47 -0
  59. package/dist/config/forced-operation.validator.d.ts +10 -0
  60. package/dist/config/forced-operation.validator.js +66 -0
  61. package/dist/config/framework-config.d.ts +148 -39
  62. package/dist/config/framework-exemptions-config.d.ts +91 -0
  63. package/dist/config/framework-exemptions-config.js +1 -0
  64. package/dist/config/framework-field-definition.d.ts +78 -0
  65. package/dist/config/framework-field-definition.js +28 -0
  66. package/dist/config/framework-resources-config.d.ts +127 -0
  67. package/dist/config/framework-resources-config.js +1 -0
  68. package/dist/config/pipeline-config.d.ts +56 -20
  69. package/dist/config/pipeline-tree.resolver.d.ts +79 -0
  70. package/dist/config/pipeline-tree.resolver.js +220 -0
  71. package/dist/config/stage-type.eraser.d.ts +65 -0
  72. package/dist/config/stage-type.eraser.js +1 -0
  73. package/dist/contracts/access-route.rules.d.ts +10 -0
  74. package/dist/contracts/access-route.rules.js +45 -0
  75. package/dist/contracts/capability.d.ts +37 -12
  76. package/dist/contracts/capability.js +20 -0
  77. package/dist/contracts/client-contract-structure.validator.d.ts +621 -114
  78. package/dist/contracts/client-contract-structure.validator.js +189 -10
  79. package/dist/contracts/contract-access.d.ts +29 -0
  80. package/dist/contracts/contract-access.js +1 -0
  81. package/dist/contracts/contract-canonicalizer.d.ts +27 -3
  82. package/dist/contracts/contract-canonicalizer.js +168 -29
  83. package/dist/contracts/contract-hash.d.ts +11 -7
  84. package/dist/contracts/contract-hash.js +4 -3
  85. package/dist/contracts/contract-limits.d.ts +4 -1
  86. package/dist/contracts/contract-limits.js +1 -0
  87. package/dist/contracts/contract-lookup.d.ts +5 -5
  88. package/dist/contracts/contract-protocol.d.ts +4 -4
  89. package/dist/contracts/contract.d.ts +51 -17
  90. package/dist/contracts/create-requirements.d.ts +35 -0
  91. package/dist/contracts/create-requirements.js +1 -0
  92. package/dist/contracts/enum-definition.d.ts +1 -1
  93. package/dist/contracts/field-check.d.ts +101 -0
  94. package/dist/contracts/field-check.js +1 -0
  95. package/dist/contracts/field.d.ts +109 -42
  96. package/dist/contracts/identifier.d.ts +4 -4
  97. package/dist/contracts/json-schema.projector.d.ts +11 -0
  98. package/dist/contracts/json-schema.projector.js +78 -0
  99. package/dist/contracts/json-shape.d.ts +12 -1
  100. package/dist/contracts/lifecycle-trait.d.ts +2 -2
  101. package/dist/contracts/resource-operations.d.ts +28 -28
  102. package/dist/contracts/resource.d.ts +15 -9
  103. package/dist/contracts/scalar-value-type.d.ts +17 -15
  104. package/dist/contracts/scalar.d.ts +3 -3
  105. package/dist/contracts/transaction-capability.d.ts +1 -1
  106. package/dist/contracts/wire-scalar-format.d.ts +4 -4
  107. package/dist/framework/access-facade.d.ts +116 -0
  108. package/dist/framework/access-facade.js +120 -0
  109. package/dist/framework/contract-view.d.ts +315 -145
  110. package/dist/framework/framework-construction.error.d.ts +21 -11
  111. package/dist/framework/framework-construction.error.js +20 -4
  112. package/dist/framework/framework.d.ts +71 -26
  113. package/dist/framework/framework.factory.d.ts +8 -6
  114. package/dist/framework/framework.factory.js +150 -38
  115. package/dist/framework/operation-facade.d.ts +192 -54
  116. package/dist/framework/operation-facade.js +10 -1
  117. package/dist/index.d.ts +67 -50
  118. package/dist/index.js +7 -6
  119. package/dist/internal.d.ts +20 -10
  120. package/dist/internal.js +9 -1
  121. package/dist/operations/database-refusal.d.ts +51 -0
  122. package/dist/operations/database-refusal.js +45 -0
  123. package/dist/operations/operation-arguments.d.ts +381 -228
  124. package/dist/operations/operation-call.d.ts +31 -28
  125. package/dist/operations/operation-identity.d.ts +10 -10
  126. package/dist/operations/operation-result.d.ts +25 -23
  127. package/dist/operations/operation-validator-core.d.ts +6 -6
  128. package/dist/operations/operation-validator-core.js +172 -38
  129. package/dist/operations/operation-validator.d.ts +10 -10
  130. package/dist/operations/projection-scope.resolver.d.ts +6 -6
  131. package/dist/operations/structural-limits.walker.d.ts +7 -7
  132. package/dist/operations/structural-limits.walker.js +145 -0
  133. package/dist/operations/validation-code.d.ts +11 -6
  134. package/dist/operations/validation-code.guidance.d.ts +6 -0
  135. package/dist/operations/validation-code.guidance.js +90 -0
  136. package/dist/operations/validation-code.js +4 -0
  137. package/dist/operations/write-scope.resolver.d.ts +10 -6
  138. package/dist/operations/write-scope.resolver.js +2 -0
  139. package/dist/policy/access-provider.interface.d.ts +91 -0
  140. package/dist/policy/access-provider.interface.js +1 -0
  141. package/dist/policy/access-provider.registry.d.ts +17 -0
  142. package/dist/policy/access-provider.registry.js +15 -0
  143. package/dist/policy/access-question.d.ts +20 -0
  144. package/dist/policy/access-question.js +1 -0
  145. package/dist/policy/access-question.registry.d.ts +5 -0
  146. package/dist/policy/access-question.registry.js +19 -0
  147. package/dist/policy/access-question.runtime.d.ts +36 -0
  148. package/dist/policy/access-question.runtime.js +297 -0
  149. package/dist/policy/access-verb.table.d.ts +56 -0
  150. package/dist/policy/access-verb.table.js +21 -0
  151. package/dist/policy/access-verbs.d.ts +46 -0
  152. package/dist/policy/access-verbs.js +1 -0
  153. package/dist/policy/policy-admission.d.ts +20 -0
  154. package/dist/policy/policy-admission.js +409 -0
  155. package/dist/policy/policy-after-update.runtime.d.ts +79 -0
  156. package/dist/policy/policy-after-update.runtime.js +208 -0
  157. package/dist/policy/policy-condition.d.ts +15 -0
  158. package/dist/policy/policy-condition.js +36 -0
  159. package/dist/policy/policy-engine.d.ts +205 -0
  160. package/dist/policy/policy-engine.js +1 -0
  161. package/dist/policy/policy-named-rows.d.ts +18 -0
  162. package/dist/policy/policy-named-rows.js +51 -0
  163. package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
  164. package/dist/policy/policy-nested-write.runtime.js +545 -0
  165. package/dist/policy/policy-read.runtime.d.ts +81 -0
  166. package/dist/policy/policy-read.runtime.js +503 -0
  167. package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
  168. package/dist/policy/policy-reference-write.runtime.js +345 -0
  169. package/dist/policy/policy-request.d.ts +41 -0
  170. package/dist/policy/policy-request.js +63 -0
  171. package/dist/policy/policy-session.d.ts +106 -0
  172. package/dist/policy/policy-session.js +295 -0
  173. package/dist/policy/policy-startup.validator.d.ts +10 -0
  174. package/dist/policy/policy-startup.validator.js +112 -0
  175. package/dist/policy/policy-write.runtime.d.ts +39 -0
  176. package/dist/policy/policy-write.runtime.js +532 -0
  177. package/dist/prebuilt/core-version.generated.d.ts +2 -0
  178. package/dist/prebuilt/core-version.generated.js +1 -0
  179. package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
  180. package/dist/prebuilt/prebuilt-changes.js +65 -0
  181. package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
  182. package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
  183. package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
  184. package/dist/prebuilt/prebuilt-contracts.js +1 -0
  185. package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
  186. package/dist/prebuilt/prebuilt-contracts.loader.js +77 -0
  187. package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
  188. package/dist/prebuilt/prebuilt-inputs.fingerprint.js +229 -0
  189. package/dist/protocol/absent-route.responder.d.ts +17 -34
  190. package/dist/protocol/absent-route.responder.js +53 -20
  191. package/dist/protocol/contract-document.responder.d.ts +5 -4
  192. package/dist/protocol/contract-document.responder.js +2 -2
  193. package/dist/protocol/http-request.decoder.d.ts +33 -13
  194. package/dist/protocol/http-request.decoder.js +34 -11
  195. package/dist/protocol/http-request.reader.d.ts +9 -6
  196. package/dist/protocol/http-request.reader.js +1 -0
  197. package/dist/protocol/http-response.encoder.d.ts +4 -4
  198. package/dist/protocol/http-response.encoder.js +94 -55
  199. package/dist/protocol/http-status.table.d.ts +2 -2
  200. package/dist/protocol/operation-response.guard.d.ts +2 -2
  201. package/dist/protocol/protocol-headers.d.ts +3 -3
  202. package/dist/protocol/protocol-surface.d.ts +10 -5
  203. package/dist/protocol/protocol-surface.js +7 -0
  204. package/dist/protocol/protocol.binder.d.ts +66 -28
  205. package/dist/protocol/protocol.binder.js +16 -10
  206. package/dist/protocol/protocol.handler.d.ts +34 -14
  207. package/dist/protocol/protocol.handler.js +122 -18
  208. package/dist/protocol/unmounted-route.error.d.ts +4 -4
  209. package/dist/protocol/unmounted-route.error.js +2 -2
  210. package/dist/runtime/caller-data.copier.d.ts +22 -7
  211. package/dist/runtime/caller-data.copier.js +30 -17
  212. package/dist/runtime/caller-data.door.d.ts +18 -11
  213. package/dist/runtime/caller-data.door.js +6 -4
  214. package/dist/runtime/computed-read-runtime.d.ts +12 -6
  215. package/dist/runtime/computed-read-runtime.js +271 -71
  216. package/dist/runtime/computed-value.error.d.ts +7 -6
  217. package/dist/runtime/computed-value.error.js +5 -4
  218. package/dist/runtime/context-executor.runtime.d.ts +60 -0
  219. package/dist/runtime/context-executor.runtime.js +277 -0
  220. package/dist/runtime/core-class.brand.d.ts +10 -0
  221. package/dist/runtime/core-class.brand.js +21 -0
  222. package/dist/runtime/create-requirement.d.ts +34 -79
  223. package/dist/runtime/create-requirement.js +205 -74
  224. package/dist/runtime/decimal.d.ts +16 -2
  225. package/dist/runtime/decimal.js +22 -1
  226. package/dist/runtime/diagnostics-reporter.d.ts +91 -30
  227. package/dist/runtime/diagnostics-reporter.js +37 -1
  228. package/dist/runtime/error-boundary.d.ts +73 -9
  229. package/dist/runtime/error-boundary.js +57 -19
  230. package/dist/runtime/error-guidance.d.ts +12 -0
  231. package/dist/runtime/error-guidance.js +1 -0
  232. package/dist/runtime/error.catalog.d.ts +49 -0
  233. package/dist/runtime/error.catalog.js +49 -0
  234. package/dist/runtime/execution-options.d.ts +18 -2
  235. package/dist/runtime/field-check.evaluator.d.ts +27 -0
  236. package/dist/runtime/field-check.evaluator.js +521 -0
  237. package/dist/runtime/field-compute.d.ts +65 -0
  238. package/dist/runtime/field-compute.js +1 -0
  239. package/dist/runtime/field-stage.plan.d.ts +15 -0
  240. package/dist/runtime/field-stage.plan.js +27 -0
  241. package/dist/runtime/field-stage.runtime.d.ts +37 -0
  242. package/dist/runtime/field-stage.runtime.js +147 -0
  243. package/dist/runtime/field-validator.runtime.d.ts +29 -0
  244. package/dist/runtime/field-validator.runtime.js +126 -0
  245. package/dist/runtime/framework-error-class.table.d.ts +33 -0
  246. package/dist/runtime/framework-error-class.table.js +25 -0
  247. package/dist/runtime/framework-error.d.ts +68 -8
  248. package/dist/runtime/framework-error.factory.d.ts +4 -0
  249. package/dist/runtime/framework-error.factory.js +15 -0
  250. package/dist/runtime/framework-error.js +32 -2
  251. package/dist/runtime/framework-warning.emitter.d.ts +6 -0
  252. package/dist/runtime/framework-warning.emitter.js +8 -0
  253. package/dist/runtime/interceptor-next.error.d.ts +5 -0
  254. package/dist/runtime/interceptor-next.error.js +6 -0
  255. package/dist/runtime/json-value.d.ts +11 -6
  256. package/dist/runtime/level-lifecycle.runtime.d.ts +26 -0
  257. package/dist/runtime/level-lifecycle.runtime.js +40 -0
  258. package/dist/runtime/misuse-reporter.d.ts +12 -12
  259. package/dist/runtime/mutation-planner.d.ts +20 -16
  260. package/dist/runtime/mutation-planner.js +48 -35
  261. package/dist/runtime/nested-write.walker.d.ts +32 -0
  262. package/dist/runtime/nested-write.walker.js +73 -0
  263. package/dist/runtime/operation-code.guidance.d.ts +6 -0
  264. package/dist/runtime/operation-code.guidance.js +167 -0
  265. package/dist/runtime/operation-request.d.ts +45 -11
  266. package/dist/runtime/operation-response.d.ts +17 -17
  267. package/dist/runtime/operation-runtime.d.ts +133 -27
  268. package/dist/runtime/operation-runtime.js +576 -84
  269. package/dist/runtime/outcome-mapper.d.ts +17 -5
  270. package/dist/runtime/outcome-mapper.js +23 -6
  271. package/dist/runtime/output-validator.d.ts +11 -11
  272. package/dist/runtime/output-validator.js +3 -3
  273. package/dist/runtime/owned-execution.registry.d.ts +16 -6
  274. package/dist/runtime/pipe-output.validator.d.ts +43 -18
  275. package/dist/runtime/pipe-output.validator.js +15 -13
  276. package/dist/runtime/pipeline.d.ts +221 -34
  277. package/dist/runtime/readonly-value.d.ts +47 -0
  278. package/dist/runtime/readonly-value.js +189 -0
  279. package/dist/runtime/referential-action.d.ts +1 -1
  280. package/dist/runtime/request-envelope.validator.d.ts +3 -3
  281. package/dist/runtime/request-envelope.validator.js +12 -7
  282. package/dist/runtime/request-id.d.ts +1 -1
  283. package/dist/runtime/request-state.d.ts +14 -0
  284. package/dist/runtime/request-state.js +1 -0
  285. package/dist/runtime/request-state.resolver.d.ts +12 -0
  286. package/dist/runtime/request-state.resolver.js +20 -0
  287. package/dist/runtime/scalar-runtime.d.ts +33 -25
  288. package/dist/runtime/scalar-runtime.js +105 -38
  289. package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
  290. package/dist/runtime/unsent-value.normalizer.js +128 -0
  291. package/dist/transactions/deferred-operation.d.ts +35 -20
  292. package/dist/transactions/operation-arguments-encoder.d.ts +3 -3
  293. package/dist/transactions/operation-arguments-encoder.js +8 -3
  294. package/dist/transactions/operation-fingerprint.js +2 -2
  295. package/dist/transactions/sql-statement.d.ts +85 -0
  296. package/dist/transactions/sql-statement.js +47 -0
  297. package/dist/transactions/sql-statement.validator.d.ts +44 -0
  298. package/dist/transactions/sql-statement.validator.js +167 -0
  299. package/dist/transactions/transaction-envelope.d.ts +9 -8
  300. package/dist/transactions/transaction-integrity-error.d.ts +6 -6
  301. package/dist/transactions/transaction-integrity-error.js +7 -2
  302. package/dist/transactions/transaction-plan-assembler.d.ts +30 -13
  303. package/dist/transactions/transaction-plan-assembler.js +184 -32
  304. package/dist/transactions/transaction-plan-validator.d.ts +50 -25
  305. package/dist/transactions/transaction-plan-validator.js +96 -38
  306. package/dist/transactions/transaction-reference-collector.d.ts +5 -5
  307. package/dist/transactions/transaction-reference-resolver.d.ts +21 -3
  308. package/dist/transactions/transaction-reference-resolver.js +26 -14
  309. package/dist/transactions/transaction-reference-validator.d.ts +74 -4
  310. package/dist/transactions/transaction-reference-validator.js +129 -71
  311. package/dist/transactions/transaction-reference.d.ts +14 -14
  312. package/dist/transactions/transaction-reference.js +5 -0
  313. package/dist/transactions/transaction-request.d.ts +22 -9
  314. package/dist/transactions/transaction-response.d.ts +6 -6
  315. package/dist/transactions/transaction-runtime.d.ts +12 -8
  316. package/dist/transactions/transaction-runtime.js +218 -50
  317. package/dist/transactions/transaction-settlement.runtime.d.ts +52 -0
  318. package/dist/transactions/transaction-settlement.runtime.js +120 -0
  319. package/dist/transactions/transaction-slot-path-error.d.ts +4 -4
  320. package/dist/transactions/transaction-slot-path-error.js +4 -2
  321. package/dist/transactions/transaction-slot-writer.js +2 -2
  322. package/dist/transactions/transaction-stage.runtime.d.ts +83 -0
  323. package/dist/transactions/transaction-stage.runtime.js +126 -0
  324. package/package.json +11 -9
  325. package/src/runtime/field-check.evaluator.ts +720 -0
  326. package/dist/config/define-fields.d.ts +0 -42
  327. package/dist/config/define-fields.js +0 -3
  328. package/dist/config/framework-behaviors-config.d.ts +0 -30
  329. package/dist/config/framework-fields-config.d.ts +0 -42
  330. package/dist/config/framework-restrictions-config.d.ts +0 -142
  331. package/dist/json/avz.d.ts +0 -96
  332. package/dist/runtime/field-behavior.d.ts +0 -48
  333. /package/dist/{config/framework-behaviors-config.js → adapters/adapter-sql-statement.js} +0 -0
  334. /package/dist/{config/framework-fields-config.js → adapters/adapter-transaction-executor.interface.js} +0 -0
  335. /package/dist/{json → avz}/index.js +0 -0
  336. /package/dist/{json → avz}/json-shape.registry.js +0 -0
  337. /package/dist/config/{framework-restrictions-config.js → exact-framework-config.js} +0 -0
  338. /package/dist/{runtime/field-behavior.js → config/field-pipeline-config.js} +0 -0
@@ -1,4 +1,5 @@
1
- import { PROJECTION_SCOPES, WRITE_SCOPES } from "./capability.js";
1
+ import { isAccessPath, isAccessUrl } from "./access-route.rules.js";
2
+ import { FILTER_MODES, PROJECTION_SCOPES, WRITE_SCOPES } from "./capability.js";
2
3
  import { AVENTARA_PROTOCOL_VERSION } from "./contract-protocol.js";
3
4
  import { LIFECYCLE_TRAITS } from "./lifecycle-trait.js";
4
5
  import { REFERENCE_WRITE_LIMITS } from "./reference-write-limit.js";
@@ -10,13 +11,16 @@ function literal(values) {
10
11
  return { is: "literal", values };
11
12
  }
12
13
  function list(item) {
13
- return { is: "list", item, nonEmpty: false, unique: false };
14
+ return { is: "list", item, minimum: 0, unique: false };
14
15
  }
15
16
  function nonEmptyList(item) {
16
- return { is: "list", item, nonEmpty: true, unique: false };
17
+ return { is: "list", item, minimum: 1, unique: false };
18
+ }
19
+ function pairOrMoreList(item) {
20
+ return { is: "list", item, minimum: 2, unique: false };
17
21
  }
18
22
  function uniqueList(item) {
19
- return { is: "list", item, nonEmpty: false, unique: true };
23
+ return { is: "list", item, minimum: 0, unique: true };
20
24
  }
21
25
  function registry(entry) {
22
26
  return { is: "registry", entry };
@@ -93,6 +97,127 @@ const RELATION_MUTATION = union(list(literal(RELATION_MUTATION_DIRECTIVES)), obj
93
97
  directives: list(literal(RELATION_MUTATION_DIRECTIVES)),
94
98
  scopes: WRITE_SCOPE_LIST,
95
99
  }));
100
+ const NAMED_FORMATS = [
101
+ "lowercase",
102
+ "uppercase",
103
+ "email",
104
+ "url",
105
+ "emoji",
106
+ "uuid",
107
+ "guid",
108
+ "nanoid",
109
+ "cuid",
110
+ "cuid2",
111
+ "ulid",
112
+ "xid",
113
+ "ksuid",
114
+ "datetime",
115
+ "date",
116
+ "time",
117
+ "duration",
118
+ "ipv4",
119
+ "ipv6",
120
+ "cidrv4",
121
+ "cidrv6",
122
+ "base64",
123
+ "base64url",
124
+ "json_string",
125
+ "e164",
126
+ "credit_card",
127
+ "iban",
128
+ "jwt",
129
+ ];
130
+ const STRING_FORMAT_CHECK = union(object({
131
+ check: literal(["string_format"]),
132
+ format: literal(["regex"]),
133
+ pattern: object({ source: STRING, flags: STRING }),
134
+ }), object({
135
+ check: literal(["string_format"]),
136
+ format: literal(["includes"]),
137
+ includes: STRING,
138
+ }), object({
139
+ check: literal(["string_format"]),
140
+ format: literal(["starts_with"]),
141
+ prefix: STRING,
142
+ }), object({
143
+ check: literal(["string_format"]),
144
+ format: literal(["ends_with"]),
145
+ suffix: STRING,
146
+ }), object({
147
+ check: literal(["string_format"]),
148
+ format: literal(NAMED_FORMATS),
149
+ }));
150
+ const STRING_LENGTH_CHECKS = {
151
+ max_length: object({ check: literal(["max_length"]), maximum: NUMBER }),
152
+ min_length: object({ check: literal(["min_length"]), minimum: NUMBER }),
153
+ length_equals: object({ check: literal(["length_equals"]), length: NUMBER }),
154
+ string_format: STRING_FORMAT_CHECK,
155
+ };
156
+ const FIELD_CHECK = {
157
+ is: "variants",
158
+ key: "check",
159
+ arms: {
160
+ less_than: object({
161
+ check: literal(["less_than"]),
162
+ value: union(NUMBER, STRING),
163
+ inclusive: BOOLEAN,
164
+ }),
165
+ greater_than: object({
166
+ check: literal(["greater_than"]),
167
+ value: union(NUMBER, STRING),
168
+ inclusive: BOOLEAN,
169
+ }),
170
+ multiple_of: object({
171
+ check: literal(["multiple_of"]),
172
+ value: union(NUMBER, STRING),
173
+ }),
174
+ max_length: object({ check: literal(["max_length"]), maximum: NUMBER }, { list: literal([true]) }),
175
+ min_length: object({ check: literal(["min_length"]), minimum: NUMBER }, { list: literal([true]) }),
176
+ length_equals: STRING_LENGTH_CHECKS.length_equals,
177
+ string_format: STRING_FORMAT_CHECK,
178
+ max_size: object({ check: literal(["max_size"]), maximum: NUMBER }),
179
+ min_size: object({ check: literal(["min_size"]), minimum: NUMBER }),
180
+ size_equals: object({ check: literal(["size_equals"]), size: NUMBER }),
181
+ },
182
+ };
183
+ const JSON_STRING_CHECK = {
184
+ is: "variants",
185
+ key: "check",
186
+ arms: STRING_LENGTH_CHECKS,
187
+ };
188
+ const JSON_NUMBER_CHECK = {
189
+ is: "variants",
190
+ key: "check",
191
+ arms: {
192
+ less_than: object({
193
+ check: literal(["less_than"]),
194
+ value: NUMBER,
195
+ inclusive: BOOLEAN,
196
+ }),
197
+ greater_than: object({
198
+ check: literal(["greater_than"]),
199
+ value: NUMBER,
200
+ inclusive: BOOLEAN,
201
+ }),
202
+ multiple_of: object({ check: literal(["multiple_of"]), value: NUMBER }),
203
+ },
204
+ };
205
+ const JSON_LIST_CHECK = {
206
+ is: "variants",
207
+ key: "check",
208
+ arms: {
209
+ max_length: object({
210
+ check: literal(["max_length"]),
211
+ maximum: NUMBER,
212
+ list: literal([true]),
213
+ }),
214
+ min_length: object({
215
+ check: literal(["min_length"]),
216
+ minimum: NUMBER,
217
+ list: literal([true]),
218
+ }),
219
+ },
220
+ };
96
221
  const SCALAR_FIELD = object({
97
222
  kind: literal(["scalar"]),
98
223
  type: union(object({ scalar: STRING }), object({ enum: STRING })),
@@ -102,12 +227,19 @@ const SCALAR_FIELD = object({
102
227
  capabilities: object({}, {
103
228
  select: BOOLEAN,
104
229
  filter: list(literal(SCALAR_FILTER_OPERATORS)),
230
+ filterModes: list(literal(FILTER_MODES)),
231
+ pathFilterModes: list(literal(FILTER_MODES)),
105
232
  order: BOOLEAN,
106
233
  orderNulls: BOOLEAN,
107
234
  create: list(literal(SCALAR_MUTATION_DIRECTIVES)),
108
235
  update: list(literal(SCALAR_MUTATION_DIRECTIVES)),
109
236
  }),
110
- }, { format: STRING, json: { is: "jsonSchema" } });
237
+ }, {
238
+ format: STRING,
239
+ json: { is: "jsonSchema" },
240
+ validators: list(FIELD_CHECK),
241
+ governed: literal([true]),
242
+ });
111
243
  const RELATION_FIELD = object({
112
244
  kind: literal(["relation"]),
113
245
  target: STRING,
@@ -127,6 +259,10 @@ const RELATION_FIELD = object({
127
259
  update: RELATION_MUTATION,
128
260
  nestedWriteFilter: literal(["scalar"]),
129
261
  }),
262
+ }, {
263
+ inverse: STRING,
264
+ referenceFields: nonEmptyList(STRING),
265
+ governed: literal([true]),
130
266
  });
131
267
  const OPERATION_AVAILABILITY = union(literal([true]), object({ projection: literal(PROJECTION_SCOPES) }, { write: literal(WRITE_SCOPES) }), object({ write: literal(WRITE_SCOPES) }, { projection: literal(PROJECTION_SCOPES) }));
132
268
  const RESOURCE = object({
@@ -162,6 +298,32 @@ const RESOURCE = object({
162
298
  }),
163
299
  upsert: object({}, { unique: OPERATION_AVAILABILITY }),
164
300
  }),
301
+ }, {
302
+ createRequirements: object({}, {
303
+ required: nonEmptyList(STRING),
304
+ oneOf: nonEmptyList(pairOrMoreList(STRING)),
305
+ parentSupplies: registry(registry(nonEmptyList(STRING))),
306
+ }),
307
+ });
308
+ const ACCESS_VERB = object({
309
+ method: literal(["GET", "POST"]),
310
+ path: { is: "route", form: "path" },
311
+ result: { is: "jsonSchema" },
312
+ }, { args: { is: "jsonSchema" } });
313
+ const ACCESS = object({}, {
314
+ url: { is: "route", form: "url" },
315
+ verbs: object({}, {
316
+ signIn: ACCESS_VERB,
317
+ signUp: ACCESS_VERB,
318
+ signOut: ACCESS_VERB,
319
+ resetPassword: ACCESS_VERB,
320
+ me: ACCESS_VERB,
321
+ switchUser: ACCESS_VERB,
322
+ lock: ACCESS_VERB,
323
+ setPin: ACCESS_VERB,
324
+ enrollDevice: ACCESS_VERB,
325
+ revokeDevice: ACCESS_VERB,
326
+ }),
165
327
  });
166
328
  export const CLIENT_CONTRACT_STRUCTURE = object({
167
329
  scalars: registry(object({ builtin: literal([true]) })),
@@ -173,13 +335,14 @@ export const CLIENT_CONTRACT_STRUCTURE = object({
173
335
  maxListLimit: NUMBER,
174
336
  maxTransactionOperations: NUMBER,
175
337
  maxBooleanNodes: NUMBER,
338
+ maxJsonDepth: NUMBER,
176
339
  }),
177
340
  transactions: literal(TRANSACTION_CAPABILITIES),
178
341
  protocol: object({
179
342
  version: literal([AVENTARA_PROTOCOL_VERSION]),
180
343
  hash: { is: "prefixed", prefix: "sha256:" },
181
344
  }),
182
- }, { referenceWrites: literal(REFERENCE_WRITE_LIMITS) });
345
+ }, { referenceWrites: literal(REFERENCE_WRITE_LIMITS), access: ACCESS });
183
346
  export function validateClientContractStructure(value) {
184
347
  const defect = defectOf(CLIENT_CONTRACT_STRUCTURE, value, "$", 0);
185
348
  if (defect !== undefined) {
@@ -201,6 +364,13 @@ function defectOf(node, value, path, depth) {
201
364
  (value.startsWith(node.prefix)
202
365
  ? undefined
203
366
  : at(path, depth, `is ${JSON.stringify(value)}, which does not begin with ${JSON.stringify(node.prefix)}`)));
367
+ case "route":
368
+ return (kindDefect(value, "string", path, depth) ??
369
+ ((node.form === "url" ? isAccessUrl : isAccessPath)(value)
370
+ ? undefined
371
+ : at(path, depth, node.form === "url"
372
+ ? "is no absolute http(s) URL and no root-relative path"
373
+ : 'is no path under the url, starting with one "/"')));
204
374
  case "list":
205
375
  return listDefect(node, value, path, depth);
206
376
  case "registry": {
@@ -272,13 +442,20 @@ function jsonSchemaDefect(value, path, depth) {
272
442
  switch (keys) {
273
443
  case "type":
274
444
  return literalDefect(JSON_SCHEMA_SCALAR_TYPES, schema.type, `${path}.type`, depth + 1);
445
+ case "checks,type":
446
+ return (literalDefect(["string", "number", "integer"], schema.type, `${path}.type`, depth + 1) ??
447
+ defectOf(list(schema.type === "string" ? JSON_STRING_CHECK : JSON_NUMBER_CHECK), schema.checks, `${path}.checks`, depth + 1));
448
+ case "checks,items,type":
449
+ return (literalDefect(["array"], schema.type, `${path}.type`, depth + 1) ??
450
+ child("items", schema.items) ??
451
+ defectOf(list(JSON_LIST_CHECK), schema.checks, `${path}.checks`, depth + 1));
275
452
  case "const":
276
453
  return Object.is(schema.const, null)
277
454
  ? undefined
278
455
  : defectOf(JSON_PRIMITIVE, schema.const, `${path}.const`, depth + 1);
279
456
  case "enum,type":
280
457
  return (literalDefect(["string"], schema.type, `${path}.type`, depth + 1) ??
281
- defectOf({ is: "list", item: STRING, nonEmpty: true, unique: true }, schema.enum, `${path}.enum`, depth + 1));
458
+ defectOf({ is: "list", item: STRING, minimum: 1, unique: true }, schema.enum, `${path}.enum`, depth + 1));
282
459
  case "additionalProperties,properties,type":
283
460
  case "additionalProperties,properties,required,type": {
284
461
  const typeDefect = literalDefect(["object"], schema.type, `${path}.type`, depth + 1) ??
@@ -296,7 +473,7 @@ function jsonSchemaDefect(value, path, depth) {
296
473
  }
297
474
  if (!Object.hasOwn(schema, "required"))
298
475
  return undefined;
299
- const requiredDefect = defectOf({ is: "list", item: STRING, nonEmpty: false, unique: true }, schema.required, `${path}.required`, depth + 1);
476
+ const requiredDefect = defectOf({ is: "list", item: STRING, minimum: 0, unique: true }, schema.required, `${path}.required`, depth + 1);
300
477
  if (requiredDefect !== undefined)
301
478
  return requiredDefect;
302
479
  const undeclared = schema.required.findIndex((name) => !Object.hasOwn(properties, name));
@@ -348,8 +525,10 @@ function listDefect(node, value, path, depth) {
348
525
  if (kind !== undefined)
349
526
  return kind;
350
527
  const entries = value;
351
- if (node.nonEmpty && entries.length === 0) {
352
- return at(path, depth, "is an empty JSON array, and needs at least one entry");
528
+ if (entries.length < node.minimum) {
529
+ return at(path, depth, entries.length === 0
530
+ ? `is an empty JSON array, and needs at least ${node.minimum === 1 ? "one entry" : "two entries"}`
531
+ : "is a JSON array of one entry, and needs at least two");
353
532
  }
354
533
  const firstIndexOf = new Map();
355
534
  for (let index = 0; index < entries.length; index += 1) {
@@ -0,0 +1,29 @@
1
+ import type { JsonSchema } from "./json-shape.js";
2
+ /**
3
+ * The ClientContract's `access` section: present exactly when the framework's
4
+ * `access` option is configured, and then it marks the `POST /_access/can`
5
+ * route. `url` and `verbs` say where Aventara Access is mounted and each of its
6
+ * `$access` verbs, when the provider states them.
7
+ */
8
+ export type AvContractClientAccess = {
9
+ /** Where the app mounted Access: absolute, or root-relative (`"/api/auth"`). */
10
+ readonly url?: string;
11
+ /**
12
+ * Each `$access` verb the provider offers: its route under `url`, and the
13
+ * JSON Schema of its arguments and result. A verb left out is no verb of
14
+ * `$access` (a `service` profile has no `signIn` or `signUp`; only a
15
+ * `kiosk` profile has `switchUser`, `lock`, `setPin`, `enrollDevice` and
16
+ * `revokeDevice`).
17
+ */
18
+ readonly verbs?: {
19
+ readonly [Verb in "signIn" | "signUp" | "signOut" | "resetPassword" | "me" | "switchUser" | "lock" | "setPin" | "enrollDevice" | "revokeDevice"]?: {
20
+ readonly method: "GET" | "POST";
21
+ /** Under `url`: `"/sign-in/email"`. */
22
+ readonly path: string;
23
+ /** The arguments' JSON Schema; absent when the verb takes none. */
24
+ readonly args?: JsonSchema;
25
+ /** The result's JSON Schema (`me`: the value when someone is signed in). */
26
+ readonly result: JsonSchema;
27
+ };
28
+ };
29
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,11 +1,35 @@
1
- import type { Contract } from "./contract.js";
1
+ import type { AvContract } from "./contract.js";
2
2
  /**
3
3
  * Thrown when a value cannot be written as canonical JSON (RFC 8785). It is a
4
4
  * `TypeError`.
5
5
  */
6
- export declare class CanonicalJsonError extends TypeError {
6
+ export declare class AvCanonicalJsonError extends TypeError {
7
7
  }
8
8
  /** Canonical JSON (RFC 8785) for a JSON-safe value. */
9
9
  export declare function canonicalizeJson(value: unknown): string;
10
+ /**
11
+ * Canonical JSON (RFC 8785) for a value as JSON carries it: a key holding
12
+ * `undefined` is left out, and an array element holding it (or a hole) is
13
+ * `null`, as `JSON.stringify` writes them. Everything else as
14
+ * {@link canonicalizeJson}.
15
+ */
16
+ export declare function canonicalizeWireJson(value: unknown): string;
17
+ /** One top-level member of a canonical Contract: its key and its value's canonical text. */
18
+ type CanonicalContractMember = {
19
+ readonly key: string;
20
+ readonly text: string;
21
+ };
22
+ /** The Contract as canonical JSON (RFC 8785), one top-level member at a time, in order. */
23
+ export declare function canonicalizeContractMembers<C extends AvContract>(contract: C): readonly CanonicalContractMember[];
24
+ /** The canonical object text the members write: `{"key":text,…}`, in their order. */
25
+ export declare function joinCanonicalContractMembers(members: readonly CanonicalContractMember[]): string;
10
26
  /** The Contract as canonical JSON (RFC 8785): the same bytes for the same Contract. */
11
- export declare function canonicalizeContract<C extends Contract>(contract: C): string;
27
+ export declare function canonicalizeContract<C extends AvContract>(contract: C): string;
28
+ /** Records `text` as the canonical text `contract` was parsed from. */
29
+ export declare function recordCanonicalContractText(contract: AvContract, text: string): void;
30
+ /**
31
+ * The Contract's canonical text: the text it was identified from, when the compiler
32
+ * recorded one, else written now. Both are the same bytes for the same Contract.
33
+ */
34
+ export declare function canonicalContractTextOf<C extends AvContract>(contract: C): string;
35
+ export {};
@@ -1,10 +1,12 @@
1
- import { PROJECTION_SCOPES, WRITE_SCOPES } from "./capability.js";
1
+ import { brandCoreClass } from "../runtime/core-class.brand.js";
2
+ import { FILTER_MODES, PROJECTION_SCOPES, WRITE_SCOPES } from "./capability.js";
2
3
  import { LIFECYCLE_TRAITS } from "./lifecycle-trait.js";
3
4
  import { projectionScopeOf, writeScopeOf } from "./resource-operations.js";
4
5
  const PAGINATION_ORDER = ["limit", "offset", "cursor"];
5
6
  const REDUCER_ORDER = ["$count"];
6
- export class CanonicalJsonError extends TypeError {
7
+ export class AvCanonicalJsonError extends TypeError {
7
8
  }
9
+ brandCoreClass(AvCanonicalJsonError, "AvCanonicalJsonError");
8
10
  function compareCodeUnits(left, right) {
9
11
  if (left === right) {
10
12
  return 0;
@@ -61,6 +63,12 @@ function normalizeCapabilities(capabilities) {
61
63
  if (Array.isArray(filter)) {
62
64
  normalized.filter = normalizeStringSet(filter);
63
65
  }
66
+ for (const key of ["filterModes", "pathFilterModes"]) {
67
+ const modes = normalized[key];
68
+ if (Array.isArray(modes)) {
69
+ normalized[key] = normalizeStringSet(modes, FILTER_MODES);
70
+ }
71
+ }
64
72
  for (const key of ["create", "update"]) {
65
73
  const value = normalized[key];
66
74
  if (Array.isArray(value)) {
@@ -103,7 +111,7 @@ function normalizeJsonSchema(schema) {
103
111
  normalizeJsonSchema(child),
104
112
  ]));
105
113
  }
106
- else if (key === "const" || key === "enum") {
114
+ else if (key === "const" || key === "enum" || key === "checks") {
107
115
  normalized[key] = value;
108
116
  }
109
117
  else {
@@ -173,8 +181,56 @@ function normalizeResource(resource) {
173
181
  fields,
174
182
  identifiers,
175
183
  operations: normalizeOperations(resource.operations),
184
+ ...(resource.createRequirements === undefined
185
+ ? {}
186
+ : {
187
+ createRequirements: normalizeCreateRequirements(resource.createRequirements),
188
+ }),
189
+ ...coreResourceFacts(resource),
190
+ };
191
+ }
192
+ function coreResourceFacts(resource) {
193
+ const facts = resource;
194
+ return {
195
+ ...(facts.schema === undefined ? {} : { schema: facts.schema }),
196
+ ...(facts.managedElsewhere === undefined
197
+ ? {}
198
+ : { managedElsewhere: facts.managedElsewhere }),
176
199
  };
177
200
  }
201
+ function isJsonObject(value) {
202
+ return typeof value === "object" && value !== null && !Array.isArray(value);
203
+ }
204
+ function normalizeCreateRequirements(requirements) {
205
+ if (!isJsonObject(requirements)) {
206
+ return requirements;
207
+ }
208
+ const normalized = { ...requirements };
209
+ if (Array.isArray(requirements.required)) {
210
+ normalized.required = normalizeStringSet(requirements.required);
211
+ }
212
+ if (Array.isArray(requirements.oneOf)) {
213
+ normalized.oneOf = requirements.oneOf
214
+ .map((group) => Array.isArray(group) && group.length > 0
215
+ ? [group[0], ...normalizeStringSet(group.slice(1))]
216
+ : group)
217
+ .sort((left, right) => compareCodeUnits(canonicalizeJson(left), canonicalizeJson(right)));
218
+ }
219
+ if (isJsonObject(requirements.parentSupplies)) {
220
+ normalized.parentSupplies = Object.fromEntries(Object.entries(requirements.parentSupplies).map(([parent, byRelation]) => [
221
+ parent,
222
+ isJsonObject(byRelation)
223
+ ? Object.fromEntries(Object.entries(byRelation).map(([relation, members]) => [
224
+ relation,
225
+ Array.isArray(members)
226
+ ? normalizeStringSet(members)
227
+ : members,
228
+ ]))
229
+ : byRelation,
230
+ ]));
231
+ }
232
+ return normalized;
233
+ }
178
234
  function normalizeContract(contract) {
179
235
  const scalars = Object.fromEntries(Object.keys(contract.scalars)
180
236
  .sort(compareCodeUnits)
@@ -201,17 +257,24 @@ function assertValidUnicode(value, path) {
201
257
  if (code >= 0xd800 && code <= 0xdbff) {
202
258
  const next = value.charCodeAt(index + 1);
203
259
  if (!(next >= 0xdc00 && next <= 0xdfff)) {
204
- throw new CanonicalJsonError(`invalid Unicode surrogate at ${path}`);
260
+ throw new AvCanonicalJsonError(`invalid Unicode surrogate at ${path()}`);
205
261
  }
206
262
  index += 1;
207
263
  continue;
208
264
  }
209
265
  if (code >= 0xdc00 && code <= 0xdfff) {
210
- throw new CanonicalJsonError(`invalid Unicode surrogate at ${path}`);
266
+ throw new AvCanonicalJsonError(`invalid Unicode surrogate at ${path()}`);
211
267
  }
212
268
  }
213
269
  }
214
- function canonicalizeValue(value, path) {
270
+ function pathOf(link) {
271
+ const segments = [];
272
+ for (let current = link; current !== undefined; current = current.parent) {
273
+ segments.push(current.segment);
274
+ }
275
+ return `$${segments.reverse().join("")}`;
276
+ }
277
+ function canonicalizePrimitive(value, link) {
215
278
  if (value === null) {
216
279
  return "null";
217
280
  }
@@ -220,47 +283,123 @@ function canonicalizeValue(value, path) {
220
283
  return value ? "true" : "false";
221
284
  case "number": {
222
285
  if (!Number.isFinite(value)) {
223
- throw new CanonicalJsonError(`non-finite number at ${path}`);
286
+ throw new AvCanonicalJsonError(`non-finite number at ${pathOf(link)}`);
224
287
  }
225
288
  const serialized = JSON.stringify(value);
226
289
  if (serialized === undefined) {
227
- throw new CanonicalJsonError(`number at ${path} is not JSON serializable`);
290
+ throw new AvCanonicalJsonError(`number at ${pathOf(link)} is not JSON serializable`);
228
291
  }
229
292
  return serialized;
230
293
  }
231
294
  case "string":
232
- assertValidUnicode(value, path);
295
+ assertValidUnicode(value, () => pathOf(link));
233
296
  return JSON.stringify(value);
234
297
  case "undefined":
235
- throw new CanonicalJsonError(`undefined value at ${path}`);
298
+ throw new AvCanonicalJsonError(`undefined value at ${pathOf(link)}`);
236
299
  case "bigint":
237
300
  case "function":
238
301
  case "symbol":
239
- throw new CanonicalJsonError(`${typeof value} value at ${path} is not JSON serializable`);
240
- case "object":
241
- break;
302
+ throw new AvCanonicalJsonError(`${typeof value} value at ${pathOf(link)} is not JSON serializable`);
303
+ default:
304
+ return undefined;
242
305
  }
243
- if (Array.isArray(value)) {
244
- return `[${Array.prototype.map
245
- .call(value, (entry, index) => canonicalizeValue(entry, `${path}[${index}]`))
246
- .join(",")}]`;
247
- }
248
- const prototype = Object.getPrototypeOf(value);
249
- if (prototype !== Object.prototype && prototype !== null) {
250
- throw new CanonicalJsonError(`non-plain object at ${path} is not canonical JSON`);
306
+ }
307
+ function canonicalizeValue(value, link = undefined, undefinedAsJson = false) {
308
+ const output = [];
309
+ const stack = [{ kind: "value", value, link }];
310
+ while (stack.length > 0) {
311
+ const task = stack.pop();
312
+ if (task.kind === "text") {
313
+ output.push(task.text);
314
+ continue;
315
+ }
316
+ if (task.kind === "key") {
317
+ assertValidUnicode(task.key, () => `${pathOf(task.link)} key`);
318
+ output.push(`${JSON.stringify(task.key)}:`);
319
+ continue;
320
+ }
321
+ const { value: current, link } = task;
322
+ const primitive = canonicalizePrimitive(current, link);
323
+ if (primitive !== undefined) {
324
+ output.push(primitive);
325
+ continue;
326
+ }
327
+ if (Array.isArray(current)) {
328
+ output.push("[");
329
+ stack.push({ kind: "text", text: "]" });
330
+ for (let index = current.length - 1; index >= 0; index -= 1) {
331
+ if (undefinedAsJson && current[index] === undefined) {
332
+ stack.push({ kind: "text", text: "null" });
333
+ }
334
+ else if (index in current) {
335
+ stack.push({
336
+ kind: "value",
337
+ value: current[index],
338
+ link: { parent: link, segment: `[${index}]` },
339
+ });
340
+ }
341
+ if (index > 0) {
342
+ stack.push({ kind: "text", text: "," });
343
+ }
344
+ }
345
+ continue;
346
+ }
347
+ const prototype = Object.getPrototypeOf(current);
348
+ if (prototype !== Object.prototype && prototype !== null) {
349
+ throw new AvCanonicalJsonError(`non-plain object at ${pathOf(link)} is not canonical JSON`);
350
+ }
351
+ const record = current;
352
+ const keys = Object.keys(record)
353
+ .filter((key) => !undefinedAsJson || record[key] !== undefined)
354
+ .sort(compareCodeUnits);
355
+ output.push("{");
356
+ stack.push({ kind: "text", text: "}" });
357
+ for (let index = keys.length - 1; index >= 0; index -= 1) {
358
+ const key = keys[index];
359
+ stack.push({
360
+ kind: "value",
361
+ value: record[key],
362
+ link: { parent: link, segment: `.${key}` },
363
+ });
364
+ stack.push({ kind: "key", key, link });
365
+ if (index > 0) {
366
+ stack.push({ kind: "text", text: "," });
367
+ }
368
+ }
251
369
  }
252
- const record = value;
253
- const entries = Object.keys(record)
370
+ return output.join("");
371
+ }
372
+ export function canonicalizeJson(value) {
373
+ return canonicalizeValue(value);
374
+ }
375
+ export function canonicalizeWireJson(value) {
376
+ return canonicalizeValue(value, undefined, true);
377
+ }
378
+ export function canonicalizeContractMembers(contract) {
379
+ const record = normalizeContract(contract);
380
+ return Object.keys(record)
254
381
  .sort(compareCodeUnits)
255
382
  .map((key) => {
256
- assertValidUnicode(key, `${path} key`);
257
- return `${JSON.stringify(key)}:${canonicalizeValue(record[key], `${path}.${key}`)}`;
383
+ assertValidUnicode(key, () => "$ key");
384
+ return {
385
+ key,
386
+ text: canonicalizeValue(record[key], {
387
+ parent: undefined,
388
+ segment: `.${key}`,
389
+ }),
390
+ };
258
391
  });
259
- return `{${entries.join(",")}}`;
260
392
  }
261
- export function canonicalizeJson(value) {
262
- return canonicalizeValue(value, "$");
393
+ export function joinCanonicalContractMembers(members) {
394
+ return `{${members.map(({ key, text }) => `${JSON.stringify(key)}:${text}`).join(",")}}`;
263
395
  }
264
396
  export function canonicalizeContract(contract) {
265
- return canonicalizeJson(normalizeContract(contract));
397
+ return joinCanonicalContractMembers(canonicalizeContractMembers(contract));
398
+ }
399
+ const canonicalTexts = new WeakMap();
400
+ export function recordCanonicalContractText(contract, text) {
401
+ canonicalTexts.set(contract, text);
402
+ }
403
+ export function canonicalContractTextOf(contract) {
404
+ return canonicalTexts.get(contract) ?? canonicalizeContract(contract);
266
405
  }
@@ -1,11 +1,15 @@
1
- import type { ClientContract } from "./contract.js";
2
- import type { ContractHash, ContractProtocol } from "./contract-protocol.js";
1
+ import type { AvContractClient } from "./contract.js";
2
+ import type { AvContractHash, AvContractProtocol } from "./contract-protocol.js";
3
3
  /** A ClientContract whose `protocol` does not carry the hash yet. */
4
- export type ClientContractHashInput = Omit<ClientContract, "protocol"> & {
5
- readonly protocol: ContractProtocol;
4
+ export type AvContractClientHashInput = Omit<AvContractClient, "protocol"> & {
5
+ readonly protocol: AvContractProtocol;
6
6
  };
7
- export declare function createClientContractHashInput(contract: ClientContract | ClientContractHashInput): ClientContractHashInput;
8
7
  /** Computes a ClientContract's `sha256:` hash, ignoring `protocol.hash` itself. */
9
- export declare function computeClientContractHash(contract: ClientContract | ClientContractHashInput): Promise<ContractHash>;
8
+ export declare function computeClientContractHash(contract: AvContractClient | AvContractClientHashInput): Promise<AvContractHash>;
9
+ /**
10
+ * The `sha256:` hash of a hash input's canonical text, already written: what
11
+ * {@link computeClientContractHash} answers for the input that text is of.
12
+ */
13
+ export declare function hashCanonicalContractText(canonical: string): Promise<AvContractHash>;
10
14
  /** Whether a ClientContract's `protocol.hash` matches its content. */
11
- export declare function verifyClientContractHash(contract: ClientContract): Promise<boolean>;
15
+ export declare function verifyClientContractHash(contract: AvContractClient): Promise<boolean>;
@@ -1,5 +1,5 @@
1
1
  import { canonicalizeContract } from "./contract-canonicalizer.js";
2
- export function createClientContractHashInput(contract) {
2
+ function createClientContractHashInput(contract) {
3
3
  const { protocol, ...semantic } = contract;
4
4
  return {
5
5
  ...semantic,
@@ -10,8 +10,9 @@ function digestHex(digest) {
10
10
  return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
11
11
  }
12
12
  export async function computeClientContractHash(contract) {
13
- const input = createClientContractHashInput(contract);
14
- const canonical = canonicalizeContract(input);
13
+ return hashCanonicalContractText(canonicalizeContract(createClientContractHashInput(contract)));
14
+ }
15
+ export async function hashCanonicalContractText(canonical) {
15
16
  const bytes = new TextEncoder().encode(canonical);
16
17
  const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
17
18
  return `sha256:${digestHex(digest)}`;