@aventara/core 1.0.0-rc.4 → 1.0.0-rc.8

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 (60) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/ERRORS.md +1 -1
  3. package/README.md +5 -1
  4. package/dist/adapters/adapter-field.d.ts +8 -0
  5. package/dist/adapters/adapter-identifier.d.ts +9 -0
  6. package/dist/adapters/adapter-identifier.js +6 -1
  7. package/dist/adapters/adapter-operation.d.ts +12 -6
  8. package/dist/compiler/contract.compiler.js +26 -3
  9. package/dist/config/framework-config.d.ts +5 -1
  10. package/dist/contracts/contract.d.ts +15 -1
  11. package/dist/contracts/field.d.ts +17 -0
  12. package/dist/contracts/scalar-value-type.d.ts +3 -1
  13. package/dist/framework/framework-construction.error.d.ts +2 -1
  14. package/dist/framework/framework-construction.error.js +11 -1
  15. package/dist/framework/framework.d.ts +4 -4
  16. package/dist/framework/operation-facade.d.ts +6 -6
  17. package/dist/index.d.ts +6 -3
  18. package/dist/internal.d.ts +1 -2
  19. package/dist/internal.js +1 -0
  20. package/dist/operations/operation-arguments.d.ts +43 -27
  21. package/dist/operations/operation-call.d.ts +2 -2
  22. package/dist/operations/operation-result.d.ts +1 -1
  23. package/dist/policy/policy-admission.js +12 -3
  24. package/dist/policy/policy-after-update.runtime.js +5 -4
  25. package/dist/policy/policy-engine.d.ts +11 -4
  26. package/dist/policy/policy-nested-write.runtime.js +11 -7
  27. package/dist/policy/policy-read.runtime.d.ts +0 -2
  28. package/dist/policy/policy-read.runtime.js +18 -9
  29. package/dist/policy/policy-request.d.ts +7 -3
  30. package/dist/policy/policy-request.js +14 -3
  31. package/dist/policy/policy-session.d.ts +14 -4
  32. package/dist/policy/policy-session.js +12 -11
  33. package/dist/policy/policy-startup.validator.js +3 -5
  34. package/dist/policy/policy-write.runtime.d.ts +7 -0
  35. package/dist/policy/policy-write.runtime.js +23 -8
  36. package/dist/prebuilt/core-version.generated.d.ts +1 -1
  37. package/dist/prebuilt/core-version.generated.js +1 -1
  38. package/dist/prebuilt/prebuilt-changes.d.ts +28 -0
  39. package/dist/prebuilt/prebuilt-changes.js +65 -0
  40. package/dist/prebuilt/prebuilt-contracts.loader.js +11 -56
  41. package/dist/protocol/absent-route.responder.d.ts +4 -4
  42. package/dist/protocol/http-request.decoder.d.ts +2 -2
  43. package/dist/protocol/http-request.reader.d.ts +2 -2
  44. package/dist/protocol/protocol-headers.d.ts +3 -3
  45. package/dist/runtime/computed-read-runtime.js +2 -7
  46. package/dist/runtime/context-executor.runtime.d.ts +2 -2
  47. package/dist/runtime/create-requirement.js +1 -1
  48. package/dist/runtime/diagnostics-reporter.d.ts +5 -5
  49. package/dist/runtime/operation-request.d.ts +9 -9
  50. package/dist/runtime/operation-runtime.d.ts +8 -8
  51. package/dist/runtime/operation-runtime.js +30 -9
  52. package/dist/runtime/owned-execution.registry.d.ts +2 -2
  53. package/dist/runtime/referential-action.d.ts +1 -1
  54. package/dist/transactions/sql-statement.d.ts +2 -2
  55. package/dist/transactions/transaction-plan-assembler.d.ts +2 -2
  56. package/dist/transactions/transaction-plan-validator.d.ts +5 -5
  57. package/dist/transactions/transaction-request.d.ts +8 -8
  58. package/dist/transactions/transaction-runtime.d.ts +2 -2
  59. package/dist/transactions/transaction-runtime.js +12 -7
  60. package/package.json +1 -1
@@ -1,3 +1,4 @@
1
+ import { adapterPrimaryIdentifier } from "../adapters/adapter-identifier.js";
1
2
  import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
3
  import { validateOperationArguments } from "../operations/operation-validator-core.js";
3
4
  import { normalizeOperationScalarValues } from "../runtime/scalar-runtime.js";
@@ -84,11 +85,11 @@ function questionKey(resource, where) {
84
85
  return undefined;
85
86
  }
86
87
  }
