keri-ts 2.0.1 → 2.1.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 (229) hide show
  1. package/esm/keri/npm/src/acdc/chaining.js +223 -89
  2. package/esm/keri/npm/src/acdc/observing.js +2 -2
  3. package/esm/keri/npm/src/acdc/regbasing.js +20 -29
  4. package/esm/keri/npm/src/acdc/regengine.js +4 -6
  5. package/esm/keri/npm/src/acdc/registering.js +13 -10
  6. package/esm/keri/npm/src/acdc/registraring.js +4 -9
  7. package/esm/keri/npm/src/acdc/salting.js +127 -25
  8. package/esm/keri/npm/src/acdc/unblinding.js +2 -4
  9. package/esm/keri/npm/src/app/bootstrap/oobiery.js +1 -1
  10. package/esm/keri/npm/src/app/credentials/root-replicating.js +123 -0
  11. package/esm/keri/npm/src/app/credentials/verifying.js +12 -3
  12. package/esm/keri/npm/src/app/delivery/forwarding.js +49 -7
  13. package/esm/keri/npm/src/app/exchanges/exchanging.js +11 -12
  14. package/esm/keri/npm/src/app/identity/configing.js +17 -43
  15. package/esm/keri/npm/src/app/identity/habbing.js +54 -35
  16. package/esm/keri/npm/src/app/identity/keeping.js +1 -1
  17. package/esm/keri/npm/src/app/identity/lmdb-habery.js +12 -0
  18. package/esm/keri/npm/src/app/ipex/ipex-graph.js +7 -70
  19. package/esm/keri/npm/src/app/ipex/ipex-grouping.js +8 -5
  20. package/esm/keri/npm/src/app/ipex/ipex-v2.js +21 -5
  21. package/esm/keri/npm/src/app/ipex/ipexing.js +1 -1
  22. package/esm/keri/npm/src/app/mailbox/mailboxing.js +5 -9
  23. package/esm/keri/npm/src/app/multisig/group-members.js +14 -0
  24. package/esm/keri/npm/src/app/multisig/grouping.js +4 -3
  25. package/esm/keri/npm/src/app/multisig/multisig-workflows.js +7 -2
  26. package/esm/keri/npm/src/app/notifications/notifying.js +5 -9
  27. package/esm/keri/npm/src/app/protocol/protocol-processing.js +35 -3
  28. package/esm/keri/npm/src/app/queries/witness-inquisitor.js +2 -2
  29. package/esm/keri/npm/src/app/runtime/agent-runtime.js +7 -10
  30. package/esm/keri/npm/src/app/transport/byte-source.js +6 -42
  31. package/esm/keri/npm/src/app/transport/cesr-egress.js +77 -13
  32. package/esm/keri/npm/src/app/transport/file-bytes.js +41 -0
  33. package/esm/keri/npm/src/app/transport/http-messenger.js +14 -9
  34. package/esm/keri/npm/src/app/transport/message-source.js +1 -1
  35. package/esm/keri/npm/src/app/transport/messengering.js +3 -4
  36. package/esm/keri/npm/src/app/transport/node-http-client.js +21 -0
  37. package/esm/keri/npm/src/app/transport/tcp-dialer.js +14 -0
  38. package/esm/keri/npm/src/app/witness/receipt-client.js +2 -2
  39. package/esm/keri/npm/src/cli/common/context.js +2 -2
  40. package/esm/keri/npm/src/cli/common/existing.js +3 -5
  41. package/esm/keri/npm/src/cli/credentials/ipex.js +2 -1
  42. package/esm/keri/npm/src/cli/endpoints/oobi-clean.js +4 -3
  43. package/esm/keri/npm/src/cli/endpoints/oobi.js +2 -2
  44. package/esm/keri/npm/src/cli/identity/challenge.js +2 -2
  45. package/esm/keri/npm/src/cli/identity/incept.js +2 -2
  46. package/esm/keri/npm/src/cli/identity/init.js +4 -3
  47. package/esm/keri/npm/src/cli/identity/interact.js +2 -2
  48. package/esm/keri/npm/src/cli/identity/rotate.js +2 -2
  49. package/esm/keri/npm/src/cli/messaging/exchange.js +2 -2
  50. package/esm/keri/npm/src/cli/messaging/multisig.js +61 -3
  51. package/esm/keri/npm/src/cli/tools/annotate.js +2 -1
  52. package/esm/keri/npm/src/cli/tools/benchmark.js +2 -1
  53. package/esm/keri/npm/src/cli/tools/db-dump.js +1 -4
  54. package/esm/keri/npm/src/core/bytes.js +9 -0
  55. package/esm/keri/npm/src/core/kel/delegation-ancestry.js +92 -0
  56. package/esm/keri/npm/src/core/kel/eventing.js +1 -2
  57. package/esm/keri/npm/src/core/kel/kever.js +11 -9
  58. package/esm/keri/npm/src/core/mailbox/kram-policy.js +2 -3
  59. package/esm/keri/npm/src/core/mailbox/kram-pruning.js +15 -22
  60. package/esm/keri/npm/src/core/mailbox/kram-staging.js +2 -2
  61. package/esm/keri/npm/src/core/routing.js +2 -2
  62. package/esm/keri/npm/src/db/basing.js +149 -203
  63. package/esm/keri/npm/src/db/core/dber.js +1062 -0
  64. package/esm/keri/npm/src/db/core/index.js +4 -2
  65. package/esm/keri/npm/src/db/core/lmdb-opener.js +30 -0
  66. package/esm/keri/npm/src/db/core/lmdber.js +199 -1067
  67. package/esm/keri/npm/src/db/core/memstore.js +532 -0
  68. package/esm/keri/npm/src/db/core/path-manager.js +109 -223
  69. package/esm/keri/npm/src/db/core/store-owner.js +104 -0
  70. package/esm/keri/npm/src/db/core/webdber.js +252 -0
  71. package/esm/keri/npm/src/db/escrowing.js +2 -2
  72. package/esm/keri/npm/src/db/exchange/exchange-nests.js +3 -2
  73. package/esm/keri/npm/src/db/keeping.js +27 -121
  74. package/esm/keri/npm/src/db/koming.js +1 -1
  75. package/esm/keri/npm/src/db/lmdb-stores.js +68 -0
  76. package/esm/keri/npm/src/db/lmdb.js +6 -0
  77. package/esm/keri/npm/src/db/mailbox/mailboxing.js +12 -65
  78. package/esm/keri/npm/src/db/noting.js +11 -55
  79. package/esm/keri/npm/src/db/reger.js +43 -105
  80. package/esm/keri/npm/src/db/replay/witness-replay.js +2 -20
  81. package/esm/keri/npm/src/db/subing.js +1 -1
  82. package/esm/keri/npm/src/npm/db-lmdb.js +3 -0
  83. package/esm/keri/npm/src/npm/runtime-node.js +3 -0
  84. package/esm/keri/npm/src/runtime/index.js +9 -10
  85. package/esm/keri/npm/src/runtime/node.js +14 -0
  86. package/esm/keri/npm/src/vdr/eventing.js +1 -1
  87. package/esm/keri/npm/src/vdr/tel-publication.js +3 -3
  88. package/esm/keri/npm/src/version.js +2 -2
  89. package/package.json +11 -4
  90. package/types/acdc/chaining.d.ts +56 -6
  91. package/types/acdc/chaining.d.ts.map +1 -1
  92. package/types/acdc/regbasing.d.ts +7 -6
  93. package/types/acdc/regbasing.d.ts.map +1 -1
  94. package/types/acdc/regengine.d.ts.map +1 -1
  95. package/types/acdc/registering.d.ts +8 -4
  96. package/types/acdc/registering.d.ts.map +1 -1
  97. package/types/acdc/registraring.d.ts.map +1 -1
  98. package/types/acdc/salting.d.ts +53 -6
  99. package/types/acdc/salting.d.ts.map +1 -1
  100. package/types/acdc/unblinding.d.ts.map +1 -1
  101. package/types/app/credentials/root-replicating.d.ts +85 -0
  102. package/types/app/credentials/root-replicating.d.ts.map +1 -0
  103. package/types/app/credentials/verifying.d.ts +2 -1
  104. package/types/app/credentials/verifying.d.ts.map +1 -1
  105. package/types/app/delivery/forwarding.d.ts +10 -0
  106. package/types/app/delivery/forwarding.d.ts.map +1 -1
  107. package/types/app/exchanges/exchanging.d.ts +2 -0
  108. package/types/app/exchanges/exchanging.d.ts.map +1 -1
  109. package/types/app/identity/configing.d.ts +7 -5
  110. package/types/app/identity/configing.d.ts.map +1 -1
  111. package/types/app/identity/habbing.d.ts +23 -5
  112. package/types/app/identity/habbing.d.ts.map +1 -1
  113. package/types/app/identity/keeping.d.ts +1 -1
  114. package/types/app/identity/lmdb-habery.d.ts +6 -0
  115. package/types/app/identity/lmdb-habery.d.ts.map +1 -0
  116. package/types/app/ipex/ipex-graph.d.ts +4 -4
  117. package/types/app/ipex/ipex-graph.d.ts.map +1 -1
  118. package/types/app/ipex/ipex-grouping.d.ts.map +1 -1
  119. package/types/app/ipex/ipex-v2.d.ts +11 -2
  120. package/types/app/ipex/ipex-v2.d.ts.map +1 -1
  121. package/types/app/ipex/ipexing.d.ts +3 -0
  122. package/types/app/ipex/ipexing.d.ts.map +1 -1
  123. package/types/app/mailbox/mailboxing.d.ts +1 -1
  124. package/types/app/mailbox/mailboxing.d.ts.map +1 -1
  125. package/types/app/multisig/group-members.d.ts +9 -0
  126. package/types/app/multisig/group-members.d.ts.map +1 -1
  127. package/types/app/multisig/grouping.d.ts.map +1 -1
  128. package/types/app/multisig/multisig-workflows.d.ts +2 -1
  129. package/types/app/multisig/multisig-workflows.d.ts.map +1 -1
  130. package/types/app/notifications/notifying.d.ts +1 -1
  131. package/types/app/notifications/notifying.d.ts.map +1 -1
  132. package/types/app/protocol/parsering.d.ts +3 -1
  133. package/types/app/protocol/parsering.d.ts.map +1 -1
  134. package/types/app/protocol/protocol-processing.d.ts +2 -0
  135. package/types/app/protocol/protocol-processing.d.ts.map +1 -1
  136. package/types/app/runtime/agent-runtime.d.ts +7 -0
  137. package/types/app/runtime/agent-runtime.d.ts.map +1 -1
  138. package/types/app/transport/byte-source.d.ts +13 -10
  139. package/types/app/transport/byte-source.d.ts.map +1 -1
  140. package/types/app/transport/cesr-egress.d.ts +21 -7
  141. package/types/app/transport/cesr-egress.d.ts.map +1 -1
  142. package/types/app/transport/file-bytes.d.ts +11 -0
  143. package/types/app/transport/file-bytes.d.ts.map +1 -0
  144. package/types/app/transport/http-client.d.ts +3 -0
  145. package/types/app/transport/http-client.d.ts.map +1 -1
  146. package/types/app/transport/http-messenger.d.ts +15 -10
  147. package/types/app/transport/http-messenger.d.ts.map +1 -1
  148. package/types/app/transport/message-source.d.ts +1 -1
  149. package/types/app/transport/messengering.d.ts +2 -2
  150. package/types/app/transport/messengering.d.ts.map +1 -1
  151. package/types/app/transport/node-http-client.d.ts +10 -0
  152. package/types/app/transport/node-http-client.d.ts.map +1 -0
  153. package/types/app/transport/tcp-dialer.d.ts +21 -0
  154. package/types/app/transport/tcp-dialer.d.ts.map +1 -0
  155. package/types/cli/common/existing.d.ts.map +1 -1
  156. package/types/cli/credentials/ipex.d.ts.map +1 -1
  157. package/types/cli/endpoints/oobi-clean.d.ts.map +1 -1
  158. package/types/cli/identity/init.d.ts.map +1 -1
  159. package/types/cli/index.d.ts +1 -1
  160. package/types/cli/index.d.ts.map +1 -1
  161. package/types/cli/messaging/multisig.d.ts +10 -1
  162. package/types/cli/messaging/multisig.d.ts.map +1 -1
  163. package/types/cli/tools/annotate.d.ts.map +1 -1
  164. package/types/cli/tools/benchmark.d.ts.map +1 -1
  165. package/types/cli/tools/db-dump.d.ts.map +1 -1
  166. package/types/core/bytes.d.ts +2 -0
  167. package/types/core/bytes.d.ts.map +1 -1
  168. package/types/core/kel/delegation-ancestry.d.ts +41 -0
  169. package/types/core/kel/delegation-ancestry.d.ts.map +1 -0
  170. package/types/core/kel/eventing.d.ts.map +1 -1
  171. package/types/core/kel/kever.d.ts +5 -4
  172. package/types/core/kel/kever.d.ts.map +1 -1
  173. package/types/core/mailbox/kram-policy.d.ts.map +1 -1
  174. package/types/core/mailbox/kram-pruning.d.ts +1 -3
  175. package/types/core/mailbox/kram-pruning.d.ts.map +1 -1
  176. package/types/db/basing.d.ts +14 -23
  177. package/types/db/basing.d.ts.map +1 -1
  178. package/types/db/core/dber.d.ts +505 -0
  179. package/types/db/core/dber.d.ts.map +1 -0
  180. package/types/db/core/index.d.ts +4 -2
  181. package/types/db/core/index.d.ts.map +1 -1
  182. package/types/db/core/lmdb-opener.d.ts +17 -0
  183. package/types/db/core/lmdb-opener.d.ts.map +1 -0
  184. package/types/db/core/lmdber.d.ts +60 -383
  185. package/types/db/core/lmdber.d.ts.map +1 -1
  186. package/types/db/core/memstore.d.ts +129 -0
  187. package/types/db/core/memstore.d.ts.map +1 -0
  188. package/types/db/core/path-manager.d.ts +22 -45
  189. package/types/db/core/path-manager.d.ts.map +1 -1
  190. package/types/db/core/store-owner.d.ts +59 -0
  191. package/types/db/core/store-owner.d.ts.map +1 -0
  192. package/types/db/core/webdber.d.ts +127 -0
  193. package/types/db/core/webdber.d.ts.map +1 -0
  194. package/types/db/escrowing.d.ts +3 -3
  195. package/types/db/escrowing.d.ts.map +1 -1
  196. package/types/db/exchange/exchange-nests.d.ts.map +1 -1
  197. package/types/db/keeping.d.ts +9 -23
  198. package/types/db/keeping.d.ts.map +1 -1
  199. package/types/db/koming.d.ts +7 -8
  200. package/types/db/koming.d.ts.map +1 -1
  201. package/types/db/lmdb-stores.d.ts +45 -0
  202. package/types/db/lmdb-stores.d.ts.map +1 -0
  203. package/types/db/lmdb.d.ts +7 -0
  204. package/types/db/lmdb.d.ts.map +1 -0
  205. package/types/db/mailbox/mailboxing.d.ts +7 -21
  206. package/types/db/mailbox/mailboxing.d.ts.map +1 -1
  207. package/types/db/noting.d.ts +7 -12
  208. package/types/db/noting.d.ts.map +1 -1
  209. package/types/db/reger.d.ts +7 -11
  210. package/types/db/reger.d.ts.map +1 -1
  211. package/types/db/replay/witness-replay.d.ts +0 -2
  212. package/types/db/replay/witness-replay.d.ts.map +1 -1
  213. package/types/db/subing.d.ts +24 -25
  214. package/types/db/subing.d.ts.map +1 -1
  215. package/types/npm/db-lmdb.d.ts +4 -0
  216. package/types/npm/db-lmdb.d.ts.map +1 -0
  217. package/types/npm/runtime-node.d.ts +4 -0
  218. package/types/npm/runtime-node.d.ts.map +1 -0
  219. package/types/runtime/index.d.ts +9 -10
  220. package/types/runtime/index.d.ts.map +1 -1
  221. package/types/runtime/node.d.ts +15 -0
  222. package/types/runtime/node.d.ts.map +1 -0
  223. package/types/version.d.ts +2 -2
  224. package/esm/keri/npm/src/acdc/relating.js +0 -59
  225. package/esm/keri/npm/src/db/baser-defaults.js +0 -11
  226. package/types/acdc/relating.d.ts +0 -21
  227. package/types/acdc/relating.d.ts.map +0 -1
  228. package/types/db/baser-defaults.d.ts +0 -5
  229. package/types/db/baser-defaults.d.ts.map +0 -1
