@aventara/core 1.0.0-rc.1 → 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 (228) hide show
  1. package/CHANGELOG.md +943 -16
  2. package/ERRORS.md +142 -0
  3. package/README.md +274 -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 +227 -24
  19. package/dist/compiler/managed-elsewhere.projector.d.ts +52 -0
  20. package/dist/compiler/managed-elsewhere.projector.js +179 -0
  21. package/dist/compiler/managed-elsewhere.validator.d.ts +9 -0
  22. package/dist/compiler/managed-elsewhere.validator.js +74 -0
  23. package/dist/config/computed-fields.d.ts +62 -0
  24. package/dist/config/computed-fields.js +73 -0
  25. package/dist/config/config-diagnostic.guidance.d.ts +6 -0
  26. package/dist/config/config-diagnostic.guidance.js +32 -0
  27. package/dist/config/config.resolver.d.ts +24 -0
  28. package/dist/config/config.resolver.js +65 -0
  29. package/dist/config/config.validator.js +222 -8
  30. package/dist/config/define-resource.d.ts +1 -5
  31. package/dist/config/entrypoint.normalizer.d.ts +3 -2
  32. package/dist/config/exact-framework-config.d.ts +67 -22
  33. package/dist/config/field-compute.resolver.d.ts +2 -0
  34. package/dist/config/field-compute.resolver.js +8 -0
  35. package/dist/config/framework-config.d.ts +53 -15
  36. package/dist/config/framework-resources-config.d.ts +25 -14
  37. package/dist/config/pipeline-config.d.ts +4 -4
  38. package/dist/config/pipeline-tree.resolver.d.ts +2 -2
  39. package/dist/contracts/access-route.rules.d.ts +10 -0
  40. package/dist/contracts/access-route.rules.js +45 -0
  41. package/dist/contracts/capability.d.ts +26 -1
  42. package/dist/contracts/capability.js +20 -0
  43. package/dist/contracts/client-contract-structure.validator.d.ts +301 -89
  44. package/dist/contracts/client-contract-structure.validator.js +37 -2
  45. package/dist/contracts/contract-access.d.ts +29 -0
  46. package/dist/contracts/contract-access.js +1 -0
  47. package/dist/contracts/contract-canonicalizer.d.ts +9 -1
  48. package/dist/contracts/contract-canonicalizer.js +30 -4
  49. package/dist/contracts/contract-hash.d.ts +0 -1
  50. package/dist/contracts/contract-hash.js +1 -1
  51. package/dist/contracts/contract.d.ts +27 -1
  52. package/dist/contracts/field.d.ts +58 -1
  53. package/dist/contracts/json-schema.projector.d.ts +11 -0
  54. package/dist/contracts/json-schema.projector.js +78 -0
  55. package/dist/contracts/scalar-value-type.d.ts +3 -1
  56. package/dist/framework/access-facade.d.ts +116 -0
  57. package/dist/framework/access-facade.js +120 -0
  58. package/dist/framework/contract-view.d.ts +120 -16
  59. package/dist/framework/framework-construction.error.d.ts +14 -4
  60. package/dist/framework/framework-construction.error.js +18 -2
  61. package/dist/framework/framework.d.ts +26 -5
  62. package/dist/framework/framework.factory.d.ts +1 -1
  63. package/dist/framework/framework.factory.js +115 -23
  64. package/dist/framework/operation-facade.d.ts +80 -13
  65. package/dist/framework/operation-facade.js +2 -1
  66. package/dist/index.d.ts +17 -5
  67. package/dist/index.js +1 -0
  68. package/dist/internal.d.ts +7 -2
  69. package/dist/internal.js +6 -0
  70. package/dist/operations/database-refusal.d.ts +51 -0
  71. package/dist/operations/database-refusal.js +45 -0
  72. package/dist/operations/operation-arguments.d.ts +148 -60
  73. package/dist/operations/operation-call.d.ts +9 -5
  74. package/dist/operations/operation-result.d.ts +6 -4
  75. package/dist/operations/operation-validator-core.js +159 -36
  76. package/dist/operations/operation-validator.d.ts +1 -1
  77. package/dist/operations/structural-limits.walker.d.ts +1 -1
  78. package/dist/operations/validation-code.guidance.d.ts +6 -0
  79. package/dist/operations/validation-code.guidance.js +90 -0
  80. package/dist/operations/write-scope.resolver.d.ts +4 -0
  81. package/dist/operations/write-scope.resolver.js +2 -0
  82. package/dist/policy/access-provider.interface.d.ts +91 -0
  83. package/dist/policy/access-provider.interface.js +1 -0
  84. package/dist/policy/access-provider.registry.d.ts +17 -0
  85. package/dist/policy/access-provider.registry.js +15 -0
  86. package/dist/policy/access-question.d.ts +20 -0
  87. package/dist/policy/access-question.js +1 -0
  88. package/dist/policy/access-question.registry.d.ts +5 -0
  89. package/dist/policy/access-question.registry.js +19 -0
  90. package/dist/policy/access-question.runtime.d.ts +36 -0
  91. package/dist/policy/access-question.runtime.js +297 -0
  92. package/dist/policy/access-verb.table.d.ts +56 -0
  93. package/dist/policy/access-verb.table.js +21 -0
  94. package/dist/policy/access-verbs.d.ts +46 -0
  95. package/dist/policy/access-verbs.js +1 -0
  96. package/dist/policy/policy-admission.d.ts +20 -0
  97. package/dist/policy/policy-admission.js +409 -0
  98. package/dist/policy/policy-after-update.runtime.d.ts +79 -0
  99. package/dist/policy/policy-after-update.runtime.js +208 -0
  100. package/dist/policy/policy-condition.d.ts +15 -0
  101. package/dist/policy/policy-condition.js +36 -0
  102. package/dist/policy/policy-engine.d.ts +205 -0
  103. package/dist/policy/policy-engine.js +1 -0
  104. package/dist/policy/policy-named-rows.d.ts +18 -0
  105. package/dist/policy/policy-named-rows.js +51 -0
  106. package/dist/policy/policy-nested-write.runtime.d.ts +44 -0
  107. package/dist/policy/policy-nested-write.runtime.js +545 -0
  108. package/dist/policy/policy-read.runtime.d.ts +81 -0
  109. package/dist/policy/policy-read.runtime.js +503 -0
  110. package/dist/policy/policy-reference-write.runtime.d.ts +51 -0
  111. package/dist/policy/policy-reference-write.runtime.js +345 -0
  112. package/dist/policy/policy-request.d.ts +41 -0
  113. package/dist/policy/policy-request.js +63 -0
  114. package/dist/policy/policy-session.d.ts +106 -0
  115. package/dist/policy/policy-session.js +295 -0
  116. package/dist/policy/policy-startup.validator.d.ts +10 -0
  117. package/dist/policy/policy-startup.validator.js +112 -0
  118. package/dist/policy/policy-write.runtime.d.ts +39 -0
  119. package/dist/policy/policy-write.runtime.js +532 -0
  120. package/dist/prebuilt/core-version.generated.d.ts +2 -0
  121. package/dist/prebuilt/core-version.generated.js +1 -0
  122. package/dist/prebuilt/prebuilt-changes.d.ts +29 -0
  123. package/dist/prebuilt/prebuilt-changes.js +65 -0
  124. package/dist/prebuilt/prebuilt-contracts.d.ts +40 -0
  125. package/dist/prebuilt/prebuilt-contracts.emitter.d.ts +16 -0
  126. package/dist/prebuilt/prebuilt-contracts.emitter.js +50 -0
  127. package/dist/prebuilt/prebuilt-contracts.js +1 -0
  128. package/dist/prebuilt/prebuilt-contracts.loader.d.ts +19 -0
  129. package/dist/prebuilt/prebuilt-contracts.loader.js +77 -0
  130. package/dist/prebuilt/prebuilt-inputs.fingerprint.d.ts +16 -0
  131. package/dist/prebuilt/prebuilt-inputs.fingerprint.js +229 -0
  132. package/dist/protocol/absent-route.responder.d.ts +9 -27
  133. package/dist/protocol/absent-route.responder.js +36 -3
  134. package/dist/protocol/contract-document.responder.d.ts +2 -1
  135. package/dist/protocol/http-request.decoder.d.ts +19 -3
  136. package/dist/protocol/http-request.decoder.js +24 -1
  137. package/dist/protocol/http-request.reader.d.ts +6 -3
  138. package/dist/protocol/http-request.reader.js +1 -0
  139. package/dist/protocol/http-response.encoder.js +2 -2
  140. package/dist/protocol/protocol-headers.d.ts +3 -3
  141. package/dist/protocol/protocol-surface.d.ts +6 -1
  142. package/dist/protocol/protocol-surface.js +7 -0
  143. package/dist/protocol/protocol.binder.d.ts +16 -1
  144. package/dist/protocol/protocol.binder.js +4 -1
  145. package/dist/protocol/protocol.handler.d.ts +12 -1
  146. package/dist/protocol/protocol.handler.js +86 -17
  147. package/dist/runtime/caller-data.copier.d.ts +18 -3
  148. package/dist/runtime/caller-data.copier.js +21 -8
  149. package/dist/runtime/caller-data.door.d.ts +13 -6
  150. package/dist/runtime/computed-read-runtime.d.ts +6 -1
  151. package/dist/runtime/computed-read-runtime.js +232 -45
  152. package/dist/runtime/computed-value.error.d.ts +3 -2
  153. package/dist/runtime/computed-value.error.js +3 -2
  154. package/dist/runtime/context-executor.runtime.d.ts +4 -3
  155. package/dist/runtime/context-executor.runtime.js +4 -2
  156. package/dist/runtime/core-class.brand.d.ts +10 -0
  157. package/dist/runtime/core-class.brand.js +21 -0
  158. package/dist/runtime/create-requirement.d.ts +31 -5
  159. package/dist/runtime/create-requirement.js +129 -21
  160. package/dist/runtime/decimal.d.ts +14 -0
  161. package/dist/runtime/decimal.js +21 -0
  162. package/dist/runtime/diagnostics-reporter.d.ts +44 -9
  163. package/dist/runtime/diagnostics-reporter.js +13 -1
  164. package/dist/runtime/error-boundary.d.ts +9 -2
  165. package/dist/runtime/error-boundary.js +12 -0
  166. package/dist/runtime/error-guidance.d.ts +12 -0
  167. package/dist/runtime/error-guidance.js +1 -0
  168. package/dist/runtime/error.catalog.d.ts +49 -0
  169. package/dist/runtime/error.catalog.js +49 -0
  170. package/dist/runtime/execution-options.d.ts +8 -0
  171. package/dist/runtime/field-check.evaluator.d.ts +0 -2
  172. package/dist/runtime/field-check.evaluator.js +1 -1
  173. package/dist/runtime/field-compute.d.ts +11 -10
  174. package/dist/runtime/field-stage.runtime.d.ts +3 -1
  175. package/dist/runtime/field-stage.runtime.js +8 -4
  176. package/dist/runtime/field-validator.runtime.d.ts +19 -1
  177. package/dist/runtime/field-validator.runtime.js +47 -8
  178. package/dist/runtime/framework-error.js +9 -0
  179. package/dist/runtime/framework-warning.emitter.d.ts +6 -0
  180. package/dist/runtime/framework-warning.emitter.js +8 -0
  181. package/dist/runtime/json-value.d.ts +10 -5
  182. package/dist/runtime/level-lifecycle.runtime.d.ts +4 -3
  183. package/dist/runtime/level-lifecycle.runtime.js +3 -5
  184. package/dist/runtime/mutation-planner.d.ts +1 -6
  185. package/dist/runtime/mutation-planner.js +3 -14
  186. package/dist/runtime/operation-code.guidance.d.ts +6 -0
  187. package/dist/runtime/operation-code.guidance.js +167 -0
  188. package/dist/runtime/operation-request.d.ts +16 -9
  189. package/dist/runtime/operation-runtime.d.ts +35 -17
  190. package/dist/runtime/operation-runtime.js +220 -49
  191. package/dist/runtime/outcome-mapper.d.ts +2 -1
  192. package/dist/runtime/output-validator.d.ts +1 -1
  193. package/dist/runtime/owned-execution.registry.d.ts +13 -3
  194. package/dist/runtime/pipe-output.validator.d.ts +10 -0
  195. package/dist/runtime/pipe-output.validator.js +4 -2
  196. package/dist/runtime/pipeline.d.ts +47 -22
  197. package/dist/runtime/readonly-value.d.ts +20 -5
  198. package/dist/runtime/readonly-value.js +74 -26
  199. package/dist/runtime/referential-action.d.ts +1 -1
  200. package/dist/runtime/scalar-runtime.d.ts +4 -11
  201. package/dist/runtime/scalar-runtime.js +91 -22
  202. package/dist/runtime/unsent-value.normalizer.d.ts +15 -0
  203. package/dist/runtime/unsent-value.normalizer.js +128 -0
  204. package/dist/transactions/operation-arguments-encoder.js +8 -3
  205. package/dist/transactions/operation-fingerprint.js +2 -2
  206. package/dist/transactions/sql-statement.d.ts +10 -2
  207. package/dist/transactions/sql-statement.validator.d.ts +2 -2
  208. package/dist/transactions/sql-statement.validator.js +38 -5
  209. package/dist/transactions/transaction-envelope.d.ts +5 -4
  210. package/dist/transactions/transaction-integrity-error.js +2 -0
  211. package/dist/transactions/transaction-plan-assembler.d.ts +12 -5
  212. package/dist/transactions/transaction-plan-assembler.js +48 -10
  213. package/dist/transactions/transaction-plan-validator.d.ts +23 -7
  214. package/dist/transactions/transaction-plan-validator.js +27 -1
  215. package/dist/transactions/transaction-reference-resolver.d.ts +3 -2
  216. package/dist/transactions/transaction-reference-validator.d.ts +43 -3
  217. package/dist/transactions/transaction-reference-validator.js +83 -57
  218. package/dist/transactions/transaction-reference.d.ts +1 -1
  219. package/dist/transactions/transaction-reference.js +5 -0
  220. package/dist/transactions/transaction-request.d.ts +8 -8
  221. package/dist/transactions/transaction-runtime.d.ts +5 -2
  222. package/dist/transactions/transaction-runtime.js +79 -27
  223. package/dist/transactions/transaction-settlement.runtime.d.ts +4 -3
  224. package/dist/transactions/transaction-slot-path-error.js +2 -0
  225. package/dist/transactions/transaction-stage.runtime.d.ts +5 -3
  226. package/dist/transactions/transaction-stage.runtime.js +7 -4
  227. package/package.json +6 -5
  228. package/src/runtime/field-check.evaluator.ts +1 -1
