@serfab/cadre-core 0.7.1 → 0.9.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 (170) hide show
  1. package/README.md +11 -10
  2. package/dist/cadre-node.d.ts +818 -19
  3. package/dist/cadre-node.js +1952 -99
  4. package/dist/cadre-node.js.map +1 -1
  5. package/dist/canonical-datetime.d.ts +33 -0
  6. package/dist/canonical-datetime.js +38 -0
  7. package/dist/canonical-datetime.js.map +1 -0
  8. package/dist/canonical-json.d.ts +12 -0
  9. package/dist/canonical-json.js +33 -0
  10. package/dist/canonical-json.js.map +1 -0
  11. package/dist/control-cohort.d.ts +63 -0
  12. package/dist/control-cohort.js +80 -0
  13. package/dist/control-cohort.js.map +1 -0
  14. package/dist/control-database.d.ts +279 -8
  15. package/dist/control-database.js +563 -134
  16. package/dist/control-database.js.map +1 -1
  17. package/dist/control-formation-recorder.d.ts +89 -0
  18. package/dist/control-formation-recorder.js +139 -0
  19. package/dist/control-formation-recorder.js.map +1 -0
  20. package/dist/control-schema.d.ts +12 -0
  21. package/dist/control-schema.js +223 -0
  22. package/dist/control-schema.js.map +1 -0
  23. package/dist/control-stream.d.ts +54 -0
  24. package/dist/control-stream.js +104 -0
  25. package/dist/control-stream.js.map +1 -0
  26. package/dist/device-token.d.ts +50 -0
  27. package/dist/device-token.js +66 -0
  28. package/dist/device-token.js.map +1 -0
  29. package/dist/diagnostics/connection-path.d.ts +118 -0
  30. package/dist/diagnostics/connection-path.js +204 -0
  31. package/dist/diagnostics/connection-path.js.map +1 -0
  32. package/dist/diagnostics/webrtc-turn-tracker.d.ts +50 -0
  33. package/dist/diagnostics/webrtc-turn-tracker.js +196 -0
  34. package/dist/diagnostics/webrtc-turn-tracker.js.map +1 -0
  35. package/dist/ed25519-key.d.ts +42 -0
  36. package/dist/ed25519-key.js +51 -0
  37. package/dist/ed25519-key.js.map +1 -0
  38. package/dist/hibernation-manager.d.ts +79 -0
  39. package/dist/hibernation-manager.js +173 -23
  40. package/dist/hibernation-manager.js.map +1 -1
  41. package/dist/index.d.ts +25 -4
  42. package/dist/index.js +59 -4
  43. package/dist/index.js.map +1 -1
  44. package/dist/key-store-file.d.ts +52 -0
  45. package/dist/key-store-file.js +194 -0
  46. package/dist/key-store-file.js.map +1 -0
  47. package/dist/key-store.d.ts +75 -0
  48. package/dist/key-store.js +66 -0
  49. package/dist/key-store.js.map +1 -0
  50. package/dist/peer-authorization.d.ts +48 -0
  51. package/dist/peer-authorization.js +66 -0
  52. package/dist/peer-authorization.js.map +1 -0
  53. package/dist/peer-record.d.ts +89 -0
  54. package/dist/peer-record.js +117 -0
  55. package/dist/peer-record.js.map +1 -0
  56. package/dist/push-credentials.d.ts +34 -0
  57. package/dist/push-credentials.js +81 -0
  58. package/dist/push-credentials.js.map +1 -0
  59. package/dist/push-fanout.d.ts +137 -0
  60. package/dist/push-fanout.js +197 -0
  61. package/dist/push-fanout.js.map +1 -0
  62. package/dist/push-node.d.ts +38 -0
  63. package/dist/push-node.js +48 -0
  64. package/dist/push-node.js.map +1 -0
  65. package/dist/push-notifier-apns.d.ts +61 -0
  66. package/dist/push-notifier-apns.js +199 -0
  67. package/dist/push-notifier-apns.js.map +1 -0
  68. package/dist/push-notifier-fcm.d.ts +44 -0
  69. package/dist/push-notifier-fcm.js +182 -0
  70. package/dist/push-notifier-fcm.js.map +1 -0
  71. package/dist/push-notifier-shared.d.ts +18 -0
  72. package/dist/push-notifier-shared.js +25 -0
  73. package/dist/push-notifier-shared.js.map +1 -0
  74. package/dist/push-notifier.d.ts +52 -0
  75. package/dist/push-notifier.js +22 -0
  76. package/dist/push-notifier.js.map +1 -0
  77. package/dist/schema-verification.d.ts +11 -2
  78. package/dist/schema-verification.js +15 -4
  79. package/dist/schema-verification.js.map +1 -1
  80. package/dist/seed-bootstrap.d.ts +228 -21
  81. package/dist/seed-bootstrap.js +489 -168
  82. package/dist/seed-bootstrap.js.map +1 -1
  83. package/dist/seed-trust-policy.d.ts +63 -0
  84. package/dist/seed-trust-policy.js +56 -0
  85. package/dist/seed-trust-policy.js.map +1 -0
  86. package/dist/strand-addr-protocol.d.ts +132 -0
  87. package/dist/strand-addr-protocol.js +313 -0
  88. package/dist/strand-addr-protocol.js.map +1 -0
  89. package/dist/strand-cohort.d.ts +54 -0
  90. package/dist/strand-cohort.js +38 -0
  91. package/dist/strand-cohort.js.map +1 -0
  92. package/dist/strand-database.d.ts +54 -6
  93. package/dist/strand-database.js +88 -100
  94. package/dist/strand-database.js.map +1 -1
  95. package/dist/strand-formation-manager.d.ts +79 -19
  96. package/dist/strand-formation-manager.js +196 -104
  97. package/dist/strand-formation-manager.js.map +1 -1
  98. package/dist/strand-formation-protocol.d.ts +162 -0
  99. package/dist/strand-formation-protocol.js +279 -0
  100. package/dist/strand-formation-protocol.js.map +1 -0
  101. package/dist/strand-instance-manager.d.ts +73 -4
  102. package/dist/strand-instance-manager.js +167 -41
  103. package/dist/strand-instance-manager.js.map +1 -1
  104. package/dist/strand-member-key.d.ts +29 -0
  105. package/dist/strand-member-key.js +38 -0
  106. package/dist/strand-member-key.js.map +1 -0
  107. package/dist/strand-member-registry.d.ts +98 -0
  108. package/dist/strand-member-registry.js +129 -0
  109. package/dist/strand-member-registry.js.map +1 -0
  110. package/dist/strand-membership-writer.d.ts +361 -0
  111. package/dist/strand-membership-writer.js +449 -0
  112. package/dist/strand-membership-writer.js.map +1 -0
  113. package/dist/strand-solicitation.d.ts +77 -2
  114. package/dist/strand-solicitation.js +25 -4
  115. package/dist/strand-solicitation.js.map +1 -1
  116. package/dist/strand-wake-payload.d.ts +30 -0
  117. package/dist/strand-wake-payload.js +20 -0
  118. package/dist/strand-wake-payload.js.map +1 -0
  119. package/dist/strand-wake-protocol.d.ts +114 -0
  120. package/dist/strand-wake-protocol.js +257 -0
  121. package/dist/strand-wake-protocol.js.map +1 -0
  122. package/dist/strand-watcher.d.ts +6 -2
  123. package/dist/strand-watcher.js +57 -17
  124. package/dist/strand-watcher.js.map +1 -1
  125. package/dist/types.d.ts +436 -33
  126. package/dist/types.js +22 -5
  127. package/dist/types.js.map +1 -1
  128. package/package.json +18 -8
  129. package/src/cadre-node.ts +2981 -948
  130. package/src/canonical-datetime.ts +39 -0
  131. package/src/canonical-json.ts +30 -0
  132. package/src/control-cohort.ts +103 -0
  133. package/src/control-database.ts +948 -383
  134. package/src/control-formation-recorder.ts +151 -0
  135. package/src/control-schema.ts +222 -0
  136. package/src/control-stream.ts +128 -0
  137. package/src/device-token.ts +89 -0
  138. package/src/diagnostics/connection-path.ts +277 -0
  139. package/src/diagnostics/webrtc-turn-tracker.ts +222 -0
  140. package/src/ed25519-key.ts +69 -0
  141. package/src/hibernation-manager.ts +197 -28
  142. package/src/index.ts +275 -79
  143. package/src/key-store-file.ts +203 -0
  144. package/src/key-store.ts +99 -0
  145. package/src/peer-authorization.ts +81 -0
  146. package/src/peer-record.ts +146 -0
  147. package/src/push-credentials.ts +84 -0
  148. package/src/push-fanout.ts +272 -0
  149. package/src/push-node.ts +64 -0
  150. package/src/push-notifier-apns.ts +247 -0
  151. package/src/push-notifier-fcm.ts +220 -0
  152. package/src/push-notifier-shared.ts +28 -0
  153. package/src/push-notifier.ts +52 -0
  154. package/src/schema-verification.ts +18 -4
  155. package/src/seed-bootstrap.ts +563 -223
  156. package/src/seed-trust-policy.ts +107 -0
  157. package/src/strand-addr-protocol.ts +410 -0
  158. package/src/strand-cohort.ts +77 -0
  159. package/src/strand-database.ts +113 -141
  160. package/src/strand-formation-manager.ts +233 -142
  161. package/src/strand-formation-protocol.ts +391 -0
  162. package/src/strand-instance-manager.ts +207 -56
  163. package/src/strand-member-key.ts +39 -0
  164. package/src/strand-member-registry.ts +177 -0
  165. package/src/strand-membership-writer.ts +640 -0
  166. package/src/strand-solicitation.ts +93 -4
  167. package/src/strand-wake-payload.ts +32 -0
  168. package/src/strand-wake-protocol.ts +331 -0
  169. package/src/strand-watcher.ts +61 -17
  170. package/src/types.ts +1032 -582
