@serfab/cadre-core 1.8.0 → 1.10.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 (126) hide show
  1. package/dist/cadre-node.d.ts +301 -121
  2. package/dist/cadre-node.js +588 -244
  3. package/dist/cadre-node.js.map +1 -1
  4. package/dist/control-authorization.d.ts +2 -2
  5. package/dist/control-authorization.js +1 -0
  6. package/dist/control-authorization.js.map +1 -1
  7. package/dist/control-cohort.d.ts +1 -1
  8. package/dist/control-cohort.js +1 -1
  9. package/dist/control-database.d.ts +105 -14
  10. package/dist/control-database.js +242 -73
  11. package/dist/control-database.js.map +1 -1
  12. package/dist/control-formation-recorder.d.ts +6 -6
  13. package/dist/control-formation-recorder.js +7 -8
  14. package/dist/control-formation-recorder.js.map +1 -1
  15. package/dist/control-schema.d.ts +1 -1
  16. package/dist/control-schema.js +90 -3
  17. package/dist/control-schema.js.map +1 -1
  18. package/dist/control-write-retry.d.ts +21 -15
  19. package/dist/control-write-retry.js +21 -15
  20. package/dist/control-write-retry.js.map +1 -1
  21. package/dist/index.d.ts +7 -7
  22. package/dist/index.js +16 -13
  23. package/dist/index.js.map +1 -1
  24. package/dist/invitation-bootstrap.d.ts +32 -0
  25. package/dist/invitation-bootstrap.js +30 -0
  26. package/dist/invitation-bootstrap.js.map +1 -0
  27. package/dist/link-budget.d.ts +204 -119
  28. package/dist/link-budget.js +208 -120
  29. package/dist/link-budget.js.map +1 -1
  30. package/dist/membership-connection-gater.d.ts +3 -3
  31. package/dist/membership-connection-gater.js +3 -3
  32. package/dist/node-local-snapshot.d.ts +6 -4
  33. package/dist/node-local-snapshot.js +7 -3
  34. package/dist/node-local-snapshot.js.map +1 -1
  35. package/dist/peer-dial.d.ts +18 -14
  36. package/dist/peer-dial.js +18 -14
  37. package/dist/peer-dial.js.map +1 -1
  38. package/dist/peer-join-backfill.d.ts +3 -12
  39. package/dist/peer-join-backfill.js +2 -3
  40. package/dist/peer-join-backfill.js.map +1 -1
  41. package/dist/pending-join-runner.d.ts +186 -0
  42. package/dist/pending-join-runner.js +649 -0
  43. package/dist/pending-join-runner.js.map +1 -0
  44. package/dist/push-fanout.d.ts +1 -1
  45. package/dist/push-fanout.js +1 -1
  46. package/dist/seed-bootstrap.d.ts +2 -2
  47. package/dist/seed-bootstrap.js +1 -1
  48. package/dist/strand-addr-protocol.js +2 -2
  49. package/dist/strand-formation-deadlines.d.ts +5 -5
  50. package/dist/strand-formation-deadlines.js +5 -5
  51. package/dist/strand-formation-manager.d.ts +18 -4
  52. package/dist/strand-formation-manager.js +48 -33
  53. package/dist/strand-formation-manager.js.map +1 -1
  54. package/dist/strand-formation-protocol.d.ts +71 -25
  55. package/dist/strand-formation-protocol.js +225 -51
  56. package/dist/strand-formation-protocol.js.map +1 -1
  57. package/dist/strand-formation-rejection.d.ts +94 -0
  58. package/dist/strand-formation-rejection.js +77 -0
  59. package/dist/strand-formation-rejection.js.map +1 -0
  60. package/dist/strand-fret-addrs.d.ts +54 -0
  61. package/dist/strand-fret-addrs.js +108 -0
  62. package/dist/strand-fret-addrs.js.map +1 -0
  63. package/dist/strand-instance-manager.d.ts +9 -38
  64. package/dist/strand-instance-manager.js +17 -74
  65. package/dist/strand-instance-manager.js.map +1 -1
  66. package/dist/strand-network-state-file.d.ts +12 -0
  67. package/dist/strand-network-state-file.js +38 -0
  68. package/dist/strand-network-state-file.js.map +1 -0
  69. package/dist/strand-network-state.d.ts +111 -0
  70. package/dist/strand-network-state.js +191 -0
  71. package/dist/strand-network-state.js.map +1 -0
  72. package/dist/strand-solicitation.d.ts +11 -3
  73. package/dist/strand-solicitation.js +9 -0
  74. package/dist/strand-solicitation.js.map +1 -1
  75. package/dist/types.d.ts +123 -40
  76. package/dist/types.js +5 -9
  77. package/dist/types.js.map +1 -1
  78. package/package.json +25 -24
  79. package/src/cadre-node.ts +637 -251
  80. package/src/control-authorization.ts +117 -116
  81. package/src/control-cohort.ts +1 -1
  82. package/src/control-database.ts +303 -82
  83. package/src/control-formation-recorder.ts +8 -9
  84. package/src/control-schema.ts +90 -3
  85. package/src/control-write-retry.ts +21 -15
  86. package/src/index.ts +36 -56
  87. package/src/invitation-bootstrap.ts +40 -0
  88. package/src/link-budget.ts +221 -120
  89. package/src/membership-connection-gater.ts +3 -3
  90. package/src/node-local-snapshot.ts +12 -7
  91. package/src/peer-dial.ts +18 -14
  92. package/src/peer-join-backfill.ts +5 -6
  93. package/src/pending-join-runner.ts +735 -0
  94. package/src/push-fanout.ts +1 -1
  95. package/src/seed-bootstrap.ts +2 -2
  96. package/src/strand-addr-protocol.ts +2 -2
  97. package/src/strand-formation-deadlines.ts +5 -5
  98. package/src/strand-formation-manager.ts +62 -37
  99. package/src/strand-formation-protocol.ts +1036 -803
  100. package/src/strand-formation-rejection.ts +129 -0
  101. package/src/strand-fret-addrs.ts +145 -0
  102. package/src/strand-instance-manager.ts +24 -97
  103. package/src/strand-network-state-file.ts +40 -0
  104. package/src/strand-network-state.ts +243 -0
  105. package/src/strand-solicitation.ts +17 -4
  106. package/src/types.ts +119 -40
  107. package/dist/strand-peer-book-file.d.ts +0 -12
  108. package/dist/strand-peer-book-file.js +0 -37
  109. package/dist/strand-peer-book-file.js.map +0 -1
  110. package/dist/strand-peer-book-protocol.d.ts +0 -168
  111. package/dist/strand-peer-book-protocol.js +0 -356
  112. package/dist/strand-peer-book-protocol.js.map +0 -1
  113. package/dist/strand-peer-book-swap.d.ts +0 -104
  114. package/dist/strand-peer-book-swap.js +0 -284
  115. package/dist/strand-peer-book-swap.js.map +0 -1
  116. package/dist/strand-peer-book.d.ts +0 -159
  117. package/dist/strand-peer-book.js +0 -361
  118. package/dist/strand-peer-book.js.map +0 -1
  119. package/dist/strand-peer-observer.d.ts +0 -88
  120. package/dist/strand-peer-observer.js +0 -180
  121. package/dist/strand-peer-observer.js.map +0 -1
  122. package/src/strand-peer-book-file.ts +0 -39
  123. package/src/strand-peer-book-protocol.ts +0 -466
  124. package/src/strand-peer-book-swap.ts +0 -338
  125. package/src/strand-peer-book.ts +0 -475
  126. package/src/strand-peer-observer.ts +0 -235