@@ -1,9 +1,11 @@
1
- import type { ClientProtocolIdentity } from "../runtime/operation-request.js";
1
+ import type { AvRequestProtocol } from "../runtime/operation-request.js";
2
2
  import type { OperationRouteSegments } from "./absent-route.responder.js";
3
3
  import type { AvProtocolRequest } from "./http-request.decoder.js";
4
4
  import type { AvProtocolResponse } from "./http-response.encoder.js";
5
5
  /** `POST <api>/_transactions`. */
6
6
  export declare const TRANSACTIONS_ROUTE = "/_transactions";
7
+ /** `POST <api>/_access/can`. */
8
+ export declare const ACCESS_CAN_ROUTE = "/_access/can";
7
9
  /** `GET <api>/_contract`. */
8
10
  export declare const CONTRACT_ROUTE = "/_contract";
9
11
  /** The methods an operation or `/_transactions` route accepts: `POST`, only. */
@@ -25,10 +27,10 @@ export type ReadRequest = {
25
27
  /** Adopted from `Aventara-Request-Id`, else minted. */
26
28
  readonly requestId: string;
27
29
  /** `undefined` when either identity header is absent (`A2000`). */
28
- readonly protocol: ClientProtocolIdentity | undefined;
30
+ readonly protocol: AvRequestProtocol | undefined;
29
31
  };