@@ -1,28 +1,33 @@
1
- /** Read-only ACDC chaining over caller-owned node verdicts; authentication and application state policy stay separate. */
1
+ /**
2
+ * Read-only ACDC chaining over caller-owned node verdicts; authentication and application state policy stay separate.
3
+ *
4
+ * KERIpy correspondence: the graph walk and Edge evaluation of upstream PR 1757's
5
+ * `acdc.evaluating.EdgeEvaluator`. keri-ts keeps a functional seam: protocols
6
+ * (IPEX) own node authentication and frame admission, then call `walkAcdcGraph`
7
+ * and `evaluateChain` without this module knowing any disclosure protocol.
8
+ */
2
9
  import { ParserError, Saider } from "cesr-ts";
3
10
  import { ValidationError } from "../core/errors.js";
11
+ import { delegationAncestry } from "../core/kel/delegation-ancestry.js";
4
12
  import { Schemer } from "../core/scheming.js";
5
- import { delegationRelation } from "./relating.js";
6
13
  import { validateSchema } from "./scheming.js";
7
- /** Reserved section/group labels include a pin at every level. */
14
+ /** Every Grant-side caller defaults to `open`, matching KERIpy's Grant walk default. */
15
+ export const DEFAULT_GRANT_WALK = "open";
16
+ /** Reserved Edge-group labels include a pin at every level. The top-level Edge Section additionally forbids `w`. */
8
17
  export const acdcGroupLabels = new Set(["d", "u", "s", "o", "w"]);
