@aventara/core 1.0.0-rc.1 → 1.0.0-rc.11

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 (261) hide show
  1. package/CHANGELOG.md +1022 -16
  2. package/ERRORS.md +142 -0
  3. package/README.md +330 -16
  4. package/dist/adapters/adapter-discovery-diagnostic.guidance.d.ts +6 -0
  5. package/dist/adapters/adapter-discovery-diagnostic.guidance.js +7 -0
  6. package/dist/adapters/adapter-field.d.ts +22 -0
  7. package/dist/adapters/adapter-identifier.d.ts +9 -0
  8. package/dist/adapters/adapter-identifier.js +6 -1
  9. package/dist/adapters/adapter-model.d.ts +9 -0
  10. package/dist/adapters/adapter-operation.d.ts +18 -3
  11. package/dist/adapters/adapter-resource.d.ts +5 -0
  12. package/dist/adapters/adapter.interface.d.ts +10 -0
  13. package/dist/avz/avz.d.ts +1 -1
  14. package/dist/avz/json-shape.registry.d.ts +2 -1
  15. package/dist/compiler/contract-compiler-diagnostic.guidance.d.ts +6 -0
  16. package/dist/compiler/contract-compiler-diagnostic.guidance.js +97 -0
  17. package/dist/compiler/contract.compiler.d.ts +6 -0
  18. package/dist/compiler/contract.compiler.js +281 -31
  19. package/dist/compiler/create-requirements.projector.js +1 -3
  20. package/dist/compiler/field-validator.compiler.js +1 -3
  21. package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
  22. package/dist/compiler/managed-elsewhere.projector.js +179 -0
  23. package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
  24. package/dist/compiler/managed-elsewhere.validator.js +74 -0
  25. package/dist/config/cache-stage.factory.d.ts +24 -0
  26. package/dist/config/cache-stage.factory.js +3 -0
  27. package/dist/config/computed-fields.d.ts +62 -0
  28. package/dist/config/computed-fields.js +73 -0
  29. package/dist/config/config-diagnostic.guidance.d.ts +6 -0
  30. package/dist/config/config-diagnostic.guidance.js +32 -0
  31. package/dist/config/config.resolver.d.ts +24 -0
  32. package/dist/config/config.resolver.js +66 -7
  33. package/dist/config/config.validator.js +283 -21
  34. package/dist/config/define-resource.d.ts +1 -5
  35. package/dist/config/entrypoint.normalizer.d.ts +3 -2
  36. package/dist/config/exact-framework-config.d.ts +73 -22
  37. package/dist/config/field-compute.resolver.d.ts +2 -0
  38. package/dist/config/field-compute.resolver.js +9 -3
  39. package/dist/config/framework-config.d.ts +53 -15
  40. package/dist/config/framework-resources-config.d.ts +25 -14
  41. package/dist/config/pipeline-config.d.ts +20 -4
  42. package/dist/config/pipeline-tree.resolver.d.ts +2 -2
  43. package/dist/config/pipeline-tree.resolver.js +2 -3
  44. package/dist/contracts/access-route.rules.d.ts +10 -0
  45. package/dist/contracts/access-route.rules.js +45 -0
  46. package/dist/contracts/canonical-json.writer.d.ts +7 -0
  47. package/dist/contracts/canonical-json.writer.js +55 -0
  48. package/dist/contracts/capability.d.ts +26 -1
  49. package/dist/contracts/capability.js +20 -0
  50. package/dist/contracts/client-contract-structure.validator.d.ts +365 -89
  51. package/dist/contracts/client-contract-structure.validator.js +49 -2
  52. package/dist/contracts/contract-access.d.ts +29 -0
  53. package/dist/contracts/contract-access.js +1 -0
  54. package/dist/contracts/contract-canonicalizer.d.ts +9 -1
  55. package/dist/contracts/contract-canonicalizer.js +35 -4
  56. package/dist/contracts/contract-hash.d.ts +0 -1
  57. package/dist/contracts/contract-hash.js +1 -1
  58. package/dist/contracts/contract-limits.d.ts +6 -0
  59. package/dist/contracts/contract-limits.js +2 -0
  60. package/dist/contracts/contract.d.ts +42 -1
  61. package/dist/contracts/field.d.ts +58 -1
  62. package/dist/contracts/json-schema.projector.d.ts +11 -0
  63. package/dist/contracts/json-schema.projector.js +76 -0
  64. package/dist/contracts/scalar-value-type.d.ts +3 -1
  65. package/dist/framework/access-facade.d.ts +116 -0
  66. package/dist/framework/access-facade.js +118 -0
  67. package/dist/framework/contract-view.d.ts +120 -16
  68. package/dist/framework/framework-construction.error.d.ts +14 -4
  69. package/dist/framework/framework-construction.error.js +18 -2
  70. package/dist/framework/framework.d.ts +26 -5
  71. package/dist/framework/framework.factory.d.ts +1 -1
  72. package/dist/framework/framework.factory.js +145 -24
  73. package/dist/framework/operation-facade.d.ts +141 -13
  74. package/dist/framework/operation-facade.js +9 -1
  75. package/dist/framework/operation-set.runner.d.ts +47 -0
  76. package/dist/framework/operation-set.runner.js +168 -0
  77. package/dist/index.d.ts +19 -5
  78. package/dist/index.js +3 -0
  79. package/dist/internal.d.ts +9 -2
  80. package/dist/internal.js +8 -0
  81. package/dist/operations/database-refusal.d.ts +51 -0
  82. package/dist/operations/database-refusal.js +45 -0
  83. package/dist/operations/operation-arguments.d.ts +148 -60
  84. package/dist/operations/operation-call.d.ts +9 -5
  85. package/dist/operations/operation-result.d.ts +6 -4
  86. package/dist/operations/operation-validator-core.js +160 -39
  87. package/dist/operations/operation-validator.d.ts +1 -1
  88. package/dist/operations/structural-limits.walker.d.ts +1 -1
  89. package/dist/operations/structural-limits.walker.js +1 -3
  90. package/dist/operations/validation-code.guidance.d.ts +6 -0
  91. package/dist/operations/validation-code.guidance.js +90 -0
  92. package/dist/operations/write-scope.resolver.d.ts +4 -0
  93. package/dist/operations/write-scope.resolver.js +2 -0
  94. package/dist/policy/access-provider.interface.d.ts +91 -0
  95. package/dist/policy/access-provider.interface.js +1 -0
  96. package/dist/policy/access-provider.registry.d.ts +17 -0
  97. package/dist/policy/access-provider.registry.js +15 -0
  98. package/dist/policy/access-question.d.ts +20 -0
  99. package/dist/policy/access-question.js +1 -0
  100. package/dist/policy/access-question.registry.d.ts +5 -0
  101. package/dist/policy/access-question.registry.js +19 -0
  102. package/dist/policy/access-question.runtime.d.ts +36 -0
  103. package/dist/policy/access-question.runtime.js +295 -0
  104. package/dist/policy/access-verb.table.d.ts +56 -0
  105. package/dist/policy/access-verb.table.js +21 -0
  106. package/dist/policy/access-verbs.d.ts +46 -0
  107. package/dist/policy/access-verbs.js +1 -0
  108. package/dist/policy/policy-admission.d.ts +20 -0
  109. package/dist/policy/policy-admission.js +407 -0
  110. package/dist/policy/policy-after-update.runtime.d.ts +79 -0
  111. package/dist/policy/policy-after-update.runtime.js +206 -0
  112. package/dist/policy/policy-condition.d.ts +15 -0
  113. package/dist/policy/policy-condition.js +36 -0
  114. package/dist/policy/policy-engine.d.ts +205 -0
  115. package/dist/policy/policy-engine.js +1 -0
  116. package/dist/policy/policy-named-rows.d.ts +18 -0
  117. package/dist/policy/policy-named-rows.js +51 -0
  118. package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
  119. package/dist/policy/policy-nested-write.runtime.js +536 -0
  120. package/dist/policy/policy-read.runtime.d.ts +81 -0
  121. package/dist/policy/policy-read.runtime.js +501 -0
  122. package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
  123. package/dist/policy/policy-reference-write.runtime.js +336 -0
  124. package/dist/policy/policy-request.d.ts +72 -0
  125. package/dist/policy/policy-request.js +115 -0
  126. package/dist/policy/policy-session.d.ts +106 -0
  127. package/dist/policy/policy-session.js +293 -0
  128. package/dist/policy/policy-startup.validator.d.ts +10 -0
  129. package/dist/policy/policy-startup.validator.js +112 -0
  130. package/dist/policy/policy-write.runtime.d.ts +39 -0
  131. package/dist/policy/policy-write.runtime.js +530 -0
  132. package/dist/prebuilt/core-version.generated.d.ts +2 -0
  133. package/dist/prebuilt/core-version.generated.js +1 -0
  134. package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
  135. package/dist/prebuilt/prebuilt-changes.js +63 -0
  136. package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
  137. package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
  138. package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
  139. package/dist/prebuilt/prebuilt-contracts.js +1 -0
  140. package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
  141. package/dist/prebuilt/prebuilt-contracts.loader.js +75 -0
  142. package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
  143. package/dist/prebuilt/prebuilt-inputs.fingerprint.js +227 -0
  144. package/dist/protocol/absent-route.responder.d.ts +49 -14
  145. package/dist/protocol/absent-route.responder.js +92 -15
  146. package/dist/protocol/contract-document.responder.d.ts +9 -1
  147. package/dist/protocol/contract-document.responder.js +3 -2
  148. package/dist/protocol/http-request.decoder.d.ts +52 -3
  149. package/dist/protocol/http-request.decoder.js +45 -6
  150. package/dist/protocol/http-request.reader.d.ts +10 -3
  151. package/dist/protocol/http-request.reader.js +12 -2
  152. package/dist/protocol/http-response.encoder.d.ts +12 -0
  153. package/dist/protocol/http-response.encoder.js +17 -3
  154. package/dist/protocol/operation-response.guard.js +1 -3
  155. package/dist/protocol/operation-set.decoder.d.ts +48 -0
  156. package/dist/protocol/operation-set.decoder.js +185 -0
  157. package/dist/protocol/operation-set.handler.d.ts +27 -0
  158. package/dist/protocol/operation-set.handler.js +179 -0
  159. package/dist/protocol/protocol-headers.d.ts +12 -3
  160. package/dist/protocol/protocol-headers.js +12 -5
  161. package/dist/protocol/protocol-surface.d.ts +16 -3
  162. package/dist/protocol/protocol-surface.js +41 -1
  163. package/dist/protocol/protocol.binder.d.ts +52 -1
  164. package/dist/protocol/protocol.binder.js +6 -1
  165. package/dist/protocol/protocol.handler.d.ts +45 -1
  166. package/dist/protocol/protocol.handler.js +164 -19
  167. package/dist/protocol/read-cache.responder.d.ts +26 -0
  168. package/dist/protocol/read-cache.responder.js +47 -0
  169. package/dist/protocol/read-query.codec.d.ts +34 -0
  170. package/dist/protocol/read-query.codec.js +125 -0
  171. package/dist/runtime/caller-data.copier.d.ts +18 -3
  172. package/dist/runtime/caller-data.copier.js +21 -8
  173. package/dist/runtime/caller-data.door.d.ts +13 -6
  174. package/dist/runtime/computed-read-runtime.d.ts +6 -1
  175. package/dist/runtime/computed-read-runtime.js +229 -48
  176. package/dist/runtime/computed-value.error.d.ts +3 -2
  177. package/dist/runtime/computed-value.error.js +3 -2
  178. package/dist/runtime/context-executor.runtime.d.ts +4 -3
  179. package/dist/runtime/context-executor.runtime.js +4 -2
  180. package/dist/runtime/core-class.brand.d.ts +10 -0
  181. package/dist/runtime/core-class.brand.js +21 -0
  182. package/dist/runtime/create-requirement.d.ts +31 -5
  183. package/dist/runtime/create-requirement.js +130 -24
  184. package/dist/runtime/decimal.d.ts +14 -0
  185. package/dist/runtime/decimal.js +21 -0
  186. package/dist/runtime/diagnostics-reporter.d.ts +49 -9
  187. package/dist/runtime/diagnostics-reporter.js +16 -9
  188. package/dist/runtime/error-boundary.d.ts +9 -2
  189. package/dist/runtime/error-boundary.js +12 -0
  190. package/dist/runtime/error-guidance.d.ts +12 -0
  191. package/dist/runtime/error-guidance.js +1 -0
  192. package/dist/runtime/error.catalog.d.ts +49 -0
  193. package/dist/runtime/error.catalog.js +49 -0
  194. package/dist/runtime/execution-options.d.ts +8 -0
  195. package/dist/runtime/field-check.evaluator.d.ts +0 -2
  196. package/dist/runtime/field-check.evaluator.js +1 -1
  197. package/dist/runtime/field-compute.d.ts +11 -10
  198. package/dist/runtime/field-stage.runtime.d.ts +3 -3
  199. package/dist/runtime/field-stage.runtime.js +9 -11
  200. package/dist/runtime/field-validator.runtime.d.ts +19 -1
  201. package/dist/runtime/field-validator.runtime.js +49 -9
  202. package/dist/runtime/framework-error.js +9 -0
  203. package/dist/runtime/framework-warning.emitter.d.ts +6 -0
  204. package/dist/runtime/framework-warning.emitter.js +8 -0
  205. package/dist/runtime/json-value.d.ts +10 -5
  206. package/dist/runtime/level-lifecycle.runtime.d.ts +4 -3
  207. package/dist/runtime/level-lifecycle.runtime.js +3 -5
  208. package/dist/runtime/mutation-planner.d.ts +1 -6
  209. package/dist/runtime/mutation-planner.js +4 -17
  210. package/dist/runtime/nested-write.walker.js +2 -1
  211. package/dist/runtime/operation-code.guidance.d.ts +6 -0
  212. package/dist/runtime/operation-code.guidance.js +167 -0
  213. package/dist/runtime/operation-request.d.ts +16 -9
  214. package/dist/runtime/operation-runtime.d.ts +35 -17
  215. package/dist/runtime/operation-runtime.js +220 -49
  216. package/dist/runtime/outcome-mapper.d.ts +2 -1
  217. package/dist/runtime/output-validator.d.ts +1 -1
  218. package/dist/runtime/output-validator.js +1 -3
  219. package/dist/runtime/owned-execution.registry.d.ts +34 -4
  220. package/dist/runtime/pipe-output.validator.d.ts +10 -0
  221. package/dist/runtime/pipe-output.validator.js +4 -2
  222. package/dist/runtime/pipeline.d.ts +52 -23
  223. package/dist/runtime/readonly-value.d.ts +20 -5
  224. package/dist/runtime/readonly-value.js +74 -26
  225. package/dist/runtime/record.guard.d.ts +14 -0
  226. package/dist/runtime/record.guard.js +10 -0
  227. package/dist/runtime/referential-action.d.ts +1 -1
  228. package/dist/runtime/request-envelope.validator.js +13 -10
  229. package/dist/runtime/scalar-runtime.d.ts +4 -21
  230. package/dist/runtime/scalar-runtime.js +91 -31
  231. package/dist/runtime/thenable.guard.d.ts +7 -0
  232. package/dist/runtime/thenable.guard.js +5 -0
  233. package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
  234. package/dist/runtime/unsent-value.normalizer.js +129 -0
  235. package/dist/transactions/operation-arguments-encoder.js +9 -10
  236. package/dist/transactions/operation-fingerprint.js +2 -2
  237. package/dist/transactions/sql-statement.d.ts +10 -2
  238. package/dist/transactions/sql-statement.validator.d.ts +2 -2
  239. package/dist/transactions/sql-statement.validator.js +40 -6
  240. package/dist/transactions/transaction-envelope.d.ts +5 -4
  241. package/dist/transactions/transaction-integrity-error.js +2 -0
  242. package/dist/transactions/transaction-plan-assembler.d.ts +12 -5
  243. package/dist/transactions/transaction-plan-assembler.js +49 -17
  244. package/dist/transactions/transaction-plan-validator.d.ts +23 -7
  245. package/dist/transactions/transaction-plan-validator.js +31 -7
  246. package/dist/transactions/transaction-reference-collector.js +8 -10
  247. package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
  248. package/dist/transactions/transaction-reference-resolver.js +1 -3
  249. package/dist/transactions/transaction-reference-validator.d.ts +43 -3
  250. package/dist/transactions/transaction-reference-validator.js +83 -57
  251. package/dist/transactions/transaction-reference.d.ts +1 -1
  252. package/dist/transactions/transaction-reference.js +5 -0
  253. package/dist/transactions/transaction-request.d.ts +8 -8
  254. package/dist/transactions/transaction-runtime.d.ts +5 -2
  255. package/dist/transactions/transaction-runtime.js +108 -27
  256. package/dist/transactions/transaction-settlement.runtime.d.ts +4 -3
  257. package/dist/transactions/transaction-slot-path-error.js +2 -0
  258. package/dist/transactions/transaction-stage.runtime.d.ts +5 -3
  259. package/dist/transactions/transaction-stage.runtime.js +8 -7
  260. package/package.json +6 -5
  261. package/src/runtime/field-check.evaluator.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  import { bindShapedField, jsonShapeOf } from "../avz/json-shape.registry.js";