30
32
  /** What a value that is not an `AvProtocolRequest` reads as. */
31
- export type UnreadableRequest = {
33
+ type UnreadableRequest = {
32
34
  readonly ok: false;
33
35
  readonly response: AvProtocolResponse;
34
36
  readonly requestId: string;
@@ -43,3 +45,4 @@ export declare function readRequest(received: unknown): ReadRequest | Unreadable
43
45
  * `undefined` when it is not one.
44
46
  */
45
47
  export declare function operationRouteSegments(path: string): OperationRouteSegments | undefined;
48
+ export {};
@@ -3,6 +3,7 @@ import { transportFailure } from "./protocol-failure.js";
3
3
  import { adoptedRequestId, normalizeHeaders, protocolIdentityOf, } from "./protocol-headers.js";
4
4
  const OPERATION_ROUTE = /^\/_resources\/([^/]*)\/([^/]*)\/([^/]*)$/;
5
5
  export const TRANSACTIONS_ROUTE = "/_transactions";
6
+ export const ACCESS_CAN_ROUTE = "/_access/can";
6
7
  export const CONTRACT_ROUTE = "/_contract";
7
8
  export const POST_ONLY = Object.freeze(["POST"]);
8
9
  export const GET_ONLY = Object.freeze(["GET"]);
@@ -1,5 +1,5 @@
1
1
  import { encodeBase64, WIRE_SCALAR_PATTERNS, } from "../contracts/wire-scalar-format.js";
2
- import { AvDecimal } from "../runtime/decimal.js";
2
+ import { isAvDecimal } from "../runtime/decimal.js";
3
3
  import { SERIALIZATION_FAILURE_MESSAGE } from "../runtime/error-boundary.js";
4
4
  import { operationFailure, } from "../runtime/operation-response.js";
5
5
  import { httpStatus } from "./http-status.table.js";
@@ -161,7 +161,7 @@ function scalarWireText(value) {
161
161
  }
162
162
  return JSON.stringify(wire);
163
163
  }
164
- if (value instanceof AvDecimal) {
164
+ if (isAvDecimal(value)) {
165
165
  return JSON.stringify(value.toString());
166
166
  }
167
167
  if (value instanceof Uint8Array) {
@@ -1,4 +1,4 @@
1
- import type { ClientProtocolIdentity } from "../runtime/operation-request.js";
1
+ import type { AvRequestProtocol } from "../runtime/operation-request.js";
2
2
  /** `AvProtocol.headers` — the header names the protocol owns, as passive data. */
3
3
  export declare const headers: Readonly<{
4
4
  readonly protocolVersion: "Aventara-Protocol-Version";
@@ -22,11 +22,11 @@ export declare function normalizeHeaders(received: ReceivedHeaders): Readonly<Re
22
22
  */
23
23
  export declare function headerValue(normalized: Readonly<Record<string, string>>, name: string): string | undefined;
24
24
  /**
25
- * The identity headers as the `ClientProtocolIdentity` core checks, or `undefined`
25
+ * The identity headers as the `AvRequestProtocol` core checks, or `undefined`
26
26
  * when either is ABSENT — a request without them is malformed: it does not say which
27
27
  * protocol and ClientContract it speaks, so there is nothing to compare.
28
28
  */
29
- export declare function protocolIdentityOf(normalized: Readonly<Record<string, string>>): ClientProtocolIdentity | undefined;
29
+ export declare function protocolIdentityOf(normalized: Readonly<Record<string, string>>): AvRequestProtocol | undefined;
30
30
  /**
31
31
  * The identity headers a request did not send, in the order the framework sends them —
32
32
  * what the `A2000` answering it names. Empty exactly when {@link protocolIdentityOf}
@@ -17,11 +17,16 @@ export type SurfaceRoute = ({
17
17
  readonly kind: "transactions";
18
18
  readonly method: "POST";
19
19
  readonly path: "/_transactions";
20
+ } | {
21
+ readonly kind: "can";
22
+ readonly method: "POST";
23
+ readonly path: "/_access/can";
20
24
  };
21
25
  /**
22
26
  * The route list of one ClientContract: every route a host mounts, from one list,
23
27
  * deep-frozen — exactly the advertised operation triples in the Contract's own key
24
28
  * order, then `GET /_contract`, then `POST /_transactions` when, and only when,
25
- * `transactions === "interactive"`.
29
+ * `transactions === "interactive"`, then `POST /_access/can` when, and only when,
30
+ * the Contract has its `access` section.
26
31
  */
27
32
  export declare function surfaceOf(client: AvContractClient): readonly SurfaceRoute[];
@@ -37,5 +37,12 @@ export function surfaceOf(client) {
37
37
  path: "/_transactions",
38
38
  }));
39
39
  }
40
+ if (client.access !== undefined) {
41
+ routes.push(Object.freeze({
42
+ kind: "can",
43
+ method: "POST",
44
+ path: "/_access/can",
45
+ }));
46
+ }
40
47
  return Object.freeze(routes);
41
48
  }