9
18
  const leafLabels = new Set([...acdcGroupLabels, "n"]);
10
- const unary = new Set(["I2I", "NI2I", "DI2I", "E1E", "NOT"]);
19
+ const unary = new Set(["I2I", "NI2I", "DI2I", "E1E", "I1I", "DI1I", "NOT"]);
20
+ /** Latest-wins issuer-to-issuee group. */
11
21
  const delegative = new Set(["I2I", "NI2I", "DI2I"]);
12
- const suppressDefault = new Set([...delegative, "E1E"]);
22
+ /** Latest-wins issuer-to-issuer group, independent of the delegative group; E1E composes with both. */
23
+ const issuerIdentity = new Set(["I1I", "DI1I"]);
24
+ /** Any explicit relation suppresses the implicit I2I/NI2I default. */
25
+ const suppressDefault = new Set([...delegative, "E1E", ...issuerIdentity]);
13
26
  /** SAD maps exclude scalar/array edge representations. */
14
27
  function record(value) {
15
28
  return value !== null && typeof value === "object" && !Array.isArray(value);
16
29
  }
17
- /** Empty section containers carry no disclosed edge semantics; malformed nonempty values refuse. */
18
- export function acdcEdgeBlocks(value) {
19
- if (!value || (Array.isArray(value) && !value.length) || (record(value) && !Object.keys(value).length))
20
- return [];
21
- if (record(value))
22
- return [value];
23
- return Array.isArray(value) && value.every(record) ? value : null;
24
- }
25
- /** Only canonical qualified digests identify expanded leaf targets and schema pins. */
30
+ /** Only canonical qualified digests identify expanded leaf targets, compact commitments and schema pins. */
26
31
  function said(value) {
27
32
  if (typeof value !== "string")
28
33
  return false;
@@ -33,12 +38,116 @@ function said(value) {
33
38
  return false;
34
39
  }
35
40
  }
