@serfab/quereus-plugin-sereus 0.8.0 → 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.
@@ -18,13 +18,13 @@
18
18
  *
19
19
  * Crypto idiom (matches `schemas/control.qsql` and the sApp RBAC fixture
20
20
  * `packages/integration-tests/fixtures/simple-sapp.qsql`): every signed write
21
- * proves itself with `verify(digest(<concatenated payload>, 'sha256', 'utf8'),
21
+ * proves itself with `verify(digest(<single joined payload>),
22
22
  * <signature>, <pubkey>, 'ed25519')`. Member keys are ed25519, so the explicit
23
23
  * curve arg is REQUIRED (verify() otherwise defaults to secp256k1).
24
24
  *
25
25
  * Population note: this ticket applies the schema and makes its constraints
26
26
  * active — it does NOT write membership rows at runtime. Inserting the `Header`,
27
- * the founding `Authority`/`Member`, and the invite/peer flows is owned by
27
+ * the founding `Manager`/`Member`, and the invite/peer flows is owned by
28
28
  * `strand-membership-lifecycle-population`.
29
29
  */
30
- export declare const STRAND_SCHEMA = " table Header (\n Id text, -- UUID of this network - generated at inception - immutable\n\n -- Types: 'o' = Open, 'c' = Closed\n -- Any peers can join an open network, but only members can join a closed network\n -- Open can still control writes in the app, but only Closed prevents reads\n Type text check (Type in ('o', 'c')),\n\n -- The app that this strand faciliates - public key from author to prevent tampering\n sAppId text,\n\n -- The version of the sApp that this strand faciliates\n sAppVersion text,\n\n -- The schema of the sApp that this strand faciliates\n sAppSchema text,\n\n -- The author's signature on the schema to guarantee authorship\n sAppSignature text,\n\n -- The engine (rules logic system) that is assumed to manage this strand\n Engine text,\n\n -- The version of the engine that is assumed to manage this strand\n EngineVersion text,\n\n primary key (/* empty - singleton */),\n constraint InsertOnly check on update, delete (false), -- One-time insert only for now - TODO: revisit for versioning\n );\n\n -- An invitation to join a strand as a member\n table Invite (\n Key text primary key,\n Expiration datetime null,\n -- TODO: ability to deactivate?\n constraint InsertOnly check on update, delete (false),\n constraint OnlyClosed check (\n exists (select 1 from Header H where H.Type = 'c')\n ),\n constraint InviteValid check on insert (\n -- Can only be inserted by an authority,\n exists (select 1 from Authority A\n where A.MemberKey = context.AuthorityKey\n and verify(digest(new.Key || '|' || coalesce(new.Expiration, ''), 'sha256', 'utf8'), context.AuthoritySignature, A.MemberKey, 'ed25519')\n )\n -- and must also prove invite private key held by issuing authority\n and verify(digest(new.Key || '|' || coalesce(new.Expiration, ''), 'sha256', 'utf8'), context.InviteSignature, new.Key, 'ed25519')\n )\n ) with context (AuthorityKey text null, AuthoritySignature text null, InviteSignature text null);\n\n -- Invite [InviteKey] has been used to add [MemberKey] as a member\n table ConsumedInvite (\n InviteKey text primary key,\n MemberKey text,\n constraint InsertOnly check on update, delete (false),\n constraint InviteExists check (exists (select 1 from Invite I where I.Key = new.InviteKey)),\n constraint MemberExists check (exists (select 1 from Member M where M.Key = new.MemberKey)),\n constraint ValidUsage check on insert (\n exists (select 1 from Invite I where I.Key = new.InviteKey and verify(digest(new.InviteKey || '|' || new.MemberKey, 'sha256', 'utf8'), context.InviteSignature, new.InviteKey, 'ed25519'))\n ),\n constraint MemberValid check (exists (select 1 from Member M where M.Key = new.MemberKey))\n ) with context (InviteSignature text null);\n\n -- A party in the closed strand network\n table Member (\n Key text primary key,\n constraint NoUpdate check on update (false),\n constraint OnlyClosed check (\n exists (select 1 from Header H where H.Type = 'c')\n ),\n constraint Authorized check on insert (\n -- There are no other records - first member needs no authorization\n (select count(1) from Member) <= 1\n\n -- or added directly by authority\n or exists (\n select 1 from Authority A\n where A.MemberKey = context.AuthorityKey\n and verify(digest(new.Key, 'sha256', 'utf8'), context.AuthoritySignature, A.MemberKey, 'ed25519')\n )\n\n -- or added by invite\n or exists (\n select 1 from ConsumedInvite CI where CI.MemberKey = new.Key\n )\n ),\n -- TODO: handle member revocation constraint\n ) with context (AuthorityKey text null, AuthoritySignature text null);\n\n -- A member-associated peer (node)\n table MemberPeer (\n MemberKey text,\n PeerId text,\n primary key (MemberKey, PeerId),\n constraint MemberExists check (exists (select 1 from Member M where M.Key = new.MemberKey)),\n constraint Authorized check (\n verify(\n digest(coalesce(new.MemberKey, old.MemberKey) || '|' || coalesce(new.PeerId, old.PeerId), 'sha256', 'utf8'),\n context.Signature,\n coalesce(new.MemberKey, old.MemberKey),\n 'ed25519'\n )\n ),\n ) with context (Signature text null);\n\n -- An authority is a member that can issue invites, authorize members, and rotate authorities\n table Authority (\n MemberKey text primary key,\n constraint OnlyClosed check (\n exists (select 1 from Header H where H.Type = 'c')\n ),\n constraint Authorized check (\n -- There are no existing records - first authority needs no authorization\n (select count(1) from Authority) <= 1\n\n -- or authorized by this former authority\n or (\n old.MemberKey is not null\n and old.MemberKey = context.AuthorityKey\n and verify(digest(old.MemberKey, 'sha256', 'utf8'), context.Signature, old.MemberKey, 'ed25519')\n )\n\n -- or authorized by another existing authority\n or exists (\n select 1 from Authority A\n where A.MemberKey = context.AuthorityKey\n and verify(digest(coalesce(new.MemberKey, old.MemberKey), 'sha256', 'utf8'), context.Signature, A.MemberKey, 'ed25519')\n )\n )\n ) with context (AuthorityKey text null, Signature text null);\n";
30
+ export declare const STRAND_SCHEMA = " table Header (\n Id text, -- UUID of this network - generated at inception - immutable\n\n -- Types: 'o' = Open, 'c' = Closed\n -- Any peers can join an open network, but only members can join a closed network\n -- Open can still control writes in the app, but only Closed prevents reads\n Type text check (Type in ('o', 'c')),\n\n -- The app that this strand faciliates - public key from author to prevent tampering\n sAppId text,\n\n -- The version of the sApp that this strand faciliates\n sAppVersion text,\n\n -- The schema of the sApp that this strand faciliates\n sAppSchema text,\n\n -- The author's signature on the schema to guarantee authorship\n sAppSignature text,\n\n -- The engine (rules logic system) that is assumed to manage this strand\n Engine text,\n\n -- The version of the engine that is assumed to manage this strand\n EngineVersion text,\n\n primary key (/* empty - singleton */),\n constraint InsertOnly check on update, delete (false), -- One-time insert only for now - TODO: revisit for versioning\n );\n\n -- An invitation to join a strand as a member\n table Invite (\n Key text primary key,\n Expiration datetime null,\n -- TODO: ability to deactivate?\n constraint InsertOnly check on update, delete (false),\n constraint OnlyClosed check (\n exists (select 1 from Header H where H.Type = 'c')\n ),\n constraint InviteValid check on insert (\n -- Can only be inserted by a manager,\n exists (select 1 from Manager A\n where A.MemberKey = context.ManagerKey\n and verify(digest(new.Key || '|' || coalesce(new.Expiration, '')), context.ManagerSignature, A.MemberKey, 'ed25519')\n )\n -- and must also prove invite private key held by issuing manager\n and verify(digest(new.Key || '|' || coalesce(new.Expiration, '')), context.InviteSignature, new.Key, 'ed25519')\n )\n ) with context (ManagerKey text null, ManagerSignature text null, InviteSignature text null);\n\n -- Invite [InviteKey] has been used to add [MemberKey] as a member\n table ConsumedInvite (\n InviteKey text primary key,\n MemberKey text,\n constraint InsertOnly check on update, delete (false),\n constraint InviteExists check (exists (select 1 from Invite I where I.Key = new.InviteKey)),\n constraint MemberExists check (exists (select 1 from Member M where M.Key = new.MemberKey)),\n constraint ValidUsage check on insert (\n exists (select 1 from Invite I where I.Key = new.InviteKey and verify(digest(new.InviteKey || '|' || new.MemberKey), context.InviteSignature, new.InviteKey, 'ed25519'))\n ),\n -- An invite with a non-null Expiration may only be consumed while it is still\n -- in the future. context.Now is the canonical-datetime \"now\" supplied by the\n -- consumeInvite writer (same canonicalDatetime() transform used to store\n -- Invite.Expiration), so both sides of the comparison are byte-identical\n -- canonical strings and the lexical \">\" comparison orders chronologically. A\n -- null Expiration never expires. Mirrors CadreControl.FormationUsage's\n -- \"FI.ExpiresAt is null or FI.ExpiresAt > context.Now\" gate.\n constraint NotExpired check on insert (\n exists (select 1 from Invite I where I.Key = new.InviteKey and (I.Expiration is null or I.Expiration > context.Now))\n ),\n constraint MemberValid check (exists (select 1 from Member M where M.Key = new.MemberKey))\n ) with context (InviteSignature text null, Now datetime null);\n\n -- A party in the closed strand network\n table Member (\n Key text primary key,\n constraint NoUpdate check on update (false),\n constraint OnlyClosed check (\n exists (select 1 from Header H where H.Type = 'c')\n ),\n constraint Authorized check on insert (\n -- There are no other records - first member needs no authorization\n (select count(1) from Member) <= 1\n\n -- or added directly by manager\n or exists (\n select 1 from Manager A\n where A.MemberKey = context.ManagerKey\n and verify(digest(new.Key), context.ManagerSignature, A.MemberKey, 'ed25519')\n )\n\n -- or added by invite\n or exists (\n select 1 from ConsumedInvite CI where CI.MemberKey = new.Key\n )\n ),\n -- TODO: handle member revocation constraint\n ) with context (ManagerKey text null, ManagerSignature text null);\n\n -- A member-associated peer (node)\n table MemberPeer (\n MemberKey text,\n PeerId text,\n primary key (MemberKey, PeerId),\n constraint MemberExists check (exists (select 1 from Member M where M.Key = new.MemberKey)),\n constraint Authorized check on insert, update, delete (\n verify(\n digest(coalesce(new.MemberKey, old.MemberKey) || '|' || coalesce(new.PeerId, old.PeerId)),\n context.Signature,\n coalesce(new.MemberKey, old.MemberKey),\n 'ed25519'\n )\n ),\n ) with context (Signature text null);\n\n -- A manager is a member that can issue invites, authorize members, and rotate managers\n table Manager (\n MemberKey text primary key,\n constraint OnlyClosed check (\n exists (select 1 from Header H where H.Type = 'c')\n ),\n constraint Authorized check on insert, update, delete (\n -- There are no existing records - first manager needs no authorization\n (select count(1) from Manager) <= 1\n\n -- or authorized by this former manager\n or (\n old.MemberKey is not null\n and old.MemberKey = context.ManagerKey\n and verify(digest(old.MemberKey), context.Signature, old.MemberKey, 'ed25519')\n )\n\n -- or authorized by another existing manager\n or exists (\n select 1 from Manager A\n where A.MemberKey = context.ManagerKey\n and verify(digest(coalesce(new.MemberKey, old.MemberKey)), context.Signature, A.MemberKey, 'ed25519')\n )\n )\n ) with context (ManagerKey text null, Signature text null);\n";
@@ -18,13 +18,13 @@
18
18
  *
19
19
  * Crypto idiom (matches `schemas/control.qsql` and the sApp RBAC fixture
20
20
  * `packages/integration-tests/fixtures/simple-sapp.qsql`): every signed write
21
- * proves itself with `verify(digest(<concatenated payload>, 'sha256', 'utf8'),
21
+ * proves itself with `verify(digest(<single joined payload>),
22
22
  * <signature>, <pubkey>, 'ed25519')`. Member keys are ed25519, so the explicit
23
23
  * curve arg is REQUIRED (verify() otherwise defaults to secp256k1).
24
24
  *
25
25
  * Population note: this ticket applies the schema and makes its constraints
26
26
  * active — it does NOT write membership rows at runtime. Inserting the `Header`,
27
- * the founding `Authority`/`Member`, and the invite/peer flows is owned by
27
+ * the founding `Manager`/`Member`, and the invite/peer flows is owned by
28
28
  * `strand-membership-lifecycle-population`.
29
29
  */
30
30
  export const STRAND_SCHEMA = ` table Header (
@@ -67,15 +67,15 @@ export const STRAND_SCHEMA = ` table Header (
67
67
  exists (select 1 from Header H where H.Type = 'c')
68
68
  ),
69
69
  constraint InviteValid check on insert (
70
- -- Can only be inserted by an authority,
71
- exists (select 1 from Authority A
72
- where A.MemberKey = context.AuthorityKey
73
- and verify(digest(new.Key || '|' || coalesce(new.Expiration, ''), 'sha256', 'utf8'), context.AuthoritySignature, A.MemberKey, 'ed25519')
70
+ -- Can only be inserted by a manager,
71
+ exists (select 1 from Manager A
72
+ where A.MemberKey = context.ManagerKey
73
+ and verify(digest(new.Key || '|' || coalesce(new.Expiration, '')), context.ManagerSignature, A.MemberKey, 'ed25519')
74
74
  )
75
- -- and must also prove invite private key held by issuing authority
76
- and verify(digest(new.Key || '|' || coalesce(new.Expiration, ''), 'sha256', 'utf8'), context.InviteSignature, new.Key, 'ed25519')
75
+ -- and must also prove invite private key held by issuing manager
76
+ and verify(digest(new.Key || '|' || coalesce(new.Expiration, '')), context.InviteSignature, new.Key, 'ed25519')
77
77
  )
78
- ) with context (AuthorityKey text null, AuthoritySignature text null, InviteSignature text null);
78
+ ) with context (ManagerKey text null, ManagerSignature text null, InviteSignature text null);
79
79
 