2
- import { PROJECTION_SCOPES, WRITE_SCOPES } from "../contracts/capability.js";
2
+ import { FILTER_MODES, PROJECTION_SCOPES, WRITE_SCOPES, } from "../contracts/capability.js";
3
3
  import { validateClientContractStructure } from "../contracts/client-contract-structure.validator.js";
4
4
  import { canonicalizeContract, canonicalizeContractMembers, canonicalizeJson, joinCanonicalContractMembers, recordCanonicalContractText, } from "../contracts/contract-canonicalizer.js";
5
5
  import { hashCanonicalContractText, } from "../contracts/contract-hash.js";
@@ -7,8 +7,10 @@ import { DEFAULT_CONTRACT_LIMITS, } from "../contracts/contract-limits.js";
7
7
  import { AVENTARA_PROTOCOL_VERSION } from "../contracts/contract-protocol.js";
8
8
  import { advertisedDirectives, advertisedReducers, holdsInAnyScope, } from "../contracts/field.js";
9
9
  import { isOperationVariantAvailable, } from "../contracts/resource-operations.js";
10
+ import { isRecord } from "../runtime/record.guard.js";
10
11
  import { checkCreateRequirements, checkHiddenRequirements, projectCreateRequirements, } from "./create-requirements.projector.js";