41
+ /**
42
+ * Classify a node's `e` field; null is malformed.
43
+ * Lists, falsy non-map values, non-SAID strings and a top-level `n` or `w` are
44
+ * malformed. A compact SAID is a valid opaque terminal that names no far nodes.
45
+ */
46
+ export function acdcEdgeSection(sad) {
47
+ if (!Object.hasOwn(sad, "e"))
48
+ return { kind: "none" };
49
+ const value = sad.e;
50
+ if (record(value)) {
51
+ if (!Object.keys(value).length)
52
+ return { kind: "none" };
53
+ // The Edge Section is itself an Edge-group, never a leaf, and carries no weight.
54
+ if (Object.hasOwn(value, "n") || Object.hasOwn(value, "w"))
55
+ return null;
56
+ return { kind: "expanded", section: value };
57
+ }
58
+ return said(value) ? { kind: "compact", said: value } : null;
59
+ }
36
60
  /** Compact Edge strings name blocks, never far ACDCs. Expanded leaves have exact labels. */
37
61
  export function acdcEdgeTarget(value) {
38
62
  if (!record(value) || !Object.hasOwn(value, "n"))
39
63
  return null;
40
64
  return Object.keys(value).every((label) => leafLabels.has(label)) && said(value.n) ? value.n : false;
41
65
  }
66
+ /**
67
+ * Walk a disclosed graph of credential views from `origin` in BFS order.
68
+ *
69
+ * Every view must verify (including its carried section SAIDs) under its own
70
+ * SAID key, every Edge Section must be well shaped, every disclosed node must be
71
+ * reachable and the reachable graph must be acyclic. Closed walks also require
72
+ * every expanded leaf target to be disclosed; open walks skip undisclosed ones
73
+ * (see `AcdcWalkPolicy`).
74
+ * Compact Edge Sections and compact Edge members are opaque terminals.
75
+ * Protocol frame admission (ilks, nests, duplicates) belongs to the caller.
76
+ */
77
+ export function walkAcdcGraph(origin, nodes, walk) {
78
+ for (const [id, { body }] of nodes)
79
+ if (body.said !== id || !body.verify())
80
+ return null;
81
+ if (!nodes.has(origin))
82
+ return null;
83
+ const seen = new Set();
84
+ const order = [];
85
+ const dependencies = new Map();
86
+ const queue = [origin];
87
+ for (let index = 0; index < queue.length; index++) {
88
+ const id = queue[index];
89
+ if (seen.has(id))
90
+ continue;
91
+ seen.add(id);
92
+ order.push(id);
93
+ const farNodes = new Set();
94
+ dependencies.set(id, farNodes);
95
+ const section = acdcEdgeSection(nodes.get(id).body.sad);
96
+ if (!section)
97
+ return null;
98
+ if (section.kind !== "expanded")
99
+ continue;
100
+ const groups = [section.section];
101
+ for (let g = 0; g < groups.length; g++) {
102
+ for (const [label, member] of Object.entries(groups[g])) {
103
+ if (acdcGroupLabels.has(label))
104
+ continue;
105
+ if (typeof member === "string") {
106
+ if (!said(member))
107
+ return null;
108
+ continue;
109
+ }
110
+ const target = acdcEdgeTarget(member);
111
+ if (target === false)
112
+ return null;
113
+ if (target === null) {
114
+ if (!record(member))
115
+ return null;
116
+ groups.push(member);
117
+ }
118
+ else if (!nodes.has(target)) {
119
+ if (walk === "closed")
120
+ return null;
121
+ }
122
+ else {
123
+ farNodes.add(target);
124
+ if (!seen.has(target))
125
+ queue.push(target);
126
+ }
127
+ }
128
+ }
129
+ }
130
+ if (seen.size !== nodes.size)
131
+ return null;
132
+ const parents = new Map();
133
+ for (const [near, children] of dependencies) {
134
+ for (const far of children) {
135
+ if (!parents.has(far))
136
+ parents.set(far, new Set());
137
+ parents.get(far).add(near);
138
+ }
139
+ }
140
+ const dependencyOrder = order.filter((id) => dependencies.get(id).size === 0);
141
+ for (let i = 0; i < dependencyOrder.length; i++) {
142
+ for (const near of parents.get(dependencyOrder[i]) ?? []) {
143
+ const children = dependencies.get(near);
144
+ children.delete(dependencyOrder[i]);
145
+ if (!children.size)
146
+ dependencyOrder.push(near);
147
+ }
148
+ }
149
+ return dependencyOrder.length === nodes.size ? order : null;
150
+ }
42
151
  /** Missing proof/pin dependencies retain their ordered schema causes for the existing escrow owner. */