80
80
  -- Invite [InviteKey] has been used to add [MemberKey] as a member
81
81
  table ConsumedInvite (
@@ -85,10 +85,20 @@ export const STRAND_SCHEMA = ` table Header (
85
85
  constraint InviteExists check (exists (select 1 from Invite I where I.Key = new.InviteKey)),
86
86
  constraint MemberExists check (exists (select 1 from Member M where M.Key = new.MemberKey)),
87
87
  constraint ValidUsage check on insert (
88
- exists (select 1 from Invite I where I.Key = new.InviteKey and verify(digest(new.InviteKey || '|' || new.MemberKey, 'sha256', 'utf8'), context.InviteSignature, new.InviteKey, 'ed25519'))
88
+ exists (select 1 from Invite I where I.Key = new.InviteKey and verify(digest(new.InviteKey || '|' || new.MemberKey), context.InviteSignature, new.InviteKey, 'ed25519'))
89
+ ),
90
+ -- An invite with a non-null Expiration may only be consumed while it is still
91
+ -- in the future. context.Now is the canonical-datetime "now" supplied by the
92
+ -- consumeInvite writer (same canonicalDatetime() transform used to store
93
+ -- Invite.Expiration), so both sides of the comparison are byte-identical
94
+ -- canonical strings and the lexical ">" comparison orders chronologically. A
95
+ -- null Expiration never expires. Mirrors CadreControl.FormationUsage's
96
+ -- "FI.ExpiresAt is null or FI.ExpiresAt > context.Now" gate.
97
+ constraint NotExpired check on insert (
98
+ exists (select 1 from Invite I where I.Key = new.InviteKey and (I.Expiration is null or I.Expiration > context.Now))
89
99
  ),
90
100
  constraint MemberValid check (exists (select 1 from Member M where M.Key = new.MemberKey))
91
- ) with context (InviteSignature text null);
101
+ ) with context (InviteSignature text null, Now datetime null);
92
102
 
93
103
  -- A party in the closed strand network
94
104
  table Member (
@@ -101,11 +111,11 @@ export const STRAND_SCHEMA = ` table Header (
101
111
  -- There are no other records - first member needs no authorization
102
112
  (select count(1) from Member) <= 1
103
113
 
104
- -- or added directly by authority
114
+ -- or added directly by manager
105
115
  or exists (
106
- select 1 from Authority A
107
- where A.MemberKey = context.AuthorityKey
108
- and verify(digest(new.Key, 'sha256', 'utf8'), context.AuthoritySignature, A.MemberKey, 'ed25519')
116
+ select 1 from Manager A
117
+ where A.MemberKey = context.ManagerKey
118
+ and verify(digest(new.Key), context.ManagerSignature, A.MemberKey, 'ed25519')
109
119
  )
110
120
 
111
121
  -- or added by invite
@@ -114,7 +124,7 @@ export const STRAND_SCHEMA = ` table Header (
114
124
  )
115
125
  ),
116
126
  -- TODO: handle member revocation constraint
117
- ) with context (AuthorityKey text null, AuthoritySignature text null);
127
+ ) with context (ManagerKey text null, ManagerSignature text null);
118
128
 
119
129
  -- A member-associated peer (node)
120
130
  table MemberPeer (
@@ -122,9 +132,9 @@ export const STRAND_SCHEMA = ` table Header (
122
132
  PeerId text,
123
133
  primary key (MemberKey, PeerId),
124
134
  constraint MemberExists check (exists (select 1 from Member M where M.Key = new.MemberKey)),
125
- constraint Authorized check (
135
+ constraint Authorized check on insert, update, delete (
126
136
  verify(
127
- digest(coalesce(new.MemberKey, old.MemberKey) || '|' || coalesce(new.PeerId, old.PeerId), 'sha256', 'utf8'),
137
+ digest(coalesce(new.MemberKey, old.MemberKey) || '|' || coalesce(new.PeerId, old.PeerId)),
128
138
  context.Signature,
129
139
  coalesce(new.MemberKey, old.MemberKey),
130
140
  'ed25519'
@@ -132,30 +142,30 @@ export const STRAND_SCHEMA = ` table Header (
132
142
  ),
133
143
  ) with context (Signature text null);
134
144
 
135
- -- An authority is a member that can issue invites, authorize members, and rotate authorities
136
- table Authority (
145
+ -- A manager is a member that can issue invites, authorize members, and rotate managers
146
+ table Manager (
137
147
  MemberKey text primary key,
138
148
  constraint OnlyClosed check (
139
149
  exists (select 1 from Header H where H.Type = 'c')
140
150
  ),
141
- constraint Authorized check (
142
- -- There are no existing records - first authority needs no authorization
143
- (select count(1) from Authority) <= 1
151
+ constraint Authorized check on insert, update, delete (
152
+ -- There are no existing records - first manager needs no authorization
153
+ (select count(1) from Manager) <= 1
144
154
 
145
- -- or authorized by this former authority
155
+ -- or authorized by this former manager
146
156
  or (
147
157
  old.MemberKey is not null
148
- and old.MemberKey = context.AuthorityKey
149
- and verify(digest(old.MemberKey, 'sha256', 'utf8'), context.Signature, old.MemberKey, 'ed25519')
158
+ and old.MemberKey = context.ManagerKey
159
+ and verify(digest(old.MemberKey), context.Signature, old.MemberKey, 'ed25519')
150
160
  )
151
161
 
152
- -- or authorized by another existing authority
162
+ -- or authorized by another existing manager
153
163
  or exists (
154
- select 1 from Authority A
155
- where A.MemberKey = context.AuthorityKey
156
- and verify(digest(coalesce(new.MemberKey, old.MemberKey), 'sha256', 'utf8'), context.Signature, A.MemberKey, 'ed25519')
164
+ select 1 from Manager A
165
+ where A.MemberKey = context.ManagerKey
166
+ and verify(digest(coalesce(new.MemberKey, old.MemberKey)), context.Signature, A.MemberKey, 'ed25519')
157
167
  )
158
168
  )
159
- ) with context (AuthorityKey text null, Signature text null);
169
+ ) with context (ManagerKey text null, Signature text null);
160
170
  `;
161
171
  //# sourceMappingURL=strand-schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"strand-schema.js","sourceRoot":"","sources":["../src/strand-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkI5B,CAAC"}
1
+ {"version":3,"file":"strand-schema.js","sourceRoot":"","sources":["../src/strand-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4I5B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serfab/quereus-plugin-sereus",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "description": "Quereus plugin that connects to a Sereus strand for SQL access",
6
6
  "main": "dist/index.js",
@@ -67,13 +67,13 @@
67
67
  "@libp2p/circuit-relay-v2": "^4.1.3",
68
68
  "@libp2p/interface": "^3.1.0",
69
69
  "@libp2p/websockets": "^10.1.3",
70
- "@optimystic/db-core": "^0.13.5",
71
- "@optimystic/db-p2p": "^0.13.5",
72
- "@optimystic/db-p2p-storage-fs": "^0.13.5",
73
- "@optimystic/db-p2p-storage-web": "^0.13.5",
74
- "@optimystic/quereus-plugin-crypto": "^0.13.5",
75
- "@optimystic/quereus-plugin-optimystic": "^0.13.5",
76
- "@quereus/quereus": "^3.2.1",
70
+ "@optimystic/db-core": "^0.14.1",
71
+ "@optimystic/db-p2p": "^0.14.1",
72
+ "@optimystic/db-p2p-storage-fs": "^0.14.1",
73
+ "@optimystic/db-p2p-storage-web": "^0.14.1",
74
+ "@optimystic/quereus-plugin-crypto": "^0.14.1",
75
+ "@optimystic/quereus-plugin-optimystic": "^0.14.1",
76
+ "@quereus/quereus": "^4.4.0",
77
77
  "debug": "^4.4.3"
78
78
  },
79
79
  "quereus": {
@@ -1,5 +1,5 @@
1
1
  import debug from 'debug';
2
- import type { Database } from '@quereus/quereus';
2
+ import type { Database, VTablePluginInfo, FunctionPluginInfo, CollationPluginInfo } from '@quereus/quereus';
3
3
  import optimysticPlugin from '@optimystic/quereus-plugin-optimystic/plugin';
4
4
  import type { Libp2p } from '@libp2p/interface';
5
5
  import type { IRepo } from '@optimystic/db-core';
@@ -27,9 +27,9 @@ interface CollectionFactory {
27
27
  */
28
28
  interface OptimysticPluginResult {
29
29
  collectionFactory: CollectionFactory;
30
- vtables: Array<{ name: string; module: unknown; auxData: unknown }>;
31
- functions: Array<{ schema: unknown }>;
32
- collations?: Array<{ name: string; func: unknown; normalizer?: unknown }>;
30
+ vtables: VTablePluginInfo[];
31
+ functions: FunctionPluginInfo[];
32
+ collations?: CollationPluginInfo[];
33
33
  /**
34
34
  * Hydrate Quereus's in-memory catalog from persisted optimystic vtab schemas.
35
35
  * Must run BEFORE `apply schema App;` on a warm restart so the declarative
@@ -43,9 +43,9 @@ interface OptimysticPluginResult {
43
43
 
44
44
  /** Registration shape shared by the crypto and optimystic plugin results. */
45
45
  interface PluginRegistrations {
46
- vtables?: Array<{ name: string; module: unknown; auxData: unknown }>;
47
- functions?: Array<{ schema: unknown }>;
48
- collations?: Array<{ name: string; func: unknown; normalizer?: unknown }>;
46
+ vtables?: VTablePluginInfo[];
47
+ functions?: FunctionPluginInfo[];
48
+ collations?: CollationPluginInfo[];
49
49
  }
50
50
 
51
51
  /**
@@ -57,13 +57,13 @@ interface PluginRegistrations {
57
57
  */
58
58
  export function applyRegistrations(db: Database, result: PluginRegistrations): void {
59
59
  for (const vtable of result.vtables ?? []) {
60
- db.registerModule(vtable.name, vtable.module as any, vtable.auxData);
60
+ db.registerModule(vtable.name, vtable.module, vtable.auxData);
61
61
  }
62
62
  for (const func of result.functions ?? []) {
63
- db.registerFunction(func.schema as any);
63
+ db.registerFunction(func.schema);
64
64
  }
65
65
  for (const collation of result.collations ?? []) {
66
- db.registerCollation(collation.name, collation.func as any, collation.normalizer as any);
66
+ db.registerCollation(collation.name, collation.func, collation.normalizer);
67
67
  }
68
68
  }
69
69
 
@@ -185,7 +185,7 @@ export async function composeStrand(
185
185
  const pluginResult = optimysticPlugin(
186
186
  db,
187
187
  pluginConfig as unknown as Parameters<typeof optimysticPlugin>[1],
188
- ) as OptimysticPluginResult;
188
+ ) as unknown as OptimysticPluginResult;
189
189
  applyRegistrations(db, pluginResult);
190
190
  log('Registered optimystic vtables and functions');
191
191
 
@@ -254,7 +254,7 @@ export async function composeStrand(
254
254
  //
255
255
  // This ticket only makes the tables present and their constraints active;
256
256
  // nothing here writes membership rows. Founder bootstrap (Header, founding
257
- // Authority/Member, invite/peer flows) is owned by the lifecycle ticket
257
+ // Manager/Member, invite/peer flows) is owned by the lifecycle ticket
258
258
  // `strand-membership-lifecycle-population`.
259
259
  log('Applying Strand membership schema for strand %s', strandId);
260
260
  await db.exec(`
@@ -1,4 +1,4 @@
1
- import type { Database } from '@quereus/quereus';
1
+ import type { Database, VTablePluginInfo, FunctionPluginInfo, CollationPluginInfo } from '@quereus/quereus';
2
2
  import cryptoPlugin from '@optimystic/quereus-plugin-crypto/plugin';
3
3
  import { createLibp2pNode } from '@optimystic/db-p2p/rn';
4
4
  import { webSockets } from '@libp2p/websockets';
@@ -10,9 +10,9 @@ import { composeStrand, applyRegistrations } from './compose-strand.js';
10
10
 
11
11
  /** The subset of the crypto plugin result we register inline in the browser. */
12
12
  interface CryptoPluginResult {
13
- vtables: Array<{ name: string; module: unknown; auxData: unknown }>;
14
- functions: Array<{ schema: unknown }>;
15
- collations: Array<{ name: string; func: unknown; normalizer?: unknown }>;
13
+ vtables: VTablePluginInfo[];
14
+ functions: FunctionPluginInfo[];
15
+ collations: CollationPluginInfo[];
16
16
  }
17
17
 
18
18
  /**
@@ -32,7 +32,7 @@ export async function connectToStrandBrowser(
32
32
  ): Promise<SereusPluginResult> {
33
33
  return composeStrand(db, options, {
34
34
  registerCrypto(database) {
35
- applyRegistrations(database, cryptoPlugin(database, {}) as CryptoPluginResult);
35
+ applyRegistrations(database, cryptoPlugin(database, {}) as unknown as CryptoPluginResult);
36
36
  },
37
37
  async resolveStorage({ strandId, resolvedTransactor, requestedStorage }) {
38
38
  if (requestedStorage) return requestedStorage;
@@ -18,13 +18,13 @@
18
18
  *
19
19
  * Crypto idiom (matches `schemas/control.qsql` and the sApp RBAC fixture
20
20
  * `packages/integration-tests/fixtures/simple-sapp.qsql`): every signed write
21
- * proves itself with `verify(digest(<concatenated payload>, 'sha256', 'utf8'),
21
+ * proves itself with `verify(digest(<single joined payload>),
22
22
  * <signature>, <pubkey>, 'ed25519')`. Member keys are ed25519, so the explicit
23
23
  * curve arg is REQUIRED (verify() otherwise defaults to secp256k1).
24
24
  *
25
25
  * Population note: this ticket applies the schema and makes its constraints
26
26
  * active — it does NOT write membership rows at runtime. Inserting the `Header`,
27
- * the founding `Authority`/`Member`, and the invite/peer flows is owned by
27
+ * the founding `Manager`/`Member`, and the invite/peer flows is owned by
28
28
  * `strand-membership-lifecycle-population`.
29
29
  */
30
30
  export const STRAND_SCHEMA = ` table Header (
@@ -67,15 +67,15 @@ export const STRAND_SCHEMA = ` table Header (
67
67
  exists (select 1 from Header H where H.Type = 'c')
68
68
  ),
69
69
  constraint InviteValid check on insert (
70
- -- Can only be inserted by an authority,
71
- exists (select 1 from Authority A
72
- where A.MemberKey = context.AuthorityKey
73
- and verify(digest(new.Key || '|' || coalesce(new.Expiration, ''), 'sha256', 'utf8'), context.AuthoritySignature, A.MemberKey, 'ed25519')
70
+ -- Can only be inserted by a manager,
71
+ exists (select 1 from Manager A
72
+ where A.MemberKey = context.ManagerKey
73
+ and verify(digest(new.Key || '|' || coalesce(new.Expiration, '')), context.ManagerSignature, A.MemberKey, 'ed25519')
74
74
  )
75
- -- and must also prove invite private key held by issuing authority
76
- and verify(digest(new.Key || '|' || coalesce(new.Expiration, ''), 'sha256', 'utf8'), context.InviteSignature, new.Key, 'ed25519')
75
+ -- and must also prove invite private key held by issuing manager
76
+ and verify(digest(new.Key || '|' || coalesce(new.Expiration, '')), context.InviteSignature, new.Key, 'ed25519')
77
77
  )
78
- ) with context (AuthorityKey text null, AuthoritySignature text null, InviteSignature text null);
78
+ ) with context (ManagerKey text null, ManagerSignature text null, InviteSignature text null);
79
79
 
80
80
  -- Invite [InviteKey] has been used to add [MemberKey] as a member
81
81
  table ConsumedInvite (
@@ -85,10 +85,20 @@ export const STRAND_SCHEMA = ` table Header (
85
85
  constraint InviteExists check (exists (select 1 from Invite I where I.Key = new.InviteKey)),
86
86
  constraint MemberExists check (exists (select 1 from Member M where M.Key = new.MemberKey)),
87
87
  constraint ValidUsage check on insert (
88
- exists (select 1 from Invite I where I.Key = new.InviteKey and verify(digest(new.InviteKey || '|' || new.MemberKey, 'sha256', 'utf8'), context.InviteSignature, new.InviteKey, 'ed25519'))
88
+ exists (select 1 from Invite I where I.Key = new.InviteKey and verify(digest(new.InviteKey || '|' || new.MemberKey), context.InviteSignature, new.InviteKey, 'ed25519'))
89
+ ),
90
+ -- An invite with a non-null Expiration may only be consumed while it is still
91
+ -- in the future. context.Now is the canonical-datetime "now" supplied by the
92
+ -- consumeInvite writer (same canonicalDatetime() transform used to store
93
+ -- Invite.Expiration), so both sides of the comparison are byte-identical
94
+ -- canonical strings and the lexical ">" comparison orders chronologically. A
95
+ -- null Expiration never expires. Mirrors CadreControl.FormationUsage's
96
+ -- "FI.ExpiresAt is null or FI.ExpiresAt > context.Now" gate.
97
+ constraint NotExpired check on insert (
98
+ exists (select 1 from Invite I where I.Key = new.InviteKey and (I.Expiration is null or I.Expiration > context.Now))
89
99
  ),
90
100
  constraint MemberValid check (exists (select 1 from Member M where M.Key = new.MemberKey))
91
- ) with context (InviteSignature text null);
101
+ ) with context (InviteSignature text null, Now datetime null);
92
102
 
93
103
  -- A party in the closed strand network
94
104
  table Member (
@@ -101,11 +111,11 @@ export const STRAND_SCHEMA = ` table Header (
101
111
  -- There are no other records - first member needs no authorization
102
112
  (select count(1) from Member) <= 1
103
113
 
104
- -- or added directly by authority
114
+ -- or added directly by manager
105
115
  or exists (
106
- select 1 from Authority A
107
- where A.MemberKey = context.AuthorityKey
108
- and verify(digest(new.Key, 'sha256', 'utf8'), context.AuthoritySignature, A.MemberKey, 'ed25519')
116
+ select 1 from Manager A
117
+ where A.MemberKey = context.ManagerKey
118
+ and verify(digest(new.Key), context.ManagerSignature, A.MemberKey, 'ed25519')
109
119
  )
110
120
 
111
121
  -- or added by invite
@@ -114,7 +124,7 @@ export const STRAND_SCHEMA = ` table Header (
114
124
  )
115
125
  ),
116
126
  -- TODO: handle member revocation constraint
117
- ) with context (AuthorityKey text null, AuthoritySignature text null);
127
+ ) with context (ManagerKey text null, ManagerSignature text null);
118
128
 
119
129
  -- A member-associated peer (node)
120
130
  table MemberPeer (
@@ -122,9 +132,9 @@ export const STRAND_SCHEMA = ` table Header (
122
132
  PeerId text,
123
133
  primary key (MemberKey, PeerId),
124
134
  constraint MemberExists check (exists (select 1 from Member M where M.Key = new.MemberKey)),
125
- constraint Authorized check (
135
+ constraint Authorized check on insert, update, delete (
126
136
  verify(
127
- digest(coalesce(new.MemberKey, old.MemberKey) || '|' || coalesce(new.PeerId, old.PeerId), 'sha256', 'utf8'),
137
+ digest(coalesce(new.MemberKey, old.MemberKey) || '|' || coalesce(new.PeerId, old.PeerId)),
128
138
  context.Signature,
129
139
  coalesce(new.MemberKey, old.MemberKey),
130
140
  'ed25519'
@@ -132,29 +142,29 @@ export const STRAND_SCHEMA = ` table Header (
132
142
  ),
133
143
  ) with context (Signature text null);
134
144
 
135
- -- An authority is a member that can issue invites, authorize members, and rotate authorities
136
- table Authority (
145
+ -- A manager is a member that can issue invites, authorize members, and rotate managers
146
+ table Manager (
137
147
  MemberKey text primary key,
138
148
  constraint OnlyClosed check (
139
149
  exists (select 1 from Header H where H.Type = 'c')
140
150
  ),
141
- constraint Authorized check (
142
- -- There are no existing records - first authority needs no authorization
143
- (select count(1) from Authority) <= 1
151
+ constraint Authorized check on insert, update, delete (
152
+ -- There are no existing records - first manager needs no authorization
153
+ (select count(1) from Manager) <= 1
144
154
 
145
- -- or authorized by this former authority
155
+ -- or authorized by this former manager
146
156
  or (
147
157
  old.MemberKey is not null
148
- and old.MemberKey = context.AuthorityKey
149
- and verify(digest(old.MemberKey, 'sha256', 'utf8'), context.Signature, old.MemberKey, 'ed25519')
158
+ and old.MemberKey = context.ManagerKey
159
+ and verify(digest(old.MemberKey), context.Signature, old.MemberKey, 'ed25519')
150
160
  )
151
161
 
152
- -- or authorized by another existing authority
162
+ -- or authorized by another existing manager
153
163
  or exists (
154
- select 1 from Authority A
155
- where A.MemberKey = context.AuthorityKey
156
- and verify(digest(coalesce(new.MemberKey, old.MemberKey), 'sha256', 'utf8'), context.Signature, A.MemberKey, 'ed25519')
164
+ select 1 from Manager A
165
+ where A.MemberKey = context.ManagerKey
166
+ and verify(digest(coalesce(new.MemberKey, old.MemberKey)), context.Signature, A.MemberKey, 'ed25519')
157
167
  )
158
168
  )
159
- ) with context (AuthorityKey text null, Signature text null);
169
+ ) with context (ManagerKey text null, Signature text null);
160
170
  `;