@@ -17,7 +17,8 @@ export type AvProtocolBinding = {
17
17
  * tagged by `kind`: one `POST` `operation` route per `(resource, family, variant)`
18
18
  * it advertises and no other, then the `contract` route `GET /_contract`
19
19
  * (always), then the `transactions` route `POST /_transactions` exactly when its
20
- * `transactions` is `"interactive"`. Each path is relative to
20
+ * `transactions` is `"interactive"`, then the `can` route `POST /_access/can`
21
+ * exactly when it has its `access` section. Each path is relative to
21
22
  * `framework.api`. Read once at bind time: every call answers the same
22
23
  * deep-frozen list, which is passive data a host may serialize.
23
24
  */
@@ -88,6 +89,20 @@ export type AvProtocolBinding = {
88
89
  /** Seeds the plan's one `ctx.$state`, as for `handleOperation`. */
89
90
  readonly state?: () => AvState | Promise<AvState>;
90
91
  }) => Promise<AvProtocolResponse>;
92
+ /**
93
+ * The `POST /_access/can` shortcut: the request decoded, its `ctx.$state`
94
+ * seeded through `options.state`, its `{ questions }` answered by the bound
95
+ * Framework's policy engine under the principal `ctx.$state.me`, and the answer
96
+ * encoded: `200 A1000` with one boolean per question, in order. It only shapes
97
+ * a UI, so it refuses malformed input only, never `403`. Absent (`404 A2002`)
98
+ * unless the bound Contract has its `access` section, which it has exactly when
99
+ * the framework's `access` option is configured. Total over any value, as
100
+ * `handleOperation` is.
101
+ */
102
+ readonly handleCan: (request: AvProtocolRequest, options?: {
103
+ /** Seeds the request's `ctx.$state`, as for `handleOperation`. */
104
+ readonly state?: () => AvState | Promise<AvState>;
105
+ }) => Promise<AvProtocolResponse>;
91
106
  /**
92
107
  * The `GET /_contract` responder: the bound ClientContract's JCS-canonical bytes,
93
108
  * `ETag` its quoted hash, `Cache-Control: no-cache`, and `304` with no body when
@@ -1,10 +1,11 @@
1
+ import { accessQuestionsOf } from "../policy/access-question.registry.js";
1
2
  import { diagnosticsSinkOf } from "../runtime/diagnostics-reporter.js";
2
3
  import { ownedExecutionOf } from "../runtime/owned-execution.registry.js";
3
4
  import { answerAbsentRequest } from "./absent-route.responder.js";
4
5
  import { contractDocumentOf, encodeContractRequest, } from "./contract-document.responder.js";
5
6
  import { decodeOperationRequest, decodeTransactionRequest, } from "./http-request.decoder.js";
6
7
  import { encodeOperationResponse, encodeTransactionResponse, } from "./http-response.encoder.js";
7
- import { handleOperationRequest, handleTransactionRequest, operationUnencodableReport, planUnencodableReport, } from "./protocol.handler.js";
8
+ import { handleCanRequest, handleOperationRequest, handleTransactionRequest, operationUnencodableReport, planUnencodableReport, } from "./protocol.handler.js";
8
9
  import { transportFailure } from "./protocol-failure.js";
9
10
  import { surfaceOf } from "./protocol-surface.js";
10
11
  export function bind(framework, options) {
@@ -21,6 +22,7 @@ export function bind(framework, options) {
21
22
  executeTransaction: (request) => framework.executeTransaction(request),
22
23
  owned: ownedExecutionOf(framework),
23
24
  sink,
25
+ can: accessQuestionsOf(framework),
24
26
  };
25
27
  return Object.freeze({
26
28
  surface: () => surface,
@@ -33,6 +35,7 @@ export function bind(framework, options) {
33
35
  failure: transportFailure,
34
36
  handleOperation: (request, options) => handleOperationRequest(handler, request, options),
35
37
  handleTransaction: (request, options) => handleTransactionRequest(handler, request, options),
38
+ handleCan: (request, options) => handleCanRequest(handler, request, options),
36
39
  encodeContract: (request) => encodeContractRequest(document, request),
37
40
  answerAbsent: (request) => answerAbsentRequest(contracts, request, sink, origin),
38
41
  });
@@ -1,6 +1,7 @@
1
1
  import type { AvContracts } from "../compiler/contract.compiler.js";
2
2
  import type { RemoteRequestOrigin } from "../config/config-layer.js";
3
3
  import type { AvFramework } from "../framework/framework.js";
4
+ import type { AccessQuestionsAnswerer } from "../policy/access-question.runtime.js";
4
5
  import { type AvDiagnosticsSink } from "../runtime/diagnostics-reporter.js";
5
6
  import type { RemoteOperationRequest } from "../runtime/operation-request.js";
6
7
  import type { OwnedExecution } from "../runtime/owned-execution.registry.js";
@@ -13,7 +14,7 @@ import { type AvProtocolResponse, type UnencodableReport } from "./http-response
13
14
  * decoder parsed without copying it again (absent for anything but a
14
15
  * constructed Framework) — and its configured diagnostics sink.
15
16
  */
