@aventara/core 0.1.0-pilot.3 → 1.0.0-rc.0

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 (167) hide show
  1. package/CHANGELOG.md +338 -0
  2. package/README.md +100 -3
  3. package/dist/adapters/adapter-discovery-diagnostic.d.ts +2 -0
  4. package/dist/adapters/adapter-field.d.ts +3 -26
  5. package/dist/adapters/adapter-identifier.d.ts +1 -11
  6. package/dist/adapters/adapter-model.d.ts +12 -0
  7. package/dist/adapters/adapter-operation-executor.interface.d.ts +5 -1
  8. package/dist/adapters/adapter-resource.d.ts +7 -28
  9. package/dist/adapters/adapter.interface.d.ts +25 -26
  10. package/dist/compiler/contract-compiler-diagnostic.d.ts +8 -0
  11. package/dist/compiler/contract.compiler.d.ts +11 -22
  12. package/dist/compiler/contract.compiler.js +67 -0
  13. package/dist/config/any-framework-config.d.ts +5 -26
  14. package/dist/config/config-diagnostic.d.ts +2 -0
  15. package/dist/config/config-layer.d.ts +6 -19
  16. package/dist/config/config.resolver.d.ts +9 -14
  17. package/dist/config/config.resolver.js +1 -0
  18. package/dist/config/config.validator.d.ts +6 -3
  19. package/dist/config/config.validator.js +6 -0
  20. package/dist/config/define-fields.d.ts +15 -48
  21. package/dist/config/effective-fields.d.ts +6 -29
  22. package/dist/config/entrypoint.normalizer.d.ts +6 -18
  23. package/dist/config/framework-behaviors-config.d.ts +11 -10
  24. package/dist/config/framework-config.d.ts +19 -16
  25. package/dist/config/framework-fields-config.d.ts +20 -7
  26. package/dist/config/framework-restrictions-config.d.ts +41 -61
  27. package/dist/config/pipeline-config.d.ts +7 -17
  28. package/dist/contracts/capability.d.ts +13 -49
  29. package/dist/contracts/client-contract-structure.validator.d.ts +28 -54
  30. package/dist/contracts/client-contract-structure.validator.js +99 -2
  31. package/dist/contracts/contract-canonicalizer.d.ts +4 -6
  32. package/dist/contracts/contract-canonicalizer.js +32 -0
  33. package/dist/contracts/contract-hash.d.ts +3 -2
  34. package/dist/contracts/contract-limits.d.ts +7 -1
  35. package/dist/contracts/contract-protocol.d.ts +7 -8
  36. package/dist/contracts/contract.d.ts +20 -4
  37. package/dist/contracts/enum-definition.d.ts +2 -0
  38. package/dist/contracts/field.d.ts +40 -167
  39. package/dist/contracts/identifier.d.ts +1 -16
  40. package/dist/contracts/json-shape.d.ts +65 -0
  41. package/dist/contracts/json-shape.js +1 -0
  42. package/dist/contracts/lifecycle-trait.d.ts +4 -3
  43. package/dist/contracts/reference-write-limit.d.ts +7 -0
  44. package/dist/contracts/reference-write-limit.js +1 -0
  45. package/dist/contracts/resource-operations.d.ts +2 -62
  46. package/dist/contracts/resource.d.ts +2 -0
  47. package/dist/contracts/scalar-value-type.d.ts +28 -48
  48. package/dist/contracts/scalar.d.ts +4 -3
  49. package/dist/contracts/transaction-capability.d.ts +2 -0
  50. package/dist/contracts/wire-scalar-format.d.ts +6 -21
  51. package/dist/framework/contract-view.d.ts +152 -130
  52. package/dist/framework/framework-construction.error.d.ts +6 -1
  53. package/dist/framework/framework.d.ts +33 -46
  54. package/dist/framework/framework.factory.d.ts +3 -17
  55. package/dist/framework/framework.factory.js +56 -13
  56. package/dist/framework/operation-facade.d.ts +3 -7
  57. package/dist/index.d.ts +8 -40
  58. package/dist/index.js +0 -20
  59. package/dist/internal.d.ts +35 -0
  60. package/dist/internal.js +16 -0
  61. package/dist/json/avz.d.ts +96 -0
  62. package/dist/json/avz.js +212 -0
  63. package/dist/json/index.d.ts +6 -0
  64. package/dist/json/index.js +1 -0
  65. package/dist/json/json-shape.registry.d.ts +22 -0
  66. package/dist/json/json-shape.registry.js +16 -0
  67. package/dist/json/zod-issue.translator.d.ts +51 -0
  68. package/dist/json/zod-issue.translator.js +142 -0
  69. package/dist/operations/operation-arguments.d.ts +198 -303
  70. package/dist/operations/operation-call.d.ts +13 -15
  71. package/dist/operations/operation-identity.d.ts +6 -2
  72. package/dist/operations/operation-identity.js +3 -0
  73. package/dist/operations/operation-result.d.ts +15 -61
  74. package/dist/operations/operation-validator-core.d.ts +6 -5
  75. package/dist/operations/operation-validator-core.js +28 -10
  76. package/dist/operations/operation-validator.d.ts +22 -9
  77. package/dist/operations/operation-validator.js +26 -10
  78. package/dist/operations/projection-scope.resolver.d.ts +1 -11
  79. package/dist/operations/structural-limits.walker.d.ts +19 -0
  80. package/dist/operations/structural-limits.walker.js +344 -0
  81. package/dist/operations/validation-code.d.ts +5 -17
  82. package/dist/operations/write-scope.resolver.d.ts +3 -28
  83. package/dist/protocol/absent-route.responder.d.ts +25 -39
  84. package/dist/protocol/absent-route.responder.js +32 -6
  85. package/dist/protocol/av-protocol.d.ts +2 -8
  86. package/dist/protocol/contract-document.responder.d.ts +5 -18
  87. package/dist/protocol/http-request.decoder.d.ts +18 -59
  88. package/dist/protocol/http-request.decoder.js +11 -3
  89. package/dist/protocol/http-request.reader.d.ts +5 -5
  90. package/dist/protocol/http-response.encoder.d.ts +14 -20
  91. package/dist/protocol/http-status.table.d.ts +0 -8
  92. package/dist/protocol/index.d.ts +2 -7
  93. package/dist/protocol/operation-response.guard.d.ts +0 -15
  94. package/dist/protocol/protocol-failure.d.ts +8 -27
  95. package/dist/protocol/protocol-headers.d.ts +15 -42
  96. package/dist/protocol/protocol-surface.d.ts +0 -22
  97. package/dist/protocol/protocol.binder.d.ts +19 -27
  98. package/dist/protocol/protocol.binder.js +3 -1
  99. package/dist/protocol/protocol.handler.d.ts +19 -23
  100. package/dist/protocol/protocol.handler.js +14 -4
  101. package/dist/protocol/unmounted-route.error.d.ts +19 -0
  102. package/dist/protocol/unmounted-route.error.js +10 -0
  103. package/dist/runtime/caller-data.copier.d.ts +59 -0
  104. package/dist/runtime/caller-data.copier.js +470 -0
  105. package/dist/runtime/caller-data.door.d.ts +56 -0
  106. package/dist/runtime/caller-data.door.js +65 -0
  107. package/dist/runtime/computed-read-runtime.js +3 -10
  108. package/dist/runtime/computed-value.error.d.ts +13 -0
  109. package/dist/runtime/computed-value.error.js +9 -0
  110. package/dist/runtime/create-requirement.d.ts +43 -7
  111. package/dist/runtime/create-requirement.js +89 -9
  112. package/dist/runtime/decimal.d.ts +5 -3
  113. package/dist/runtime/diagnostics-reporter.d.ts +33 -37
  114. package/dist/runtime/diagnostics-reporter.js +11 -4
  115. package/dist/runtime/error-boundary.d.ts +14 -10
  116. package/dist/runtime/error-boundary.js +65 -35
  117. package/dist/runtime/execution-options.d.ts +3 -7
  118. package/dist/runtime/field-behavior.d.ts +14 -21
  119. package/dist/runtime/framework-error.d.ts +14 -2
  120. package/dist/runtime/json-value.d.ts +7 -15
  121. package/dist/runtime/misuse-reporter.d.ts +32 -0
  122. package/dist/runtime/misuse-reporter.js +19 -0
  123. package/dist/runtime/mutation-planner.d.ts +6 -12
  124. package/dist/runtime/mutation-planner.js +13 -11
  125. package/dist/runtime/operation-request.d.ts +11 -11
  126. package/dist/runtime/operation-response.d.ts +18 -23
  127. package/dist/runtime/operation-runtime.d.ts +25 -33
  128. package/dist/runtime/operation-runtime.js +37 -18
  129. package/dist/runtime/outcome-mapper.js +12 -2
  130. package/dist/runtime/output-validator.d.ts +10 -0
  131. package/dist/runtime/output-validator.js +11 -0
  132. package/dist/runtime/owned-execution.registry.d.ts +13 -0
  133. package/dist/runtime/owned-execution.registry.js +7 -0
  134. package/dist/runtime/pipeline.d.ts +33 -36
  135. package/dist/runtime/referential-action.d.ts +8 -26
  136. package/dist/runtime/request-envelope.validator.d.ts +5 -0
  137. package/dist/runtime/request-envelope.validator.js +118 -0
  138. package/dist/runtime/request-id.d.ts +3 -10
  139. package/dist/runtime/scalar-runtime.d.ts +42 -14
  140. package/dist/runtime/scalar-runtime.js +162 -79
  141. package/dist/transactions/deferred-operation.d.ts +10 -21
  142. package/dist/transactions/operation-arguments-encoder.d.ts +1 -0
  143. package/dist/transactions/operation-fingerprint.d.ts +3 -1
  144. package/dist/transactions/transaction-envelope.d.ts +2 -4
  145. package/dist/transactions/transaction-integrity-error.d.ts +4 -15
  146. package/dist/transactions/transaction-plan-assembler.d.ts +6 -1
  147. package/dist/transactions/transaction-plan-assembler.js +74 -75
  148. package/dist/transactions/transaction-plan-validator.d.ts +33 -24
  149. package/dist/transactions/transaction-plan-validator.js +204 -153
  150. package/dist/transactions/transaction-reference-collector.d.ts +30 -0
  151. package/dist/transactions/transaction-reference-collector.js +204 -0
  152. package/dist/transactions/transaction-reference-resolver.d.ts +9 -12
  153. package/dist/transactions/transaction-reference-resolver.js +10 -5
  154. package/dist/transactions/transaction-reference-validator.js +24 -17
  155. package/dist/transactions/transaction-reference.d.ts +31 -64
  156. package/dist/transactions/transaction-request.d.ts +6 -8
  157. package/dist/transactions/transaction-response.d.ts +10 -7
  158. package/dist/transactions/transaction-response.js +24 -1
  159. package/dist/transactions/transaction-runtime.d.ts +7 -5
  160. package/dist/transactions/transaction-runtime.js +4 -3
  161. package/dist/transactions/transaction-slot-path-error.d.ts +5 -15
  162. package/dist/transactions/transaction-slot-writer.d.ts +3 -13
  163. package/package.json +17 -3
  164. package/dist/operations/operation-boolean-nodes.d.ts +0 -11
  165. package/dist/operations/operation-boolean-nodes.js +0 -283
  166. package/dist/operations/operation-nesting.d.ts +0 -8
  167. package/dist/operations/operation-nesting.js +0 -307