87
- function existsOperation(core, resource, where) {
88
+ function existsOperation(core, model, resource, where) {
88
89
  const contract = lookupResource(core, resource);
89
- const [identifier] = contract?.identifiers ?? [];
90
+ const identifier = adapterPrimaryIdentifier(model, resource);
90
91
  const first = contract?.operations.find?.first !== undefined;
91
- return first && identifier !== undefined
92
+ return first && identifier.length > 0
92
93
  ? {
93
94
  resource,
94
95
  family: "find",
@@ -102,16 +103,16 @@ function existsOperation(core, resource, where) {
102
103
  arguments: { where },
103
104
  };
104
105
  }
105
- export function openPolicySession(policy, core, principal, origin, execution) {
106
+ export function openPolicySession(policy, core, model, principal, origin, execution) {
106
107
  const caches = {
107
108
  scopes: new Map(),
108
109
  createGrants: new Map(),
109
110
  fields: new Map(),
110
111
  exists: new WeakMap(),
111
112
  };
112
- return sessionOn(policy, core, principal, origin, execution, caches);
113
+ return sessionOn(policy, core, model, principal, origin, execution, caches);
113
114
  }
114
- function sessionOn(policy, core, principal, origin, execution, caches) {
115
+ function sessionOn(policy, core, model, principal, origin, execution, caches) {
115
116
  const { engine } = policy;
116
117
  const exists = (resource, where) => {
117
118
  const key = questionKey(resource, where);
@@ -124,7 +125,7 @@ function sessionOn(policy, core, principal, origin, execution, caches) {
124
125
  if (known !== undefined) {
125
126
  return known;
126
127
  }
127
- const operation = existsOperation(core, resource, where);
128
+ const operation = existsOperation(core, model, resource, where);
128
129
  const answer = execution.boundary
129
130
  .execute(() => execution.executor.execute(operation))
130
131
  .then((result) => typeof result === "number" ? result > 0 : result != null);
@@ -174,11 +175,11 @@ function sessionOn(policy, core, principal, origin, execution, caches) {
174
175
  return scope;
175
176
  },
176
177
  fields(resource, access) {
177
- const key = `${resource}\u0000${access}`;
178
+ const key = `${resource}\u0000${access.access}\u0000${access.access === "write" ? access.action : ""}`;
178
179
  let fields = caches.fields.get(key);
179
180
  if (fields === undefined) {
180
181
  fields = Promise.resolve()
181
- .then(() => engine.fieldsOf({ principal, origin, resource, access }))
182
+ .then(() => engine.fieldsOf({ principal, origin, resource, ...access }))
182
183
  .then((answer) => fieldsAnswer(core, resource, answer));
183
184
  caches.fields.set(key, fields);
184
185
  }
@@ -211,10 +212,10 @@ function sessionOn(policy, core, principal, origin, execution, caches) {
211
212
  policy.afterChecks[resource]?.includes(action) === true);
212
213
  },
213
214
  on(next) {
214
- return sessionOn(policy, core, principal, origin, next, caches);
215
+ return sessionOn(policy, core, model, principal, origin, next, caches);
215
216
  },
216
217
  renewed() {
217
- return sessionOn(policy, core, principal, origin, execution, {
218
+ return sessionOn(policy, core, model, principal, origin, execution, {
218
219
  ...caches,
219
220
  exists: new WeakMap(),
220
221
  });
@@ -9,12 +9,12 @@ function governedDiagnostics(core, governed) {
9
9
  const path = `policy.engine.governed.${resourceName}`;
10
10
  const resource = lookupResource(core, resourceName);
11
11
  if (resource === undefined) {
12
- diagnostics.push(invalid(path, `${path}: "${resourceName}" is no Resource of the Core Contract`));
12
+ diagnostics.push(invalid(path, `"${resourceName}" is no Resource of the Core Contract`));
13
13
  continue;
14
14
  }
15
15
  for (const name of names) {
16
16
  if (lookupField(resource, name) === undefined) {
17
- diagnostics.push(invalid(path, `${path}: "${name}" is no field or relation of Resource "${resourceName}" in the Core Contract`));
17
+ diagnostics.push(invalid(path, `"${name}" is no field or relation of Resource "${resourceName}" in the Core Contract`));
18
18
  }
19
19
  }
20
20
  }
@@ -24,9 +24,7 @@ function afterCheckDiagnostics(core, afterChecks) {
24
24
  return Object.keys(afterChecks).flatMap((resourceName) => {
25
25
  const path = `policy.engine.afterChecks.${resourceName}`;
26
26
  return lookupResource(core, resourceName) === undefined
27
- ? [
28
- invalid(path, `${path}: "${resourceName}" is no Resource of the Core Contract`),
29
- ]
27
+ ? [invalid(path, `"${resourceName}" is no Resource of the Core Contract`)]
30
28
  : [];
31
29
  });
32
30
  }
@@ -9,6 +9,13 @@ import type { PolicySession } from "./policy-session.js";
9
9
  export type PolicyWrite = PolicyRead & {
10
10
  /** A unique write that matched nothing: `A4002` for a row the caller can read, `A2003` otherwise. */
11
11
  readonly miss?: () => Promise<AvOperationFailureResponse>;
12
+ /**
13
+ * A unique update holding nested writes whose adapter call failed: the miss's
14
+ * answer when its row is outside the scopes (an adapter may fail the nested
15
+ * write there instead of answering the miss), `undefined` when the failure
16
+ * stands.
17
+ */
18
+ readonly failedMiss?: () => Promise<AvOperationFailureResponse | undefined>;
12
19
  };
13
20
  /**
14
21
  * Whether a write the policy checks needs an interactive transaction to roll
@@ -1,3 +1,4 @@
1
+ import { adapterPrimaryIdentifier } from "../adapters/adapter-identifier.js";
1
2
  import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
3
  import { uniqueMissFailure } from "../runtime/outcome-mapper.js";
3
4
  import { frozenCopy } from "../runtime/readonly-value.js";
@@ -5,7 +6,7 @@ import { policyRefusal } from "./policy-admission.js";
5
6
  import { afterCheckFields, afterUpdate, checkChanged, } from "./policy-after-update.runtime.js";
6
7
  import { allOf, everyOf, noneOf, someOf, whereOf, } from "./policy-condition.js";
7
8
  import { planNestedWrites, writesNested, } from "./policy-nested-write.runtime.js";
8
- import { enforceReadPolicy, identifiedRows, identifierOf, returnedRowChecks, } from "./policy-read.runtime.js";
9
+ import { enforceReadPolicy, identifiedRows, returnedRowChecks, } from "./policy-read.runtime.js";
9
10
  const UNVERIFIABLE = "cannot be verified on this database: it has no interactive transaction to roll the write back in";
10
11
  function isRecord(value) {
11
12
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -52,7 +53,7 @@ async function checkCreated(session, core, model, resource, grants, created) {
52
53
  if (created.length === 0) {
53
54
  return undefined;
54
55
  }
55
- const these = identifiedRows(core, identifierOf(model, resource), resource, created);
56
+ const these = identifiedRows(core, adapterPrimaryIdentifier(model, resource), resource, created);
56
57
  const missed = allOf(these, someOf([...grants.values()].map(noneOf)));
57
58
  if (missed !== false &&
58
59
  (await session.renewed().exists(resource, whereOf(missed)))) {
@@ -72,7 +73,7 @@ function uncheckableCreate(model, request, grants, inTransaction) {
72
73
  return refused(`${what}, which ${UNVERIFIABLE}.`);
73
74
  }
74
75
  if (request.variant === "count" ||
75
- identifierOf(model, request.resource).length === 0) {
76
+ adapterPrimaryIdentifier(model, request.resource).length === 0) {
76
77
  return refused(`${what}, and this create does not return the rows it creates to check by.`);
77
78
  }
78
79
  return undefined;
@@ -244,7 +245,8 @@ async function enforceScopedWrite(session, core, model, request, plan, adapterAr
244
245
  if (changes !== undefined && !inTransaction) {
245
246
  return refused(`The policy checks this update on Resource "${resource}" after it runs (${changes.after ? "its grant's after condition" : "whether it moves a row out of what the caller may read"}), which ${UNVERIFIABLE}.`);
246
247
  }
247
- if (changes !== undefined && identifierOf(model, resource).length === 0) {
248
+ if (changes !== undefined &&
249
+ adapterPrimaryIdentifier(model, resource).length === 0) {
248
250
  return refused(`The policy checks this update on Resource "${resource}" after it runs, and the Resource has no identifier to find the changed rows by.`);
249
251
  }
250
252
  const nested = action === "update"
@@ -259,6 +261,19 @@ async function enforceScopedWrite(session, core, model, request, plan, adapterAr
259
261
  const miss = request.variant === "unique"
260
262
  ? missOf(session, request, args.where)
261
263
  : undefined;
264
+ const failedMiss = miss !== undefined && nested !== undefined
265
+ ? async () => {
266
+ const reach = allOf(isRecord(args.where) ? args.where : true, scope);
267
+ return reach !== false &&
268
+ (await session.renewed().exists(resource, whereOf(reach)))
269
+ ? undefined
270
+ : miss();
271
+ }
272
+ : undefined;
273
+ const misses = {
274
+ ...(miss === undefined ? {} : { miss }),
275
+ ...(failedMiss === undefined ? {} : { failedMiss }),
276
+ };
262
277
  const carried = changes?.after === true
263
278
  ? afterCheckFields(core, model, resource)
264
279
  : undefined;
@@ -272,7 +287,7 @@ async function enforceScopedWrite(session, core, model, request, plan, adapterAr
272
287
  return blocked;
273
288
  }
274
289
  if (read.kind !== "run") {
275
- return miss === undefined ? read : { ...read, miss };
290
+ return { ...read, ...misses };
276
291
  }
277
292
  let run = read;
278
293
  if (action === "delete" && run.checks.root.length > 0) {
@@ -294,7 +309,7 @@ async function enforceScopedWrite(session, core, model, request, plan, adapterAr
294
309
  ...runArgs,
295
310
  select: changes.after
296
311
  ? [...afterCheckFields(core, model, resource)]
297
- : [...identifierOf(model, resource)],
312
+ : [...adapterPrimaryIdentifier(model, resource)],
298
313
  },
299
314
  };
300
315
  run = withChangedRows(asMany, (data) => checkChanged(session, core, model, resource, changes, rowsOf(data), changes.after));
@@ -305,7 +320,7 @@ async function enforceScopedWrite(session, core, model, request, plan, adapterAr
305
320
  }
306
321
  if (counted) {
307
322
  const runArgs = isRecord(run.arguments) ? run.arguments : {};
308
- const identifier = identifierOf(model, resource);
323
+ const identifier = adapterPrimaryIdentifier(model, resource);
309
324
  changed = await session.rows(resource, isRecord(runArgs.where) ? runArgs.where : {}, identifier);
310
325
  if (changed.length === 0) {
311
326
  return { kind: "empty", data: 0 };
@@ -329,7 +344,7 @@ async function enforceScopedWrite(session, core, model, request, plan, adapterAr
329
344
  run = withNestedWrites(run, "data", nested);
330
345
  }
331
346
  run = withoutCarried(run, args, carried);
332
- return miss === undefined ? run : { ...run, miss };
347
+ return { ...run, ...misses };
333
348
  }
334
349
  async function enforceUpsert(session, core, model, request, plan, adapterArguments, args, inTransaction) {
335
350
  const resource = request.resource;
@@ -1,2 +1,2 @@
1
1
  /** The version of this `@aventara/core`. */
2
- export declare const CORE_VERSION = "1.0.0-rc.4";
2
+ export declare const CORE_VERSION = "1.0.0-rc.8";
@@ -1 +1 @@
1
- export const CORE_VERSION = "1.0.0-rc.4";
1
+ export const CORE_VERSION = "1.0.0-rc.8";
@@ -0,0 +1,28 @@
1
+ import type { PrebuiltPartFingerprints } from "./prebuilt-inputs.fingerprint.js";
2
+ /** `a`, `a and b`, `a, b and c`. */
3
+ export declare function listedNames(names: readonly string[]): string;
4
+ /** What a prebuilt file was written in, by and for. */
5
+ export type PrebuiltHeader = {
6
+ readonly format: number;
7
+ readonly core: string;
8
+ readonly protocol: number;
9
+ };
10
+ /**
11
+ * Each way a stored file's header differs from `current`, in the order the
12
+ * runtime checks them: the file format, the core version, the protocol.
13
+ */
14
+ export declare function prebuiltHeaderChanges(stored: unknown, current: PrebuiltHeader): readonly string[];
15
+ /**
16
+ * Each way a stored file's part fingerprints differ from `current`: the
17
+ * Resources whose inputs changed, the new ones, the gone ones, and, when
18
+ * `sameHeader`, the inputs that belong to no single Resource.
19
+ */
20
+ export declare function prebuiltInputChanges(stored: unknown, current: PrebuiltPartFingerprints, sameHeader?: boolean): readonly string[];
21
+ /**
22
+ * What differs between a stored prebuilt file and `current`, one clause per
23
+ * difference: its header's, then its inputs' (`… since it was written`).
24
+ * Empty when the two record the same header and inputs.
25
+ */
26
+ export declare function prebuiltFileChanges(stored: unknown, current: PrebuiltHeader & {
27
+ readonly fingerprints: PrebuiltPartFingerprints;
28
+ }): readonly string[];
@@ -0,0 +1,65 @@
1
+ function isRecord(value) {
2
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3
+ }
4
+ export function listedNames(names) {
5
+ return names.length < 2
6
+ ? names.join("")
7
+ : `${names.slice(0, -1).join(", ")} and ${names.at(-1)}`;
8
+ }
9
+ export function prebuiltHeaderChanges(stored, current) {
10
+ const header = isRecord(stored) ? stored : {};
11
+ const changes = [];
12
+ if (header.format !== current.format) {
13
+ changes.push(`it is written in file format ${String(header.format)}, and this @aventara/core reads format ${current.format}`);
14
+ }
15
+ if (header.core !== current.core) {
16
+ changes.push(`it was built by @aventara/core ${String(header.core)}, and this is ${current.core}`);
17
+ }
18
+ if (header.protocol !== current.protocol) {
19
+ changes.push(`it was built for protocol version ${String(header.protocol)}, and this @aventara/core speaks version ${current.protocol}`);
20
+ }
21
+ return changes;
22
+ }
23
+ export function prebuiltInputChanges(stored, current, sameHeader = true) {
24
+ const storedResources = isRecord(stored) ? stored.resources : undefined;
25
+ const before = isRecord(storedResources) ? storedResources : {};
26
+ const changed = [];
27
+ const added = [];
28
+ const removed = [];
29
+ for (const [name, fingerprint] of Object.entries(current.resources)) {
30
+ if (!Object.hasOwn(before, name)) {
31
+ added.push(name);
32
+ }
33
+ else if (before[name] !== fingerprint) {
34
+ changed.push(name);
35
+ }
36
+ }
37
+ for (const name of Object.keys(before)) {
38
+ if (!Object.hasOwn(current.resources, name)) {
39
+ removed.push(name);
40
+ }
41
+ }
42
+ const resources = (names) => `${names.length === 1 ? "Resource" : "Resources"} ${listedNames(names)}`;
43
+ const be = (names) => (names.length === 1 ? "is" : "are");
44
+ const changes = [];
45
+ if (changed.length > 0) {
46
+ changes.push(`${resources(changed)} changed`);
47
+ }
48
+ if (added.length > 0) {
49
+ changes.push(`${resources(added)} ${be(added)} new`);
50
+ }
51
+ if (removed.length > 0) {
52
+ changes.push(`${resources(removed)} ${be(removed)} gone`);
53
+ }
54
+ if (sameHeader && (!isRecord(stored) || stored.shared !== current.shared)) {
55
+ changes.push("the configuration or model outside the Resources changed");
56
+ }
57
+ return changes;
58
+ }
59
+ export function prebuiltFileChanges(stored, current) {
60
+ const header = prebuiltHeaderChanges(stored, current);
61
+ const inputs = prebuiltInputChanges(isRecord(stored) ? stored.fingerprints : undefined, current.fingerprints, header.length === 0);
62
+ return inputs.length === 0
63
+ ? header
64
+ : [...header, `${listedNames(inputs)} since it was written`];
65
+ }
@@ -3,53 +3,18 @@ import { recordCanonicalContractText } from "../contracts/contract-canonicalizer
3
3
  import { AVENTARA_PROTOCOL_VERSION } from "../contracts/contract-protocol.js";
4
4
  import { emitFrameworkWarning } from "../runtime/framework-warning.emitter.js";
5
5
  import { CORE_VERSION } from "./core-version.generated.js";
6
+ import { listedNames, prebuiltHeaderChanges, prebuiltInputChanges, } from "./prebuilt-changes.js";
6
7
  import { PREBUILT_FORMAT } from "./prebuilt-contracts.js";
7
8
  import { prebuiltInputsFingerprint, prebuiltPartFingerprints, } from "./prebuilt-inputs.fingerprint.js";
8
9
  export const PREBUILT_STALE_WARNING = "AVENTARA_PREBUILT_STALE";
9
10
  function isRecord(value) {
10
11
  return value !== null && typeof value === "object" && !Array.isArray(value);
11
12
  }
12
- function listed(names) {
13
- return names.length < 2
14
- ? names.join("")
15
- : `${names.slice(0, -1).join(", ")} and ${names.at(-1)}`;
16
- }
17
13
  async function changedInputs(stored, model, config) {
18
- const live = await prebuiltPartFingerprints(model, config);
19
- const storedResources = isRecord(stored) ? stored.resources : undefined;
20
- const before = isRecord(storedResources) ? storedResources : {};
21
- const changed = [];
22
- const added = [];
23
- const removed = [];
24
- for (const [name, fingerprint] of Object.entries(live.resources)) {
25
- if (!Object.hasOwn(before, name)) {
26
- added.push(name);
27
- }
28
- else if (before[name] !== fingerprint) {
29
- changed.push(name);
30
- }
31
- }
32
- for (const name of Object.keys(before)) {
33
- if (!Object.hasOwn(live.resources, name)) {
34
- removed.push(name);
35
- }
36
- }
37
- const parts = [];
38
- if (changed.length > 0) {
39
- parts.push(`${changed.length === 1 ? "Resource" : "Resources"} ${listed(changed)} changed`);
40
- }
41
- if (added.length > 0) {
42
- parts.push(`${added.length === 1 ? "Resource" : "Resources"} ${listed(added)} ${added.length === 1 ? "is" : "are"} new`);
43
- }
44
- if (removed.length > 0) {
45
- parts.push(`${removed.length === 1 ? "Resource" : "Resources"} ${listed(removed)} ${removed.length === 1 ? "is" : "are"} gone`);
46
- }
47
- if (!isRecord(stored) || stored.shared !== live.shared) {
48
- parts.push("the configuration or model outside the Resources changed");
49
- }
50
- return parts.length === 0
14
+ const changes = prebuiltInputChanges(stored, await prebuiltPartFingerprints(model, config));
15
+ return changes.length === 0
51
16
  ? "its fingerprint does not match the configuration and model"
52
- : `${listed(parts)} since it was built`;
17
+ : `${listedNames(changes)} since it was built`;
53
18
  }
54
19
  function textAt(record, key) {
55
20
  const value = Object.hasOwn(record, key) ? record[key] : undefined;
@@ -86,23 +51,13 @@ export async function loadPrebuiltContracts(prebuilt, model, config, resolved) {
86
51
  if (!isRecord(prebuilt)) {
87
52
  return { ok: false, reason: "it is not a prebuilt Contracts file" };
88
53
  }
89
- if (prebuilt.format !== PREBUILT_FORMAT) {
90
- return {
91
- ok: false,
92
- reason: `it is written in file format ${String(prebuilt.format)}, and this @aventara/core reads format ${PREBUILT_FORMAT}`,
93
- };
94
- }
95
- if (prebuilt.core !== CORE_VERSION) {
96
- return {
97
- ok: false,
98
- reason: `it was built by @aventara/core ${String(prebuilt.core)}, and this is ${CORE_VERSION}`,
99
- };
100
- }
101
- if (prebuilt.protocol !== AVENTARA_PROTOCOL_VERSION) {
102
- return {
103
- ok: false,
104
- reason: `it was built for protocol version ${String(prebuilt.protocol)}, and this @aventara/core speaks version ${AVENTARA_PROTOCOL_VERSION}`,
105
- };
54
+ const [header] = prebuiltHeaderChanges(prebuilt, {
55
+ format: PREBUILT_FORMAT,
56
+ core: CORE_VERSION,
57
+ protocol: AVENTARA_PROTOCOL_VERSION,
58
+ });
59
+ if (header !== undefined) {
60
+ return { ok: false, reason: header };
106
61
  }
107
62
  if ((await prebuiltInputsFingerprint(model, config)) !== prebuilt.fingerprint) {
108
63
  return {
@@ -2,7 +2,7 @@ import type { AvContracts } from "../compiler/contract.compiler.js";
2
2
  import type { RemoteRequestOrigin } from "../config/config-layer.js";
3
3
  import { type AvOperationIdentity } from "../operations/operation-identity.js";
4
4
  import { type AvDiagnosticsSink } from "../runtime/diagnostics-reporter.js";
5
- import type { ClientProtocolIdentity } from "../runtime/operation-request.js";
5
+ import type { AvRequestProtocol } from "../runtime/operation-request.js";
6
6
  import { type AvOperationFailureResponse } from "../runtime/operation-response.js";
7
7
  import type { AvProtocolRequest } from "./http-request.decoder.js";
8
8
  import { type ReadRequest } from "./http-request.reader.js";
@@ -36,7 +36,7 @@ export type OperationRouteResolution = {
36
36
  * is a standard operation the Resource advertises, read through
37
37
  * `isOperationVariantAvailable` alone.
38
38
  */
39
- export declare function resolveOperationRoute(contracts: AvContracts, protocol: ClientProtocolIdentity, route: OperationRouteSegments, origin?: RemoteRequestOrigin): OperationRouteResolution;
39
+ export declare function resolveOperationRoute(contracts: AvContracts, protocol: AvRequestProtocol, route: OperationRouteSegments, origin?: RemoteRequestOrigin): OperationRouteResolution;
40
40
  /**
41
41
  * The `/_transactions` route under one client protocol identity: version → hash → the
42
42
  * ClientContract's transaction capability. The route exists only when that capability
@@ -44,14 +44,14 @@ export declare function resolveOperationRoute(contracts: AvContracts, protocol:
44
44
  * it — and is otherwise absent with core's own refusal of a plan. `undefined` when the
45
45
  * route is there.
46
46
  */
47
- export declare function transactionsRouteFailure(contracts: AvContracts, protocol: ClientProtocolIdentity, origin?: RemoteRequestOrigin): AvOperationFailureResponse | undefined;
47
+ export declare function transactionsRouteFailure(contracts: AvContracts, protocol: AvRequestProtocol, origin?: RemoteRequestOrigin): AvOperationFailureResponse | undefined;
48
48
  /**
49
49
  * What a route's checks before its body resolve to: the route a request
50
50
  * reaches, or the framework response that answers it instead.
51
51
  */
52
52
  type RouteCheck<Route> = ({
53
53
  readonly ok: true;
54
- readonly protocol: ClientProtocolIdentity;
54
+ readonly protocol: AvRequestProtocol;
55
55
  } & Route) | {
56
56
  readonly ok: false;
57
57
  readonly response: AvProtocolResponse;
@@ -1,7 +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 { RemoteOperationRequest } from "../runtime/operation-request.js";
4
- import type { AgentTransactionRequest, ClientTransactionRequest } from "../transactions/transaction-request.js";
4
+ import type { AvAgentTransactionRequest, AvClientTransactionRequest } from "../transactions/transaction-request.js";
5
5
  import type { AvProtocolResponse } from "./http-response.encoder.js";
6
6
  /** One HTTP request as a host hands it to the protocol. */
7
7
  export type AvProtocolRequest = {
@@ -56,7 +56,7 @@ export type DecodedOperationRequest = Extract<DecodedOperation, {
56
56
  ok: true;
57
57
  }>;
58
58
  /** What `protocol.decodeTransaction` answers. */
59
- export type DecodedTransaction = Decoded<ClientTransactionRequest | AgentTransactionRequest>;
59
+ export type DecodedTransaction = Decoded<AvClientTransactionRequest | AvAgentTransactionRequest>;
60
60
  /**
61
61
  * `protocol.decodeOperation(request)` — one operation route's HTTP request as
62
62
  * the client-origin request `framework.execute` takes, or its answer.
@@ -1,4 +1,4 @@
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";
@@ -25,7 +25,7 @@ export type ReadRequest = {
25
25
  /** Adopted from `Aventara-Request-Id`, else minted. */
26
26
  readonly requestId: string;
27
27
  /** `undefined` when either identity header is absent (`A2000`). */
28
- readonly protocol: ClientProtocolIdentity | undefined;
28
+ readonly protocol: AvRequestProtocol | undefined;
29
29
  };
30
30
  /** What a value that is not an `AvProtocolRequest` reads as. */
31
31
  export type UnreadableRequest = {
@@ -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}
@@ -1,3 +1,4 @@
1
+ import { adapterPrimaryIdentifier } from "../adapters/adapter-identifier.js";
1
2
  import { lookupField, lookupResource } from "../contracts/contract-lookup.js";
2
3
  import { AvComputedValueError } from "./computed-value.error.js";
3
4
  import { frozenCopy } from "./readonly-value.js";
@@ -37,12 +38,6 @@ function appendUniqueProjection(values, value) {
37
38
  values.push(value);
38
39
  }
39
40
  }
40
- function adapterIdentifier(model, resource) {
41
- const resources = model.resources;
42
- return ((Object.hasOwn(resources, resource)
43
- ? resources[resource]?.identifiers?.[0]
44
- : undefined) ?? []);
45
- }
46
41
  function supportsProjection(request) {
47
42
  if (request.family === "upsert") {
48
43
  return true;
@@ -59,7 +54,7 @@ function addScalarProjection(core, model, active, compute, resourceName, fieldNa
59
54
  if (stage !== undefined) {
60
55
  appendUnique(computed, fieldName);
61
56
  if (stage.dependsOn.length === 0) {
62
- for (const member of adapterIdentifier(model, resourceName)) {
57
+ for (const member of adapterPrimaryIdentifier(model, resourceName)) {
63
58
  appendUniqueProjection(adapterSelect, member);
64
59
  }
65
60
  }
@@ -7,7 +7,7 @@ import type { AvOperationFamily } from "../operations/operation-identity.js";
7
7
  import { type AvDiagnosticsSink } from "./diagnostics-reporter.js";
8
8
  import type { AvComputeContext } from "./field-compute.js";
9
9
  import type { MisuseReporter } from "./misuse-reporter.js";
10
- import type { ApplicationOperationRequest } from "./operation-request.js";
10
+ import type { AvApplicationOperationRequest } from "./operation-request.js";
11
11
  import type { AvOperationResponse } from "./operation-response.js";
12
12
  import type { AvContext, AvTransactionContext, AvTransportContext } from "./pipeline.js";
13
13
  import type { AvState } from "./request-state.js";
@@ -35,7 +35,7 @@ export type ContextFacts = {
35
35
  readonly $args: unknown;
36
36
  };
37
37
  /** Runs one raw application-origin call in `transaction`, or standalone. Total. */
38
- export type RawOperationRunner<M extends AvAdapterModel> = (request: ApplicationOperationRequest, transaction: AvAdapterTransactionExecutor<M> | undefined) => Promise<AvOperationResponse>;
38
+ export type RawOperationRunner<M extends AvAdapterModel> = (request: AvApplicationOperationRequest, transaction: AvAdapterTransactionExecutor<M> | undefined) => Promise<AvOperationResponse>;
39
39
  export type ContextExecutorDependencies<M extends AvAdapterModel> = {
40
40
  /** The model, as construction read it once: the ctx's Resources. */
41
41
  readonly model: M;
@@ -13,7 +13,7 @@ function edgesOf(table, resource) {
13
13
  return Array.isArray(listed) ? listed : [];
14
14
  }
15
15
  function referencesOf(edge) {
16
- return Array.isArray(edge.references) ? edge.references : [];
16
+ return Array.isArray(edge.referenceFields) ? edge.referenceFields : [];
17
17
  }
18
18
  function creatableScalar(contract, resource, field) {
19
19
  const found = lookupField(lookupResource(contract, resource), field);
@@ -1,7 +1,7 @@
1
1
  import type { AvRequestOrigin } from "../config/config-layer.js";
2
2
  import type { AvOperationFamily } from "../operations/operation-identity.js";
3
- import type { FrameworkTransactionRequest } from "../transactions/transaction-request.js";
4
- import type { FrameworkOperationRequest } from "./operation-request.js";
3
+ import type { AvTransactionRequest } from "../transactions/transaction-request.js";
4
+ import type { AvOperationRequest } from "./operation-request.js";
5
5
  import { type AvOperationErrorCode, type AvOperationFailureResponse } from "./operation-response.js";
6
6
  /**
7
7
  * One unplanned failure of an operation: the raw error, the code the caller
@@ -100,14 +100,14 @@ export declare function diagnosticsSinkOf(framework: object): AvDiagnosticsSink
100
100
  * Binds the configured sink to one operation request. The sink is not awaited,
101
101
  * and nothing it throws or rejects with reaches the response.
102
102
  */
103
- export declare function createDiagnosticsReporter(sink: AvDiagnosticsSink | undefined, request: FrameworkOperationRequest, operation?: number): DiagnosticsReporter;
103
+ export declare function createDiagnosticsReporter(sink: AvDiagnosticsSink | undefined, request: AvOperationRequest, operation?: number): DiagnosticsReporter;
104
104
  /** The diagnostics channel of one transaction request. */
105
105
  export type TransactionDiagnosticsChannel = {
106
106
  /** A plan-level report; `operation` attributes it to a recorded failing index. */
107
107
  readonly transaction: (operation?: number) => DiagnosticsReporter;
108
108
  /** A report carrying one plan operation's own identity and index. */
109
- readonly operation: (request: FrameworkOperationRequest, operation: number) => DiagnosticsReporter;
109
+ readonly operation: (request: AvOperationRequest, operation: number) => DiagnosticsReporter;
110
110
  };
111
111
  /** Binds the configured sink to one transaction request and its plan operations. */
112
- export declare function createTransactionDiagnosticsChannel(sink: AvDiagnosticsSink | undefined, request: FrameworkTransactionRequest): TransactionDiagnosticsChannel;
112
+ export declare function createTransactionDiagnosticsChannel(sink: AvDiagnosticsSink | undefined, request: AvTransactionRequest): TransactionDiagnosticsChannel;
113
113
  export {};
@@ -6,7 +6,7 @@ import type { AvState } from "./request-state.js";
6
6
  * The protocol version and Contract hash a remote caller says it was built for:
7
7
  * the Client Contract's for a client, the Agent Contract's for an agent.
8
8
  */
9
- export type ClientProtocolIdentity = {
9
+ export type AvRequestProtocol = {
10
10
  readonly version: number;
11
11
  readonly hash: string;
12
12
  };
@@ -21,7 +21,7 @@ type RuntimeOperationBase = AvOperationIdentity & {
21
21
  readonly state?: AvState;
22
22
  };
23
23
  /** An in-process request, run under the Application Contract. */
24
- export type ApplicationOperationRequest = RuntimeOperationBase & {
24
+ export type AvApplicationOperationRequest = RuntimeOperationBase & {
25
25
  readonly origin: "application";
26
26
  readonly protocol?: never;
27
27
  readonly transport?: never;
@@ -30,24 +30,24 @@ export type ApplicationOperationRequest = RuntimeOperationBase & {
30
30
  * A remote request, run under the Client Contract; `protocol` is the identity
31
31
  * the client sent.
32
32
  */
33
- export type ClientOperationRequest = RuntimeOperationBase & {
33
+ export type AvClientOperationRequest = RuntimeOperationBase & {
34
34
  readonly origin: "client";
35
- readonly protocol: ClientProtocolIdentity;
35
+ readonly protocol: AvRequestProtocol;
36
36
  readonly transport?: AvTransportContext;
37
37
  };
38
38
  /**
39
39
  * An AI agent's request, run under the Agent Contract; `protocol` is the
40
40
  * identity of the Agent Contract the caller (an MCP server) was built from.
41
41
  */
42
- export type AgentOperationRequest = RuntimeOperationBase & {
42
+ export type AvAgentOperationRequest = RuntimeOperationBase & {
43
43
  readonly origin: "agent";
44
- readonly protocol: ClientProtocolIdentity;
44
+ readonly protocol: AvRequestProtocol;
45
45
  readonly transport?: AvTransportContext;
46
46
  };
47
47
  /** A request from outside the server: a client's or an agent's. */
48
- export type RemoteOperationRequest = ClientOperationRequest | AgentOperationRequest;
48
+ export type RemoteOperationRequest = AvClientOperationRequest | AvAgentOperationRequest;
49
49
  /** One operation request, as `framework.execute` takes it. */
50
- export type FrameworkOperationRequest = ApplicationOperationRequest | ClientOperationRequest | AgentOperationRequest;
50
+ export type AvOperationRequest = AvApplicationOperationRequest | AvClientOperationRequest | AvAgentOperationRequest;
51
51
  type WithoutArguments<Request> = Request extends unknown ? Omit<Request, "arguments"> : never;
52
52
  /**
53
53
  * A request as every stage after the Framework Validation Layer sees it:
@@ -57,7 +57,7 @@ type WithoutArguments<Request> = Request extends unknown ? Omit<Request, "argume
57
57
  * unreachable by type. Distributive, so the origin and family/variant
58
58
  * correlations survive the omission.
59
59
  */
60
- export type OperationExecutionRequest = WithoutArguments<FrameworkOperationRequest>;
60
+ export type OperationExecutionRequest = WithoutArguments<AvOperationRequest>;
61
61
  /**
62
62
  * A request whose stages run: its `state` settled once, the seed or the `{}`
63
63
  * the runtime made for it, so every stage is told the same object.