@@ -1,116 +1,117 @@
1
- /**
2
- * The single definition of the field vector every signed control-plane message
3
- * covers. Both producers of signed bytes — `control-database.ts`'s
4
- * `buildAuthorizationMessage` (raw digest bytes) and `peer-authorization.ts`'s
5
- * digest helpers (base64url digest strings) — build their vector here, so the
6
- * byte layout cannot drift between them or away from the SQL constraints in
7
- * `schemas/control.qsql`.
8
- *
9
- * Every vector leads with two fixed literals:
10
- *
11
- * digest(<domain>, <action>, <row field 1>, ..., <row field n>)
12
- *
13
- * so a signature verifies ONLY against the one rule it was minted for. Without
14
- * the tags, several rules built byte-identical tuples (e.g. `ValidationKey`
15
- * insert and `OwnerKey` insert both signed `digest(Key, StampId)`), so an
16
- * approval for a narrow grant doubled as an approval for full ownership.
17
- *
18
- * This module deliberately has no Quereus / Optimystic / libp2p imports so the
19
- * lightweight verifiers (`peer-authorization.ts`, consumed by the offline
20
- * `cadre enroll register` check) can use it without pulling in the runtime.
21
- */
22
-
23
- /**
24
- * Names of the CadreControl tables, in schema order. The single list: the
25
- * {@link ControlTable} union is derived from it and `ControlDatabase.countRows`
26
- * guards its dynamic `from` clause against it (keeping the table name off the
27
- * SQL-injection surface), so a new table cannot be added to one and missed in
28
- * the other.
29
- *
30
- * `Revocation` is here for the same two reasons as every other entry: it
31
- * derives a `'CadreControl.Revocation'` domain tag — its `Authorized` CHECK
32
- * verifies an owner signature over the `'remove'`-tagged digest that
33
- * `peer-authorization.ts`'s `revocationDigest` mints, and its `AuthorizedReissue`
34
- * CHECK the `'reissue'`-tagged digest `ControlDatabase.reissueRevocations`
35
- * signs — and `countRows` counts it.
36
- */
37
- export const CONTROL_TABLES = [
38
- 'OwnerKey',
39
- 'ValidationKey',
40
- 'Strand',
41
- 'StrandPartyKey',
42
- 'JoinedStrand',
43
- 'CadrePeer',
44
- 'DeviceToken',
45
- 'FormationInvite',
46
- 'FormationUsage',
47
- 'Revocation',
48
- ] as const;
49
-
50
- /**
51
- * Name of a CadreControl table. Doubles as the table half of a
52
- * {@link ControlDomain} tag.
53
- */
54
- export type ControlTable = typeof CONTROL_TABLES[number];
55
-
56
- /**
57
- * The control tables whose rows carry a single-use `StampId` retired into
58
- * `CadreControl.Revocation` on delete — i.e. the ones the schema's
59
- * `NotRevoked` / `RevocationRecorded` CHECK pair guards, and the only values
60
- * `Revocation.RowIsGone` accepts in `TableName`. `Extract` from
61
- * {@link ControlTable} rather than a fresh literal list, so a renamed table is a
62
- * compile error here instead of a silently dead branch.
63
- *
64
- * Lives in this import-free module rather than beside its main consumer
65
- * (`control-database.ts`) so the lightweight signers — `peer-authorization.ts`'s
66
- * `revocationDigest` — can type against it without pulling in the runtime.
67
- */
68
- export type RevocableTable = Extract<ControlTable, 'OwnerKey' | 'CadrePeer' | 'ValidationKey' | 'Strand' | 'StrandPartyKey' | 'JoinedStrand' | 'DeviceToken'>;
69
-
70
- /**
71
- * What a signature authorizes, scoped to one table rule — or, for
72
- * `'Cadre.Enrollment'`, the offline peer vouch that `cadre enroll register`
73
- * verifies (no table checks it, so it needs its own domain to stay disjoint
74
- * from every table rule).
75
- */
76
- export type ControlDomain = `CadreControl.${ControlTable}` | 'Cadre.Enrollment';
77
-
78
- /**
79
- * The action half of the tag:
80
- * - `'add'` / `'remove'` — insert / delete of the named row.
81
- * - `'vouch'` — an owner (or validation key) vouches the row's semantics
82
- * without adding or removing it: the `CadrePeer` membership vouch (shared,
83
- * deliberately, by its insert and its owner-update branch), the
84
- * `FormationUsage` disclosure validation, and the offline enrollment vouch.
85
- * `DeviceToken` has no `'vouch'` digest — its owner re-touch branch was
86
- * removed (it rewrote the row outside the monotonicity guard), so an owner
87
- * correcting a token deletes and re-inserts it.
88
- * - `'publish'` — a peer self-signs its OWN record (the `CadrePeer` /
89
- * `DeviceToken` self-update branches), with its own key rather than an
90
- * owner key.
91
- * - `'consent'` — a peer self-signs its OWN `FormationUsage` redemption (the
92
- * joiner proving it agreed to join), with its own key. Distinct from the
93
- * approver's `'vouch'` over the same table so the two stored signatures are
94
- * never interchangeable.
95
- * - `'reissue'` — an owner re-writes an existing `Revocation` tombstone,
96
- * bumping its `ReissuedAt` counter so a tombstone committed while the node
97
- * was alone can be re-broadcast. Distinct from `'remove'` so a tombstone
98
- * append approval can never be replayed as a re-issue and vice versa.
99
- */
100
- export type ControlAction = 'add' | 'remove' | 'vouch' | 'publish' | 'consent' | 'reissue';
101
-
102
- /**
103
- * The full ordered field vector a control-plane signature covers. Digest this
104
- * with the crypto plugin's injective multi-field encoding (every field TEXT);
105
- * the SQL mirror passes the same literals as leading `digest(...)` arguments:
106
- *
107
- * TS: digest(controlAuthorizationFields('CadreControl.X', 'add', [a, b]), 'sha256', ...)
108
- * SQL: digest('CadreControl.X', 'add', new.A, new.B)
109
- */
110
- export function controlAuthorizationFields(
111
- domain: ControlDomain,
112
- action: ControlAction,
113
- rowFields: string[],
114
- ): string[] {
115
- return [domain, action, ...rowFields];
116
- }
1
+ /**
2
+ * The single definition of the field vector every signed control-plane message
3
+ * covers. Both producers of signed bytes — `control-database.ts`'s
4
+ * `buildAuthorizationMessage` (raw digest bytes) and `peer-authorization.ts`'s
5
+ * digest helpers (base64url digest strings) — build their vector here, so the
6
+ * byte layout cannot drift between them or away from the SQL constraints in
7
+ * `schemas/control.qsql`.
8
+ *
9
+ * Every vector leads with two fixed literals:
10
+ *
11
+ * digest(<domain>, <action>, <row field 1>, ..., <row field n>)
12
+ *
13
+ * so a signature verifies ONLY against the one rule it was minted for. Without
14
+ * the tags, several rules built byte-identical tuples (e.g. `ValidationKey`
15
+ * insert and `OwnerKey` insert both signed `digest(Key, StampId)`), so an
16
+ * approval for a narrow grant doubled as an approval for full ownership.
17
+ *
18
+ * This module deliberately has no Quereus / Optimystic / libp2p imports so the
19
+ * lightweight verifiers (`peer-authorization.ts`, consumed by the offline
20
+ * `cadre enroll register` check) can use it without pulling in the runtime.
21
+ */
22
+
23
+ /**
24
+ * Names of the CadreControl tables, in schema order. The single list: the
25
+ * {@link ControlTable} union is derived from it and `ControlDatabase.countRows`
26
+ * guards its dynamic `from` clause against it (keeping the table name off the
27
+ * SQL-injection surface), so a new table cannot be added to one and missed in
28
+ * the other.
29
+ *
30
+ * `Revocation` is here for the same two reasons as every other entry: it
31
+ * derives a `'CadreControl.Revocation'` domain tag — its `Authorized` CHECK
32
+ * verifies an owner signature over the `'remove'`-tagged digest that
33
+ * `peer-authorization.ts`'s `revocationDigest` mints, and its `AuthorizedReissue`
34
+ * CHECK the `'reissue'`-tagged digest `ControlDatabase.reissueRevocations`
35
+ * signs — and `countRows` counts it.
36
+ */
37
+ export const CONTROL_TABLES = [
38
+ 'OwnerKey',
39
+ 'ValidationKey',
40
+ 'Strand',
41
+ 'StrandPartyKey',
42
+ 'JoinedStrand',
43
+ 'PendingJoin',
44
+ 'CadrePeer',
45
+ 'DeviceToken',
46
+ 'FormationInvite',
47
+ 'FormationUsage',
48
+ 'Revocation',
49
+ ] as const;
50
+
51
+ /**
52
+ * Name of a CadreControl table. Doubles as the table half of a
53
+ * {@link ControlDomain} tag.
54
+ */
55
+ export type ControlTable = typeof CONTROL_TABLES[number];
56
+
57
+ /**
58
+ * The control tables whose rows carry a single-use `StampId` retired into
59
+ * `CadreControl.Revocation` on delete — i.e. the ones the schema's
60
+ * `NotRevoked` / `RevocationRecorded` CHECK pair guards, and the only values
61
+ * `Revocation.RowIsGone` accepts in `TableName`. `Extract` from
62
+ * {@link ControlTable} rather than a fresh literal list, so a renamed table is a
63
+ * compile error here instead of a silently dead branch.
64
+ *
65
+ * Lives in this import-free module rather than beside its main consumer
66
+ * (`control-database.ts`) so the lightweight signers — `peer-authorization.ts`'s
67
+ * `revocationDigest` — can type against it without pulling in the runtime.
68
+ */
69
+ export type RevocableTable = Extract<ControlTable, 'OwnerKey' | 'CadrePeer' | 'ValidationKey' | 'Strand' | 'StrandPartyKey' | 'JoinedStrand' | 'PendingJoin' | 'DeviceToken'>;
70
+
71
+ /**
72
+ * What a signature authorizes, scoped to one table rule — or, for
73
+ * `'Cadre.Enrollment'`, the offline peer vouch that `cadre enroll register`
74
+ * verifies (no table checks it, so it needs its own domain to stay disjoint
75
+ * from every table rule).
76
+ */
77
+ export type ControlDomain = `CadreControl.${ControlTable}` | 'Cadre.Enrollment';
78
+
79
+ /**
80
+ * The action half of the tag:
81
+ * - `'add'` / `'remove'` — insert / delete of the named row.
82
+ * - `'vouch'` — an owner (or validation key) vouches the row's semantics
83
+ * without adding or removing it: the `CadrePeer` membership vouch (shared,
84
+ * deliberately, by its insert and its owner-update branch), the
85
+ * `FormationUsage` disclosure validation, and the offline enrollment vouch.
86
+ * `DeviceToken` has no `'vouch'` digest — its owner re-touch branch was
87
+ * removed (it rewrote the row outside the monotonicity guard), so an owner
88
+ * correcting a token deletes and re-inserts it.
89
+ * - `'publish'` — a peer self-signs its OWN record (the `CadrePeer` /
90
+ * `DeviceToken` self-update branches), with its own key rather than an
91
+ * owner key.
92
+ * - `'consent'` — a peer self-signs its OWN `FormationUsage` redemption (the
93
+ * joiner proving it agreed to join), with its own key. Distinct from the
94
+ * approver's `'vouch'` over the same table so the two stored signatures are
95
+ * never interchangeable.
96
+ * - `'reissue'` — an owner re-writes an existing `Revocation` tombstone,
97
+ * bumping its `ReissuedAt` counter so a tombstone committed while the node
98
+ * was alone can be re-broadcast. Distinct from `'remove'` so a tombstone
99
+ * append approval can never be replayed as a re-issue and vice versa.
100
+ */
101
+ export type ControlAction = 'add' | 'remove' | 'vouch' | 'publish' | 'consent' | 'reissue';
102
+
103
+ /**
104
+ * The full ordered field vector a control-plane signature covers. Digest this
105
+ * with the crypto plugin's injective multi-field encoding (every field TEXT);
106
+ * the SQL mirror passes the same literals as leading `digest(...)` arguments:
107
+ *
108
+ * TS: digest(controlAuthorizationFields('CadreControl.X', 'add', [a, b]), 'sha256', ...)
109
+ * SQL: digest('CadreControl.X', 'add', new.A, new.B)
110
+ */
111
+ export function controlAuthorizationFields(
112
+ domain: ControlDomain,
113
+ action: ControlAction,
114
+ rowFields: string[],
115
+ ): string[] {
116
+ return [domain, action, ...rowFields];
117
+ }
@@ -32,7 +32,7 @@ import type { CohortPeerRow } from './strand-cohort.js';
32
32
  * An interval between pass starts, not a deadline on a pass. Passes are
33
33
  * single-flight, so a pass that runs longer than this is joined rather than
34
34
  * stacked, and the effective cadence becomes the pass length: one unreachable
35
- * sibling's dial alone can take the whole per-peer dial budget (64 s at the
35
+ * sibling's dial alone can take the whole per-peer dial budget (86 s at the
36
36
  * default declared link).
37
37
  */
38
38
  export const DEFAULT_CONTROL_COHORT_RECONCILE_MS = 15_000;