16
- export type HandlerContext = {
17
+ type HandlerContext = {
17
18
  readonly contracts: AvContracts;
18
19
  /** The origin every request the binding decodes runs under. */
19
20
  readonly origin: RemoteRequestOrigin;
@@ -21,6 +22,8 @@ export type HandlerContext = {
21
22
  readonly executeTransaction: AvFramework["executeTransaction"];
22
23
  readonly owned: OwnedExecution | undefined;
23
24
  readonly sink: AvDiagnosticsSink | undefined;
25
+ /** The Framework's `can` answerer: absent for one without `access`, or anything `createFramework` did not return. */
26
+ readonly can: AccessQuestionsAnswerer | undefined;
24
27
  };
25
28
  /** What a host passes beside one protocol request. */
26
29
  export type ProtocolCallOptions = {
@@ -62,3 +65,11 @@ export declare function handleOperationRequest(context: HandlerContext, request:
62
65
  * planUnencodableReport}.
63
66
  */
64
67
  export declare function handleTransactionRequest(context: HandlerContext, request: AvProtocolRequest, options?: ProtocolCallOptions): Promise<AvProtocolResponse>;
68
+ /**
69
+ * `protocol.handleCan(request)`: the `/_access/can` request decoded, its state
70
+ * seeded, its questions answered by the bound Framework, and the answer encoded —
71
+ * `200 A1000` with one boolean per question, in order, or the refusal. Total over
72
+ * any value, as {@link handleOperationRequest} is.
73
+ */
74
+ export declare function handleCanRequest(context: HandlerContext, request: AvProtocolRequest, options?: ProtocolCallOptions): Promise<AvProtocolResponse>;
75
+ export {};
@@ -1,16 +1,54 @@
1
+ import { copyAtDoor } from "../runtime/caller-data.door.js";
1
2
  import { createDiagnosticsReporter, createReporter, } from "../runtime/diagnostics-reporter.js";
2
3
  import { sanitizeOperationFailure } from "../runtime/error-boundary.js";
3
- import { decodeOperationRequest, decodeTransactionRequest, isParsedByDecoder, } from "./http-request.decoder.js";
4
+ import { internalFailure, } from "../runtime/operation-response.js";
5
+ import { capturePlanAtCall } from "../transactions/transaction-plan-validator.js";
6
+ import { decodeCanRequest, decodeOperationRequest, decodeTransactionRequest, isParsedByDecoder, } from "./http-request.decoder.js";
4
7
  import { encodeOperationResponse, encodeTransactionResponse, } from "./http-response.encoder.js";
5
- function operationEntry(context, request) {
6
- return context.owned !== undefined && isParsedByDecoder(request.arguments)
7
- ? context.owned.execute
8
- : context.execute;
8
+ function admitOperation(context, request) {
9
+ const owned = context.owned;
10
+ if (isParsedByDecoder(request.arguments)) {
11
+ return { request, run: owned?.execute ?? context.execute };
12
+ }
13
+ const copy = copyAtDoor(request.arguments);
14
+ if (owned === undefined) {
15
+ return {
16
+ request: copy.ok ? { ...request, arguments: copy.value } : request,
17
+ run: context.execute,
18
+ };
19
+ }
20
+ if (copy.ok) {
21
+ return {
22
+ request: { ...request, arguments: copy.value },
23
+ run: (admitted) => owned.execute(admitted),
24
+ };
25
+ }
26
+ return {
27
+ request: { ...request, arguments: {} },
28
+ run: (admitted) => owned.execute(admitted, copy.error),
29
+ };
9
30
  }
10
- function transactionEntry(context, request) {
11
- return context.owned !== undefined && isParsedByDecoder(request.plan)
12
- ? context.owned.executeTransaction
13
- : context.executeTransaction;
31
+ function admitTransaction(context, request) {
32
+ const owned = context.owned;
33
+ if (isParsedByDecoder(request.plan)) {
34
+ return {
35
+ request,
36
+ run: owned?.executeTransaction ?? context.executeTransaction,
37
+ };
38
+ }
39
+ const captured = capturePlanAtCall(request.plan);
40
+ if (owned === undefined) {
41
+ return {
42
+ request: captured.refused.size === 0
43
+ ? { ...request, plan: captured.plan }
44
+ : request,
45
+ run: context.executeTransaction,
46
+ };
47
+ }
48
+ return {
49
+ request: { ...request, plan: captured.plan },
50
+ run: (admitted) => owned.executeTransaction(admitted, captured.refused.size === 0 ? undefined : captured.refused),
51
+ };
14
52
  }
15
53
  async function seededState(options, report, view) {
16
54
  if (options?.state === undefined) {
@@ -48,11 +86,12 @@ export async function handleOperationRequest(context, request, options) {
48
86
  if (!decoded.ok) {
49
87
  return decoded.response;
50
88
  }
51
- const seeded = await seededState(options, createDiagnosticsReporter(context.sink, decoded.request), { path: ["arguments"], arguments: decoded.request.arguments });
89
+ const admitted = admitOperation(context, decoded.request);
90
+ const seeded = await seededState(options, createDiagnosticsReporter(context.sink, admitted.request), { path: ["arguments"], arguments: admitted.request.arguments });
52
91
  const response = seeded.ok
53
- ? await operationEntry(context, decoded.request)(seeded.state === undefined
54
- ? decoded.request
55
- : { ...decoded.request, state: seeded.state })
92
+ ? await admitted.run(seeded.state === undefined
93
+ ? admitted.request
94
+ : { ...admitted.request, state: seeded.state })
56
95
  : seeded.response;
57
96
  return encodeOperationResponse(response, decoded.requestId, operationUnencodableReport(context.sink, decoded.request));
58
97
  }
@@ -61,15 +100,45 @@ export async function handleTransactionRequest(context, request, options) {
61
100
  if (!decoded.ok) {
62
101
  return decoded.response;
63
102
  }
103
+ const admitted = admitTransaction(context, decoded.request);
64
104
  const seeded = await seededState(options, createReporter(context.sink, {
65
105
  kind: "transaction",
66
106
  origin: context.origin,
67
107
  requestId: decoded.requestId,
68
- }), { path: ["plan"], arguments: decoded.request.plan });
108
+ }), { path: ["plan"], arguments: admitted.request.plan });
69
109
  const response = seeded.ok
70
- ? await transactionEntry(context, decoded.request)(seeded.state === undefined
71
- ? decoded.request
72
- : { ...decoded.request, state: seeded.state })
110
+ ? await admitted.run(seeded.state === undefined
111
+ ? admitted.request
112
+ : { ...admitted.request, state: seeded.state })
73
113
  : seeded.response;
74
114
  return encodeTransactionResponse(response, decoded.requestId, planUnencodableReport(context.sink, decoded.requestId, context.origin));
75
115
  }
116
+ export async function handleCanRequest(context, request, options) {
117
+ const decoded = decodeCanRequest(context.contracts, request, context.origin);
118
+ if (!decoded.ok) {
119
+ return decoded.response;
120
+ }
121
+ const { requestId, body } = decoded.request;
122
+ const report = createReporter(context.sink, {
123
+ kind: "can",
124
+ origin: "client",
125
+ requestId,
126
+ });
127
+ if (context.can === undefined) {
128
+ report(new Error("The bound Framework has no answerer for /_access/can."), "A3000");
129
+ return encodeOperationResponse(internalFailure(), requestId);
130
+ }
131
+ const seeded = await seededState(options, report, {
132
+ path: ["questions"],
133
+ arguments: body,
134
+ });
135
+ const response = seeded.ok
136
+ ? await context.can({
137
+ origin: context.origin,
138
+ requestId,
139
+ ...(seeded.state === undefined ? {} : { state: seeded.state }),
140
+ body,
141
+ })
142
+ : seeded.response;
143
+ return encodeOperationResponse(response, requestId);
144
+ }
@@ -1,5 +1,5 @@
1
1
  /** Why a caller value could not be copied. */
2
- export type CallerDataFailureKind = "unreadable-value" | "non-plain-value";
2
+ type CallerDataFailureKind = "unreadable-value" | "non-plain-value";
3
3
  /** A data location inside the copied value, from its root. */
4
4
  export type CallerDataPath = readonly (string | number)[];
5
5
  /**
@@ -41,6 +41,22 @@ export type CallerDataPolicy = {
41
41
  readonly keep?: CallerDataKeep;
42
42
  readonly mirror?: CallerDataMirror;
43
43
  };
44
+ /** The members a structural mirror copies by value rather than mirroring. */
45
+ type MirrorMembers = {
46
+ /** The policy a member at `path` (from the mirror's root) is copied by, or `undefined`. */
47
+ readonly copyAt: (path: CallerDataPath) => CallerDataPolicy | undefined;
48
+ /** Receives a member whose copy failed; the mirror holds `undefined` for it. */
49
+ readonly refused: (path: CallerDataPath, error: AvCallerDataError) => void;
50
+ };
51
+ /**
52
+ * Mirrors `value` by its descriptors, as a `$ref` control object is mirrored (no
53
+ * getter runs, an accessor stays a tripwire), except the members `members.copyAt`
54
+ * names by their path: each is copied by value under the policy it returns, and one
55
+ * whose copy fails is reported to `members.refused` and held as `undefined`.
56
+ *
57
+ * @throws {@link AvCallerDataError} at `[]` when `value` itself cannot be reflected.
58
+ */
59
+ export declare function mirrorCallerData(value: object, members: MirrorMembers): unknown;
44
60
  /**
45
61
  * Places a mirror tripwire's failure in the value the door copied: its path from the
46
62
  * copy's root, where `error.path` started from the mirror. A failure that is not a
@@ -55,5 +71,4 @@ export declare function locateCallerDataError(error: AvCallerDataError, copy: un
55
71
  * naming its path from `value`.
56
72
  */
57
73
  export declare function copyCallerData(value: unknown, policy?: CallerDataPolicy): unknown;
58
- /** The `V1001` message a door answers a {@link AvCallerDataError} with. */
59
- export declare function callerDataFailureMessage(kind: CallerDataFailureKind): string;
74
+ export {};
@@ -1,4 +1,4 @@
1
- import { AvDecimal } from "./decimal.js";
1
+ import { AvDecimal, decimalDigitsOf, isAvDecimal } from "./decimal.js";
2
2
  const FAILURE_MESSAGES = {
3
3
  "unreadable-value": "Value could not be read.",
4
4
  "non-plain-value": "Value must be plain data.",
@@ -19,7 +19,6 @@ const NO_POLICY = {};
19
19
  const OBJECT_PROTOTYPE = Object.prototype;
20
20
  const DATE_PROTOTYPE = Date.prototype;
21
21
  const dateValueOf = Date.prototype.getTime;
22
- const decimalValueOf = AvDecimal.prototype.toString;
23
22
  const FAST_WALK_DEPTH = 256;
24
23
  const SLOW_WALK = Symbol("slow walk");
25
24
  class FastWalkFailure {
@@ -33,8 +32,8 @@ function copyValueType(value, prototype) {
33
32
  if (prototype === DATE_PROTOTYPE || value instanceof Date) {
34
33
  return new Date(dateValueOf.call(value));
35
34
  }
36
- if (value instanceof AvDecimal) {
37
- return new AvDecimal(decimalValueOf.call(value));
35
+ if (isAvDecimal(value)) {
36
+ return new AvDecimal(decimalDigitsOf(value));
38
37
  }
39
38
  if (value instanceof Uint8Array) {
40
39
  return new Uint8Array(value);
@@ -268,7 +267,7 @@ function pathSegment(array, key) {
268
267
  }
269
268
  return key;
270
269
  }
271
- function mirrorControlData(value) {
270
+ function mirrorControlData(value, members) {
272
271
  const shape = reflectNode(value);
273
272
  if (shape === undefined) {
274
273
  throw new AvCallerDataError("unreadable-value", []);
@@ -375,6 +374,20 @@ function mirrorControlData(value) {
375
374
  continue;
376
375
  }
377
376
  const memberLink = childLink(link, pathSegment(shape.array, key));
377
+ const byValue = members?.copyAt(pathOf(memberLink));
378
+ if (byValue !== undefined) {
379
+ try {
380
+ store(copyCallerData(member, byValue));
381
+ }
382
+ catch (error) {
383
+ if (!(error instanceof AvCallerDataError)) {
384
+ throw error;
385
+ }
386
+ members?.refused(pathOf(memberLink), error);
387
+ store(undefined);
388
+ }
389
+ continue;
390
+ }
378
391
  const memberShape = reflectNode(member);
379
392
  if (memberShape === undefined) {
380
393
  store(UNREADABLE);
@@ -408,6 +421,9 @@ function mirrorControlData(value) {
408
421
  }
409
422
  return root;
410
423
  }
424
+ export function mirrorCallerData(value, members) {
425
+ return mirrorControlData(value, members);
426
+ }
411
427
  export function locateCallerDataError(error, copy) {
412
428
  const within = error.within;
413
429
  if (within === undefined) {
@@ -465,6 +481,3 @@ export function copyCallerData(value, policy = NO_POLICY) {
465
481
  }
466
482
  return guardNative(() => copyFast(value, 0, policy), (failure) => copySlow(value, policy, failure instanceof FastWalkFailure ? failure.at : undefined));
467
483
  }
468
- export function callerDataFailureMessage(kind) {
469
- return FAILURE_MESSAGES[kind];
470
- }
@@ -6,15 +6,21 @@ import type { AvMisuseEvent, MisuseReporter } from "./misuse-reporter.js";
6
6
  *
7
7
  * - `"caller"`: a server-side caller's own objects — copied at the door.
8
8
  * - `"owned"`: data no caller holds a reference to — a body the protocol decoder
9
- * parsed with `JSON.parse` for this request alone, or a plan the typed runner
10
- * assembled from copies its builders took. It is never copied again.
9
+ * parsed with `JSON.parse` for this request alone, a host's parsed body the
10
+ * protocol's shortcut copied at the call, or a plan the typed runner assembled
11
+ * from copies its builders took. It is never copied again.
11
12
  *
12
- * Only core's own modules choose `"owned"`: the public `framework.execute` and
13
- * `executeTransaction` always pass `"caller"`.
13
+ * - `{ refused }`: a body the protocol's shortcut copied at the call, whose copy
14
+ * failed — answered at the door as `"caller"` would answer it, never read again.
15
+ *
16
+ * Only core's own modules choose anything but `"caller"`: the public
17
+ * `framework.execute` and `executeTransaction` always pass `"caller"`.
14
18
  */
15
- export type ArgumentsSource = "caller" | "owned";
19
+ export type ArgumentsSource = "caller" | "owned" | {
20
+ readonly refused: AvCallerDataError;
21
+ };
16
22
  /** The operation identity a misuse event may name, as far as it could be read. */
17
- export type MisuseIdentity = Omit<AvMisuseEvent, "kind" | "path">;
23
+ type MisuseIdentity = Omit<AvMisuseEvent, "kind" | "path">;
18
24
  /**
19
25
  * The identity of a request the framework holds a copy of, keeping only what is
20
26
  * identity: an origin, a Resource name and a standard operation, each present only
@@ -54,3 +60,4 @@ export declare function copyAtDoor(value: unknown, policy?: CallerDataPolicy): C
54
60
  * plan validator inspects and copies step by step.
55
61
  */
56
62
  export declare function copyEnvelopeAtDoor(request: unknown, members: readonly string[]): CallerDataCopy;
63
+ export {};
@@ -21,6 +21,11 @@ export type PlannedReadOperation = {
21
21
  readonly projection: ReadProjectionPlan | undefined;
22
22
  readonly materialize: boolean;
23
23
  };
24
+ /**
25
+ * The fields a level returns when it states no projection: every scalar of the
26
+ * active Contract whose `select` is `true` and that is not governed.
27
+ */
28
+ export declare function defaultProjectionFields(active: AvContract, resourceName: string): readonly string[];
24
29
  /**
25
30
  * Clone the caller projection into the internal Adapter projection: the read
26
31
  * set the Adapter is asked for, always explicit for a projecting variant, plus
@@ -33,5 +38,5 @@ export declare function planReadOperation(core: AvContractCore, model: AvAdapter
33
38
  * Materialize computed scalar reads and remove internal dependency fields,
34
39
  * against `active` — the Contract `planReadOperation` was given as `active`.
35
40
  */
36
- export declare function materializeReadOperation(active: AvContract, compute: ResolvedComputeConfig | undefined, request: OperationExecutionRequest, plan: PlannedReadOperation, value: unknown, contextFactory: ContextFactory): Promise<unknown>;
41
+ export declare function materializeReadOperation(active: AvContract, compute: ResolvedComputeConfig | undefined, _request: OperationExecutionRequest, plan: PlannedReadOperation, value: unknown, contextFactory: ContextFactory): Promise<unknown>;
37
42
  export {};