43
152
  function unknown(reason, retryable = false, schemas = []) {
44
153
  return { kind: "unknown", reason, retryable, schemas };
@@ -54,11 +163,64 @@ function reduce(op, members) {
54
163
  }
55
164
  return { kind: op === "AND" ? "valid" : "invalid" };
56
165
  }
166
+ /** Accepted delegation ancestry is the only evidence beyond the two ACDCs; missing KEL evidence can still arrive. */
167
+ function delegatedFrom(db, op, pre, ancestor) {
168
+ const ancestry = delegationAncestry(db, pre, ancestor);
169
+ if (ancestry.kind === "valid")
170
+ return { kind: "valid" };
171
+ if (ancestry.kind === "refused")
172
+ return { kind: "invalid" };
173
+ return unknown(`${op} delegation evidence: ${ancestry.reason}`, true);
174
+ }
175
+ /**
176
+ * Evaluate the unary relations of one leaf between its near and far ACDCs.
177
+ *
178
+ * Unrecognized tokens and the unimplemented NOT are non-retryable unknowns that
179
+ * are ANDed with, not substituted for, the recognized relations. Absent any
180
+ * explicit relation, I2I applies when the far node has an issuee, else NI2I.
181
+ * The delegative and issuer-identity groups are each latest-wins.
182
+ */
183
+ function leafRelation(db, ops, near, far) {
184
+ const relations = [];
185
+ const unrecognized = ops.filter((token) => !unary.has(token));
186
+ if (unrecognized.length)
187
+ relations.push(unknown(`Unrecognized unary Edge operator ${unrecognized.join(", ")}.`));
188
+ if (ops.includes("NOT"))
189
+ relations.push(unknown("Unimplemented unary Edge operator NOT."));
190
+ const operators = [...ops];
191
+ if (!operators.some((token) => suppressDefault.has(token)))
192
+ operators.push(far.issuee !== null ? "I2I" : "NI2I");
193
+ const delegate = operators.findLast((token) => delegative.has(token));
194
+ const identity = operators.findLast((token) => issuerIdentity.has(token));
195
+ const truth = (value) => ({ kind: value ? "valid" : "invalid" });
196
+ if (operators.includes("E1E")) {
197
+ relations.push(truth(Boolean(near.issuee && far.issuee && near.issuee === far.issuee)));
198
+ }
199
+ if (delegate === "I2I")
200
+ relations.push(truth(Boolean(far.issuee && near.issuer === far.issuee)));
201
+ if (delegate === "DI2I") {
202
+ if (!near.issuer || !far.issuee)
203
+ relations.push({ kind: "invalid" });
204
+ else if (near.issuer !== far.issuee)
205
+ relations.push(delegatedFrom(db, "DI2I", near.issuer, far.issuee));
206
+ }
207
+ // Issuer identity never reads issuees.
208
+ if (identity) {
209
+ if (!near.issuer || !far.issuer)
210
+ relations.push({ kind: "invalid" });
211
+ else if (near.issuer !== far.issuer) {
212
+ relations.push(identity === "I1I" ? { kind: "invalid" } : delegatedFrom(db, "DI1I", near.issuer, far.issuer));
213
+ }
214
+ }
215
+ return reduce("AND", relations);
216
+ }
57
217
  /**
58
218
  * Validate every own schema, then conjoin each caller verdict with its complete edge expression.
59
219
  * Every branch is inspected for malformed shape, even when its truth value is unused.
220
+ * Under an open walk an undisclosed far node is a non-retryable unknown for its leaf.
60
221
  * Protocol callers supply issuer authentication; applications supply their state policy.
61
- * This helper reads schemas but writes no records and publishes no cues.
222
+ * The graph must come from `walkAcdcGraph` (directly or through a protocol walk).
223
+ * This helper reads schemas and KEL state but writes no records and publishes no cues.
62
224
  */