11
12
  import { applyValidators, bindFieldValidators, checkLayerValidators, compileValidatorTable, } from "./field-validator.compiler.js";
13
+ import { explainManagedRefusals, hideManagedElsewhere, managedElsewhereOf, managedWriteReason, markCoreResources, pruneManagedEnums, withholdManagedWrites, } from "./managed-elsewhere.projector.js";
12
14
  const UNIQUE_VARIANTS = [
13
15
  ["find", "unique"],
14
16
  ["update", "unique"],
@@ -23,9 +25,6 @@ const COMPUTED_TRAITS = new Set([
23
25
  function diagnostic(code, path, message) {
24
26
  return { code, path, message };
25
27
  }
26
- function isRecord(value) {
27
- return value !== null && typeof value === "object" && !Array.isArray(value);
28
- }
29
28
  function cloneValue(value) {
30
29
  if (Array.isArray(value)) {
31
30
  return value.map((entry) => cloneValue(entry));
@@ -41,6 +40,12 @@ function normalizeAdapterScalarCapabilities(capabilities) {
41
40
  ...(capabilities.filter !== undefined
42
41
  ? { filter: [...capabilities.filter] }
43
42
  : {}),
43
+ ...(capabilities.filterModes !== undefined
44
+ ? { filterModes: [...capabilities.filterModes] }
45
+ : {}),
46
+ ...(capabilities.pathFilterModes !== undefined
47
+ ? { pathFilterModes: [...capabilities.pathFilterModes] }
48
+ : {}),
44
49
  ...(capabilities.order !== undefined ? { order: capabilities.order } : {}),
45
50
  ...(capabilities.orderNulls !== undefined
46
51
  ? { orderNulls: capabilities.orderNulls }
@@ -71,8 +76,65 @@ function cloneAdapterField(field) {
71
76
  cardinality: field.cardinality,
72
77
  nullable: field.nullable,
73
78
  capabilities: cloneValue(field.capabilities),
79
+ ...(typeof field.inverse === "string" ? { inverse: field.inverse } : {}),
80
+ ...(Array.isArray(field.referenceFields) && field.referenceFields.length > 0
81
+ ? { referenceFields: [...field.referenceFields] }
82
+ : {}),
83
+ ...(Array.isArray(field.referenceFields) &&
84
+ Array.isArray(field.references) &&
85
+ field.references.length > 0 &&
86
+ field.references.length === field.referenceFields.length
87
+ ? { references: [...field.references] }
88
+ : {}),
74
89
  };
75
90
  }
91
+ function pruneHiddenPairings(projection, references) {
92
+ const resources = projection.resources;
93
+ for (const [name, resource] of Object.entries(resources)) {
94
+ for (const field of Object.values(resource.fields)) {
95
+ if (field.kind !== "relation") {
96
+ continue;
97
+ }
98
+ if (Array.isArray(field.references) &&
99
+ (references === "none" ||
100
+ !wholePairing(resource.fields, Object.hasOwn(resources, String(field.target))
101
+ ? resources[String(field.target)]?.fields
102
+ : undefined, field.referenceFields, field.references))) {
103
+ delete field.references;
104
+ }
105
+ if (Array.isArray(field.referenceFields)) {
106
+ const shown = field.referenceFields.filter((reference) => typeof reference === "string" &&
107
+ Object.hasOwn(resource.fields, reference) &&
108
+ resource.fields[reference]?.kind === "scalar");
109
+ if (shown.length > 0) {
110
+ field.referenceFields = shown;
111
+ }
112
+ else {
113
+ delete field.referenceFields;
114
+ }
115
+ }
116
+ if (typeof field.inverse !== "string") {
117
+ continue;
118
+ }
119
+ const other = Object.hasOwn(resources, String(field.target))
120
+ ? resources[String(field.target)]?.fields[field.inverse]
121
+ : undefined;
122
+ if (other?.kind !== "relation" || other.target !== name) {
123
+ delete field.inverse;
124
+ }
125
+ }
126
+ }
127
+ }
128
+ function wholePairing(fields, targetFields, referenceFields, references) {
129
+ const shownIn = (within, name) => typeof name === "string" &&
130
+ within !== undefined &&
131
+ Object.hasOwn(within, name) &&
132
+ within[name]?.kind === "scalar";
133
+ return (Array.isArray(referenceFields) &&
134
+ referenceFields.length === references.length &&
135
+ referenceFields.every((name) => shownIn(fields, name)) &&
136
+ references.every((name) => shownIn(targetFields, name)));
137
+ }
76
138
  function cloneOperations(operations) {
77
139
  return cloneValue(operations);
78
140
  }
@@ -86,8 +148,40 @@ function cloneAdapterResource(resource) {
86
148
  operations: cloneOperations(resource.operations),
87
149
  };
88
150
  }
151
+ function canonicalModes(modes) {
152
+ const stated = Array.isArray(modes) ? modes : [];
153
+ const known = FILTER_MODES.filter((mode) => mode === "default" || stated.includes(mode));
154
+ const unknown = stated.filter((mode) => !FILTER_MODES.includes(mode));
155
+ return [...known, ...unknown];
156
+ }
157
+ function qualifyFilterModes(projection) {
158
+ for (const resource of Object.values(projection.resources)) {
159
+ for (const field of Object.values(resource.fields)) {
160
+ if (field.kind !== "scalar") {
161
+ continue;
162
+ }
163
+ const capabilities = field.capabilities;
164
+ const filter = Array.isArray(capabilities.filter)
165
+ ? capabilities.filter
166
+ : [];
167
+ if (!filter.includes("mode")) {
168
+ delete capabilities.filterModes;
169
+ delete capabilities.pathFilterModes;
170
+ continue;
171
+ }
172
+ const stated = capabilities.filterModes;
173
+ capabilities.filterModes = canonicalModes(stated);
174
+ if (filter.includes("path")) {
175
+ capabilities.pathFilterModes = canonicalModes(capabilities.pathFilterModes ?? stated);
176
+ }
177
+ else {
178
+ delete capabilities.pathFilterModes;
179
+ }
180
+ }
181
+ }
182
+ }
89
183
  function createBaseline(model) {
90
- return {
184
+ const baseline = {
91
185
  scalars: Object.fromEntries(Object.entries(model.scalars).map(([key, value]) => [
92
186
  key,
93
187
  cloneValue(value),
@@ -106,6 +200,8 @@ function createBaseline(model) {
106
200
  ? {}
107
201
  : { referenceWrites: model.referenceWrites }),
108
202
  };
203
+ qualifyFilterModes(baseline);
204
+ return baseline;
109
205
  }
110
206
  function definitionPath(resource, field) {
111
207
  return `root.resources.${resource}.fields.${field}.definition`;
@@ -285,7 +381,7 @@ function checkFieldCompute(model, resourceName, fieldName, field, compute, path,
285
381
  }
286
382
  }
287
383
  }
288
- function checkResourceTree(model, baseline, scope, tree, definitions, diagnostics) {
384
+ function checkResourceTree(model, baseline, scope, tree, definitions, managed, diagnostics) {
289
385
  if (!isRecord(tree)) {
290
386
  return;
291
387
  }
@@ -296,12 +392,22 @@ function checkResourceTree(model, baseline, scope, tree, definitions, diagnostic
296
392
  diagnostics.push(diagnostic("COMPILER_UNKNOWN_RESOURCE", resourcePath, `resource "${resourceName}" is not present in the canonical adapter model`));
297
393
  continue;
298
394
  }
395
+ if ((scope === "client" || scope === "agent") &&
396
+ managed.has(resourceName)) {
397
+ diagnostics.push(diagnostic("COMPILER_UNKNOWN_RESOURCE", resourcePath, `resource "${resourceName}" is managed elsewhere (resources.${resourceName}.managedElsewhere), so the ${scope} layer never has it: nothing configured for it here runs`));
398
+ continue;
399
+ }
299
400
  if (!isRecord(entry)) {
300
401
  continue;
301
402
  }
302
403
  if (isRecord(entry.operations)) {
303
404
  for (const [family, level] of Object.entries(entry.operations)) {
304
405
  const familyPath = `${resourcePath}.operations.${family}`;
406
+ const managedReason = managedWriteReason(managed, resourceName, family);
407
+ if (managedReason !== undefined) {
408
+ diagnostics.push(diagnostic("COMPILER_UNAVAILABLE_OPERATION", familyPath, managedReason));
409
+ continue;
410
+ }
305
411
  const variants = resource.operations[family];
306
412
  if (!isRecord(variants)) {
307
413
  diagnostics.push(diagnostic("COMPILER_UNAVAILABLE_OPERATION", familyPath, `operation family "${family}" is not available for resource "${resourceName}"`));
@@ -330,7 +436,8 @@ function checkResourceTree(model, baseline, scope, tree, definitions, diagnostic
330
436
  diagnostics.push(diagnostic("COMPILER_UNKNOWN_FIELD", `${resourcePath}.fields.${fieldName}`, `field "${fieldName}" is neither discovered by the adapter nor defined at the root`));
331
437
  continue;
332
438
  }
333
- if (!isRecord(fieldEntry) || !isRecord(fieldEntry.pipelines)) {
439
+ if (!isRecord(fieldEntry) ||
440
+ !isRecord(fieldEntry.pipelines)) {
334
441
  continue;
335
442
  }
336
443
  const pipelinesPath = `${resourcePath}.fields.${fieldName}.pipelines`;
@@ -349,9 +456,14 @@ function checkReservedResourceNames(model, diagnostics) {
349
456
  }
350
457
  }
351
458
  }
459
+ function isAdapterStated(axis) {
460
+ return axis?.kind === "limit" || axis?.kind === "adapterTokens";
461
+ }
352
462
  const SCALAR_CAPABILITY_AXES = {
353
463
  select: { kind: "flag" },
354
464
  filter: { kind: "tokens" },
465
+ filterModes: { kind: "adapterTokens", values: FILTER_MODES },
466
+ pathFilterModes: { kind: "adapterTokens", values: FILTER_MODES },
355
467
  order: { kind: "flag" },
356
468
  orderNulls: { kind: "flag" },
357
469
  create: { kind: "tokens" },
@@ -445,11 +557,11 @@ function fieldName(resource, field) {
445
557
  }
446
558
  function exemptableAxis(walk, universeField, capability, label, path) {
447
559
  const axis = capabilityAxisFor(universeField.kind, capability);
448
- if (axis === undefined || axis.kind === "limit") {
560
+ if (axis === undefined || isAdapterStated(axis)) {
449
561
  const names = Object.entries(universeField.kind === "scalar"
450
562
  ? SCALAR_CAPABILITY_AXES
451
563
  : RELATION_CAPABILITY_AXES)
452
- .filter(([, entry]) => entry.kind !== "limit")
564
+ .filter(([, entry]) => !isAdapterStated(entry))
453
565
  .map(([name]) => name);
454
566
  unavailableCapability(path, `"${capability}" is not a capability a ${universeField.kind} field's exemption can name; it takes ${names.join(", ")}`, walk.diagnostics);
455
567
  return undefined;
@@ -533,7 +645,7 @@ function exemptField(walk, universeField, parentField, entry, label, path) {
533
645
  const result = walk.style === "omit" ? cloneValue(parentCapabilities) : {};
534
646
  if (walk.style === "pick") {
535
647
  for (const [key, value] of Object.entries(parentCapabilities)) {
536
- if (capabilityAxisFor(universeField.kind, key)?.kind === "limit") {
648
+ if (isAdapterStated(capabilityAxisFor(universeField.kind, key))) {
537
649
  result[key] = cloneValue(value);
538
650
  }
539
651
  }
@@ -552,7 +664,7 @@ function exemptField(walk, universeField, parentField, entry, label, path) {
552
664
  return undefined;
553
665
  }
554
666
  if (walk.style === "pick" &&
555
- !Object.keys(result).some((key) => capabilityAxisFor(universeField.kind, key)?.kind !== "limit")) {
667
+ !Object.keys(result).some((key) => !isAdapterStated(capabilityAxisFor(universeField.kind, key)))) {
556
668
  return undefined;
557
669
  }
558
670
  return { ...cloneValue(parentField), capabilities: result };
@@ -651,7 +763,9 @@ function exemptOperations(walk, resourceName, universe, parent, entry, path) {
651
763
  if (value === false || value === undefined) {
652
764
  continue;
653
765
  }
654
- if (value !== true && !Array.isArray(value) && !isRecord(value)) {
766
+ if (value !== true &&
767
+ !Array.isArray(value) &&
768
+ !isRecord(value)) {
655
769
  walk.diagnostics.push(diagnostic("COMPILER_UNAVAILABLE_OPERATION", familyPath, "an operation family takes true, false, a list of its variants or an object of them"));
656
770
  continue;
657
771
  }
@@ -698,7 +812,8 @@ function exemptResource(walk, resourceName, universe, parent, entry, path) {
698
812
  }
699
813
  function projectExposure(walk, universe, parent, exemptions) {
700
814
  const path = `${walk.layer}.exemptions.resources`;
701
- const entries = isRecord(exemptions) && isRecord(exemptions.resources)
815
+ const entries = isRecord(exemptions) &&
816
+ isRecord(exemptions.resources)
702
817
  ? exemptions.resources
703
818
  : {};
704
819
  const resources = {};
@@ -742,7 +857,8 @@ function projectExposure(walk, universe, parent, exemptions) {
742
857
  }
743
858
  function pruneEmptyOperationFamilies(operations) {
744
859
  for (const [family, variants] of Object.entries(operations)) {
745
- if (isRecord(variants) && Object.keys(variants).length === 0) {
860
+ if (isRecord(variants) &&
861
+ Object.keys(variants).length === 0) {
746
862
  delete operations[family];
747
863
  }
748
864
  }
@@ -839,6 +955,11 @@ function representationFault(axis, value) {
839
955
  return typeof value === "string" && axis.values.includes(value)
840
956
  ? undefined
841
957
  : `one of ${axis.values.join(", ")} is expected`;
958
+ case "adapterTokens":
959
+ return isTokenList(value) &&
960
+ value.every((token) => axis.values.includes(token))
961
+ ? undefined
962
+ : `a list of ${axis.values.join(", ")} is expected`;
842
963
  case "flag":
843
964
  return typeof value === "boolean" ? undefined : "a boolean is expected";
844
965
  case "tokens":
@@ -912,35 +1033,71 @@ function exposureStyle(layer) {
912
1033
  }
913
1034
  function projectCore(model, config, diagnostics) {
914
1035
  const scope = config.root;
1036
+ const managed = managedElsewhereOf(config.trees.root);
915
1037
  const providerBaseline = createBaseline(model);
916
1038
  const baseline = cloneValue(providerBaseline);
917
1039
  baseline.limits = resolveLimits(scope);
918
1040
  baseline.transactions = resolveTransactions(model, "root", scope, diagnostics);
919
- checkResourceTree(model, baseline, "root", config.trees.root, config.definitions, diagnostics);
1041
+ checkResourceTree(model, baseline, "root", config.trees.root, config.definitions, managed, diagnostics);
920
1042
  applyFieldDefinitions(model, baseline, config.definitions, diagnostics);
1043
+ const unwithheld = managed.size === 0 ? baseline : cloneValue(baseline);
1044
+ withholdManagedWrites(baseline, managed);
1045
+ markGovernedFields(baseline, config.policy?.governed);
921
1046
  applyCompute(baseline, scope.compute);
922
1047
  checkLayerValidators(baseline.resources, "root", config.trees.root, diagnostics);
923
1048
  const validators = compileValidatorTable(baseline.resources, scope.pipelines);
924
1049
  const projection = projectExposure({ layer: "root", style: exposureStyle(scope), diagnostics }, baseline, baseline, scope.exemptions);
1050
+ qualifyFilterModes(projection);
1051
+ pruneHiddenPairings(projection, "shown");
925
1052
  projectCreateRequirements(model, projection.resources);
926
- checkHiddenRequirements(model, "root", baseline.resources, baseline.resources, projection.resources, diagnostics);
1053
+ const rootChecked = diagnostics.length;
1054
+ checkHiddenRequirements(model, "root", baseline.resources, unwithheld.resources, projection.resources, diagnostics);
1055
+ explainManagedRefusals(diagnostics, rootChecked, "root", baseline, managed);
927
1056
  applyValidators(projection.resources, validators);
928
1057
  validateProjection(projection, "root", diagnostics);
929
1058
  return { baseline, projection, validators };
930
1059
  }
1060
+ function markGovernedFields(baseline, governed) {
1061
+ if (governed === undefined) {
1062
+ return;
1063
+ }
1064
+ for (const [resourceName, names] of Object.entries(governed)) {
1065
+ const resource = Object.hasOwn(baseline.resources, resourceName)
1066
+ ? baseline.resources[resourceName]
1067
+ : undefined;
1068
+ if (resource === undefined) {
1069
+ continue;
1070
+ }
1071
+ for (const name of names) {
1072
+ const field = Object.hasOwn(resource.fields, name)
1073
+ ? resource.fields[name]
1074
+ : undefined;
1075
+ if (field !== undefined) {
1076
+ field.governed = true;
1077
+ }
1078
+ }
1079
+ }
1080
+ }
931
1081
  function projectDerivedScope(model, scopeName, core, parentView, config, diagnostics) {
932
1082
  const scope = config[scopeName];
1083
+ const managed = managedElsewhereOf(config.trees.root);
933
1084
  const baseline = cloneValue(core.baseline);
934
1085
  baseline.limits = resolveLimits(scope);
935
1086
  baseline.transactions = resolveTransactions(model, scopeName, scope, scopeName === "agent" &&
936
1087
  scope.transactionsStyle === config[config.agent.parent].transactionsStyle
937
1088
  ? []
938
1089
  : diagnostics);
939
- checkResourceTree(model, baseline, scopeName, config.trees[scopeName], config.definitions, diagnostics);
1090
+ checkResourceTree(model, baseline, scopeName, config.trees[scopeName], config.definitions, managed, diagnostics);
940
1091
  applyCompute(baseline, scope.compute);
941
1092
  checkLayerValidators(baseline.resources, scopeName, config.trees[scopeName], diagnostics);
942
1093
  const validators = compileValidatorTable(baseline.resources, scope.pipelines);
943
1094
  const parent = cloneValue(parentView);
1095
+ const unhidden = (scopeName === "client" || scopeName === "agent") && managed.size > 0
1096
+ ? cloneValue(parent)
1097
+ : parent;
1098
+ if (unhidden !== parent) {
1099
+ hideManagedElsewhere(parent, managed);
1100
+ }
944
1101
  parent.limits = resolveLimits(scope);
945
1102
  parent.transactions = baseline.transactions;
946
1103
  applyCompute(parent, scope.compute);
@@ -950,8 +1107,15 @@ function projectDerivedScope(model, scopeName, core, parentView, config, diagnos
950
1107
  diagnostics,
951
1108
  ...(scopeName === "agent" ? { parent: config.agent.parent } : {}),
952
1109
  }, baseline, parent, scope.exemptions);
1110
+ qualifyFilterModes(projection);
1111
+ pruneHiddenPairings(projection, "none");
1112
+ if (unhidden !== parent) {
1113
+ pruneManagedEnums(projection, unhidden, managed);
1114
+ }
953
1115
  projectCreateRequirements(model, projection.resources);
954
- checkHiddenRequirements(model, scopeName, baseline.resources, parent.resources, projection.resources, diagnostics);
1116
+ const layerChecked = diagnostics.length;
1117
+ checkHiddenRequirements(model, scopeName, baseline.resources, unhidden.resources, projection.resources, diagnostics);
1118
+ explainManagedRefusals(diagnostics, layerChecked, scopeName, baseline, managed);
955
1119
  applyValidators(projection.resources, validators);
956
1120
  validateProjection(projection, scopeName, diagnostics);
957
1121
  return { projection, validators };
@@ -984,12 +1148,16 @@ export async function compileContracts(model, config) {
984
1148
  : agentParent === "application"
985
1149
  ? applicationProjection.projection
986
1150
  : clientProjection.projection, compilerConfig, diagnostics);
1151
+ markCoreResources(coreCompilation.projection, model, managedElsewhereOf(compilerConfig.trees.root));
987
1152
  if (diagnostics.length > 0) {
988
1153
  return { ok: false, diagnostics };
989
1154
  }
990
1155
  const core = semanticObject(coreCompilation.projection);
991
1156
  const application = semanticObject(applicationProjection.projection);
992
- const client = await identifiedContract(clientProjection.projection);
1157
+ const clientMarked = withReadCache(clientProjection.projection, compilerConfig.client.pipelines);
1158
+ const client = await identifiedContract(compilerConfig.access === undefined
1159
+ ? clientMarked
1160
+ : { ...clientMarked, access: compilerConfig.access });
993
1161
  const agent = await identifiedContract(agentProjection.projection);
994
1162
  for (const [layer, contract] of [
995
1163
  ["client", client],
@@ -1007,18 +1175,100 @@ export async function compileContracts(model, config) {
1007
1175
  };
1008
1176
  }
1009
1177
  }
1010
- bindShapedFields(core, compilerConfig.definitions);
1011
- bindShapedFields(application, compilerConfig.definitions);
1012
- bindShapedFields(client, compilerConfig.definitions);
1013
- bindShapedFields(agent, compilerConfig.definitions);
1014
- bindFieldValidators(core, coreCompilation.validators);
1015
- bindFieldValidators(application, applicationProjection.validators);
1016
- bindFieldValidators(client, clientProjection.validators);
1017
- bindFieldValidators(agent, agentProjection.validators);
1018
- return {
1019
- ok: true,
1020
- contracts: { core, application, client, agent },
1021
- };
1178
+ const contracts = { core, application, client, agent };
1179
+ bindRuntimePieces(contracts, compilerConfig.definitions, {
1180
+ core: coreCompilation.validators,
1181
+ application: applicationProjection.validators,
1182
+ client: clientProjection.validators,
1183
+ agent: agentProjection.validators,
1184
+ });
1185
+ return { ok: true, contracts };
1186
+ }
1187
+ function lastCacheOf(levels) {
1188
+ for (let index = (levels?.length ?? 0) - 1; index >= 0; index -= 1) {
1189
+ const stage = levels?.[index]?.cache;
1190
+ if (stage !== undefined) {
1191
+ return { for: stage.for ?? "user", maxAge: stage.maxAge };
1192
+ }
1193
+ }
1194
+ return undefined;
1195
+ }
1196
+ function withReadCache(projection, tree) {
1197
+ const layer = lastCacheOf(tree.layer);
1198
+ const resources = {};
1199
+ for (const [name, resource] of Object.entries(projection.resources)) {
1200
+ const pipelines = Object.hasOwn(tree.resources, name)
1201
+ ? tree.resources[name]
1202
+ : undefined;
1203
+ const find = Object.hasOwn(pipelines?.families ?? {}, "find")
1204
+ ? pipelines?.families.find
1205
+ : undefined;
1206
+ const fallback = lastCacheOf(find?.pipelines) ??
1207
+ lastCacheOf(pipelines?.pipelines) ??
1208
+ layer;
1209
+ const advertised = (resource.operations.find ?? {});
1210
+ const marks = {};
1211
+ for (const variant of Object.keys(advertised)) {
1212
+ if (!isOperationVariantAvailable(advertised[variant])) {
1213
+ continue;
1214
+ }
1215
+ const own = Object.hasOwn(find?.variants ?? {}, variant)
1216
+ ? find?.variants[variant]?.pipelines
1217
+ : undefined;
1218
+ const mark = lastCacheOf(own) ?? fallback;
1219
+ if (mark !== undefined) {
1220
+ marks[variant] = mark;
1221
+ }
1222
+ }
1223
+ resources[name] =
1224
+ Object.keys(marks).length === 0
1225
+ ? resource
1226
+ : { ...resource, cache: marks };
1227
+ }
1228
+ return { ...projection, resources };
1229
+ }
1230
+ function bindRuntimePieces(contracts, definitions, validators) {
1231
+ for (const origin of ["core", "application", "client", "agent"]) {
1232
+ bindShapedFields(contracts[origin], definitions);
1233
+ bindFieldValidators(contracts[origin], validators[origin]);
1234
+ }
1235
+ }
1236
+ export function bindPrebuiltContracts(model, config, contracts) {
1237
+ const compilerConfig = config;
1238
+ const fields = validatedFieldsView(model, compilerConfig.definitions);
1239
+ bindRuntimePieces(contracts, compilerConfig.definitions, {
1240
+ core: compileValidatorTable(fields, compilerConfig.root.pipelines),
1241
+ application: compileValidatorTable(fields, compilerConfig.application.pipelines),
1242
+ client: compileValidatorTable(fields, compilerConfig.client.pipelines),
1243
+ agent: compileValidatorTable(fields, compilerConfig.agent.pipelines),
1244
+ });
1245
+ }
1246
+ function validatedFieldsView(model, definitions) {
1247
+ const resources = { ...model.resources };
1248
+ for (const [resourceName, resourceDefinitions] of Object.entries(definitions)) {
1249
+ const resource = Object.hasOwn(model.resources, resourceName)
1250
+ ? model.resources[resourceName]
1251
+ : undefined;
1252
+ if (resource === undefined) {
1253
+ continue;
1254
+ }
1255
+ let added;
1256
+ for (const [fieldName, definition] of Object.entries(resourceDefinitions)) {
1257
+ if (Object.hasOwn(resource.fields, fieldName)) {
1258
+ continue;
1259
+ }
1260
+ added ??= {};
1261
+ added[fieldName] = {
1262
+ kind: "scalar",
1263
+ type: definition.type,
1264
+ list: definition.list,
1265
+ };
1266
+ }
1267
+ if (added !== undefined) {
1268
+ resources[resourceName] = { fields: { ...resource.fields, ...added } };
1269
+ }
1270
+ }
1271
+ return resources;
1022
1272
  }
1023
1273
  async function identifiedContract(projection) {
1024
1274
  const members = canonicalizeContractMembers({
@@ -1,8 +1,6 @@
1
1
  import { advertisedDirectives, advertisedDirectivesAt, } from "../contracts/field.js";
2
2
  import { isOperationVariantAvailable, writeScopeOf, } from "../contracts/resource-operations.js";
3
- function isRecord(value) {
4
- return value !== null && typeof value === "object" && !Array.isArray(value);
5
- }
3
+ import { isRecord } from "../runtime/record.guard.js";
6
4
  function own(record, key) {
7
5
  return Object.hasOwn(record, key) ? record[key] : undefined;
8
6
  }
@@ -1,8 +1,6 @@
1
1
  import { avzCheckOf, } from "../avz/avz-check.registry.js";
2
2
  import { FIELD_CHECK_SUBJECTS, } from "../runtime/field-check.evaluator.js";
3
- function isRecord(value) {
4
- return value !== null && typeof value === "object" && !Array.isArray(value);
5
- }
3
+ import { isRecord } from "../runtime/record.guard.js";
6
4
  function own(record, key) {
7
5
  return Object.hasOwn(record, key) ? record[key] : undefined;
8
6
  }
@@ -0,0 +1,52 @@
1
+ import type { AvAdapterModel } from "../adapters/adapter-model.js";
2
+ import type { AvContractCompilerDiagnostic } from "./contract-compiler-diagnostic.js";
3
+ type ProjectedField = Record<string, unknown> & {
4
+ kind: "scalar" | "relation";
5
+ };
6
+ type ProjectedResource = {
7
+ fields: Record<string, ProjectedField>;
8
+ operations: Record<string, unknown>;
9
+ schema?: string;
10
+ managedElsewhere?: true;
11
+ };
12
+ type ProjectedContract = {
13
+ resources: Record<string, ProjectedResource>;
14
+ };
15
+ /** The Resources the root's `resources` tree marks `managedElsewhere: true`. */
16
+ export declare function managedElsewhereOf(rootTree: unknown): ReadonlySet<string>;
17
+ /**
18
+ * Takes every write of a managed Resource away from `baseline`: its write
19
+ * families, its fields' `create`/`update`, and the directives of every relation
20
+ * into it that would write its rows.
21
+ */
22
+ export declare function withholdManagedWrites(baseline: ProjectedContract, managed: ReadonlySet<string>): void;
23
+ /**
24
+ * Leaves every managed Resource out of `view`, with every relation into it: the
25
+ * client's and the agent's parent view.
26
+ */
27
+ export declare function hideManagedElsewhere(view: ProjectedContract, managed: ReadonlySet<string>): void;
28
+ /**
29
+ * Leaves out of `view` (a client's or the agent's projection) each enum the
30
+ * managed Resources' fields use in `unhidden` (the view before they were
31
+ * hidden) and no field of `view` uses.
32
+ */
33
+ export declare function pruneManagedEnums(view: ProjectedContract & {
34
+ enums: Record<string, unknown>;
35
+ }, unhidden: ProjectedContract, managed: ReadonlySet<string>): void;
36
+ /**
37
+ * The Core Contract's Resource facts: the `schema` the adapter states, and
38
+ * `managedElsewhere: true` on each managed Resource.
39
+ */
40
+ export declare function markCoreResources(projection: ProjectedContract, model: AvAdapterModel, managed: ReadonlySet<string>): void;
41
+ /**
42
+ * Why a write family of a managed Resource is unavailable, or `undefined` when
43
+ * the Resource is not managed or the family is not a write.
44
+ */
45
+ export declare function managedWriteReason(managed: ReadonlySet<string>, resource: string, family: string): string | undefined;
46
+ /**
47
+ * Adds to each create-requirement refusal from `from` on whose relation points
48
+ * at a managed Resource why that relation cannot be written, and the reference
49
+ * fields that can: exposing the relation, the refusal's own advice, is not open.
50
+ */
51
+ export declare function explainManagedRefusals(diagnostics: AvContractCompilerDiagnostic[], from: number, layer: string, universe: ProjectedContract, managed: ReadonlySet<string>): void;
52
+ export {};