@@ -79,8 +79,11 @@ function projectPath(value) {
79
79
  export const OPERATION_ARGUMENTS_PATH = [
80
80
  "arguments",
81
81
  ];
82
+ export function planStepPath(index) {
83
+ return ["operations", index];
84
+ }
82
85
  export function planOperationArgumentsPath(index) {
83
- return ["operations", index, "args"];
86
+ return [...planStepPath(index), "args"];
84
87
  }
85
88
  const UNRESOLVED = Symbol("unresolved-path-segment");
86
89
  function readOwnMember(container, key) {
@@ -100,38 +103,43 @@ function readSegment(container, segment) {
100
103
  }
101
104
  return readOwnMember(container, segment);
102
105
  }
103
- function resolvesAgainstArguments(path, view) {
106
+ function vouchPath(path, view) {
104
107
  try {
105
- if (path.length < view.path.length) {
106
- return false;
107
- }
108
- for (let index = 0; index < view.path.length; index += 1) {
109
- if (path[index] !== view.path[index]) {
110
- return false;
111
- }
108
+ const root = [view.path, OPERATION_ARGUMENTS_PATH].find((prefix) => startsWith(path, prefix));
109
+ if (root === undefined) {
110
+ return undefined;
112
111
  }
113
112
  let current = view.arguments;
114
- for (let index = view.path.length; index < path.length; index += 1) {
113
+ for (let index = root.length; index < path.length; index += 1) {
115
114
  const segment = path[index];
116
115
  if (segment === undefined) {
117
- return false;
116
+ return undefined;
118
117
  }
119
118
  current = readSegment(current, segment);
120
119
  if (current === UNRESOLVED) {
121
- return false;
120
+ return undefined;
122
121
  }
123
122
  }
124
- return true;
123
+ return [...view.path, ...path.slice(root.length)];
125
124
  }
126
125
  catch {
127
- return false;
126
+ return undefined;
128
127
  }
129
128
  }
129
+ function startsWith(path, prefix) {
130
+ return (path.length >= prefix.length &&
131
+ prefix.every((segment, index) => path[index] === segment));
132
+ }
130
133
  function isValidationCode(value) {
131
134
  return (typeof value === "string" &&
132
135
  VALIDATION_CODES.includes(value));
133
136
  }
134
- function projectIssue(value, unvouched, view) {
137
+ export const MAX_DEVELOPER_ISSUE_MESSAGE_LENGTH = 1_000;
138
+ function isDeveloperMessage(message) {
139
+ return (message.length <= MAX_DEVELOPER_ISSUE_MESSAGE_LENGTH &&
140
+ message.trim().length > 0);
141
+ }
142
+ function projectIssue(value, unvouched, view, author) {
135
143
  if (typeof value !== "object" || value === null) {
136
144
  return undefined;
137
145
  }
@@ -142,23 +150,32 @@ function projectIssue(value, unvouched, view) {
142
150
  }
143
151
  return undefined;
144
152
  }
145
- const message = readProperty(value, "message");
153
+ const supplied = readProperty(value, "message");
146
154
  const rawPath = readProperty(value, "path");
147
- if (typeof message !== "string") {
155
+ if (typeof supplied !== "string") {
148
156
  return undefined;
149
157
  }
150
- const owned = VALIDATION_CODE_MESSAGES[code];
158
+ let message = VALIDATION_CODE_MESSAGES[code];
159
+ if (author === "developer") {
160
+ if (isDeveloperMessage(supplied)) {
161
+ message = supplied;
162
+ }
163
+ else {
164
+ unvouched.push(supplied);
165
+ }
166
+ }
151
167
  if (rawPath === undefined) {
152
- return { code, message: owned };
168
+ return { code, message };
153
169
  }
154
- const path = projectPath(rawPath);
155
- if (path === undefined || !resolvesAgainstArguments(path, view)) {
170
+ const projected = projectPath(rawPath);
171
+ const path = projected === undefined ? undefined : vouchPath(projected, view);
172
+ if (path === undefined) {
156
173
  unvouched.push(rawPath);
157
- return { code, message: owned };
174
+ return { code, message };
158
175
  }
159
- return { path, code, message: owned };
176
+ return { path, code, message };
160
177
  }
161
- function projectCause(value, unvouched, view) {
178
+ function projectCause(value, unvouched, view, author) {
162
179
  const message = readProperty(value, "message");
163
180
  if (typeof message !== "string") {
164
181
  return undefined;
@@ -166,7 +183,7 @@ function projectCause(value, unvouched, view) {
166
183
  const rawIssues = readList(readProperty(value, "issues"));
167
184
  const rawOperation = readProperty(value, "operation");
168
185
  const issues = rawIssues
169
- ?.map((issue) => projectIssue(issue, unvouched, view))
186
+ ?.map((issue) => projectIssue(issue, unvouched, view, author))
170
187
  .filter((issue) => issue !== undefined);
171
188
  return {
172
189
  message,
@@ -206,7 +223,7 @@ function isOperationErrorCode(value) {
206
223
  OPERATION_CODES.includes(value) &&
207
224
  !value.startsWith("A1"));
208
225
  }
209
- function vetDeliberateOutcome(error, view) {
226
+ function vetDeliberateOutcome(error, view, author) {
210
227
  if (!isFrameworkErrorInstance(error)) {
211
228
  return undefined;
212
229
  }
@@ -218,7 +235,7 @@ function vetDeliberateOutcome(error, view) {
218
235
  return MALFORMED_OUTCOME;
219
236
  }
220
237
  const unvouched = [];
221
- const cause = projectCause(rawCause, unvouched, view);
238
+ const cause = projectCause(rawCause, unvouched, view, author);
222
239
  return cause === undefined ? MALFORMED_OUTCOME : { code, cause, unvouched };
223
240
  }
224
241
  function reportUnvouched(outcome, report) {
@@ -226,13 +243,20 @@ function reportUnvouched(outcome, report) {
226
243
  report(value, outcome.code);
227
244
  }
228
245
  }
246
+ function reportDeliberate(thrown, outcome, report) {
247
+ if (isInternalCode(outcome.code)) {
248
+ report(thrown, outcome.code, { deliberate: true });
249
+ return;
250
+ }
251
+ reportUnvouched(outcome, report);
252
+ }
229
253
  function deliberateFailure(outcome) {
230
254
  return operationFailure(outcome.code, isInternalCode(outcome.code)
231
255
  ? internalCause(outcome.code, outcome.cause)
232
256
  : outcome.cause);
233
257
  }
234
258
  export function sanitizeOperationFailure(error, origin, report, view) {
235
- const outcome = vetDeliberateOutcome(error, view);
259
+ const outcome = vetDeliberateOutcome(error, view, origin === "adapter" ? "adapter" : "developer");
236
260
  if (outcome === undefined) {
237
261
  report(error, unexpectedCode(origin));
238
262
  return unexpectedFailure(origin);
@@ -240,7 +264,9 @@ export function sanitizeOperationFailure(error, origin, report, view) {
240
264
  if (outcome === MALFORMED_OUTCOME) {
241
265
  report(error, "A3000");
242
266
  }
243
- reportUnvouched(outcome, report);
267
+ else {
268
+ reportDeliberate(error, outcome, report);
269
+ }
244
270
  return deliberateFailure(outcome);
245
271
  }
246
272
  export async function resolveOperationFailure(error, filters, context, boundary, report, view) {
@@ -249,20 +275,24 @@ export async function resolveOperationFailure(error, filters, context, boundary,
249
275
  if (filter === undefined) {
250
276
  continue;
251
277
  }
252
- const handled = await attemptFilter(filter, error, context, view);
278
+ const handled = await attemptFilter(filter, error, context, view, boundary);
253
279
  if (handled !== undefined) {
254
- if (handled === MALFORMED_OUTCOME) {
280
+ if (handled.outcome === MALFORMED_OUTCOME) {
255
281
  report(error, "A3000");
256
282
  }
257
- reportUnvouched(handled, report);
258
- return deliberateFailure(handled);
283
+ else {
284
+ reportDeliberate(handled.returned, handled.outcome, report);
285
+ }
286
+ return deliberateFailure(handled.outcome);
259
287
  }
260
288
  }
261
289
  return sanitizeOperationFailure(error, boundary.originOf(error), report, view);
262
290
  }
263
- async function attemptFilter(filter, error, context, view) {
291
+ async function attemptFilter(filter, error, context, view, boundary) {
264
292
  try {
265
- return vetDeliberateOutcome(await filter(error, context), view);
293
+ const returned = await filter(error, context);
294
+ const outcome = vetDeliberateOutcome(returned, view, boundary.originOf(returned) === "adapter" ? "adapter" : "developer");
295
+ return outcome === undefined ? undefined : { returned, outcome };
266
296
  }
267
297
  catch {
268
298
  return undefined;
@@ -1,11 +1,7 @@
1
1
  /**
2
- * The caller's say over an in-process request it does not write by hand: the
3
- * second argument of every `framework.application.*` / `framework.client.*` call
4
- * and of `framework.transaction`.
5
- *
6
- * Not "transport options": an in-process call has no transport. A deferred handle
7
- * (`framework.appTx.*` / `framework.clientTx.*`) takes none — a handle is not a
8
- * request, and the id belongs to the run that executes it.
2
+ * Options for one in-process call: the optional second argument of every
3
+ * `framework.application.*` / `framework.client.*` call and of
4
+ * `framework.transaction`.
9
5
  */
10
6
  export type ExecutionOptions = {
11
7
  /**
@@ -6,34 +6,31 @@ import type { FrameworkResourceKey } from "../config/framework-fields-config.js"
6
6
  import type { PipelineContext } from "./pipeline.js";
7
7
  /**
8
8
  * What a write-stage compute callback is told about the field it is computing.
9
- *
10
- * `R` is the Resource the behavior is bound to and `Cfg` the authored
11
- * configuration literal, so `resource` is the literal Resource name and `field` —
12
- * like every other field-key position in the framework — is {@link
13
- * EffectiveFieldKey}: what the adapter discovered plus what the configuration
14
- * added.
15
- *
16
- * `data` is keyed on the same set and stays `unknown`-valued.
17
- *
18
- * Under the default `Cfg` the key set degenerates to `string` and this is
19
- * byte-for-byte the shape it was before `Cfg` existed.
20
9
  */
21
10
  type ComputedWriteContext<M extends AdapterModel, Cfg, R extends FrameworkResourceKey<M>> = {
22
- readonly scope: RequestOrigin;
11
+ readonly origin: RequestOrigin;
23
12
  readonly resource: R;
24
13
  readonly field: EffectiveFieldKey<M, Cfg, R>;
25
14
  readonly value: unknown;
26
15
  readonly data: Readonly<Record<EffectiveFieldKey<M, Cfg, R>, unknown>>;
27
16
  readonly operation: PipelineContext;
28
17
  };
18
+ /**
19
+ * Computes a field's value when a row is created. It receives the incoming
20
+ * `data` and returns the value to store.
21
+ */
29
22
  export type ComputeOnCreate<M extends AdapterModel = AdapterModel, Cfg = AnyFrameworkConfig, R extends FrameworkResourceKey<M> = FrameworkResourceKey<M>> = (context: ComputedWriteContext<M, Cfg, R>) => unknown | Promise<unknown>;
23
+ /**
24
+ * Computes a field's value when a row is updated. It receives the incoming
25
+ * `data` and returns the value to store.
26
+ */
30
27
  export type ComputeOnUpdate<M extends AdapterModel = AdapterModel, Cfg = AnyFrameworkConfig, R extends FrameworkResourceKey<M> = FrameworkResourceKey<M>> = (context: ComputedWriteContext<M, Cfg, R>) => unknown | Promise<unknown>;
31
28
  /**
32
- * The read-stage counterpart. It sees the persisted `record` rather than the
33
- * inbound `data`, keyed on the same effective field set.
29
+ * Computes a field's value when a row is read. It receives the stored `record`
30
+ * and returns the value to return.
34
31
  */
35
32
  export type ComputeOnRead<M extends AdapterModel = AdapterModel, Cfg = AnyFrameworkConfig, R extends FrameworkResourceKey<M> = FrameworkResourceKey<M>> = (context: {
36
- readonly scope: RequestOrigin;
33
+ readonly origin: RequestOrigin;
37
34
  readonly resource: R;
38
35
  readonly field: EffectiveFieldKey<M, Cfg, R>;
39
36
  readonly value: unknown;
@@ -41,12 +38,8 @@ export type ComputeOnRead<M extends AdapterModel = AdapterModel, Cfg = AnyFramew
41
38
  readonly operation: PipelineContext;
42
39
  }) => unknown | Promise<unknown>;
43
40
  /**
44
- * A computed read, optionally declaring the fields it reads.
45
- *
46
- * `dependsOn` is a field-key position and therefore keys on
47
- * {@link EffectiveFieldKey} like every other one. A name outside that set is
48
- * an array-element assignability failure (`TS2322`), not an excess property:
49
- * the author wrote a `string` where a member of the key union was required.
41
+ * A computed read: a compute function, or `{ compute, dependsOn }` naming the
42
+ * fields it reads.
50
43
  */
51
44
  export type ComputedReadBehavior<M extends AdapterModel = AdapterModel, Cfg = AnyFrameworkConfig, R extends FrameworkResourceKey<M> = FrameworkResourceKey<M>> = ComputeOnRead<M, Cfg, R> | {
52
45
  readonly dependsOn?: readonly EffectiveFieldKey<M, Cfg, R>[];
@@ -1,7 +1,19 @@
1
1
  import type { Cause, OperationErrorCode } from "./operation-response.js";
2
2
  /**
3
- * Stable typed error used by server-side pipelines, behaviors and Adapters to
4
- * deliberately surface one framework error outcome.
3
+ * Throw from a pipeline, behavior or Adapter to answer the request with one
4
+ * framework error code and cause.
5
+ *
6
+ * For any code outside `A3xxx`, `cause.message` is sent to the caller exactly as
7
+ * written: put nothing in it you would not show the caller (no database text,
8
+ * SQL, stack, path or secret). So is each issue's `message`, when your own code
9
+ * (a pipe, guard, hook, interceptor, filter or behavior) throws it and it is not
10
+ * blank and at most 1,000 characters; otherwise, and for an issue an Adapter
11
+ * throws, the caller receives the framework's own text for the issue's code. An
12
+ * issue's `code` must be a validation code (`V1000` and up) and its `path` must
13
+ * name a member of the request's own arguments, or the issue, or the path, is
14
+ * not sent. For an `A3xxx` code the caller receives the framework's generic
15
+ * message instead, and nothing of the cause; the error itself reaches the root
16
+ * `diagnostics` sink once, marked `deliberate: true`.
5
17
  */
6
18
  export declare class FrameworkError extends Error {
7
19
  readonly code: OperationErrorCode;
@@ -1,22 +1,14 @@
1
1
  /**
2
- * A JSON value: the runtime form of the `json` scalar, inside and out.
2
+ * A JSON value: the form of the `json` scalar, in arguments and results.
3
3
  *
4
- * It is exactly what `normalizeJsonValue` (`runtime/scalar-runtime.ts`) admits,
5
- * and that traversal emits only this type, so the runtime and the type are one
6
- * fact rather than two that agree. Measured in all three scopes alike: a `Date`,
7
- * a `bigint`, a `Uint8Array`, core's `Decimal`, any other class instance and an
8
- * `undefined` property are refused (`V1001`), and none of them is a member here.
4
+ * A `Date`, a `bigint`, a `Uint8Array`, a {@link Decimal}, any other class
5
+ * instance and an `undefined` property are refused (`V1001`), as are a
6
+ * non-finite `number` (`V1004`) and a cycle (`V1001`).
9
7
  *
10
- * Two runtime refusals a type cannot carry: a non-finite `number` (`V1004`) and
11
- * a cycle (`V1001`).
8
+ * Results are fresh plain copies, so mutating one is safe.
12
9
  *
13
- * The containers are `readonly`, which an input accepts in either form and a
14
- * result under-claims: the framework hands back a fresh plain copy, so mutating
15
- * one is safe, but nothing is promised about it.
16
- *
17
- * A `json` FIELD's form is this without its top-level `null`
18
- * (`ApplicationScalarForms["json"]`): a field-level `null` is the field's
19
- * absence, which only `nullable: true` admits.
10
+ * A `json` field's value is this without its top-level `null`: a field-level
11
+ * `null` is the field's absence, which only `nullable: true` admits.
20
12
  */
21
13
  export type JsonValue = string | number | boolean | null | readonly JsonValue[] | {
22
14
  readonly [key: string]: JsonValue;
@@ -0,0 +1,32 @@
1
+ import type { RequestOrigin } from "../config/config-layer.js";
2
+ import type { OperationFamily } from "../operations/operation-identity.js";
3
+ /**
4
+ * One caller value the framework refused because it could not be read
5
+ * (`"unreadable-value"`: a revoked Proxy, a throwing getter or trap) or is not plain
6
+ * data (`"non-plain-value"`: a class instance other than `Date`, `Decimal` or
7
+ * `Uint8Array`). The caller received `A2004` with one `V1001` at `path`.
8
+ *
9
+ * The operation's identity is present when the framework could read it — absent for
10
+ * a request whose own envelope could not be read — and `operation` is the step's
11
+ * index in a transaction plan.
12
+ */
13
+ export type FrameworkMisuseEvent = {
14
+ readonly kind: "unreadable-value" | "non-plain-value";
15
+ /** The issue path the caller received. */
16
+ readonly path: readonly (string | number)[];
17
+ readonly origin?: RequestOrigin;
18
+ readonly resource?: string;
19
+ readonly family?: OperationFamily;
20
+ readonly variant?: string;
21
+ readonly operation?: number;
22
+ };
23
+ /**
24
+ * Receives a {@link FrameworkMisuseEvent} for every caller value the framework
25
+ * refused as unreadable or not plain data. Set once, as the root configuration's
26
+ * `misuse`. What it returns, throws or rejects with never reaches the response.
27
+ */
28
+ export type FrameworkMisuseSink = (event: FrameworkMisuseEvent) => void | Promise<void>;
29
+ /** The channel as the runtime holds it: total, never awaited. */
30
+ export type MisuseReporter = (event: FrameworkMisuseEvent) => void;
31
+ /** Binds the configured sink; without one, nothing is observed. */
32
+ export declare function createMisuseReporter(sink: FrameworkMisuseSink | undefined): MisuseReporter;
@@ -0,0 +1,19 @@
1
+ const IGNORE_MISUSE = () => undefined;
2
+ export function createMisuseReporter(sink) {
3
+ if (sink === undefined) {
4
+ return IGNORE_MISUSE;
5
+ }
6
+ return (event) => {
7
+ try {
8
+ const settled = sink(event);
9
+ if (typeof settled === "object" &&
10
+ settled !== null &&
11
+ typeof settled.then === "function") {
12
+ settled.then(undefined, () => undefined);
13
+ }
14
+ }
15
+ catch {
16
+ return;
17
+ }
18
+ };
19
+ }
@@ -4,11 +4,10 @@ import type { Contract, CoreContract } from "../contracts/contract.js";
4
4
  import type { OperationExecutionRequest } from "./operation-request.js";
5
5
  import type { PipelineContext } from "./pipeline.js";
6
6
  /**
7
- * The two Contracts a write reads. The **Core** Contract decides what the Adapter
8
- * is asked to store; the **active** Contract adds the fields its scope declared
9
- * under `application.fields` / `client.fields`, which Core does not carry. Such a
10
- * field is VIRTUAL by construction (`contract.compiler.ts`), so its behaviours run
11
- * and its value is stripped before the Adapter call — never sent.
7
+ * The two Contracts a write reads. The Core Contract decides what the Adapter is asked
8
+ * to store; the active Contract adds the fields its scope declared under
9
+ * `application.fields` / `client.fields`, which Core does not carry. Such a field is
10
+ * virtual: its behaviours run and its value is stripped before the Adapter call.
12
11
  */
13
12
  export type WriteContracts = {
14
13
  readonly core: CoreContract;
@@ -21,13 +20,8 @@ export type RelationRecordSite = {
21
20
  readonly stage: WriteStage;
22
21
  };
23
22
  /**
24
- * The sole grammar for relation-mutation record operands. Every write pass
25
- * maps these sites with its own record leaf, leaving identifier-only
26
- * directives untouched. The identifier operands this table deliberately leaves
27
- * empty are described by `RELATION_MUTATION_SELECTOR_SITES` in
28
- * `transactions/operation-arguments-encoder.ts`, the only pass that has to
29
- * encode them; both tables are keyed by `RelationMutationDirective`, so a new
30
- * directive fails to compile in both places.
23
+ * The sole grammar for relation-mutation record operands. Every write pass maps these
24
+ * sites with its own record leaf, leaving identifier-only directives untouched.
31
25
  */
32
26
  export declare const RELATION_MUTATION_RECORD_SITES: {
33
27
  readonly $create: readonly [{
@@ -1,7 +1,6 @@
1
1
  import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
- import { FrameworkError } from "./framework-error.js";
3
- import { INTERNAL_FAILURE_MESSAGE } from "./operation-response.js";
4
- import { normalizeScalarFieldValue } from "./scalar-runtime.js";
2
+ import { ComputedValueError } from "./computed-value.error.js";
3
+ import { jsonShapeIssues, normalizeScalarFieldValue, } from "./scalar-runtime.js";
5
4
  function writeScalarField(contracts, resourceName, fieldName) {
6
5
  const field = lookupField(lookupResource(contracts.core, resourceName), fieldName) ??
7
6
  lookupField(lookupResource(contracts.active, resourceName), fieldName);
@@ -34,12 +33,6 @@ function cloneRecord(value) {
34
33
  function relationEntries(value) {
35
34
  return Array.isArray(value) ? value : [value];
36
35
  }
37
- function behaviorFailure(issues) {
38
- throw new FrameworkError("A3000", {
39
- message: INTERNAL_FAILURE_MESSAGE,
40
- issues,
41
- });
42
- }
43
36
  async function computeRecord(contracts, behaviors, request, resourceName, stage, data, contextFactory) {
44
37
  if (!isRecord(data)) {
45
38
  return data;
@@ -64,7 +57,7 @@ async function computeRecord(contracts, behaviors, request, resourceName, stage,
64
57
  continue;
65
58
  }
66
59
  const computed = await callback({
67
- scope: request.scope,
60
+ origin: request.origin,
68
61
  resource: resourceName,
69
62
  field: fieldName,
70
63
  value: logicalData[fieldName],
@@ -76,7 +69,16 @@ async function computeRecord(contracts, behaviors, request, resourceName, stage,
76
69
  }
77
70
  const validation = normalizeScalarFieldValue(contracts.core, field, computed, "runtime", ["behaviors", resourceName, fieldName, stage]);
78
71
  if (!validation.ok) {
79
- behaviorFailure(validation.issues);
72
+ throw new ComputedValueError(resourceName, fieldName, stage, validation.issues);
73
+ }
74
+ const shapeIssues = jsonShapeIssues(field, validation.value, [
75
+ "behaviors",
76
+ resourceName,
77
+ fieldName,
78
+ stage,
79
+ ]);
80
+ if (shapeIssues.length > 0) {
81
+ throw new ComputedValueError(resourceName, fieldName, stage, shapeIssues);
80
82
  }
81
83
  logicalData[fieldName] = validation.value;
82
84
  }
@@ -1,12 +1,6 @@
1
- import type { RequestOrigin } from "../config/config-layer.js";
2
1
  import type { OperationIdentity } from "../operations/operation-identity.js";
3
2
  import type { PipelineTransportContext } from "./pipeline.js";
4
- /**
5
- * @deprecated Use {@link RequestOrigin}. The set it names is not a property of
6
- * an operation but the origin layer a request belongs to, derived from
7
- * `ConfigLayer`; kept as an alias so existing consumers keep compiling.
8
- */
9
- export type OperationScope = RequestOrigin;
3
+ /** The protocol version and ClientContract hash a client says it was built for. */
10
4
  export type ClientProtocolIdentity = {
11
5
  readonly version: number;
12
6
  readonly hash: string;
@@ -16,24 +10,30 @@ type RuntimeOperationBase = OperationIdentity & {
16
10
  readonly arguments: unknown;
17
11
  readonly requestId: string;
18
12
  };
13
+ /** An in-process request, run under the Application Contract. */
19
14
  export type ApplicationOperationRequest = RuntimeOperationBase & {
20
- readonly scope: "application";
15
+ readonly origin: "application";
21
16
  readonly protocol?: never;
22
17
  readonly transport?: never;
23
18
  };
19
+ /**
20
+ * A remote request, run under the Client Contract; `protocol` is the identity
21
+ * the client sent.
22
+ */
24
23
  export type ClientOperationRequest = RuntimeOperationBase & {
25
- readonly scope: "client";
24
+ readonly origin: "client";
26
25
  readonly protocol: ClientProtocolIdentity;
27
26
  readonly transport?: PipelineTransportContext;
28
27
  };
28
+ /** One operation request, as `framework.execute` takes it. */
29
29
  export type FrameworkOperationRequest = ApplicationOperationRequest | ClientOperationRequest;
30
30
  type WithoutArguments<Request> = Request extends unknown ? Omit<Request, "arguments"> : never;
31
31
  /**
32
32
  * A request as every stage after the Framework Validation Layer sees it:
33
- * identity, scope, request id and transport, but never `arguments`. Those
33
+ * identity, origin, request id and transport, but never `arguments`. Those
34
34
  * stages act on the validated arguments passed beside it; the unvalidated
35
35
  * view — inside a transaction plan still carrying `$ref` placeholders — is
36
- * unreachable by type. Distributive, so the scope and family/variant
36
+ * unreachable by type. Distributive, so the origin and family/variant
37
37
  * correlations survive the omission.
38
38
  */
39
39
  export type OperationExecutionRequest = WithoutArguments<FrameworkOperationRequest>;
@@ -1,21 +1,24 @@
1
1
  import type { ValidationIssue } from "../operations/validation-code.js";
2
+ /** Every outcome code, as a runtime list. */
2
3
  export declare const OPERATION_CODES: readonly ["A1000", "A1001", "A1002", "A1003", "A1004", "A1005", "A1006", "A1007", "A1008", "A1009", "A2000", "A2001", "A2002", "A2003", "A2004", "A2005", "A2006", "A2007", "A2008", "A2009", "A2010", "A2011", "A2012", "A2013", "A2014", "A3000", "A3001", "A3002", "A3003", "A3004", "A4000", "A4001", "A4002"];
4
+ /**
5
+ * Every outcome code: `A1xxx` success, `A2xxx` caller error, `A3xxx` internal
6
+ * failure, `A4xxx` authentication or permission denial.
7
+ */
3
8
  export type OperationCode = (typeof OPERATION_CODES)[number];
9
+ /** The success codes, `A1xxx`. */
4
10
  export type OperationSuccessCode = Extract<OperationCode, `A1${string}`>;
11
+ /** Every outcome code that is not a success. */
5
12
  export type OperationErrorCode = Exclude<OperationCode, OperationSuccessCode>;
6
13
  /** Internal-failure family: nothing in the cause is caller-actionable. */
7
14
  export type OperationInternalErrorCode = Extract<OperationErrorCode, `A3${string}`>;
15
+ /** Why a request failed: a message, and the validation issues when there are any. */
8
16
  export type Cause = {
9
17
  readonly message: string;
10
18
  readonly issues?: readonly ValidationIssue[];
11
19
  readonly operation?: number;
12
20
  };
13
- /**
14
- * The canonical wire envelope (spec section 13): a flat `{ data, code,
15
- * cause }` shape. `OperationResponse<T>` below is a discriminated union
16
- * derived from this one shape — every arm is a differently-constrained
17
- * projection of the same three fields, never an independent structure.
18
- */
21
+ /** The response envelope: `{ data, code, cause }`. */
19
22
  type OperationResponseEnvelope<TData, TCode extends OperationCode, TCause extends Cause | null> = {
20
23
  readonly data: TData;
21
24
  readonly code: TCode;
@@ -23,33 +26,25 @@ type OperationResponseEnvelope<TData, TCode extends OperationCode, TCause extend
23
26
  };
24
27
  /** Success codes that carry response data (every success code but A1001). */
25
28
  export type OperationSuccessDataCode = Exclude<OperationSuccessCode, "A1001">;
26
- /** Arm (a): success with data — non-null data, null cause. */
29
+ /** A success with data: `cause` is `null`. */
27
30
  export type OperationSuccessResponse<T> = OperationResponseEnvelope<T, OperationSuccessDataCode, null>;
28
- /** Arm (b): no-match success (A1001) — null data, null cause. */
31
+ /** A success with no matching row (`A1001`): `data` and `cause` are `null`. */
29
32
  export type OperationNoMatchResponse = OperationResponseEnvelope<null, "A1001", null>;
30
- /** Arm (c): failure — null data, non-null cause. */
33
+ /** A failure: `data` is `null` and `cause` says why. */
31
34
  export type OperationFailureResponse = OperationResponseEnvelope<null, OperationErrorCode, Cause>;
32
- export type OperationResponse<T = unknown> = OperationSuccessResponse<T> | OperationNoMatchResponse | OperationFailureResponse;
33
35
  /**
34
- * Builds the success-with-data arm. The only sanctioned way to construct
35
- * one: a runtime-computed `code` (e.g. from a table-driven outcome mapper)
36
- * still yields a well-typed {@link OperationSuccessResponse}.
36
+ * What an operation answers: success with data, a no-match success (`A1001`),
37
+ * or a failure with a cause.
37
38
  */
39
+ export type OperationResponse<T = unknown> = OperationSuccessResponse<T> | OperationNoMatchResponse | OperationFailureResponse;
40
+ /** Builds a success response with data. */
38
41
  export declare function operationSuccess<T>(data: T, code: OperationSuccessDataCode): OperationSuccessResponse<T>;
39
42
  /** Builds the no-match success arm (A1001). */
40
43
  export declare function operationNoMatch(): OperationNoMatchResponse;
41
- /**
42
- * Builds the failure arm. The only sanctioned way to construct one: a
43
- * runtime-computed error `code` still yields a well-typed
44
- * {@link OperationFailureResponse}.
45
- */
44
+ /** Builds a failure response. */
46
45
  export declare function operationFailure(code: OperationErrorCode, cause: Cause): OperationFailureResponse;
47
46
  /** The one generic internal-failure text; every A3000 carries it. */
48
47
  export declare const INTERNAL_FAILURE_MESSAGE = "Internal framework error.";
49
- /**
50
- * The generic internal-failure envelope. Nothing about an internal failure is
51
- * caller-actionable, so every A3000 the framework emits is this exact value -
52
- * one constant rather than one restatement per boundary.
53
- */
48
+ /** The response every internal failure (`A3000`) answers with. */
54
49
  export declare function internalFailure(): OperationFailureResponse;
55
50
  export {};