@kubun/store-p2p 0.18.1 → 0.20.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.
- package/lib/api.d.ts +5 -2
- package/lib/api.js +10 -6
- package/lib/definition.d.ts +6 -1
- package/lib/definition.js +37 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/migrations.js +90 -90
- package/lib/ops/app-lane.d.ts +1 -1
- package/lib/ops/app-lane.js +18 -12
- package/lib/ops/app-outbox.d.ts +4 -2
- package/lib/ops/app-outbox.js +33 -33
- package/lib/ops/catalog-offers.d.ts +1 -1
- package/lib/ops/catalog-offers.js +9 -10
- package/lib/ops/catalog-routes.js +9 -9
- package/lib/ops/catalog-sync.d.ts +2 -1
- package/lib/ops/catalog-sync.js +39 -42
- package/lib/ops/circles.js +33 -33
- package/lib/ops/control.d.ts +1 -1
- package/lib/ops/control.js +12 -10
- package/lib/ops/delegations.d.ts +2 -1
- package/lib/ops/delegations.js +17 -25
- package/lib/ops/discovery.d.ts +1 -1
- package/lib/ops/discovery.js +23 -10
- package/lib/ops/document-sweep.js +5 -5
- package/lib/ops/groups.d.ts +3 -2
- package/lib/ops/groups.js +60 -62
- package/lib/ops/hubs.js +38 -57
- package/lib/ops/log-handler-completion.js +3 -3
- package/lib/ops/mls.d.ts +1 -1
- package/lib/ops/mls.js +36 -26
- package/lib/ops/own-agents.d.ts +3 -3
- package/lib/ops/own-agents.js +128 -72
- package/lib/ops/sync.d.ts +1 -1
- package/lib/ops/sync.js +17 -8
- package/lib/scope.d.ts +8 -0
- package/lib/scope.js +8 -0
- package/lib/tables.d.ts +52 -42
- package/package.json +14 -13
package/lib/api.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { StoreAPIContext } from '@kubun/db';
|
|
1
2
|
import type { Adapter } from '@kubun/db-adapter';
|
|
2
3
|
import { type Runtime } from '@sozai/runtime';
|
|
3
4
|
import type { Kysely } from 'kysely';
|
|
@@ -17,6 +18,7 @@ import { type LogHandlerCompletionOps } from './ops/log-handler-completion.js';
|
|
|
17
18
|
import { type MLSOps } from './ops/mls.js';
|
|
18
19
|
import { type OwnAgentsOps } from './ops/own-agents.js';
|
|
19
20
|
import { type SyncOps } from './ops/sync.js';
|
|
21
|
+
import { type P2PScope } from './scope.js';
|
|
20
22
|
import type { P2PStoreTables } from './tables.js';
|
|
21
23
|
export type { AppLaneOps, OpenedAppFrameExpectedVersion, OpenedAppFrameRecord, SaveOpenedAppFrameParams, } from './ops/app-lane.js';
|
|
22
24
|
export type { AppOutboxOps } from './ops/app-outbox.js';
|
|
@@ -39,8 +41,9 @@ export type { PruneBroadcastLogParams, SyncOps } from './ops/sync.js';
|
|
|
39
41
|
* tables and its own helpers; this intersection is the only coupling between
|
|
40
42
|
* them, so a caller still sees one flat API.
|
|
41
43
|
*/
|
|
42
|
-
export type P2PStoreAPI = GroupOps & CatalogOfferOps & CatalogRouteOps & CatalogSyncOps & CircleOps & DelegationOps & MLSOps & SyncOps & ControlOps & AppLaneOps & AppOutboxOps & LogHandlerCompletionOps & HubOps & DiscoveryOps & DocumentSweepOps & OwnAgentsOps;
|
|
44
|
+
export type P2PStoreAPI = P2PScope & GroupOps & CatalogOfferOps & CatalogRouteOps & CatalogSyncOps & CircleOps & DelegationOps & MLSOps & SyncOps & ControlOps & AppLaneOps & AppOutboxOps & LogHandlerCompletionOps & HubOps & DiscoveryOps & DocumentSweepOps & OwnAgentsOps;
|
|
43
45
|
export type CreateP2PStoreOptions = {
|
|
46
|
+
context: StoreAPIContext;
|
|
44
47
|
getRandomValues?: Runtime['getRandomValues'];
|
|
45
48
|
};
|
|
46
|
-
export declare function createP2PStore(db: Kysely<P2PStoreTables>, adapter: Adapter, options
|
|
49
|
+
export declare function createP2PStore(db: Kysely<P2PStoreTables>, adapter: Adapter, options: CreateP2PStoreOptions): P2PStoreAPI;
|
package/lib/api.js
CHANGED
|
@@ -15,20 +15,24 @@ import { createLogHandlerCompletionOps } from './ops/log-handler-completion.js';
|
|
|
15
15
|
import { createMLSOps } from './ops/mls.js';
|
|
16
16
|
import { createOwnAgentsOps } from './ops/own-agents.js';
|
|
17
17
|
import { createSyncOps } from './ops/sync.js';
|
|
18
|
-
|
|
18
|
+
import { runP2PScope } from './scope.js';
|
|
19
|
+
export function createP2PStore(db, adapter, options) {
|
|
19
20
|
return {
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
async [runP2PScope] (run) {
|
|
22
|
+
return await run(db, options.context);
|
|
23
|
+
},
|
|
24
|
+
...createGroupOps(db, adapter, options.context),
|
|
25
|
+
...createOwnAgentsOps(db, adapter, options.context),
|
|
22
26
|
...createCatalogOfferOps(db),
|
|
23
27
|
...createCatalogRouteOps(db),
|
|
24
|
-
...createCatalogSyncOps(db, adapter),
|
|
28
|
+
...createCatalogSyncOps(db, adapter, options.context),
|
|
25
29
|
...createCircleOps(db, adapter),
|
|
26
|
-
...createDelegationOps(db),
|
|
30
|
+
...createDelegationOps(db, options.context),
|
|
27
31
|
...createMLSOps(db, adapter),
|
|
28
32
|
...createSyncOps(db, adapter),
|
|
29
33
|
...createControlOps(db, adapter),
|
|
30
34
|
...createAppLaneOps(db, adapter),
|
|
31
|
-
...createAppOutboxOps(db, adapter, options.getRandomValues ?? createRuntime().getRandomValues),
|
|
35
|
+
...createAppOutboxOps(db, adapter, options.getRandomValues ?? createRuntime().getRandomValues, options.context),
|
|
32
36
|
...createHubOps(db, adapter),
|
|
33
37
|
...createLogHandlerCompletionOps(db),
|
|
34
38
|
...createDiscoveryOps(db, adapter),
|
package/lib/definition.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type { StoreDefinition } from '@kubun/db';
|
|
1
|
+
import type { StoreDefinition, StoreProvider } from '@kubun/db';
|
|
2
|
+
import type { Runtime } from '@sozai/runtime';
|
|
2
3
|
import type { P2PStoreAPI } from './api.js';
|
|
3
4
|
import type { P2PStoreTables } from './tables.js';
|
|
5
|
+
export declare class P2PStoreConfigurationError extends Error {
|
|
6
|
+
constructor(field: 'getRandomValues');
|
|
7
|
+
}
|
|
8
|
+
export declare function configureP2PStore(provider: StoreProvider, deps: Pick<Runtime, 'getRandomValues'>): void;
|
|
4
9
|
export declare const p2pStoreDefinition: StoreDefinition<P2PStoreTables, P2PStoreAPI>;
|
package/lib/definition.js
CHANGED
|
@@ -1,7 +1,43 @@
|
|
|
1
|
+
import { createRuntime } from '@sozai/runtime';
|
|
1
2
|
import { createP2PStore } from './api.js';
|
|
2
3
|
import { getP2PMigrations } from './migrations.js';
|
|
4
|
+
const dependencies = new WeakMap();
|
|
5
|
+
const fallbackRuntime = createRuntime();
|
|
6
|
+
export class P2PStoreConfigurationError extends Error {
|
|
7
|
+
constructor(field){
|
|
8
|
+
super(`p2p: conflicting dependency ${field}`);
|
|
9
|
+
this.name = 'P2PStoreConfigurationError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function configureP2PStore(provider, deps) {
|
|
13
|
+
const existing = dependencies.get(provider);
|
|
14
|
+
if (existing != null) {
|
|
15
|
+
if (existing.getRandomValues !== deps.getRandomValues) {
|
|
16
|
+
throw new P2PStoreConfigurationError('getRandomValues');
|
|
17
|
+
}
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
dependencies.set(provider, {
|
|
21
|
+
...deps
|
|
22
|
+
});
|
|
23
|
+
}
|
|
3
24
|
export const p2pStoreDefinition = {
|
|
4
25
|
name: 'p2p',
|
|
26
|
+
unprefixedTables: ()=>false,
|
|
5
27
|
migrations: getP2PMigrations,
|
|
6
|
-
|
|
28
|
+
sync: {
|
|
29
|
+
p2p_own_agents_grants: {
|
|
30
|
+
key: [
|
|
31
|
+
'controller_did',
|
|
32
|
+
'kind'
|
|
33
|
+
],
|
|
34
|
+
compare: [
|
|
35
|
+
'issued_at'
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
createAPI: (db, adapter, context)=>createP2PStore(db, adapter, {
|
|
40
|
+
context,
|
|
41
|
+
getRandomValues: (array)=>(dependencies.get(context.root) ?? fallbackRuntime).getRandomValues(array)
|
|
42
|
+
})
|
|
7
43
|
};
|
package/lib/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { StoreProvider } from '@kubun/db';
|
|
|
2
2
|
import type { P2PStoreAPI } from './api.js';
|
|
3
3
|
export type { BeginLogHandlerCompletionParams, BindingEvidence, CatalogCursorBounds, CatalogCursorState, CatalogOffer, CatalogRoute, CatalogSyncOps, ControlRequestKind, ControlRequestOutcome, CreateP2PStoreOptions, DocumentRepairAnswerKind, DocumentRepairRow, DueObservationRepairQuery, GetMemberRemovalsParams, LogHandlerCompletionKey, LogHandlerCompletionOps, ObservationRepairPosition, ObservationRepairSchedule, OpenedAppFrameExpectedVersion, OpenedAppFrameRecord, OwnAgentsGrant, OwnAgentsJoinCapability, OwnAgentsOps, OwnAgentsRecord, OwnAgentsRecordKey, P2PStoreAPI, PruneBroadcastLogParams, PutPendingJoinRequestParams, RecordDocumentRepairParams, ReserveSenderGenerationsParams, SaveOpenedAppFrameParams, SetLocalPeerProfileParams, UpsertPeerAnnouncementParams, } from './api.js';
|
|
4
4
|
export { createP2PStore } from './api.js';
|
|
5
|
-
export { p2pStoreDefinition } from './definition.js';
|
|
5
|
+
export { configureP2PStore, P2PStoreConfigurationError, p2pStoreDefinition } from './definition.js';
|
|
6
6
|
export { canonicalHubURL } from './hub-url.js';
|
|
7
7
|
export { AppOutboxDecryptionError, type AppOutboxPortOptions, AppOutboxTransactionError, type ClearAppOutboxRowsOptions, PendingRevocationAdmissionError, UndeliveredRevocationsError, } from './ops/app-outbox.js';
|
|
8
8
|
export { MAX_REPAIRS_PER_LISTER } from './ops/catalog-sync.js';
|
package/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { createP2PStore } from './api.js';
|
|
2
|
-
export { p2pStoreDefinition } from './definition.js';
|
|
2
|
+
export { configureP2PStore, P2PStoreConfigurationError, p2pStoreDefinition } from './definition.js';
|
|
3
3
|
export { canonicalHubURL } from './hub-url.js';
|
|
4
4
|
export { AppOutboxDecryptionError, AppOutboxTransactionError, PendingRevocationAdmissionError, UndeliveredRevocationsError } from './ops/app-outbox.js';
|
|
5
5
|
export { MAX_REPAIRS_PER_LISTER } from './ops/catalog-sync.js';
|
package/lib/migrations.js
CHANGED
|
@@ -23,37 +23,37 @@ import { sql } from 'kysely';
|
|
|
23
23
|
const now = ctx.functions.now;
|
|
24
24
|
const init = {
|
|
25
25
|
async up (db) {
|
|
26
|
-
await db.schema.createTable('
|
|
26
|
+
await db.schema.createTable('p2p_access_default_revocations').ifNotExists().addColumn('controller_did', t.text, (col)=>col.notNull()).addColumn('device_did', t.text, (col)=>col.notNull()).addPrimaryKeyConstraint('pk_p2p_access_default_revocations', [
|
|
27
27
|
'controller_did',
|
|
28
28
|
'device_did'
|
|
29
29
|
]).execute();
|
|
30
30
|
// Every authenticated device binding this device has observed. Append-only:
|
|
31
31
|
// ownership is historical, so revocation, removal or MLS state loss never
|
|
32
32
|
// takes a row away.
|
|
33
|
-
await db.schema.createTable('
|
|
33
|
+
await db.schema.createTable('p2p_binding_evidence').ifNotExists().addColumn('controller_did', t.text, (col)=>col.notNull()).addColumn('device_did', t.text, (col)=>col.notNull()).addColumn('first_seen_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addPrimaryKeyConstraint('pk_p2p_binding_evidence', [
|
|
34
34
|
'controller_did',
|
|
35
35
|
'device_did'
|
|
36
36
|
]).execute();
|
|
37
|
-
await db.schema.createIndex('idx_p2p_binding_evidence_device').ifNotExists().on('
|
|
37
|
+
await db.schema.createIndex('idx_p2p_binding_evidence_device').ifNotExists().on('p2p_binding_evidence').column('device_did').execute();
|
|
38
38
|
// Groups
|
|
39
|
-
await db.schema.createTable('
|
|
39
|
+
await db.schema.createTable('p2p_groups').ifNotExists().addColumn('id', t.text, (col)=>col.notNull().primaryKey()).addColumn('name', t.text, (col)=>col.notNull()).addColumn('description', t.text, (col)=>col.notNull().defaultTo('')).addColumn('created_by', t.text, (col)=>col.notNull()).addColumn('hlc', t.text, (col)=>col.notNull()).addColumn('kind', t.text, (col)=>col.notNull().defaultTo('standard'))// A completed join or local create starts joined; see `GroupStatus`.
|
|
40
40
|
.addColumn('status', t.text, (col)=>col.notNull().defaultTo('joined'))// Token of the last handle advance whose projections no reconcile has
|
|
41
41
|
// caught up with yet; NULL when they match the current handle.
|
|
42
42
|
.addColumn('projections_dirty', t.text)// Epoch the last successful reconcile caught the projections up to.
|
|
43
43
|
.addColumn('projections_epoch', 'integer').addColumn('created_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addColumn('updated_at', t.timestamp).execute();
|
|
44
|
-
await db.schema.createTable('
|
|
44
|
+
await db.schema.createTable('p2p_own_agents_records').ifNotExists().addColumn('type', t.text, (col)=>col.notNull()).addColumn('owner', t.text, (col)=>col.notNull()).addColumn('id', t.text, (col)=>col.notNull()).addColumn('hlc', t.text, (col)=>col.notNull()).addColumn('op_jwt', t.text, (col)=>col.notNull()).addColumn('op_hash', t.text, (col)=>col.notNull()).addColumn('payload', t.binary).addColumn('payload_digest', t.text).addColumn('deleted', 'integer', (col)=>col.notNull()).addColumn('meta', t.json, (col)=>col.notNull()).addColumn('created_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addPrimaryKeyConstraint('pk_p2p_own_agents_records', [
|
|
45
45
|
'type',
|
|
46
46
|
'owner',
|
|
47
47
|
'id',
|
|
48
48
|
'op_hash'
|
|
49
49
|
]).execute();
|
|
50
|
-
await db.schema.createTable('
|
|
50
|
+
await db.schema.createTable('p2p_own_agents_grants').ifNotExists().addColumn('controller_did', t.text, (col)=>col.notNull()).addColumn('kind', t.text, (col)=>col.notNull()).addColumn('token', t.text, (col)=>col.notNull()).addColumn('issued_at', t.bigint, (col)=>col.notNull()).addColumn('expires_at', t.bigint, (col)=>col.notNull()).addPrimaryKeyConstraint('pk_p2p_own_agents_grants', [
|
|
51
51
|
'controller_did',
|
|
52
52
|
'kind'
|
|
53
53
|
]).execute();
|
|
54
|
-
await db.schema.createTable('
|
|
54
|
+
await db.schema.createTable('p2p_own_agents_join_capabilities').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull().primaryKey()).addColumn('recipient_did', t.text, (col)=>col.notNull()).addColumn('capability_id', t.text, (col)=>col.notNull()).addColumn('token', t.text, (col)=>col.notNull()).addColumn('expires_at', t.bigint, (col)=>col.notNull()).addColumn('signer_did', t.text).addColumn('signer_leaf_key', t.binary).addColumn('signer_capability', t.text).addColumn('signer_prefix', t.json).execute();
|
|
55
55
|
// Group members
|
|
56
|
-
await db.schema.createTable('
|
|
56
|
+
await db.schema.createTable('p2p_group_members').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('member_did', t.text, (col)=>col.notNull()).addColumn('role', t.text, (col)=>col.notNull().defaultTo('member'))// LWW version key for the row, set on insert and refreshed on re-add.
|
|
57
57
|
.addColumn('hlc', t.text, (col)=>col.notNull())// HLC at which this peer learned the member was removed from the MLS
|
|
58
58
|
// group. NULL means the member is active; a non-null value tombstones
|
|
59
59
|
// the row so read-ACL / sync-scope queries exclude it while the
|
|
@@ -62,28 +62,28 @@ import { sql } from 'kysely';
|
|
|
62
62
|
'group_id',
|
|
63
63
|
'member_did'
|
|
64
64
|
]).execute();
|
|
65
|
-
await db.schema.createIndex('idx_p2p_group_members_did').ifNotExists().on('
|
|
66
|
-
await db.schema.createTable('
|
|
65
|
+
await db.schema.createIndex('idx_p2p_group_members_did').ifNotExists().on('p2p_group_members').column('member_did').execute();
|
|
66
|
+
await db.schema.createTable('p2p_catalog_offers').ifNotExists().addColumn('owner', t.text, (col)=>col.notNull()).addColumn('exposure_id', t.text, (col)=>col.notNull()).addColumn('catalog_id', t.text, (col)=>col.notNull()).addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('circle_id', t.text, (col)=>col.notNull()).addPrimaryKeyConstraint('pk_p2p_catalog_offers', [
|
|
67
67
|
'owner',
|
|
68
68
|
'exposure_id'
|
|
69
69
|
]).execute();
|
|
70
|
-
await db.schema.createIndex('idx_p2p_catalog_offers_group_circle').ifNotExists().on('
|
|
70
|
+
await db.schema.createIndex('idx_p2p_catalog_offers_group_circle').ifNotExists().on('p2p_catalog_offers').columns([
|
|
71
71
|
'group_id',
|
|
72
72
|
'circle_id'
|
|
73
73
|
]).execute();
|
|
74
|
-
await db.schema.createTable('
|
|
74
|
+
await db.schema.createTable('p2p_catalog_routes').ifNotExists().addColumn('owner', t.text, (col)=>col.notNull()).addColumn('catalog_id', t.text, (col)=>col.notNull()).addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('pull', 'integer', (col)=>col.notNull().defaultTo(0)).addColumn('push', 'integer', (col)=>col.notNull().defaultTo(0)).addPrimaryKeyConstraint('pk_p2p_catalog_routes', [
|
|
75
75
|
'owner',
|
|
76
76
|
'catalog_id',
|
|
77
77
|
'group_id'
|
|
78
78
|
]).execute();
|
|
79
79
|
// Groups whose document data this device does not serve; absence means served.
|
|
80
|
-
await db.schema.createTable('
|
|
80
|
+
await db.schema.createTable('p2p_unserved_groups').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull().primaryKey()).execute();
|
|
81
81
|
// Document-sync progress with one peer in one group: the last resolved
|
|
82
82
|
// document key, whether the current cycle's examined ranges were all clear,
|
|
83
83
|
// the hash of the accepted rule set without absolute bounds, and the
|
|
84
84
|
// absolute bounds in use until the cursor wraps.
|
|
85
|
-
await db.schema.createTable('
|
|
86
|
-
.addColumn('last_token', t.text).addColumn('cycle_clear', 'integer', (col)=>col.notNull().defaultTo(1)).addColumn('bounds', t.
|
|
85
|
+
await db.schema.createTable('p2p_catalog_cursors').ifNotExists().addColumn('peer_did', t.text, (col)=>col.notNull()).addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('rules_hash', t.text, (col)=>col.notNull()).addColumn('last_key', t.text)// The responder's sealed position for `last_key`; opaque here.
|
|
86
|
+
.addColumn('last_token', t.text).addColumn('cycle_clear', 'integer', (col)=>col.notNull().defaultTo(1)).addColumn('bounds', t.json, (col)=>col.notNull()).addPrimaryKeyConstraint('pk_p2p_catalog_cursors', [
|
|
87
87
|
'peer_did',
|
|
88
88
|
'group_id'
|
|
89
89
|
]).execute();
|
|
@@ -92,22 +92,22 @@ import { sql } from 'kysely';
|
|
|
92
92
|
// retry; null when no peer listed it and the row only remembers answers.
|
|
93
93
|
// Rows expire from `created_at`, so none outlives its window whoever
|
|
94
94
|
// listed it.
|
|
95
|
-
await db.schema.createTable('
|
|
95
|
+
await db.schema.createTable('p2p_document_repairs').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('document_id', t.text, (col)=>col.notNull()).addColumn('listed_by', t.text).addColumn('holdings_digest', t.text, (col)=>col.notNull()).addColumn('created_at', t.bigint, (col)=>col.notNull()).addColumn('attempted_at', t.bigint, (col)=>col.notNull()).addPrimaryKeyConstraint('pk_p2p_document_repairs', [
|
|
96
96
|
'group_id',
|
|
97
97
|
'document_id'
|
|
98
98
|
]).execute();
|
|
99
|
-
await db.schema.createIndex('idx_p2p_document_repairs_lister').ifNotExists().on('
|
|
99
|
+
await db.schema.createIndex('idx_p2p_document_repairs_lister').ifNotExists().on('p2p_document_repairs').columns([
|
|
100
100
|
'group_id',
|
|
101
101
|
'listed_by',
|
|
102
102
|
'attempted_at'
|
|
103
103
|
]).execute();
|
|
104
|
-
await db.schema.createIndex('idx_p2p_document_repairs_created').ifNotExists().on('
|
|
104
|
+
await db.schema.createIndex('idx_p2p_document_repairs_created').ifNotExists().on('p2p_document_repairs').columns([
|
|
105
105
|
'group_id',
|
|
106
106
|
'created_at'
|
|
107
107
|
]).execute();
|
|
108
108
|
// A peer's last answer, "unavailable" or "refused", for a repair row's
|
|
109
109
|
// current holdings. A change of holdings removes the answers.
|
|
110
|
-
await db.schema.createTable('
|
|
110
|
+
await db.schema.createTable('p2p_document_repair_answers').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('document_id', t.text, (col)=>col.notNull()).addColumn('peer_did', t.text, (col)=>col.notNull()).addColumn('answer', t.text, (col)=>col.notNull()).addPrimaryKeyConstraint('pk_p2p_document_repair_answers', [
|
|
111
111
|
'group_id',
|
|
112
112
|
'document_id',
|
|
113
113
|
'peer_did'
|
|
@@ -115,13 +115,13 @@ import { sql } from 'kysely';
|
|
|
115
115
|
// When this device next asks peers for an observed document's value, for
|
|
116
116
|
// the obligation observed at `fetch_hlc`. The connector owns the
|
|
117
117
|
// obligation; a row leaves only when it resolves.
|
|
118
|
-
await db.schema.createTable('
|
|
119
|
-
await db.schema.createIndex('idx_p2p_observation_repairs_next').ifNotExists().on('
|
|
118
|
+
await db.schema.createTable('p2p_observation_repairs').ifNotExists().addColumn('document_id', t.text, (col)=>col.notNull().primaryKey()).addColumn('fetch_hlc', t.text, (col)=>col.notNull()).addColumn('attempts', 'integer', (col)=>col.notNull()).addColumn('next_attempt_at', t.bigint, (col)=>col.notNull()).addColumn('tried_count', 'integer', (col)=>col.notNull()).execute();
|
|
119
|
+
await db.schema.createIndex('idx_p2p_observation_repairs_next').ifNotExists().on('p2p_observation_repairs').columns([
|
|
120
120
|
'next_attempt_at',
|
|
121
121
|
'document_id'
|
|
122
122
|
]).execute();
|
|
123
123
|
// The peers already asked for an obligation that answered without it.
|
|
124
|
-
await db.schema.createTable('
|
|
124
|
+
await db.schema.createTable('p2p_observation_repair_peers').ifNotExists().addColumn('document_id', t.text, (col)=>col.notNull()).addColumn('peer_did', t.text, (col)=>col.notNull()).addPrimaryKeyConstraint('pk_p2p_observation_repair_peers', [
|
|
125
125
|
'document_id',
|
|
126
126
|
'peer_did'
|
|
127
127
|
]).execute();
|
|
@@ -129,12 +129,12 @@ import { sql } from 'kysely';
|
|
|
129
129
|
// or duplicate request is not surfaced again. Separate from the membership
|
|
130
130
|
// row because it must outlive a removal: a re-added member's old requests
|
|
131
131
|
// stay spent.
|
|
132
|
-
await db.schema.createTable('
|
|
132
|
+
await db.schema.createTable('p2p_group_leave_requests').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('member_did', t.text, (col)=>col.notNull()).addColumn('hlc', t.text, (col)=>col.notNull()).addPrimaryKeyConstraint('pk_p2p_group_leave_requests', [
|
|
133
133
|
'group_id',
|
|
134
134
|
'member_did'
|
|
135
135
|
]).execute();
|
|
136
136
|
// Circles
|
|
137
|
-
await db.schema.createTable('
|
|
137
|
+
await db.schema.createTable('p2p_circles').ifNotExists().addColumn('id', t.text, (col)=>col.notNull().primaryKey()).addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('name', t.text, (col)=>col.notNull()).addColumn('description', t.text, (col)=>col.notNull().defaultTo('')).addColumn('hlc', t.text, (col)=>col.notNull())// Projection of the group's current `openCircleIDs`: 1 marks the circle
|
|
138
138
|
// open (every group member has implicit access), 0 closed. Integer 0/1
|
|
139
139
|
// mirrors the catalog `active` flag, keeping the read-back value uniform
|
|
140
140
|
// across SQLite and Postgres. A circle is closed until a settings fold
|
|
@@ -142,38 +142,38 @@ import { sql } from 'kysely';
|
|
|
142
142
|
.addColumn('open', 'integer', (col)=>col.notNull().defaultTo(0))// NULL means the circle is active; a non-null value tombstones the row
|
|
143
143
|
// so reads exclude it while the removal HLC stays comparable.
|
|
144
144
|
.addColumn('removed_at_hlc', t.text).addColumn('created_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addColumn('updated_at', t.timestamp).execute();
|
|
145
|
-
await db.schema.createIndex('idx_p2p_circles_group').ifNotExists().on('
|
|
145
|
+
await db.schema.createIndex('idx_p2p_circles_group').ifNotExists().on('p2p_circles').column('group_id').execute();
|
|
146
146
|
// Circle members
|
|
147
|
-
await db.schema.createTable('
|
|
147
|
+
await db.schema.createTable('p2p_circle_members').ifNotExists().addColumn('circle_id', t.text, (col)=>col.notNull()).addColumn('member_did', t.text, (col)=>col.notNull()).addColumn('role', t.text, (col)=>col.notNull().defaultTo('member')).addColumn('hlc', t.text, (col)=>col.notNull())// NULL means the circle member is active; a non-null value tombstones
|
|
148
148
|
// the row so reads exclude it while the removal HLC stays comparable.
|
|
149
149
|
.addColumn('removed_at_hlc', t.text).addColumn('created_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addColumn('updated_at', t.timestamp).addPrimaryKeyConstraint('pk_p2p_circle_members', [
|
|
150
150
|
'circle_id',
|
|
151
151
|
'member_did'
|
|
152
152
|
]).execute();
|
|
153
|
-
await db.schema.createIndex('idx_p2p_circle_members_did').ifNotExists().on('
|
|
153
|
+
await db.schema.createIndex('idx_p2p_circle_members_did').ifNotExists().on('p2p_circle_members').column('member_did').execute();
|
|
154
154
|
// Group-delegation edge. The delegation token and revocation rows live in
|
|
155
155
|
// the core delegation store (group-agnostic); this thin edge records the
|
|
156
156
|
// one group a delegation `jti` was granted in, so the p2p layer can still
|
|
157
157
|
// resolve a cap's group for revoke-broadcast targeting and listing
|
|
158
158
|
// enrichment. One group per `jti`, so `jti` is the primary key.
|
|
159
|
-
await db.schema.createTable('
|
|
160
|
-
await db.schema.createIndex('idx_p2p_group_delegation_pending_grant').ifNotExists().on('
|
|
159
|
+
await db.schema.createTable('p2p_group_delegation').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('jti', t.text, (col)=>col.notNull().primaryKey()).addColumn('pending_grant_hlc', t.text).addColumn('pending_grant_digest', t.text).addColumn('pending_revocation_hlc', t.text).addColumn('pending_revocation_digest', t.text).execute();
|
|
160
|
+
await db.schema.createIndex('idx_p2p_group_delegation_pending_grant').ifNotExists().on('p2p_group_delegation').columns([
|
|
161
161
|
'group_id',
|
|
162
162
|
'pending_grant_hlc'
|
|
163
163
|
]).execute();
|
|
164
|
-
await db.schema.createIndex('idx_p2p_group_delegation_pending_revocation').ifNotExists().on('
|
|
164
|
+
await db.schema.createIndex('idx_p2p_group_delegation_pending_revocation').ifNotExists().on('p2p_group_delegation').columns([
|
|
165
165
|
'group_id',
|
|
166
166
|
'pending_revocation_hlc'
|
|
167
167
|
]).execute();
|
|
168
168
|
// Group MLS state
|
|
169
|
-
await db.schema.createTable('
|
|
169
|
+
await db.schema.createTable('p2p_group_mls_state').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('device_id', t.text, (col)=>col.notNull()).addColumn('mls_state', t.binary, (col)=>col.notNull()).addColumn('credential', t.json, (col)=>col.notNull()).addColumn('epoch', 'integer', (col)=>col.notNull())// Orders in-place secret-tree mutations within one epoch.
|
|
170
170
|
.addColumn('state_version', 'integer', (col)=>col.notNull().defaultTo(0)).addColumn('is_deleted', 'integer', (col)=>col.notNull().defaultTo(0))// Highest sender generation reserved at this epoch; restore skips past it.
|
|
171
|
-
.addColumn('sender_generation_hwm', 'integer', (col)=>col.notNull().defaultTo(0)).addColumn('ledger_entries', t.
|
|
171
|
+
.addColumn('sender_generation_hwm', 'integer', (col)=>col.notNull().defaultTo(0)).addColumn('ledger_entries', t.json, (col)=>col.notNull().defaultTo(sql`'[]'`)).addColumn('updated_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addPrimaryKeyConstraint('pk_p2p_group_mls_state', [
|
|
172
172
|
'group_id',
|
|
173
173
|
'device_id'
|
|
174
174
|
]).execute();
|
|
175
175
|
// Sync peers
|
|
176
|
-
await db.schema.createTable('
|
|
176
|
+
await db.schema.createTable('p2p_sync_peers').ifNotExists().addColumn('id', t.text, (col)=>col.notNull().primaryKey()).addColumn('peer_did', t.text, (col)=>col.notNull().unique()).addColumn('endpoint', t.text, (col)=>col.notNull())// No `trust_level`, `allowed_users`, `priority` or `mode`. They were
|
|
177
177
|
// stored and never read: what a peer may see is decided per document at
|
|
178
178
|
// the far end, and a locally-written row is not a credential. `priority`
|
|
179
179
|
// in particular looked like the ranking knob after ranking had moved to
|
|
@@ -183,27 +183,27 @@ import { sql } from 'kysely';
|
|
|
183
183
|
// argument, per call.
|
|
184
184
|
.addColumn('config', t.json, (col)=>col.notNull()).addColumn('created_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addColumn('updated_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).execute();
|
|
185
185
|
// Sync checkpoints
|
|
186
|
-
await db.schema.createTable('
|
|
186
|
+
await db.schema.createTable('p2p_sync_checkpoints').ifNotExists().addColumn('id', t.text, (col)=>col.notNull().primaryKey()).addColumn('peer_did', t.text, (col)=>col.notNull()).addColumn('scope', t.text, (col)=>col.notNull()).addColumn('checkpoint_hlc', t.text, (col)=>col.notNull()).addColumn('updated_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).execute();
|
|
187
187
|
// Broadcast log
|
|
188
|
-
await db.schema.createTable('
|
|
188
|
+
await db.schema.createTable('p2p_broadcast_log').ifNotExists().addColumn('doc_id', t.text, (col)=>col.notNull()).addColumn('version', t.text, (col)=>col.notNull()).addColumn('mls_group_id', t.text, (col)=>col.notNull()).addColumn('broadcast_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addPrimaryKeyConstraint('pk_p2p_broadcast_log', [
|
|
189
189
|
'doc_id',
|
|
190
190
|
'version',
|
|
191
191
|
'mls_group_id'
|
|
192
192
|
]).execute();
|
|
193
|
-
await db.schema.createIndex('idx_p2p_broadcast_log_doc').ifNotExists().on('
|
|
193
|
+
await db.schema.createIndex('idx_p2p_broadcast_log_doc').ifNotExists().on('p2p_broadcast_log').column('doc_id').execute();
|
|
194
194
|
// The broadcast log is pruned by age.
|
|
195
|
-
await db.schema.createIndex('idx_p2p_broadcast_log_broadcast_at').ifNotExists().on('
|
|
195
|
+
await db.schema.createIndex('idx_p2p_broadcast_log_broadcast_at').ifNotExists().on('p2p_broadcast_log').column('broadcast_at').execute();
|
|
196
196
|
// Hubs (device-local, never synced — no hlc column)
|
|
197
|
-
await db.schema.createTable('
|
|
197
|
+
await db.schema.createTable('p2p_hubs').ifNotExists().addColumn('id', t.text, (col)=>col.notNull().primaryKey()).addColumn('label', t.text).addColumn('url', t.text, (col)=>col.notNull().unique()).addColumn('server_did', t.text).addColumn('created_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addColumn('updated_at', t.timestamp).execute();
|
|
198
198
|
// Group hubs (join table, device-local — no hlc column). A group commits
|
|
199
199
|
// through exactly one bound hub; `is_commit_hub` marks which. Integer 0/1
|
|
200
200
|
// mirrors the circle `open` flag so the value reads back uniformly across
|
|
201
201
|
// SQLite and Postgres.
|
|
202
|
-
await db.schema.createTable('
|
|
202
|
+
await db.schema.createTable('p2p_group_hubs').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('hub_id', t.text, (col)=>col.notNull()).addColumn('is_commit_hub', 'integer', (col)=>col.notNull().defaultTo(0)).addColumn('created_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addPrimaryKeyConstraint('pk_p2p_group_hubs', [
|
|
203
203
|
'group_id',
|
|
204
204
|
'hub_id'
|
|
205
205
|
]).execute();
|
|
206
|
-
await db.schema.createIndex('idx_p2p_group_hubs_hub').ifNotExists().on('
|
|
206
|
+
await db.schema.createIndex('idx_p2p_group_hubs_hub').ifNotExists().on('p2p_group_hubs').column('hub_id').execute();
|
|
207
207
|
// The single designation is a database constraint, not a convention a
|
|
208
208
|
// writer upholds. A transaction alone cannot uphold it: two devices
|
|
209
209
|
// binding their first hub concurrently touch DIFFERENT rows, so under
|
|
@@ -211,7 +211,7 @@ import { sql } from 'kysely';
|
|
|
211
211
|
// both claim it — the group then commits to two logs, which is the fork
|
|
212
212
|
// the designation exists to prevent. Partial unique indexes carry the
|
|
213
213
|
// same meaning on both adapter families (SQLite >= 3.8, Postgres).
|
|
214
|
-
await db.schema.createIndex(COMMIT_HUB_UNIQUE_INDEX).ifNotExists().unique().on('
|
|
214
|
+
await db.schema.createIndex(COMMIT_HUB_UNIQUE_INDEX).ifNotExists().unique().on('p2p_group_hubs').column('group_id').where(sql.ref('is_commit_hub'), '=', 1).execute();
|
|
215
215
|
// ControlRequest work queue: the client-visible record of a control-plane
|
|
216
216
|
// request (a ledger write, an invite, a removal) from enqueue to
|
|
217
217
|
// settlement, keyed by the same id the commit journal carries for the
|
|
@@ -220,39 +220,39 @@ import { sql } from 'kysely';
|
|
|
220
220
|
// nullable because most requests produce nothing to hand back; it is
|
|
221
221
|
// written on settle and deleted with the row on ack, so the retention of
|
|
222
222
|
// whatever it holds is bounded by the request's own lifetime.
|
|
223
|
-
await db.schema.createTable('
|
|
223
|
+
await db.schema.createTable('p2p_control_requests').ifNotExists().addColumn('id', t.text, (col)=>col.notNull().primaryKey()).addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('kind', t.text, (col)=>col.notNull()).addColumn('status', t.text, (col)=>col.notNull().defaultTo('pending')).addColumn('error', t.text).addColumn('result', t.text).addColumn('enqueued_at', t.text, (col)=>col.notNull()).addColumn('settled_at', t.text)// Epoch of the advance that settled the request committed.
|
|
224
224
|
.addColumn('settled_epoch', 'integer').execute();
|
|
225
|
-
await db.schema.createIndex('idx_p2p_control_requests_group').ifNotExists().on('
|
|
225
|
+
await db.schema.createIndex('idx_p2p_control_requests_group').ifNotExists().on('p2p_control_requests').columns([
|
|
226
226
|
'group_id',
|
|
227
227
|
'enqueued_at'
|
|
228
228
|
]).execute();
|
|
229
229
|
// CommitJournal store (backs the `@kumiai/rpc` CommitJournal port).
|
|
230
230
|
// `group_id` is the primary key: a single slot per group, so a fresh `put`
|
|
231
231
|
// upserts/replaces the whole row.
|
|
232
|
-
await db.schema.createTable('
|
|
232
|
+
await db.schema.createTable('p2p_commit_journal').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull().primaryKey()).addColumn('publish_id', t.text, (col)=>col.notNull()).addColumn('expected_head', t.text).addColumn('epoch', t.bigint, (col)=>col.notNull()).addColumn('accepted_as', t.text).addColumn('commit', t.binary, (col)=>col.notNull()).addColumn('bodies', t.json, (col)=>col.notNull()).addColumn('kind', t.text, (col)=>col.notNull()).addColumn('journal', t.binary, (col)=>col.notNull()).addColumn('holds_log_sends', 'integer', (col)=>col.notNull().defaultTo(0)).execute();
|
|
233
233
|
// App-lane anchor + per-topic read positions (back the `@kumiai/rpc`
|
|
234
234
|
// `AnchorStore` and `AppCursorStore` ports). The anchor table is a single
|
|
235
235
|
// slot per group, so a rotation upserts and replaces the whole row;
|
|
236
236
|
// cursors are keyed by (group, topic) so a deleted group takes its cursors
|
|
237
237
|
// with it.
|
|
238
|
-
await db.schema.createTable('
|
|
239
|
-
await db.schema.createTable('
|
|
240
|
-
await db.schema.createTable('
|
|
238
|
+
await db.schema.createTable('p2p_group_anchor').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull().primaryKey()).addColumn('secret', t.binary, (col)=>col.notNull()).addColumn('epoch', t.bigint, (col)=>col.notNull()).addColumn('pending', t.json).execute();
|
|
239
|
+
await db.schema.createTable('p2p_app_outbox_state').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull().primaryKey()).addColumn('key', t.binary).addColumn('commit_cursor', t.json).execute();
|
|
240
|
+
await db.schema.createTable('p2p_app_outbox').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('seq', t.bigint, (col)=>col.notNull()).addColumn('protocol', t.text, (col)=>col.notNull()).addColumn('prc', t.text, (col)=>col.notNull()).addColumn('data', t.binary, (col)=>col.notNull()).addColumn('iv', t.binary, (col)=>col.notNull()).addColumn('last_attempt', t.json).addPrimaryKeyConstraint('pk_p2p_app_outbox', [
|
|
241
241
|
'group_id',
|
|
242
242
|
'seq'
|
|
243
243
|
]).execute();
|
|
244
|
-
await db.schema.createTable('
|
|
244
|
+
await db.schema.createTable('p2p_app_cursor').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('topic_id', t.text, (col)=>col.notNull()).addColumn('position', t.text, (col)=>col.notNull()).addPrimaryKeyConstraint('pk_p2p_app_cursor', [
|
|
245
245
|
'group_id',
|
|
246
246
|
'topic_id'
|
|
247
247
|
]).execute();
|
|
248
248
|
// Decrypted app frames awaiting application. The frame ID is stable across
|
|
249
249
|
// redelivery, so the first staged record wins until it is completed.
|
|
250
|
-
await db.schema.createTable('
|
|
250
|
+
await db.schema.createTable('p2p_app_pending').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('device_id', t.text, (col)=>col.notNull()).addColumn('frame_id', t.text, (col)=>col.notNull()).addColumn('topic_id', t.text, (col)=>col.notNull()).addColumn('protocol', t.text, (col)=>col.notNull()).addColumn('segment', 'integer', (col)=>col.notNull()).addColumn('position', t.text, (col)=>col.notNull()).addColumn('payload', t.binary, (col)=>col.notNull()).addColumn('sender_did', t.text, (col)=>col.notNull()).addColumn('created_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addPrimaryKeyConstraint('pk_p2p_app_pending', [
|
|
251
251
|
'group_id',
|
|
252
252
|
'device_id',
|
|
253
253
|
'frame_id'
|
|
254
254
|
]).execute();
|
|
255
|
-
await db.schema.createTable('
|
|
255
|
+
await db.schema.createTable('p2p_log_handler_completion').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('procedure', t.text, (col)=>col.notNull()).addColumn('entity', t.text, (col)=>col.notNull()).addColumn('hlc', t.text, (col)=>col.notNull()).addColumn('notify', 'integer', (col)=>col.notNull().defaultTo(0)).addColumn('completed', 'integer', (col)=>col.notNull().defaultTo(0)).addPrimaryKeyConstraint('pk_p2p_log_handler_completion', [
|
|
256
256
|
'group_id',
|
|
257
257
|
'procedure',
|
|
258
258
|
'entity',
|
|
@@ -262,65 +262,65 @@ import { sql } from 'kysely';
|
|
|
262
262
|
// authenticated `peer/announce` frames. `peer_did` is the MLS-authenticated
|
|
263
263
|
// announcer, which is why the primary key is (group, peer) and there is no
|
|
264
264
|
// column for a body-supplied DID: nothing self-asserted may pick the row.
|
|
265
|
-
await db.schema.createTable('
|
|
265
|
+
await db.schema.createTable('p2p_peer_announcements').ifNotExists().addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('peer_did', t.text, (col)=>col.notNull()).addColumn('label', t.text, (col)=>col.notNull().defaultTo('')).addColumn('availability', t.text, (col)=>col.notNull()).addColumn('capabilities', t.json, (col)=>col.notNull().defaultTo('[]')).addColumn('hlc', t.text, (col)=>col.notNull()).addColumn('announced_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).addColumn('announced_epoch', 'integer', (col)=>col.notNull().defaultTo(0)).addPrimaryKeyConstraint('pk_p2p_peer_announcements', [
|
|
266
266
|
'group_id',
|
|
267
267
|
'peer_did'
|
|
268
268
|
]).execute();
|
|
269
269
|
// Answers "which groups have I seen this device in", the read a roster
|
|
270
270
|
// removal and a cross-group route lookup both need.
|
|
271
|
-
await db.schema.createIndex('idx_p2p_peer_announcements_peer').ifNotExists().on('
|
|
271
|
+
await db.schema.createIndex('idx_p2p_peer_announcements_peer').ifNotExists().on('p2p_peer_announcements').column('peer_did').execute();
|
|
272
272
|
// This device's own advertisement, device-wide. One row, keyed on the
|
|
273
273
|
// device's DID rather than on a fixed sentinel, so a profile written under
|
|
274
274
|
// one identity is never read back under another.
|
|
275
|
-
await db.schema.createTable('
|
|
275
|
+
await db.schema.createTable('p2p_local_peer_profile').ifNotExists().addColumn('peer_did', t.text, (col)=>col.notNull().primaryKey()).addColumn('label', t.text, (col)=>col.notNull().defaultTo('')).addColumn('availability', t.text, (col)=>col.notNull()).addColumn('capabilities', t.json, (col)=>col.notNull().defaultTo('[]')).addColumn('updated_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).execute();
|
|
276
276
|
// The private half of a join request, held between `prepareJoinRequest`
|
|
277
277
|
// and `completeJoin`. The offline exchange spans a human round-trip, so
|
|
278
278
|
// the two calls can be different processes — a CLI device is always two.
|
|
279
279
|
// Keyed on the requesting DID: a second request replaces the first rather
|
|
280
280
|
// than leaving dead key material behind, and the row is deleted the moment
|
|
281
281
|
// it is consumed.
|
|
282
|
-
await db.schema.createTable('
|
|
282
|
+
await db.schema.createTable('p2p_pending_join_requests').ifNotExists().addColumn('did', t.text, (col)=>col.notNull().primaryKey())// The caller's own encoding, opaque here: a key package holds BigInts
|
|
283
283
|
// and binary, which plain JSON cannot carry.
|
|
284
284
|
.addColumn('payload', t.text, (col)=>col.notNull()).addColumn('created_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).execute();
|
|
285
285
|
},
|
|
286
286
|
async down (db) {
|
|
287
|
-
await db.schema.dropTable('
|
|
288
|
-
await db.schema.dropTable('
|
|
289
|
-
await db.schema.dropTable('
|
|
290
|
-
await db.schema.dropTable('
|
|
291
|
-
await db.schema.dropTable('
|
|
292
|
-
await db.schema.dropTable('
|
|
293
|
-
await db.schema.dropTable('
|
|
294
|
-
await db.schema.dropTable('
|
|
295
|
-
await db.schema.dropTable('
|
|
296
|
-
await db.schema.dropTable('
|
|
297
|
-
await db.schema.dropTable('
|
|
298
|
-
await db.schema.dropTable('
|
|
299
|
-
await db.schema.dropTable('
|
|
300
|
-
await db.schema.dropTable('
|
|
301
|
-
await db.schema.dropTable('
|
|
302
|
-
await db.schema.dropTable('
|
|
303
|
-
await db.schema.dropTable('
|
|
304
|
-
await db.schema.dropTable('
|
|
305
|
-
await db.schema.dropTable('
|
|
306
|
-
await db.schema.dropTable('
|
|
307
|
-
await db.schema.dropTable('
|
|
308
|
-
await db.schema.dropTable('
|
|
309
|
-
await db.schema.dropTable('
|
|
310
|
-
await db.schema.dropTable('
|
|
287
|
+
await db.schema.dropTable('p2p_access_default_revocations').ifExists().execute();
|
|
288
|
+
await db.schema.dropTable('p2p_binding_evidence').ifExists().execute();
|
|
289
|
+
await db.schema.dropTable('p2p_own_agents_join_capabilities').ifExists().execute();
|
|
290
|
+
await db.schema.dropTable('p2p_own_agents_grants').ifExists().execute();
|
|
291
|
+
await db.schema.dropTable('p2p_own_agents_records').ifExists().execute();
|
|
292
|
+
await db.schema.dropTable('p2p_observation_repair_peers').ifExists().execute();
|
|
293
|
+
await db.schema.dropTable('p2p_observation_repairs').ifExists().execute();
|
|
294
|
+
await db.schema.dropTable('p2p_document_repair_answers').ifExists().execute();
|
|
295
|
+
await db.schema.dropTable('p2p_document_repairs').ifExists().execute();
|
|
296
|
+
await db.schema.dropTable('p2p_catalog_cursors').ifExists().execute();
|
|
297
|
+
await db.schema.dropTable('p2p_catalog_routes').ifExists().execute();
|
|
298
|
+
await db.schema.dropTable('p2p_unserved_groups').ifExists().execute();
|
|
299
|
+
await db.schema.dropTable('p2p_catalog_offers').ifExists().execute();
|
|
300
|
+
await db.schema.dropTable('p2p_pending_join_requests').ifExists().execute();
|
|
301
|
+
await db.schema.dropTable('p2p_local_peer_profile').ifExists().execute();
|
|
302
|
+
await db.schema.dropTable('p2p_peer_announcements').ifExists().execute();
|
|
303
|
+
await db.schema.dropTable('p2p_app_pending').ifExists().execute();
|
|
304
|
+
await db.schema.dropTable('p2p_log_handler_completion').ifExists().execute();
|
|
305
|
+
await db.schema.dropTable('p2p_app_cursor').ifExists().execute();
|
|
306
|
+
await db.schema.dropTable('p2p_app_outbox').ifExists().execute();
|
|
307
|
+
await db.schema.dropTable('p2p_app_outbox_state').ifExists().execute();
|
|
308
|
+
await db.schema.dropTable('p2p_group_anchor').ifExists().execute();
|
|
309
|
+
await db.schema.dropTable('p2p_commit_journal').ifExists().execute();
|
|
310
|
+
await db.schema.dropTable('p2p_control_requests').ifExists().execute();
|
|
311
311
|
await db.schema.dropIndex(COMMIT_HUB_UNIQUE_INDEX).ifExists().execute();
|
|
312
|
-
await db.schema.dropTable('
|
|
313
|
-
await db.schema.dropTable('
|
|
314
|
-
await db.schema.dropTable('
|
|
315
|
-
await db.schema.dropTable('
|
|
316
|
-
await db.schema.dropTable('
|
|
317
|
-
await db.schema.dropTable('
|
|
318
|
-
await db.schema.dropTable('
|
|
319
|
-
await db.schema.dropTable('
|
|
320
|
-
await db.schema.dropTable('
|
|
321
|
-
await db.schema.dropTable('
|
|
322
|
-
await db.schema.dropTable('
|
|
323
|
-
await db.schema.dropTable('
|
|
312
|
+
await db.schema.dropTable('p2p_group_hubs').ifExists().execute();
|
|
313
|
+
await db.schema.dropTable('p2p_hubs').ifExists().execute();
|
|
314
|
+
await db.schema.dropTable('p2p_broadcast_log').ifExists().execute();
|
|
315
|
+
await db.schema.dropTable('p2p_sync_checkpoints').ifExists().execute();
|
|
316
|
+
await db.schema.dropTable('p2p_sync_peers').ifExists().execute();
|
|
317
|
+
await db.schema.dropTable('p2p_group_mls_state').ifExists().execute();
|
|
318
|
+
await db.schema.dropTable('p2p_group_delegation').ifExists().execute();
|
|
319
|
+
await db.schema.dropTable('p2p_circle_members').ifExists().execute();
|
|
320
|
+
await db.schema.dropTable('p2p_circles').ifExists().execute();
|
|
321
|
+
await db.schema.dropTable('p2p_group_leave_requests').ifExists().execute();
|
|
322
|
+
await db.schema.dropTable('p2p_group_members').ifExists().execute();
|
|
323
|
+
await db.schema.dropTable('p2p_groups').ifExists().execute();
|
|
324
324
|
}
|
|
325
325
|
};
|
|
326
326
|
return {
|
package/lib/ops/app-lane.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Adapter } from '@kubun/db-adapter';
|
|
2
2
|
import { type AnchorSlot } from '@kumiai/rpc';
|
|
3
3
|
import type { Kysely } from 'kysely';
|
|
4
4
|
import type { AppCursor, GroupAnchor, InsertGroupMLSState, P2PStoreTables, PendingAppFrameRow } from '../tables.js';
|