63
225
  export function evaluateChain(graph, verdicts, db) {
64
226
  // Own schemas are global obligations, unlike optional edge pins and node verdicts.
@@ -78,12 +240,15 @@ export function evaluateChain(graph, verdicts, db) {
78
240
  if (!node || !auth)
79
241
  return null;
80
242
  memo.set(id, unknown(`Node ${id} is already being evaluated.`));
81
- const blocks = acdcEdgeBlocks(node.sad.e);
82
- if (!blocks)
243
+ const section = acdcEdgeSection(node.sad);
244
+ if (!section)
83
245
  return null;
84
246
  const members = [auth];
85
- for (const block of blocks) {
86
- const result = evaluateEdge(block, node, []);
247
+ if (section.kind === "compact") {
248
+ members.push(unknown(`Node ${id} carries compact Edge Section ${section.said}, which cannot be evaluated.`));
249
+ }
250
+ else if (section.kind === "expanded") {
251
+ const result = evaluateGroup(section.section, node, []);
87
252
  if (!result)
88
253
  return null;
89
254
  members.push(result);
@@ -92,50 +257,41 @@ export function evaluateChain(graph, verdicts, db) {
92
257
  memo.set(id, result);
93
258
  return result;
94
259
  };
95
- const evaluateEdge = (edge, near, inherited) => {
96
- const target = acdcEdgeTarget(edge);
97
- if (target === false)
98
- return null;
99
- const pins = Object.hasOwn(edge, "s") ? [...inherited, edge.s] : inherited;
100
- if (target !== null)
101
- return evaluateLeaf(edge, target, near, pins);
102
- const op = Object.hasOwn(edge, "o") ? edge.o : "AND";
260
+ const evaluateGroup = (group, near, inherited) => {
261
+ const pins = Object.hasOwn(group, "s") ? [...inherited, group.s] : inherited;
262
+ const op = Object.hasOwn(group, "o") ? group.o : "AND";
103
263
  if (typeof op !== "string")
104
264
  return null;
105
265
  const members = [];
106
- for (const [label, member] of Object.entries(edge)) {
266
+ for (const [label, member] of Object.entries(group)) {
107
267
  if (acdcGroupLabels.has(label))
108
268
  continue;
109
269
  if (typeof member === "string") {
110
- members.push(unknown(`Compact Edge ${label} cannot be dereferenced.`));
111
- }
112
- else {
113
- if (!record(member))
270
+ if (!said(member))
114
271
  return null;
115
- const result = evaluateEdge(member, near, pins);
116
- if (!result)
117
- return null;
118
- members.push(result);
272
+ members.push(unknown(`Compact Edge ${label} cannot be dereferenced.`));
273
+ continue;
119
274
  }
275
+ const target = acdcEdgeTarget(member);
276
+ if (target === false || !record(member))
277
+ return null;
278
+ const result = target === null ? evaluateGroup(member, near, pins) : evaluateLeaf(member, target, near, pins);
279
+ if (!result)
280
+ return null;
281
+ members.push(result);
120
282
  }
121
283
  if (!members.length)
122
284
  return null;
123
285
  return op === "AND" || op === "OR" ? reduce(op, members) : unknown(`Unsupported Edge-group operator ${op}.`);
124
286
  };
125
- const evaluateLeaf = (edge, target, near, pins) => {
126
- const far = graph.nodes.get(target)?.body;
127
- if (!far)
128
- return null;
287
+ const evaluateLeaf = (edge, target, near, inherited) => {
288
+ const pins = Object.hasOwn(edge, "s") ? [...inherited, edge.s] : inherited;
129
289
  const op = edge.o;
130
290
  const ops = op == null ? [] : typeof op === "string" ? [op] : Array.isArray(op) ? [...op] : null;
131
- if (!ops)
291
+ if (!ops || !ops.every((token) => typeof token === "string"))
132
292
  return null;
133
293
  // Pin shape is morphological, so validate it before unsupported tokens or relations.
134
294
  const resolved = [];
135
- const ownSchema = far.schema;
136
- const ownSchemaId = record(ownSchema) ? ownSchema.$id : ownSchema;
137
- if (pins.length && typeof ownSchemaId !== "string")
138
- return null;
139
295
  for (const pin of pins) {
140
296
  if (typeof pin === "string") {
141
297
  if (!said(pin))
@@ -159,55 +315,33 @@ export function evaluateChain(graph, verdicts, db) {
159
315
  else
160
316
  return null;
161
317
  }
162
- let own;
163
- if (ops.some((token) => typeof token !== "string" || !unary.has(token))) {
164
- own = unknown("Unrecognized unary Edge operator.");
318
+ const far = graph.nodes.get(target)?.body;
319
+ if (!far) {
320
+ // A closed walk never yields a graph with an undisclosed target.
321
+ return graph.walk === "open" ? unknown(`Far node ${target} is not disclosed.`) : null;
165
322
  }
166
- else {
167
- const operators = ops;
168
- if (!operators.some((token) => suppressDefault.has(token)))
169
- operators.push(far.issuee !== null ? "I2I" : "NI2I");
170
- const delegate = operators.findLast((token) => delegative.has(token));
171
- if (operators.includes("NOT")) {
172
- own = unknown("Unimplemented unary Edge operator.");
173
- }
174
- else {
175
- let matched = (!operators.includes("E1E") || Boolean(near.issuee && far.issuee && near.issuee === far.issuee))
176
- && (delegate !== "I2I" || Boolean(far.issuee && near.issuer === far.issuee));
177
- let pending;
178
- if (matched && delegate === "DI2I") {
179
- if (!far.issuee || !near.issuer)
180
- matched = false;
181
- else if (near.issuer !== far.issuee) {
182
- const relation = delegationRelation(db, near.issuer, far.issuee);
183
- if (relation.kind === "refused")
184
- matched = false;
185
- else if (relation.kind === "pending")
186
- pending = unknown(relation.reason, true);
187
- }
188
- }
189
- own = { kind: matched ? "valid" : "invalid" };
190
- if (matched) {
191
- for (let pin of resolved) {
192
- if (pin === ownSchemaId && record(ownSchema))
193
- pin = ownSchema;
194
- const result = validateSchema(far, db, pin);
195
- if (result.kind === "valid")
196
- continue;
197
- own = result.kind === "missing"
198
- ? unknown(`Missing edge schema ${result.said}.`, true, [result.said])
199
- : { kind: "invalid" };
200
- break;
201
- }
202
- }
203
- // Pending delegation cannot replace a pin's decided refusal.
204
- if (pending)
205
- own = reduce("AND", [own, pending]);
323
+ const ownSchema = far.schema;
324
+ const ownSchemaId = record(ownSchema) ? ownSchema.$id : ownSchema;
325
+ if (pins.length && typeof ownSchemaId !== "string")
326
+ return null;
327
+ const relation = leafRelation(db, ops, near, far);
328
+ const own = [relation];
329
+ // A decided relation refusal needs no pin evidence; otherwise every pin is evaluated, not only the first failure.
330
+ if (relation.kind !== "invalid") {
331
+ for (let pin of resolved) {
332
+ if (pin === ownSchemaId && record(ownSchema))
333
+ pin = ownSchema;
334
+ const result = validateSchema(far, db, pin);
335
+ if (result.kind === "valid")
336
+ continue;
337
+ own.push(result.kind === "missing"
338
+ ? unknown(`Missing edge schema ${result.said}.`, true, [result.said])
339
+ : { kind: "invalid" });
206
340
  }
207
341
  }
208
342
  // Do not short-circuit a far subtree: its shape cannot be outvoted by this leaf.
209
343
  const farVerdict = evaluateNode(target);
210
- return farVerdict ? reduce("AND", [own, farVerdict]) : null;
344
+ return farVerdict ? reduce("AND", [reduce("AND", own), farVerdict]) : null;
211
345
  };
212
346
  return graph.order.length ? evaluateNode(graph.order[0]) : null;
213
347
  }
@@ -76,7 +76,7 @@ export class RegistryObserver {
76
76
  const baser = this.store.baser;
77
77
  if (baser.readonly)
78
78
  throw new DatabaseOperationError("Cannot write readonly registry storage.");
79
- return baser.env.transactionSync(() => {
79
+ return baser.transaction(() => {
80
80
  this.store.putEvent(serder);
81
81
  this.store.escrowMissingAnchor(event.regid, Number(event.sn), event.said);
82
82
  if (opening)
@@ -106,7 +106,7 @@ export class RegistryObserver {
106
106
  }
107
107
  /** Stored inception is durable issuer identity, including while its anchor is still absent. */
108
108
  engine(regid) {
109
- if (!this.store.baser.env)
109
+ if (!this.store.baser.opened)
110
110
  throw new DatabaseNotOpenError("Registry observer store is closed.");
111
111
  const rip = this.store.event(regid);
112
112
  if (!rip) {
@@ -1,7 +1,6 @@
1
1
  /** Public ACDC registry database layout and joined LMDB lifecycle. */
2
- import { b, Diger, NumberPrimitive, Saider, SerderACDC } from "cesr-ts";
3
- import { DatabaseNotOpenError } from "../core/errors.js";
4
- import { LMDBer } from "../db/core/lmdber.js";
2
+ import { Diger, NumberPrimitive, Saider, SerderACDC } from "cesr-ts";
3
+ import { StoreOwner } from "../db/core/store-owner.js";
5
4
  import { B64OnIoSetSuber, BytesSuber, CatCesrSuber, CesrOnSuber, CesrSuber, SerderSuber } from "../db/subing.js";
6
5
  /**
7
6
  * Own one environment for public registry TEL bodies, accepted ordinals and heads.
@@ -9,24 +8,9 @@ import { B64OnIoSetSuber, BytesSuber, CatCesrSuber, CesrOnSuber, CesrSuber, Serd
9
8
  * evidence nor migrates rows. Every current store has anchor and escrow tables.
10
9
  * Construction stays closed; callers own reopen and joined close.
11
10
  */
12
- export class RegBaser extends LMDBer {
13
- /** Named databases are root entries; testing presence opens no additional handles. */
14
- hasTable(name) {
15
- if (!this.env)
16
- throw new DatabaseNotOpenError("Registry environment is closed.");
17
- // Native lmdb-js exposes its C-string terminator in root metadata keys;
18
- // the Deno backend also supports the unterminated representation.
19
- return this.env.getBinary(b(name)) !== undefined
20
- || this.env.getBinary(b(`${name}\0`)) !== undefined;
21
- }
22
- constructor(options = {}) {
23
- super(options, {
24
- tailDirPath: "keri/acdc/reg",
25
- cleanTailDirPath: "keri/clean/acdc/reg",
26
- altTailDirPath: options.compat ? ".keri/acdc/reg" : ".tufa/acdc/reg",
27
- altCleanTailDirPath: options.compat ? ".keri/clean/acdc/reg" : ".tufa/clean/acdc/reg",
28
- tempPrefix: "keri_acdc_reg_",
29
- });
11
+ export class RegBaser extends StoreOwner {
12
+ constructor() {
13
+ super(...arguments);
30
14
  /** Event-SAID -> parsed rip/bup body; body presence alone is not acceptance. */
31
15
  Object.defineProperty(this, "evts", {
32
16
  enumerable: true,
@@ -79,17 +63,17 @@ export class RegBaser extends LMDBer {
79
63
  }
80
64
  /** Rebind the same environment's typed tables after every joined reopen. */
81
65
  *reopen(options = {}) {
82
- const opened = yield* super.reopen(options);
66
+ const opened = yield* this.store.reopen(options);
83
67
  if (!opened)
84
68
  return false;
85
69
  try {
86
- this.evts = new SerderSuber(this, { subkey: "evts.", ctor: SerderACDC });
87
- this.tels = new CesrOnSuber(this, { subkey: "tels.", ctor: Saider });
88
- this.heads = new CesrSuber(this, { subkey: "heds.", ctor: Saider });
89
- this.openings = new BytesSuber(this, { subkey: "openings." });
90
- this.ancs = new CatCesrSuber(this, { subkey: "ancs.", ctor: [NumberPrimitive, Diger] });
91
- this.maes = new B64OnIoSetSuber(this, { subkey: "maes." });
92
- this.ooes = new B64OnIoSetSuber(this, { subkey: "ooes." });
70
+ this.evts = new SerderSuber(this.store, { subkey: "evts.", ctor: SerderACDC });
71
+ this.tels = new CesrOnSuber(this.store, { subkey: "tels.", ctor: Saider });
72
+ this.heads = new CesrSuber(this.store, { subkey: "heds.", ctor: Saider });
73
+ this.openings = new BytesSuber(this.store, { subkey: "openings." });
74
+ this.ancs = new CatCesrSuber(this.store, { subkey: "ancs.", ctor: [NumberPrimitive, Diger] });
75
+ this.maes = new B64OnIoSetSuber(this.store, { subkey: "maes." });
76
+ this.ooes = new B64OnIoSetSuber(this.store, { subkey: "ooes." });
93
77
  return true;
94
78
  }
95
79
  catch (error) {
@@ -98,3 +82,10 @@ export class RegBaser extends LMDBer {
98
82
  }
99
83
  }
100
84
  }
85
+ /** Placement of this store kind. */
86
+ Object.defineProperty(RegBaser, "Family", {
87
+ enumerable: true,
88
+ configurable: true,
89
+ writable: true,
90
+ value: { tail: "acdc/reg" }
91
+ });
@@ -256,12 +256,11 @@ export class RegistryEventer {
256
256
  const previous = this.acceptedEvent(event);
257
257
  if (previous)
258
258
  return previous;
259
- const env = this.store.baser.env;
260
- if (!env)
259
+ if (!this.store.baser.opened)
261
260
  throw new DatabaseNotOpenError("Registry acceptance requires an open backing store.");
262
261
  if (this.store.baser.readonly)
263
262
  throw new DatabaseOperationError("Cannot write readonly registry storage.");
264
- return env.transactionSync(() => {
263
+ return this.store.baser.transaction(() => {
265
264
  const prior = this.acceptedAt(event.regid, Number(event.sn) - 1);
266
265
  if (prior && prior.said !== event.prior)
267
266
  return { kind: "reject", reason: "prior" };
@@ -303,12 +302,11 @@ export class RegistryEventer {
303
302
  this.regk = event.regid;
304
303
  return previous;
305
304
  }
306
- const env = this.store.baser.env;
307
- if (!env)
305
+ if (!this.store.baser.opened)
308
306
  throw new DatabaseNotOpenError("Registry acceptance requires an open backing store.");
309
307
  if (this.store.baser.readonly)
310
308
  throw new DatabaseOperationError("Cannot write readonly registry storage.");
311
- const decision = env.transactionSync(() => {
309
+ const decision = this.store.baser.transaction(() => {
312
310
  const previous = this.acceptedEvent(event);
313
311
  if (previous)
314
312
  return previous;
@@ -37,10 +37,13 @@ function retainedOpening(raw) {
37
37
  export class RegistryRecord extends RawRecord {
38
38
  }
39
39
  /** Acquire one backing owner; failures/cancellation join cleanup before ownership transfers. */
40
- export function* openRegistry({ web = false, reopen = true, ...options } = {}) {
41
- if (web)
42
- throw new ValidationError("web registry backend is not yet supported by V2 Regery");
43
- const baser = new RegBaser(options);
40
+ export function* openRegistry({ reopen = true, opener, ...options } = {}) {
41
+ if (!opener)
42
+ throw new ValidationError("A registry store needs a store opener.");
43
+ return yield* adoptRegistry(new RegBaser(opener.create(RegBaser.Family, options)), reopen);
44
+ }
45
+ /** Take ownership of a constructed registry owner, reopening it unless told otherwise. */
46
+ export function* adoptRegistry(baser, reopen = true) {
44
47
  let delivered = false;
45
48
  try {
46
49
  if (reopen && !(yield* baser.reopen()))
@@ -81,7 +84,7 @@ export class RegistryStore {
81
84
  writable: true,
82
85
  value: null
83
86
  });
84
- Object.defineProperty(this, "aliasEnv", {
87
+ Object.defineProperty(this, "aliasTable", {
85
88
  enumerable: true,
86
89
  configurable: true,
87
90
  writable: true,
@@ -90,13 +93,13 @@ export class RegistryStore {
90
93
  }
91
94
  /** Local alias mapper is optional; refresh it after the owner's reopen. */
92
95
  get records() {
93
- if (!this.baser.env)
96
+ if (!this.baser.opened)
94
97
  throw new DatabaseNotOpenError("Registry backing store is closed.");
95
- if (this.aliasEnv !== this.baser.env) {
98
+ if (this.aliasTable !== this.baser.evts.sdb) {
96
99
  this.aliases = this.baser.hasTable("regs.")
97
- ? new Komer(this.baser, { subkey: "regs.", recordClass: RegistryRecord })
100
+ ? new Komer(this.baser.store, { subkey: "regs.", recordClass: RegistryRecord })
98
101
  : null;
99
- this.aliasEnv = this.baser.env;
102
+ this.aliasTable = this.baser.evts.sdb;
100
103
  }
101
104
  return this.aliases;
102
105
  }
@@ -110,7 +113,7 @@ export class RegistryStore {
110
113
  if (!records) {
111
114
  if (this.baser.readonly)
112
115
  throw new DatabaseOperationError("Cannot create readonly registry aliases.");
113
- records = this.aliases = new Komer(this.baser, { subkey: "regs.", recordClass: RegistryRecord });
116
+ records = this.aliases = new Komer(this.baser.store, { subkey: "regs.", recordClass: RegistryRecord });
114
117
  }
115
118
  return records;
116
119
  }
@@ -13,12 +13,8 @@ export function* createRegery({ hby, baser, ...options }) {
13
13
  try {
14
14
  if (!baser) {
15
15
  baser = yield* openRegistry({
16
- name: hby.name,
17
- base: hby.base,
18
- temp: hby.temp,
19
- headDirPath: hby.headDirPath,
20
- compat: hby.compat,
21
- readonly: hby.readonly,
16
+ ...hby.storeIdentity(),
17
+ opener: hby.opener,
22
18
  ...options,
23
19
  });
24
20
  }
@@ -90,12 +86,11 @@ export class Regery {
90
86
  const rip = regcept(hab.pre, options);
91
87
  if (this.regs.has(rip.said))
92
88
  throw new ValidationError(`Registry already exists: ${rip.said}`);
93
- const env = this.baser.env;
94
- if (!env)
89
+ if (!this.baser.opened)
95
90
  throw new DatabaseNotOpenError("Registry backing store is closed.");
96
91
  const records = this.store.initializeRecords();
97
92
  const registry = new Registry(hab, this.store, name);
98
- env.transactionSync(() => {
93
+ this.baser.transaction(() => {
99
94
  if (records.get(name))
100
95
  throw new ValidationError(`Registry alias already exists: ${name}`);
101
96
  const result = registry.processEvent(rip);