@@ -1 +1 @@
1
- {"version":3,"file":"control-database.js","sourceRoot":"","sources":["../src/control-database.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"control-database.js","sourceRoot":"","sources":["../src/control-database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ import type { ControlDatabase } from './control-database.js';
2
+ import type { FormationUsageRecorder, ResolvedHostStrand } from './strand-solicitation.js';
3
+ import type { OpenInvitation } from './types.js';
4
+ /**
5
+ * {@link FormationUsageRecorder} backed by the real `CadreControl` tables.
6
+ *
7
+ * It reads `FormationInvite` / `FormationUsage` to answer token-validity and
8
+ * usage questions, and writes the consent row that records a redemption. Two
9
+ * provisioning shapes are supported, keyed on whether the invite binds a host strand:
10
+ *
11
+ * - **Bound (provision-then-record):** the host strand already exists (owner-signed
12
+ * up front and named by the invite's `StrandId`), so {@link resolveStrand} reports it
13
+ * and {@link recordUsage} writes the consent row against that pre-existing strand
14
+ * (record-only) rather than inserting a new `Strand`.
15
+ * - **Unbound (responder-provisions):** the invite carries no `StrandId`, so
16
+ * {@link provisionAndRecord} mints a fresh strand and records consent against it
17
+ * ATOMICALLY (one `FormationUsage` row), closing the single-use hole the older
18
+ * never-record fallback left open.
19
+ *
20
+ * This replaces the in-memory stubs used by the formation tests so the consent path
21
+ * is exercised against the persisted control network.
22
+ *
23
+ * Usage accounting follows the schema's `FormationUsage.Authorized` semantics:
24
+ * a null `TotalUses` means unlimited uses; otherwise the invite is "used up"
25
+ * once the recorded usage count reaches `TotalUses`.
26
+ */
27
+ export declare class ControlFormationUsageRecorder implements FormationUsageRecorder {
28
+ private readonly controlDatabase;
29
+ constructor(controlDatabase: ControlDatabase);
30
+ /** A token is valid when a matching, unexpired `FormationInvite` exists. */
31
+ isTokenValid(token: string): Promise<{
32
+ valid: boolean;
33
+ invitation?: OpenInvitation;
34
+ }>;
35
+ /**
36
+ * A token is "used" when its recorded usage count has reached the invite's
37
+ * `TotalUses`. A null `TotalUses` (unlimited) is never used up; an unknown
38
+ * token is reported not-used (validity is handled by {@link isTokenValid}).
39
+ */
40
+ isTokenUsed(token: string): Promise<boolean>;
41
+ /**
42
+ * Record consent against an **already-existing** host strand (record-only): the
43
+ * single `FormationUsage` insert auto-commits and the deferred `StrandExists`
44
+ * CHECK is satisfied by the pre-existing strand. This is the provision-then-record
45
+ * commitment — the strand was minted owner-signed up front, so we do NOT
46
+ * re-insert it (which would double-insert the same PK). `initiatorKey` is carried
47
+ * as the usage `PeerId` (advisory). Use {@link ControlDatabase.redeemInvitation}
48
+ * for the consent-creates-strand path instead.
49
+ */
50
+ recordUsage(token: string, initiatorKey: string, strandId: string): Promise<void>;
51
+ /**
52
+ * Classify the host strand this invite binds to (see {@link ResolvedHostStrand}):
53
+ *
54
+ * - no invite / no `StrandId` → `unbound` (responder-provisions path).
55
+ * - `StrandId` set AND the strand row is present → `bound`, carrying its
56
+ * `MemberPrivateKey` (the closed-strand read-gating secret) for delivery to a
57
+ * validated invitee.
58
+ * - `StrandId` set but the strand row is absent → `missing` (the host strand has not
59
+ * converged on this responder yet); the manager rejects cleanly instead of recording
60
+ * usage against a non-existent strand, which would fail the deferred `StrandExists`
61
+ * CHECK at commit and drop the result frame.
62
+ */
63
+ resolveStrand(token: string): Promise<ResolvedHostStrand>;
64
+ /**
65
+ * Provision a NEW strand for an UNBOUND invite and record consent against it in ONE
66
+ * transaction (the responder-provisions fallback, now single-use-enforced).
67
+ *
68
+ * Mints a fresh, globally-unique strand id from {@link randomBytes} — the same
69
+ * cross-platform CSPRNG `control-database`'s `generateStampId` uses, NOT
70
+ * `crypto.randomUUID` / `Date.now` / `Math.random` (not uniformly available across
71
+ * node/browser/RN) — then delegates to {@link ControlDatabase.redeemInvitation}, whose
72
+ * single `begin … commit` inserts the consent-authorized `Strand` row AND the matching
73
+ * `FormationUsage` row together (both deferred CHECKs see both rows at commit). That one
74
+ * `FormationUsage` row makes the unbound redemption single-use exactly like the bound
75
+ * path: the next redemption of a `TotalUses:1` invite sees `count 1 >= 1` and is rejected.
76
+ *
77
+ * The strand is open (`'o'`) — an unbound responder-provisioned strand has no membership
78
+ * key — so the returned `memberPrivateKey` is null. `sAppId` is accepted for parity/future
79
+ * use; `redeemInvitation` does not currently thread it into the `Strand` row.
80
+ *
81
+ * A concurrent redemption of the same single-use invite collides on the
82
+ * `(Token, UseNumber)` PK and this call THROWS for the loser — the manager maps that to a
83
+ * clean protocol rejection (it never lets the dropped insert close the stream silently).
84
+ */
85
+ provisionAndRecord(token: string, initiatorKey: string, _sAppId: string): Promise<{
86
+ strandId: string;
87
+ memberPrivateKey: string | null;
88
+ }>;
89
+ }
@@ -0,0 +1,139 @@
1
+ import debug from 'debug';
2
+ import { randomBytes } from '@optimystic/quereus-plugin-crypto';
3
+ const log = debug('sereus:cadre:formation-recorder');
4
+ /** Far-future sentinel for an invitation that never expires (max valid JS Date). */
5
+ const NEVER_EXPIRES = new Date(8640000000000000);
6
+ /**
7
+ * {@link FormationUsageRecorder} backed by the real `CadreControl` tables.
8
+ *
9
+ * It reads `FormationInvite` / `FormationUsage` to answer token-validity and
10
+ * usage questions, and writes the consent row that records a redemption. Two
11
+ * provisioning shapes are supported, keyed on whether the invite binds a host strand:
12
+ *
13
+ * - **Bound (provision-then-record):** the host strand already exists (owner-signed
14
+ * up front and named by the invite's `StrandId`), so {@link resolveStrand} reports it
15
+ * and {@link recordUsage} writes the consent row against that pre-existing strand
16
+ * (record-only) rather than inserting a new `Strand`.
17
+ * - **Unbound (responder-provisions):** the invite carries no `StrandId`, so
18
+ * {@link provisionAndRecord} mints a fresh strand and records consent against it
19
+ * ATOMICALLY (one `FormationUsage` row), closing the single-use hole the older
20
+ * never-record fallback left open.
21
+ *
22
+ * This replaces the in-memory stubs used by the formation tests so the consent path
23
+ * is exercised against the persisted control network.
24
+ *
25
+ * Usage accounting follows the schema's `FormationUsage.Authorized` semantics:
26
+ * a null `TotalUses` means unlimited uses; otherwise the invite is "used up"
27
+ * once the recorded usage count reaches `TotalUses`.
28
+ */
29
+ export class ControlFormationUsageRecorder {
30
+ constructor(controlDatabase) {
31
+ this.controlDatabase = controlDatabase;
32
+ }
33
+ /** A token is valid when a matching, unexpired `FormationInvite` exists. */
34
+ async isTokenValid(token) {
35
+ const invite = await this.controlDatabase.queryFormationInvite(token);
36
+ if (!invite) {
37
+ return { valid: false };
38
+ }
39
+ if (invite.expiresAtMs !== null && invite.expiresAtMs <= Date.now()) {
40
+ log('Token expired: %s', token);
41
+ return { valid: false };
42
+ }
43
+ return {
44
+ valid: true,
45
+ invitation: {
46
+ token: invite.token,
47
+ sAppId: invite.sAppId,
48
+ expiration: invite.expiresAtMs !== null ? new Date(invite.expiresAtMs) : NEVER_EXPIRES,
49
+ bootstrap: [],
50
+ },
51
+ };
52
+ }
53
+ /**
54
+ * A token is "used" when its recorded usage count has reached the invite's
55
+ * `TotalUses`. A null `TotalUses` (unlimited) is never used up; an unknown
56
+ * token is reported not-used (validity is handled by {@link isTokenValid}).
57
+ */
58
+ async isTokenUsed(token) {
59
+ const invite = await this.controlDatabase.queryFormationInvite(token);
60
+ if (!invite || invite.totalUses === null) {
61
+ return false;
62
+ }
63
+ const uses = await this.controlDatabase.countFormationUsage(token);
64
+ return uses >= invite.totalUses;
65
+ }
66
+ /**
67
+ * Record consent against an **already-existing** host strand (record-only): the
68
+ * single `FormationUsage` insert auto-commits and the deferred `StrandExists`
69
+ * CHECK is satisfied by the pre-existing strand. This is the provision-then-record
70
+ * commitment — the strand was minted owner-signed up front, so we do NOT
71
+ * re-insert it (which would double-insert the same PK). `initiatorKey` is carried
72
+ * as the usage `PeerId` (advisory). Use {@link ControlDatabase.redeemInvitation}
73
+ * for the consent-creates-strand path instead.
74
+ */
75
+ async recordUsage(token, initiatorKey, strandId) {
76
+ await this.controlDatabase.recordFormationUsage({ token, strandId, peerId: initiatorKey });
77
+ log('Recorded formation usage: token=%s strand=%s', token, strandId);
78
+ }
79
+ /**
80
+ * Classify the host strand this invite binds to (see {@link ResolvedHostStrand}):
81
+ *
82
+ * - no invite / no `StrandId` → `unbound` (responder-provisions path).
83
+ * - `StrandId` set AND the strand row is present → `bound`, carrying its
84
+ * `MemberPrivateKey` (the closed-strand read-gating secret) for delivery to a
85
+ * validated invitee.
86
+ * - `StrandId` set but the strand row is absent → `missing` (the host strand has not
87
+ * converged on this responder yet); the manager rejects cleanly instead of recording
88
+ * usage against a non-existent strand, which would fail the deferred `StrandExists`
89
+ * CHECK at commit and drop the result frame.
90
+ */
91
+ async resolveStrand(token) {
92
+ const invite = await this.controlDatabase.queryFormationInvite(token);
93
+ if (!invite || !invite.strandId) {
94
+ return { kind: 'unbound' };
95
+ }
96
+ const strand = await this.controlDatabase.queryStrand(invite.strandId);
97
+ if (!strand) {
98
+ return { kind: 'missing', strandId: invite.strandId };
99
+ }
100
+ return {
101
+ kind: 'bound',
102
+ strandId: invite.strandId,
103
+ memberPrivateKey: strand.MemberPrivateKey ?? null,
104
+ };
105
+ }
106
+ /**
107
+ * Provision a NEW strand for an UNBOUND invite and record consent against it in ONE
108
+ * transaction (the responder-provisions fallback, now single-use-enforced).
109
+ *
110
+ * Mints a fresh, globally-unique strand id from {@link randomBytes} — the same
111
+ * cross-platform CSPRNG `control-database`'s `generateStampId` uses, NOT
112
+ * `crypto.randomUUID` / `Date.now` / `Math.random` (not uniformly available across
113
+ * node/browser/RN) — then delegates to {@link ControlDatabase.redeemInvitation}, whose
114
+ * single `begin … commit` inserts the consent-authorized `Strand` row AND the matching
115
+ * `FormationUsage` row together (both deferred CHECKs see both rows at commit). That one
116
+ * `FormationUsage` row makes the unbound redemption single-use exactly like the bound
117
+ * path: the next redemption of a `TotalUses:1` invite sees `count 1 >= 1` and is rejected.
118
+ *
119
+ * The strand is open (`'o'`) — an unbound responder-provisioned strand has no membership
120
+ * key — so the returned `memberPrivateKey` is null. `sAppId` is accepted for parity/future
121
+ * use; `redeemInvitation` does not currently thread it into the `Strand` row.
122
+ *
123
+ * A concurrent redemption of the same single-use invite collides on the
124
+ * `(Token, UseNumber)` PK and this call THROWS for the loser — the manager maps that to a
125
+ * clean protocol rejection (it never lets the dropped insert close the stream silently).
126
+ */
127
+ async provisionAndRecord(token, initiatorKey, _sAppId) {
128
+ const strandId = `strand-${randomBytes(128, 'hex')}`;
129
+ await this.controlDatabase.redeemInvitation({
130
+ token,
131
+ strandId,
132
+ type: 'o',
133
+ peerId: initiatorKey,
134
+ });
135
+ log('Provisioned + recorded unbound strand: token=%s strand=%s', token, strandId);
136
+ return { strandId, memberPrivateKey: null };
137
+ }
138
+ }
139
+ //# sourceMappingURL=control-formation-recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-formation-recorder.js","sourceRoot":"","sources":["../src/control-formation-recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Embedded control schema for cross-platform compatibility.
3
+ *
4
+ * This is the authoritative runtime copy of the CadreControl authorization
5
+ * schema. It is duplicated from `schemas/control.qsql` so that React Native and
6
+ * other filesystem-less environments get the schema without a runtime file read.
7
+ *
8
+ * The two copies MUST stay identical — `control-schema-drift.spec.ts` fails the
9
+ * build if they drift. Any edit here must be mirrored in `schemas/control.qsql`
10
+ * and vice versa.
11
+ */
12
+ export declare const CONTROL_SCHEMA = "-- This manages a Sereus party's cadre, or set of nodes, and their participation in strands (networks)\ndeclare schema CadreControl {\n -- A key that can authorize various control changes\n table OwnerKey (\n Key text primary key,\n StampId text not null unique, -- single-use authorization nonce (anti-replay)\n constraint Authorized check (\n -- Bootstrap: first owner key needs no existing authorization\n (select count(1) from OwnerKey) <= 1\n\n -- Old owner authorizes by signing over THIS row (Key, StampId); single-use via unique StampId\n or (old.Key is not null and old.Key = context.OwnerKey and verify(digest(new.Key, new.StampId), context.Signature, old.Key, 'ed25519'))\n\n -- or other owners authorize by signing over THIS row (Key, StampId); single-use via unique StampId\n or exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.Key, new.StampId), context.Signature, A.Key, 'ed25519'))\n )\n ) with context (OwnerKey text null, Signature text null);\n\n -- A key that can validate a strand formation disclosure\n table ValidationKey (\n Key text primary key,\n StampId text not null unique, -- single-use authorization nonce (anti-replay)\n constraint Authorized check (\n -- Owners authorize by signing over THIS row (Key, StampId); single-use via unique StampId\n exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.Key, new.StampId), context.Signature, A.Key, 'ed25519'))\n )\n ) with context (OwnerKey text, Signature text);\n\n -- A network of members sharing an sApp database, each contributing peer nodes (their cadre) to the overall cohort\n -- Cadre peers should participate in each of these strands\n table Strand (\n Id text primary key, -- UUID\n MemberPrivateKey text null unique, -- Our private key as a member of this strand\n Type text, -- Types: 'o' = Open, 'c' = Closed -- Open can still control writes in the sApp, but only Closed controls reads\n StampId text not null unique, -- single-use authorization nonce (anti-replay)\n constraint Authorized check (\n -- Authorized by an owner signing over THIS row (Id, Type, MemberPrivateKey, StampId); single-use via unique StampId\n exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.Id, new.Type, coalesce(new.MemberPrivateKey, ''), new.StampId), context.Signature, A.Key, 'ed25519'))\n\n -- or authorized by a cadre peer who has received a valid formation invitation.\n -- That path has no signed writer yet; when one is built it must still supply a\n -- fresh, unique StampId to satisfy the not-null/unique anti-replay column.\n or exists (select 1 from FormationUsage FU where FU.StrandId = new.Id)\n ),\n constraint MemberKeyClosedOnly check (\n -- An open strand ('o') has no membership gate, so it must not carry a\n -- member key. A non-null MemberPrivateKey requires a closed strand ('c').\n new.MemberPrivateKey is null or new.Type = 'c'\n )\n ) with context (OwnerKey text, Signature text);\n\n -- A peer (node) that is part of the cadre, carrying a self-published,\n -- freshness-stamped, self-signed address record (see PeerAddressRecord in cadre-core).\n -- The row IS the peer-address record: a resolver reads it, re-verifies Sig against\n -- PublicKey, checks freshness (UpdatedAt) and trust, then dials the addrs.\n table CadrePeer (\n PeerId text primary key,\n PublicKey text null, -- ed25519 (base64url) whose libp2p identity == PeerId (null if non-Ed25519)\n Multiaddr text, -- comma-joined current addrs (signaling / p2p-circuit first)\n UpdatedAt int null, -- epoch ms; strictly increases per self-update (replay/rollback guard)\n Sig text null, -- ed25519 self-signature over the signed payload (base64url); null until self-published\n StampId text not null unique, -- single-use authorization nonce (anti-replay), bound into the voucher/remove digests; rotates on (re)insert\n VouchOwner text null, -- ed25519 (base64url) owner key that vouched this membership (== insert context.OwnerKey)\n VouchSig text null, -- that owner's signature over digest(PeerId, StampId) (== insert context.Signature). A reader checks VouchOwner against its NODE-LOCAL trusted-owner anchor (not this replicated table, which a self-owner can pollute) to decide authorized membership.\n constraint AuthorizedInsert check on insert (\n -- Authorized by an owner key, which vouches both membership and the\n -- PublicKey<->PeerId binding (cadre-core derives PublicKey from PeerId before insert).\n -- The digest binds PeerId + the single-use StampId nonce (two TEXT fields),\n -- matching cadre-core peer-authorization.ts:cadrePeerVoucherDigest.\n exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.PeerId, new.StampId), context.Signature, A.Key, 'ed25519'))\n -- Persist the vouching (owner, signature) onto the row so a reader can later\n -- re-check VouchOwner against its node-local anchor. The stored pair MUST equal\n -- the pair the verify above validated, so a writer cannot store a voucher it did\n -- not actually receive a signature for.\n and new.VouchOwner = context.OwnerKey\n and new.VouchSig = context.Signature\n ),\n constraint AuthorizedDelete check on delete (\n -- Delete is authorized by a signature over a DISTINCT 'remove'-scoped digest bound\n -- to the row's StampId (cadre-core peer-authorization.ts:cadrePeerRemoveDigest), so\n -- the stored voucher (a signature over digest(PeerId, StampId)) can NEVER be replayed\n -- to authorize a delete. The remove signature rides in context and is never stored.\n exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(old.PeerId, old.StampId, 'remove'), context.Signature, A.Key, 'ed25519'))\n ),\n constraint AuthorizedUpdate check on update (\n -- Peer self-updates its own addrs + freshness, signing with its OWN ed25519 key\n -- (the key behind PeerId). PeerId/PublicKey/StampId/voucher are immutable on\n -- self-update, UpdatedAt must strictly increase (replay guard), and Sig is verified\n -- against the stored PublicKey over the same payload the publish path signs\n -- (cadre-core peer-record.ts:peerRecordSignedPayload).\n (\n new.PeerId = old.PeerId\n and new.PublicKey = old.PublicKey\n and new.StampId = old.StampId\n and new.VouchOwner = old.VouchOwner\n and new.VouchSig = old.VouchSig\n and new.UpdatedAt > coalesce(old.UpdatedAt, 0)\n and verify(\n digest(new.PeerId || '|' || new.Multiaddr || '|' || cast(new.UpdatedAt as text)),\n new.Sig, new.PublicKey, 'ed25519')\n )\n -- or an owner re-authorizes (rotation / correction): re-vouches the row over\n -- its current StampId, so the stored voucher is re-bound to the re-authorizing owner.\n or (\n exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.PeerId, new.StampId), context.Signature, A.Key, 'ed25519'))\n and new.VouchOwner = context.OwnerKey\n and new.VouchSig = context.Signature\n )\n )\n ) with context (OwnerKey text null, Signature text);\n\n -- A mobile cadre peer's platform push token (FCM/APNs), self-published so a\n -- server peer can deliver a push-wake to a suspended app over the platform push\n -- channel (a control-network dial cannot reach an OS-suspended process). The row\n -- mirrors CadrePeer: a resolver re-verifies Sig against the CadrePeer.PublicKey for\n -- this PeerId (see device-token.ts:deviceTokenSignedPayload), checks freshness, then\n -- hands the token to the push sender.\n table DeviceToken (\n PeerId text primary key, -- the CadrePeer this token belongs to\n Platform text not null, -- 'fcm' | 'apns'\n Token text not null, -- opaque platform device/registration token\n UpdatedAt int null, -- epoch ms; strictly increases per self-update (replay guard)\n Sig text null, -- ed25519 self-sig over (PeerId|Platform|Token|UpdatedAt)\n constraint AuthorizedInsert check on insert, delete (\n -- Authorized by an owner key (membership vouch), exactly like CadrePeer.\n -- The single-field digest frames the base58btc PeerId as TEXT.\n exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(coalesce(new.PeerId, old.PeerId)), context.Signature, A.Key, 'ed25519'))\n ),\n constraint AuthorizedUpdate check on update (\n -- Peer self-updates its own token, signing with its OWN ed25519 key (the key\n -- behind PeerId). PeerId is immutable, UpdatedAt must strictly increase (replay\n -- guard), and Sig is verified against the stored CadrePeer.PublicKey over the\n -- signed payload (cadre-core device-token.ts:deviceTokenSignedPayload). Platform\n -- and Token may change on self-update (platform switch / reinstall / rotation).\n (\n new.PeerId = old.PeerId\n and new.UpdatedAt > coalesce(old.UpdatedAt, 0)\n and exists (select 1 from CadrePeer P where P.PeerId = new.PeerId and verify(\n digest(new.PeerId || '|' || new.Platform || '|' || new.Token || '|' || cast(new.UpdatedAt as text)),\n new.Sig, P.PublicKey, 'ed25519'))\n )\n -- or an owner re-authorizes (rotation / correction)\n or exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.PeerId), context.Signature, A.Key, 'ed25519'))\n )\n ) with context (OwnerKey text null, Signature text);\n\n -- An open invitation to form a strand with this party\n table FormationInvite (\n Token text primary key, -- Just a random string\n sAppId text, -- The app for the strand that will be formed\n ExpiresAt datetime null,\n TotalUses int null check (TotalUses >= 0),\n ValidationUrl text null, -- Web hook - send disclosure, IP address...\n StrandId text null, -- Host strand this invite binds to (provision-then-record). Non-null => the responder records consent against this pre-existing strand; null => legacy responder-provisions path.\n StampId text not null unique, -- single-use authorization nonce (anti-replay)\n constraint AuthorizedAddOrRemove check on insert, delete (\n -- Authorized by an owner signing over THIS row\n -- (Token, sAppId, ExpiresAt, TotalUses, ValidationUrl, StrandId, StampId); single-use via unique StampId.\n -- coalesce(new.F, old.F) binds the NEW row on insert and the OLD row on delete (cf. CadrePeer).\n -- StrandId is a nullable bound field: it signs as '' when absent (cf. ValidationUrl).\n exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(\n digest(\n coalesce(new.Token, old.Token),\n coalesce(new.sAppId, old.sAppId),\n coalesce(cast(coalesce(new.ExpiresAt, old.ExpiresAt) as text), ''),\n coalesce(cast(coalesce(new.TotalUses, old.TotalUses) as text), ''),\n coalesce(coalesce(new.ValidationUrl, old.ValidationUrl), ''),\n coalesce(coalesce(new.StrandId, old.StrandId), ''),\n coalesce(new.StampId, old.StampId)\n ),\n context.Signature, A.Key, 'ed25519'))\n ),\n -- Invites are insert/delete only: forbid in-place mutation so the row-bound\n -- AuthorizedAddOrRemove signature cannot be sidestepped by updating consent\n -- parameters (TotalUses/ExpiresAt/...) after a legitimate insert. A bare check\n -- defaults to insert+update; the check on insert, delete above excludes update,\n -- so this guard is required. Mirrors FormationUsage.InsertOnly.\n constraint Immutable check on update (false)\n ) with context (OwnerKey text, Signature text);\n\n table FormationUsage (\n Token text,\n UseNumber int,\n Disclosure text,\n StrandId text,\n primary key (Token, UseNumber),\n constraint InsertOnly check on update, delete (false),\n constraint Monotonic check (\n -- Read the PRE-transaction snapshot (committed.*): this CHECK auto-defers\n -- to commit (it has a subquery), by which point the row being inserted is\n -- live, so a plain from-FormationUsage would count this row itself and make\n -- UseNumber = max+1 unsatisfiable. committed.* excludes the in-flight row,\n -- giving sequential 1,2,3... per token (cross-transaction; concurrent\n -- redemptions of the same token collide on the (Token, UseNumber) PK).\n new.UseNumber = coalesce((select max(UseNumber) from committed.FormationUsage U where U.Token = new.Token), 0) + 1\n ),\n constraint Authorized check on insert (\n -- Satisfies an invitation\n exists (\n select 1 from FormationInvite FI\n where FI.Token = new.Token\n and (FI.TotalUses is null or FI.TotalUses >= new.UseNumber)\n and (FI.ExpiresAt is null or FI.ExpiresAt > context.Now)\n and (FI.ValidationUrl is null or verify(digest(new.Token || new.Disclosure), context.ValidationSignature, context.ValidationKey, 'ed25519'))\n )\n ),\n constraint StrandExists check (exists (select 1 from Strand S where S.Id = new.StrandId)),\n ) with context (PeerId text, PeerSignature text, Now datetime, ValidationKey text null, ValidationSignature text null);\n}\n\napply schema CadreControl;";
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Embedded control schema for cross-platform compatibility.
3
+ *
4
+ * This is the authoritative runtime copy of the CadreControl authorization
5
+ * schema. It is duplicated from `schemas/control.qsql` so that React Native and
6
+ * other filesystem-less environments get the schema without a runtime file read.
7
+ *
8
+ * The two copies MUST stay identical — `control-schema-drift.spec.ts` fails the
9
+ * build if they drift. Any edit here must be mirrored in `schemas/control.qsql`
10
+ * and vice versa.
11
+ */
12
+ export const CONTROL_SCHEMA = `-- This manages a Sereus party's cadre, or set of nodes, and their participation in strands (networks)
13
+ declare schema CadreControl {
14
+ -- A key that can authorize various control changes
15
+ table OwnerKey (
16
+ Key text primary key,
17
+ StampId text not null unique, -- single-use authorization nonce (anti-replay)
18
+ constraint Authorized check (
19
+ -- Bootstrap: first owner key needs no existing authorization
20
+ (select count(1) from OwnerKey) <= 1
21
+
22
+ -- Old owner authorizes by signing over THIS row (Key, StampId); single-use via unique StampId
23
+ or (old.Key is not null and old.Key = context.OwnerKey and verify(digest(new.Key, new.StampId), context.Signature, old.Key, 'ed25519'))
24
+
25
+ -- or other owners authorize by signing over THIS row (Key, StampId); single-use via unique StampId
26
+ or exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.Key, new.StampId), context.Signature, A.Key, 'ed25519'))
27
+ )
28
+ ) with context (OwnerKey text null, Signature text null);
29
+
30
+ -- A key that can validate a strand formation disclosure
31
+ table ValidationKey (
32
+ Key text primary key,
33
+ StampId text not null unique, -- single-use authorization nonce (anti-replay)
34
+ constraint Authorized check (
35
+ -- Owners authorize by signing over THIS row (Key, StampId); single-use via unique StampId
36
+ exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.Key, new.StampId), context.Signature, A.Key, 'ed25519'))
37
+ )
38
+ ) with context (OwnerKey text, Signature text);
39
+
40
+ -- A network of members sharing an sApp database, each contributing peer nodes (their cadre) to the overall cohort
41
+ -- Cadre peers should participate in each of these strands
42
+ table Strand (
43
+ Id text primary key, -- UUID
44
+ MemberPrivateKey text null unique, -- Our private key as a member of this strand
45
+ Type text, -- Types: 'o' = Open, 'c' = Closed -- Open can still control writes in the sApp, but only Closed controls reads
46
+ StampId text not null unique, -- single-use authorization nonce (anti-replay)
47
+ constraint Authorized check (
48
+ -- Authorized by an owner signing over THIS row (Id, Type, MemberPrivateKey, StampId); single-use via unique StampId
49
+ exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.Id, new.Type, coalesce(new.MemberPrivateKey, ''), new.StampId), context.Signature, A.Key, 'ed25519'))
50
+
51
+ -- or authorized by a cadre peer who has received a valid formation invitation.
52
+ -- That path has no signed writer yet; when one is built it must still supply a
53
+ -- fresh, unique StampId to satisfy the not-null/unique anti-replay column.
54
+ or exists (select 1 from FormationUsage FU where FU.StrandId = new.Id)
55
+ ),
56
+ constraint MemberKeyClosedOnly check (
57
+ -- An open strand ('o') has no membership gate, so it must not carry a
58
+ -- member key. A non-null MemberPrivateKey requires a closed strand ('c').
59
+ new.MemberPrivateKey is null or new.Type = 'c'
60
+ )
61
+ ) with context (OwnerKey text, Signature text);
62
+
63
+ -- A peer (node) that is part of the cadre, carrying a self-published,
64
+ -- freshness-stamped, self-signed address record (see PeerAddressRecord in cadre-core).
65
+ -- The row IS the peer-address record: a resolver reads it, re-verifies Sig against
66
+ -- PublicKey, checks freshness (UpdatedAt) and trust, then dials the addrs.
67
+ table CadrePeer (
68
+ PeerId text primary key,
69
+ PublicKey text null, -- ed25519 (base64url) whose libp2p identity == PeerId (null if non-Ed25519)
70
+ Multiaddr text, -- comma-joined current addrs (signaling / p2p-circuit first)
71
+ UpdatedAt int null, -- epoch ms; strictly increases per self-update (replay/rollback guard)
72
+ Sig text null, -- ed25519 self-signature over the signed payload (base64url); null until self-published
73
+ StampId text not null unique, -- single-use authorization nonce (anti-replay), bound into the voucher/remove digests; rotates on (re)insert
74
+ VouchOwner text null, -- ed25519 (base64url) owner key that vouched this membership (== insert context.OwnerKey)
75
+ VouchSig text null, -- that owner's signature over digest(PeerId, StampId) (== insert context.Signature). A reader checks VouchOwner against its NODE-LOCAL trusted-owner anchor (not this replicated table, which a self-owner can pollute) to decide authorized membership.
76
+ constraint AuthorizedInsert check on insert (
77
+ -- Authorized by an owner key, which vouches both membership and the
78
+ -- PublicKey<->PeerId binding (cadre-core derives PublicKey from PeerId before insert).
79
+ -- The digest binds PeerId + the single-use StampId nonce (two TEXT fields),
80
+ -- matching cadre-core peer-authorization.ts:cadrePeerVoucherDigest.
81
+ exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.PeerId, new.StampId), context.Signature, A.Key, 'ed25519'))
82
+ -- Persist the vouching (owner, signature) onto the row so a reader can later
83
+ -- re-check VouchOwner against its node-local anchor. The stored pair MUST equal
84
+ -- the pair the verify above validated, so a writer cannot store a voucher it did
85
+ -- not actually receive a signature for.
86
+ and new.VouchOwner = context.OwnerKey
87
+ and new.VouchSig = context.Signature
88
+ ),
89
+ constraint AuthorizedDelete check on delete (
90
+ -- Delete is authorized by a signature over a DISTINCT 'remove'-scoped digest bound
91
+ -- to the row's StampId (cadre-core peer-authorization.ts:cadrePeerRemoveDigest), so
92
+ -- the stored voucher (a signature over digest(PeerId, StampId)) can NEVER be replayed
93
+ -- to authorize a delete. The remove signature rides in context and is never stored.
94
+ exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(old.PeerId, old.StampId, 'remove'), context.Signature, A.Key, 'ed25519'))
95
+ ),
96
+ constraint AuthorizedUpdate check on update (
97
+ -- Peer self-updates its own addrs + freshness, signing with its OWN ed25519 key
98
+ -- (the key behind PeerId). PeerId/PublicKey/StampId/voucher are immutable on
99
+ -- self-update, UpdatedAt must strictly increase (replay guard), and Sig is verified
100
+ -- against the stored PublicKey over the same payload the publish path signs
101
+ -- (cadre-core peer-record.ts:peerRecordSignedPayload).
102
+ (
103
+ new.PeerId = old.PeerId
104
+ and new.PublicKey = old.PublicKey
105
+ and new.StampId = old.StampId
106
+ and new.VouchOwner = old.VouchOwner
107
+ and new.VouchSig = old.VouchSig
108
+ and new.UpdatedAt > coalesce(old.UpdatedAt, 0)
109
+ and verify(
110
+ digest(new.PeerId || '|' || new.Multiaddr || '|' || cast(new.UpdatedAt as text)),
111
+ new.Sig, new.PublicKey, 'ed25519')
112
+ )
113
+ -- or an owner re-authorizes (rotation / correction): re-vouches the row over
114
+ -- its current StampId, so the stored voucher is re-bound to the re-authorizing owner.
115
+ or (
116
+ exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.PeerId, new.StampId), context.Signature, A.Key, 'ed25519'))
117
+ and new.VouchOwner = context.OwnerKey
118
+ and new.VouchSig = context.Signature
119
+ )
120
+ )
121
+ ) with context (OwnerKey text null, Signature text);
122
+
123
+ -- A mobile cadre peer's platform push token (FCM/APNs), self-published so a
124
+ -- server peer can deliver a push-wake to a suspended app over the platform push
125
+ -- channel (a control-network dial cannot reach an OS-suspended process). The row
126
+ -- mirrors CadrePeer: a resolver re-verifies Sig against the CadrePeer.PublicKey for
127
+ -- this PeerId (see device-token.ts:deviceTokenSignedPayload), checks freshness, then
128
+ -- hands the token to the push sender.
129
+ table DeviceToken (
130
+ PeerId text primary key, -- the CadrePeer this token belongs to
131
+ Platform text not null, -- 'fcm' | 'apns'
132
+ Token text not null, -- opaque platform device/registration token
133
+ UpdatedAt int null, -- epoch ms; strictly increases per self-update (replay guard)
134
+ Sig text null, -- ed25519 self-sig over (PeerId|Platform|Token|UpdatedAt)
135
+ constraint AuthorizedInsert check on insert, delete (
136
+ -- Authorized by an owner key (membership vouch), exactly like CadrePeer.
137
+ -- The single-field digest frames the base58btc PeerId as TEXT.
138
+ exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(coalesce(new.PeerId, old.PeerId)), context.Signature, A.Key, 'ed25519'))
139
+ ),
140
+ constraint AuthorizedUpdate check on update (
141
+ -- Peer self-updates its own token, signing with its OWN ed25519 key (the key
142
+ -- behind PeerId). PeerId is immutable, UpdatedAt must strictly increase (replay
143
+ -- guard), and Sig is verified against the stored CadrePeer.PublicKey over the
144
+ -- signed payload (cadre-core device-token.ts:deviceTokenSignedPayload). Platform
145
+ -- and Token may change on self-update (platform switch / reinstall / rotation).
146
+ (
147
+ new.PeerId = old.PeerId
148
+ and new.UpdatedAt > coalesce(old.UpdatedAt, 0)
149
+ and exists (select 1 from CadrePeer P where P.PeerId = new.PeerId and verify(
150
+ digest(new.PeerId || '|' || new.Platform || '|' || new.Token || '|' || cast(new.UpdatedAt as text)),
151
+ new.Sig, P.PublicKey, 'ed25519'))
152
+ )
153
+ -- or an owner re-authorizes (rotation / correction)
154
+ or exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(digest(new.PeerId), context.Signature, A.Key, 'ed25519'))
155
+ )
156
+ ) with context (OwnerKey text null, Signature text);
157
+
158
+ -- An open invitation to form a strand with this party
159
+ table FormationInvite (
160
+ Token text primary key, -- Just a random string
161
+ sAppId text, -- The app for the strand that will be formed
162
+ ExpiresAt datetime null,
163
+ TotalUses int null check (TotalUses >= 0),
164
+ ValidationUrl text null, -- Web hook - send disclosure, IP address...
165
+ StrandId text null, -- Host strand this invite binds to (provision-then-record). Non-null => the responder records consent against this pre-existing strand; null => legacy responder-provisions path.
166
+ StampId text not null unique, -- single-use authorization nonce (anti-replay)
167
+ constraint AuthorizedAddOrRemove check on insert, delete (
168
+ -- Authorized by an owner signing over THIS row
169
+ -- (Token, sAppId, ExpiresAt, TotalUses, ValidationUrl, StrandId, StampId); single-use via unique StampId.
170
+ -- coalesce(new.F, old.F) binds the NEW row on insert and the OLD row on delete (cf. CadrePeer).
171
+ -- StrandId is a nullable bound field: it signs as '' when absent (cf. ValidationUrl).
172
+ exists (select 1 from OwnerKey A where A.Key = context.OwnerKey and verify(
173
+ digest(
174
+ coalesce(new.Token, old.Token),
175
+ coalesce(new.sAppId, old.sAppId),
176
+ coalesce(cast(coalesce(new.ExpiresAt, old.ExpiresAt) as text), ''),
177
+ coalesce(cast(coalesce(new.TotalUses, old.TotalUses) as text), ''),
178
+ coalesce(coalesce(new.ValidationUrl, old.ValidationUrl), ''),
179
+ coalesce(coalesce(new.StrandId, old.StrandId), ''),
180
+ coalesce(new.StampId, old.StampId)
181
+ ),
182
+ context.Signature, A.Key, 'ed25519'))
183
+ ),
184
+ -- Invites are insert/delete only: forbid in-place mutation so the row-bound
185
+ -- AuthorizedAddOrRemove signature cannot be sidestepped by updating consent
186
+ -- parameters (TotalUses/ExpiresAt/...) after a legitimate insert. A bare check
187
+ -- defaults to insert+update; the check on insert, delete above excludes update,
188
+ -- so this guard is required. Mirrors FormationUsage.InsertOnly.
189
+ constraint Immutable check on update (false)
190
+ ) with context (OwnerKey text, Signature text);
191
+
192
+ table FormationUsage (
193
+ Token text,
194
+ UseNumber int,
195
+ Disclosure text,
196
+ StrandId text,
197
+ primary key (Token, UseNumber),
198
+ constraint InsertOnly check on update, delete (false),
199
+ constraint Monotonic check (
200
+ -- Read the PRE-transaction snapshot (committed.*): this CHECK auto-defers
201
+ -- to commit (it has a subquery), by which point the row being inserted is
202
+ -- live, so a plain from-FormationUsage would count this row itself and make
203
+ -- UseNumber = max+1 unsatisfiable. committed.* excludes the in-flight row,
204
+ -- giving sequential 1,2,3... per token (cross-transaction; concurrent
205
+ -- redemptions of the same token collide on the (Token, UseNumber) PK).
206
+ new.UseNumber = coalesce((select max(UseNumber) from committed.FormationUsage U where U.Token = new.Token), 0) + 1
207
+ ),
208
+ constraint Authorized check on insert (
209
+ -- Satisfies an invitation
210
+ exists (
211
+ select 1 from FormationInvite FI
212
+ where FI.Token = new.Token
213
+ and (FI.TotalUses is null or FI.TotalUses >= new.UseNumber)
214
+ and (FI.ExpiresAt is null or FI.ExpiresAt > context.Now)
215
+ and (FI.ValidationUrl is null or verify(digest(new.Token || new.Disclosure), context.ValidationSignature, context.ValidationKey, 'ed25519'))
216
+ )
217
+ ),
218
+ constraint StrandExists check (exists (select 1 from Strand S where S.Id = new.StrandId)),
219
+ ) with context (PeerId text, PeerSignature text, Now datetime, ValidationKey text null, ValidationSignature text null);
220
+ }
221
+
222
+ apply schema CadreControl;`;
223
+ //# sourceMappingURL=control-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-schema.js","sourceRoot":"","sources":["../src/control-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAkNH,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Shared control-network stream primitives.
3
+ *
4
+ * The cadre control protocols — seed delivery (`seed-bootstrap.ts`), push-wake
5
+ * (`strand-wake-protocol.ts`), and strand formation (`strand-formation-protocol.ts`)
6
+ * — all speak 4-byte big-endian length-prefixed JSON frames over a libp2p 3.x
7
+ * stream. This module lifts the previously-triplicated stream shape, frame
8
+ * writer, and `withTimeout` wrapper into one place, and adds a timeout-bounded,
9
+ * abort-on-timeout read-to-EOF helper so a misbehaving peer that opens a stream
10
+ * and never half-closes its write end cannot pin a receiver forever.
11
+ *
12
+ * Dependency-free by design: it imports nothing from the protocol modules, so
13
+ * the import graph stays acyclic (`control-stream` ← `seed-bootstrap` ←
14
+ * `strand-wake-protocol`). In particular it returns RAW bytes from
15
+ * {@link readStreamToEnd} rather than decoding a frame — callers own the
16
+ * `decodeLengthPrefixedFrame` guard.
17
+ */
18
+ /**
19
+ * Minimal libp2p 3.x stream surface: AsyncIterable for reads, `send()` for
20
+ * writes, `close()` to half-close the write end (EOF), `abort()` to reset.
21
+ */
22
+ export interface ControlStream extends AsyncIterable<Uint8Array> {
23
+ send(data: Uint8Array): boolean;
24
+ close(): Promise<void>;
25
+ abort(err: Error): void;
26
+ }
27
+ /** Write a JSON object as a single 4-byte big-endian length-prefixed frame. */
28
+ export declare function writeFrame(stream: ControlStream, obj: unknown): void;
29
+ /**
30
+ * Reject if `op` does not settle within `ms`. On timeout, invoke `onTimeout`
31
+ * (used by the sender to abort the in-flight dial/stream so it does not leak)
32
+ * before rejecting. A throwing `onTimeout` is swallowed so it cannot mask the
33
+ * timeout rejection. The rejection message is exactly `<label> timed out after
34
+ * <ms>ms`, so callers fold any domain prefix into `label`.
35
+ */
36
+ export declare function withTimeout<T>(ms: number, label: string, op: () => Promise<T>, onTimeout?: () => void): Promise<T>;
37
+ /**
38
+ * Read a stream to EOF, capped at `maxBytes`, bounded by `timeoutMs`, returning
39
+ * the assembled bytes (the caller decodes via `decodeLengthPrefixedFrame`).
40
+ *
41
+ * Implemented as `Promise.race([readLoop, timeout])`:
42
+ * - The size cap throws synchronously inside `readLoop` (a well-behaved peer may
43
+ * have sent a real-but-too-large frame and could still be reading for the ack,
44
+ * so this path does NOT abort the stream — it just rejects).
45
+ * - The timeout path is the true hang: it ALSO calls `stream.abort(err)` to
46
+ * release the stuck read. The race guarantees the helper settles at the
47
+ * deadline even if `abort()` does not immediately unblock the iterator (e.g. a
48
+ * test double whose `abort()` is a no-op).
49
+ */
50
+ export declare function readStreamToEnd(stream: ControlStream, opts: {
51
+ maxBytes: number;
52
+ timeoutMs: number;
53
+ label: string;
54
+ }): Promise<Uint8Array>;