@kubun/store-graph 0.17.0 → 0.18.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/access-default-records.d.ts +18 -0
- package/lib/access-default-records.js +167 -0
- package/lib/api.d.ts +411 -52
- package/lib/api.js +2427 -188
- package/lib/catalog-merge.d.ts +5 -0
- package/lib/catalog-merge.js +117 -0
- package/lib/catalog-records.d.ts +34 -0
- package/lib/catalog-records.js +527 -0
- package/lib/catalog-scope.d.ts +120 -0
- package/lib/catalog-scope.js +165 -0
- package/lib/catalog-state.d.ts +21 -0
- package/lib/catalog-state.js +122 -0
- package/lib/catalog-types.d.ts +71 -0
- package/lib/catalog-types.js +1 -0
- package/lib/errors.d.ts +15 -0
- package/lib/errors.js +33 -0
- package/lib/identifiers.d.ts +7 -0
- package/lib/identifiers.js +27 -0
- package/lib/index.d.ts +11 -4
- package/lib/index.js +7 -2
- package/lib/migrations.d.ts +8 -10
- package/lib/migrations.js +111 -18
- package/lib/query-builder.js +1 -1
- package/lib/tables.d.ts +197 -39
- package/package.json +14 -10
package/lib/migrations.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
|
+
import { sql } from 'kysely';
|
|
1
2
|
/**
|
|
2
|
-
* A shipped migration
|
|
3
|
-
* changes nothing on that database and silently diverges
|
|
4
|
-
* code.
|
|
5
|
-
*
|
|
3
|
+
* A shipped migration should be immutable: once a database has run it, editing
|
|
4
|
+
* it changes nothing on that database and silently diverges its schema from the
|
|
5
|
+
* code. Schema changes after a release that preserves databases need a NEW
|
|
6
|
+
* migration.
|
|
6
7
|
*
|
|
7
|
-
* `0-init`
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* so folding the change into the initial schema costs nothing and keeps `0-init`
|
|
12
|
-
* readable as the whole schema. Do NOT repeat it after this release ships.
|
|
8
|
+
* `0-init` was edited in place again for the pending arrival group, sender, retry columns and
|
|
9
|
+
* due index. Existing databases will not acquire them and must be recreated.
|
|
10
|
+
* This is a breaking reset. Do NOT repeat an in-place edit once a release that
|
|
11
|
+
* must preserve existing databases ships; add a new migration then.
|
|
13
12
|
*/ export function getGraphMigrations(ctx) {
|
|
14
13
|
const t = ctx.types;
|
|
15
14
|
const now = ctx.functions.now;
|
|
16
15
|
const init = {
|
|
17
16
|
async up (db) {
|
|
18
17
|
// Document models
|
|
19
|
-
await db.schema.createTable('kubun_graph_document_models').ifNotExists().addColumn('id', t.text, (col)=>col.notNull().primaryKey()).addColumn('version', t.text, (col)=>col.notNull()).addColumn('name', t.text, (col)=>col.notNull()).addColumn('behavior', t.text, (col)=>col.notNull()).addColumn('unique_fields', t.json).addColumn('interfaces', t.json, (col)=>col.notNull()).addColumn('schema', t.json, (col)=>col.notNull()).addColumn('fields_meta', t.json, (col)=>col.notNull()).addColumn('created_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).execute();
|
|
18
|
+
await db.schema.createTable('kubun_graph_document_models').ifNotExists().addColumn('id', t.text, (col)=>col.notNull().primaryKey()).addColumn('version', t.text, (col)=>col.notNull()).addColumn('name', t.text, (col)=>col.notNull()).addColumn('behavior', t.text, (col)=>col.notNull()).addColumn('unique_fields', t.json).addColumn('interfaces', t.json, (col)=>col.notNull()).addColumn('schema', t.json, (col)=>col.notNull()).addColumn('fields_meta', t.json, (col)=>col.notNull()).addColumn('provider_merge_policy', t.json).addColumn('date_field', t.text).addColumn('resolved_date_field', t.text).addColumn('created_at', t.timestamp, (col)=>col.defaultTo(now).notNull()).execute();
|
|
20
19
|
// Document model interfaces
|
|
21
20
|
await db.schema.createTable('kubun_graph_document_model_interfaces').ifNotExists().addColumn('interface_id', t.text, (col)=>col.notNull().references('kubun_graph_document_models.id')).addColumn('implementation_id', t.text, (col)=>col.notNull().references('kubun_graph_document_models.id')).addUniqueConstraint('kubun_graph_document_model_interfaces_pkey', [
|
|
22
21
|
'interface_id',
|
|
@@ -47,22 +46,97 @@
|
|
|
47
46
|
'owner_did',
|
|
48
47
|
'model_id'
|
|
49
48
|
]).execute();
|
|
49
|
+
// The group row serialises concurrent parking on PostgreSQL. SQLite serialises writers.
|
|
50
|
+
await db.schema.createTable('kubun_graph_pending_groups').ifNotExists().addColumn('group_id', t.text, (col)=>col.primaryKey()).execute();
|
|
50
51
|
// Mutation log
|
|
51
|
-
await db.schema.createTable('kubun_graph_mutation_log').ifNotExists().addColumn('mutation_hash', t.text, (col)=>col.primaryKey()).addColumn('model_id', t.text, (col)=>col.notNull()).addColumn('document_id', t.text, (col)=>col.notNull()).addColumn('author_did', t.text, (col)=>col.notNull()).addColumn('hlc', t.text, (col)=>col.notNull()).addColumn('mutation_jwt', t.text, (col)=>col.notNull()).addColumn('status', t.text, (col)=>col.notNull().defaultTo('applied')).execute();
|
|
52
|
+
await db.schema.createTable('kubun_graph_mutation_log').ifNotExists().addColumn('mutation_hash', t.text, (col)=>col.primaryKey()).addColumn('model_id', t.text, (col)=>col.notNull()).addColumn('document_id', t.text, (col)=>col.notNull()).addColumn('author_did', t.text, (col)=>col.notNull()).addColumn('hlc', t.text, (col)=>col.notNull()).addColumn('mutation_jwt', t.text, (col)=>col.notNull()).addColumn('arrival_group_id', t.text).addColumn('sender_peer_did', t.text).addColumn('parked_at', t.bigint).addColumn('status', t.text, (col)=>col.notNull().defaultTo('applied')).addColumn('attempt_count', 'integer', (col)=>col.notNull().defaultTo(0)).addColumn('last_attempt_at', t.bigint).addColumn('next_attempt_at', t.bigint).execute();
|
|
52
53
|
await db.schema.createIndex('idx_graph_mutation_log_hlc').ifNotExists().on('kubun_graph_mutation_log').column('hlc').execute();
|
|
53
54
|
await db.schema.createIndex('idx_graph_mutation_log_document').ifNotExists().on('kubun_graph_mutation_log').column('document_id').execute();
|
|
54
55
|
await db.schema.createIndex('idx_graph_mutation_log_status').ifNotExists().on('kubun_graph_mutation_log').column('status').execute();
|
|
56
|
+
await db.schema.createIndex('idx_graph_mutation_log_pending_group').ifNotExists().on('kubun_graph_mutation_log').columns([
|
|
57
|
+
'status',
|
|
58
|
+
'arrival_group_id',
|
|
59
|
+
'sender_peer_did'
|
|
60
|
+
]).execute();
|
|
61
|
+
await db.schema.createIndex('idx_graph_mutation_log_due_pending').ifNotExists().on('kubun_graph_mutation_log').columns([
|
|
62
|
+
'status',
|
|
63
|
+
'next_attempt_at'
|
|
64
|
+
]).execute();
|
|
65
|
+
await db.schema.createTable('kubun_graph_catalog_use').ifNotExists().addColumn('owner_did', t.text, (col)=>col.notNull()).addColumn('catalog_id', t.text, (col)=>col.notNull()).addColumn('name', t.text, (col)=>col.notNull()).addColumn('rules', t.json, (col)=>col.notNull()).addColumn('level', t.text).addColumn('followed', 'integer', (col)=>col.notNull().defaultTo(0)).addPrimaryKeyConstraint('kubun_graph_catalog_use_pkey', [
|
|
66
|
+
'owner_did',
|
|
67
|
+
'catalog_id'
|
|
68
|
+
]).execute();
|
|
69
|
+
await db.schema.createTable('kubun_graph_scope_identity').ifNotExists().addColumn('id', 'integer', (col)=>col.primaryKey()).addColumn('reader_did', t.text, (col)=>col.notNull()).addColumn('default_read_level', t.text, (col)=>col.notNull()).execute();
|
|
70
|
+
await db.schema.createTable('kubun_graph_catalog_scope_tick').ifNotExists().addColumn('id', 'integer', (col)=>col.primaryKey()).addColumn('last_at', t.bigint, (col)=>col.notNull()).execute();
|
|
71
|
+
await db.schema.createTable('kubun_graph_scope_changes').ifNotExists().addColumn('document_id', t.text, (col)=>col.primaryKey()).addColumn('version', 'integer', (col)=>col.notNull()).execute();
|
|
72
|
+
await db.schema.createTable('kubun_graph_document_refs').ifNotExists().addColumn('document_id', t.text, (col)=>col.notNull()).addColumn('ref', t.text, (col)=>col.notNull()).addColumn('displays', 'integer', (col)=>col.notNull()).addColumn('retains', 'integer', (col)=>col.notNull()).addPrimaryKeyConstraint('kubun_graph_document_refs_pkey', [
|
|
73
|
+
'document_id',
|
|
74
|
+
'ref'
|
|
75
|
+
]).execute();
|
|
76
|
+
await db.schema.createTable('kubun_graph_gc_marks').ifNotExists().addColumn('document_id', t.text, (col)=>col.primaryKey()).addColumn('digest', t.text, (col)=>col.notNull()).addColumn('marked_at', t.bigint, (col)=>col.notNull()).execute();
|
|
77
|
+
await db.schema.createTable('kubun_graph_custody_scans').ifNotExists().addColumn('owner_did', t.text, (col)=>col.notNull()).addColumn('catalog_id', t.text, (col)=>col.notNull()).addColumn('after_document_id', t.text).addPrimaryKeyConstraint('kubun_graph_custody_scans_pkey', [
|
|
78
|
+
'owner_did',
|
|
79
|
+
'catalog_id'
|
|
80
|
+
]).execute();
|
|
81
|
+
await db.schema.createTable('kubun_graph_custody_nonces').ifNotExists().addColumn('nonce', t.text, (col)=>col.primaryKey()).addColumn('custodian', t.text, (col)=>col.notNull()).addColumn('assignment_digest', t.text, (col)=>col.notNull()).addColumn('expires_at', t.bigint, (col)=>col.notNull()).execute();
|
|
82
|
+
await db.schema.createTable('kubun_graph_custody_receipts').ifNotExists().addColumn('document_id', t.text, (col)=>col.notNull()).addColumn('custodian', t.text, (col)=>col.notNull()).addColumn('group_id', t.text, (col)=>col.notNull()).addColumn('custody_owner', t.text, (col)=>col.notNull()).addColumn('catalog_owner', t.text, (col)=>col.notNull()).addColumn('catalog_id', t.text, (col)=>col.notNull()).addColumn('assignment_digest', t.text, (col)=>col.notNull()).addColumn('head_digest', t.text, (col)=>col.notNull()).addColumn('mutation_digest', t.text, (col)=>col.notNull()).addColumn('received_at', t.bigint, (col)=>col.notNull()).addPrimaryKeyConstraint('kubun_graph_custody_receipts_pkey', [
|
|
83
|
+
'document_id',
|
|
84
|
+
'custodian'
|
|
85
|
+
]).execute();
|
|
86
|
+
await db.schema.createTable('kubun_graph_document_holds').ifNotExists().addColumn('hold_id', t.text, (col)=>col.primaryKey()).addColumn('document_id', t.text, (col)=>col.notNull()).addColumn('created_by', t.text, (col)=>col.notNull()).addColumn('reason', t.text).addColumn('expires_at', t.bigint).addColumn('released_at', t.bigint).execute();
|
|
87
|
+
await db.schema.createIndex('idx_graph_document_holds_document').ifNotExists().on('kubun_graph_document_holds').column('document_id').execute();
|
|
88
|
+
// Aging finds the holds that expired since its last tick.
|
|
89
|
+
await db.schema.createIndex('idx_graph_document_holds_expires_at').ifNotExists().on('kubun_graph_document_holds').column('expires_at').execute();
|
|
90
|
+
await db.schema.createTable('kubun_graph_document_scope_dates').ifNotExists().addColumn('document_id', t.text, (col)=>col.notNull()).addColumn('field', t.text, (col)=>col.notNull()).addColumn('scope_date', t.bigint, (col)=>col.notNull()).addPrimaryKeyConstraint('kubun_graph_document_scope_dates_pkey', [
|
|
91
|
+
'document_id',
|
|
92
|
+
'field'
|
|
93
|
+
]).execute();
|
|
94
|
+
// Documents this device swept: what a ref recompute reads of each, so a rule matching it
|
|
95
|
+
// again can be told apart from a document never received. Local only.
|
|
96
|
+
await db.schema.createTable('kubun_graph_swept_documents').ifNotExists().addColumn('document_id', t.text, (col)=>col.primaryKey()).addColumn('model_id', t.text, (col)=>col.notNull()).addColumn('owner', t.text, (col)=>col.notNull()).addColumn('created_at', t.bigint, (col)=>col.notNull()).addColumn('scope_date', t.bigint).addColumn('field_dates', t.text, (col)=>col.notNull()).addColumn('read_access', t.text).addColumn('mutation_digest', t.text, (col)=>col.notNull()).addColumn('swept_at', t.bigint, (col)=>col.notNull()).addColumn('in_scope', 'integer', (col)=>col.notNull()).addColumn('scope_left_at', t.bigint, (col)=>col.notNull()).execute();
|
|
97
|
+
await db.schema.createIndex('idx_graph_swept_documents_model').ifNotExists().on('kubun_graph_swept_documents').column('model_id').execute();
|
|
98
|
+
await db.schema.createIndex('idx_graph_document_scope_dates_window').ifNotExists().on('kubun_graph_document_scope_dates').columns([
|
|
99
|
+
'field',
|
|
100
|
+
'scope_date'
|
|
101
|
+
]).execute();
|
|
102
|
+
// Catalog holder lookups are bytewise prefix ranges. On Postgres they
|
|
103
|
+
// compare `ref collate "C"`, which an index under a linguistic database
|
|
104
|
+
// collation cannot serve; SQLite compares bytewise already.
|
|
105
|
+
const refIndex = db.schema.createIndex('idx_graph_document_refs_ref').ifNotExists().on('kubun_graph_document_refs');
|
|
106
|
+
await (ctx.dialect === 'postgres' ? refIndex.expression(sql`ref collate "C"`) : refIndex.column('ref')).execute();
|
|
55
107
|
// Cluster models (model -> cluster mapping)
|
|
56
108
|
await db.schema.createTable('kubun_graph_cluster_models').ifNotExists().addColumn('model_id', t.text, (col)=>col.notNull().primaryKey()).addColumn('cluster_id', t.text, (col)=>col.notNull()).addColumn('cluster_index', 'integer', (col)=>col.notNull()).execute();
|
|
57
109
|
await db.schema.createIndex('idx_graph_cluster_models_cluster').ifNotExists().on('kubun_graph_cluster_models').column('cluster_id').execute();
|
|
58
110
|
// Cluster definitions
|
|
59
111
|
await db.schema.createTable('kubun_graph_clusters').ifNotExists().addColumn('id', t.text, (col)=>col.notNull().primaryKey()).addColumn('definition', t.json, (col)=>col.notNull()).execute();
|
|
112
|
+
await db.schema.createTable('kubun_graph_access_default_records').ifNotExists().addColumn('type', t.text, (col)=>col.notNull()).addColumn('owner', t.text, (col)=>col.notNull()).addColumn('id', t.text, (col)=>col.notNull()).addColumn('op_hash', t.text, (col)=>col.notNull()).addColumn('hlc', t.text, (col)=>col.notNull()).addColumn('op_jwt', t.text, (col)=>col.notNull()).addColumn('payload', t.binary).addPrimaryKeyConstraint('kubun_graph_access_default_records_pkey', [
|
|
113
|
+
'type',
|
|
114
|
+
'owner',
|
|
115
|
+
'id'
|
|
116
|
+
]).execute();
|
|
117
|
+
await db.schema.createTable('kubun_graph_catalog_drafts').ifNotExists().addColumn('catalog_id', t.text, (col)=>col.primaryKey()).addColumn('state', t.text, (col)=>col.notNull()).execute();
|
|
118
|
+
await db.schema.createTable('kubun_graph_catalog_publications').ifNotExists().addColumn('catalog_id', t.text, (col)=>col.notNull()).addColumn('version_id', t.text, (col)=>col.notNull()).addPrimaryKeyConstraint('kubun_graph_catalog_publications_pkey', [
|
|
119
|
+
'catalog_id',
|
|
120
|
+
'version_id'
|
|
121
|
+
]).execute();
|
|
122
|
+
await db.schema.createTable('kubun_graph_catalog_recipient_versions').ifNotExists().addColumn('catalog_id', t.text, (col)=>col.notNull()).addColumn('version_id', t.text, (col)=>col.notNull()).addColumn('signed_record', t.text, (col)=>col.notNull()).addPrimaryKeyConstraint('kubun_graph_catalog_recipient_versions_pkey', [
|
|
123
|
+
'catalog_id',
|
|
124
|
+
'version_id'
|
|
125
|
+
]).execute();
|
|
126
|
+
await db.schema.createTable('kubun_graph_catalog_pending_heads').ifNotExists().addColumn('catalog_id', t.text, (col)=>col.primaryKey()).addColumn('head_version_id', t.text, (col)=>col.notNull()).addColumn('group_id', t.text).addColumn('retry_at', t.bigint, (col)=>col.notNull()).addColumn('attempts', 'integer', (col)=>col.notNull()).execute();
|
|
127
|
+
await db.schema.createTable('kubun_graph_catalog_admitted_heads').ifNotExists().addColumn('catalog_id', t.text, (col)=>col.primaryKey()).addColumn('signed_record', t.text, (col)=>col.notNull()).execute();
|
|
60
128
|
// Catalogs
|
|
61
|
-
await db.schema.createTable('
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
129
|
+
await db.schema.createTable('kubun_graph_catalog_records').ifNotExists().addColumn('type', t.text, (col)=>col.notNull()).addColumn('owner', t.text, (col)=>col.notNull()).addColumn('id', t.text, (col)=>col.notNull()).addColumn('op_hash', t.text, (col)=>col.notNull()).addColumn('hlc', t.text, (col)=>col.notNull()).addColumn('op_jwt', t.text, (col)=>col.notNull()).addColumn('payload', t.binary).addColumn('catalog_id', t.text).addColumn('group_id', t.text).addColumn('circle_id', t.text).addPrimaryKeyConstraint('kubun_graph_catalog_records_pkey', [
|
|
130
|
+
'type',
|
|
131
|
+
'owner',
|
|
132
|
+
'id',
|
|
133
|
+
'op_hash'
|
|
134
|
+
]).execute();
|
|
135
|
+
await db.schema.createIndex('idx_graph_catalog_record_group').ifNotExists().on('kubun_graph_catalog_records').columns([
|
|
136
|
+
'group_id',
|
|
137
|
+
'catalog_id',
|
|
138
|
+
'circle_id'
|
|
139
|
+
]).execute();
|
|
66
140
|
// `.ifNotExists()` protects a half-created table from being recreated —
|
|
67
141
|
// and, because this migration was edited in place, it equally protects a
|
|
68
142
|
// table an EARLIER run created from ever acquiring the columns that edit
|
|
@@ -85,11 +159,30 @@
|
|
|
85
159
|
}
|
|
86
160
|
},
|
|
87
161
|
async down (db) {
|
|
162
|
+
await db.schema.dropTable('kubun_graph_catalog_drafts').ifExists().execute();
|
|
163
|
+
await db.schema.dropTable('kubun_graph_catalog_publications').ifExists().execute();
|
|
164
|
+
await db.schema.dropTable('kubun_graph_catalog_recipient_versions').ifExists().execute();
|
|
165
|
+
await db.schema.dropTable('kubun_graph_catalog_pending_heads').ifExists().execute();
|
|
166
|
+
await db.schema.dropTable('kubun_graph_catalog_admitted_heads').ifExists().execute();
|
|
167
|
+
await db.schema.dropTable('kubun_graph_access_default_records').ifExists().execute();
|
|
168
|
+
await db.schema.dropTable('kubun_graph_catalog_records').ifExists().execute();
|
|
169
|
+
await db.schema.dropTable('kubun_graph_scope_changes').ifExists().execute();
|
|
170
|
+
await db.schema.dropTable('kubun_graph_catalog_scope_tick').ifExists().execute();
|
|
171
|
+
await db.schema.dropTable('kubun_graph_scope_identity').ifExists().execute();
|
|
172
|
+
await db.schema.dropTable('kubun_graph_document_scope_dates').ifExists().execute();
|
|
173
|
+
await db.schema.dropTable('kubun_graph_swept_documents').ifExists().execute();
|
|
174
|
+
await db.schema.dropTable('kubun_graph_gc_marks').ifExists().execute();
|
|
175
|
+
await db.schema.dropTable('kubun_graph_custody_scans').ifExists().execute();
|
|
176
|
+
await db.schema.dropTable('kubun_graph_custody_nonces').ifExists().execute();
|
|
177
|
+
await db.schema.dropTable('kubun_graph_custody_receipts').ifExists().execute();
|
|
178
|
+
await db.schema.dropTable('kubun_graph_document_holds').ifExists().execute();
|
|
179
|
+
await db.schema.dropTable('kubun_graph_document_refs').ifExists().execute();
|
|
180
|
+
await db.schema.dropTable('kubun_graph_catalog_use').ifExists().execute();
|
|
88
181
|
await db.schema.dropTable('kubun_graph_search_models').ifExists().execute();
|
|
89
|
-
await db.schema.dropTable('kubun_graph_catalogs').ifExists().execute();
|
|
90
182
|
await db.schema.dropTable('kubun_graph_clusters').ifExists().execute();
|
|
91
183
|
await db.schema.dropTable('kubun_graph_cluster_models').ifExists().execute();
|
|
92
184
|
await db.schema.dropTable('kubun_graph_mutation_log').ifExists().execute();
|
|
185
|
+
await db.schema.dropTable('kubun_graph_pending_groups').ifExists().execute();
|
|
93
186
|
await db.schema.dropTable('kubun_graph_user_model_access_defaults').ifExists().execute();
|
|
94
187
|
await db.schema.dropTable('kubun_graph_document_model_links').ifExists().execute();
|
|
95
188
|
await db.schema.dropTable('kubun_graph_models').ifExists().execute();
|
package/lib/query-builder.js
CHANGED
|
@@ -315,7 +315,7 @@ export function applyValueFilter(eb, keys, filter, adapter, coerce) {
|
|
|
315
315
|
const items = [
|
|
316
316
|
...new Set(value)
|
|
317
317
|
];
|
|
318
|
-
// Vacuously true
|
|
318
|
+
// Vacuously true: every array includes the empty set. Handled here, not in
|
|
319
319
|
// SQL, so the adapter seam never sees an empty IN-list.
|
|
320
320
|
return items.length === 0 ? sql`1 = 1` : adapter.arrayIncludesAllPredicate(getRawKeyPath(eb, keys), items);
|
|
321
321
|
}
|
package/lib/tables.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CreatedAtColumn, UpdatedAtColumn } from '@kubun/db-adapter';
|
|
2
2
|
import type { DocumentID } from '@kubun/id';
|
|
3
|
-
import type {
|
|
4
|
-
import type { ColumnType, Insertable, Selectable, Updateable } from 'kysely';
|
|
3
|
+
import type { AccessLevel, DocumentFieldsMeta, DocumentFilter, DocumentModel, DocumentModelSchema, DocumentModelsRecord, DocumentNode, DocumentOrderBy } from '@kubun/protocol';
|
|
4
|
+
import type { ColumnType, Generated, Insertable, Selectable, Updateable } from 'kysely';
|
|
5
5
|
type JSONValueColumn<T> = ColumnType<T, T, T>;
|
|
6
6
|
export type DocumentData = Record<string, unknown>;
|
|
7
7
|
export type DocumentTable<Data extends DocumentData = DocumentData> = {
|
|
@@ -14,6 +14,9 @@ export type DocumentTable<Data extends DocumentData = DocumentData> = {
|
|
|
14
14
|
unique: Uint8Array;
|
|
15
15
|
created_at: CreatedAtColumn;
|
|
16
16
|
updated_at: UpdatedAtColumn;
|
|
17
|
+
mutation_created_at: ColumnType<number | null, number | null | undefined, number | null>;
|
|
18
|
+
mutation_updated_at: ColumnType<number | null, number | null | undefined, number | null>;
|
|
19
|
+
scope_date: ColumnType<number | null, number | null | undefined, number | null>;
|
|
17
20
|
};
|
|
18
21
|
export type Document<Data extends DocumentData = DocumentData> = Selectable<DocumentTable<Data>>;
|
|
19
22
|
export type InsertDocument<Data extends DocumentData = DocumentData> = Insertable<DocumentTable<Data>>;
|
|
@@ -27,6 +30,11 @@ export type DocumentModelTable = {
|
|
|
27
30
|
interfaces: JSONValueColumn<Array<string>>;
|
|
28
31
|
schema: JSONValueColumn<DocumentModelSchema>;
|
|
29
32
|
fields_meta: JSONValueColumn<DocumentFieldsMeta>;
|
|
33
|
+
provider_merge_policy: JSONValueColumn<{
|
|
34
|
+
group: Array<string>;
|
|
35
|
+
}> | null;
|
|
36
|
+
date_field: ColumnType<string | null, string | null | undefined, string | null>;
|
|
37
|
+
resolved_date_field: ColumnType<string | null, string | null | undefined, string | null>;
|
|
30
38
|
created_at: CreatedAtColumn;
|
|
31
39
|
updated_at: UpdatedAtColumn;
|
|
32
40
|
};
|
|
@@ -71,13 +79,139 @@ export type MutationLogTable = {
|
|
|
71
79
|
mutation_hash: string;
|
|
72
80
|
model_id: string;
|
|
73
81
|
document_id: string;
|
|
82
|
+
/** Unverified signed issuer, informational only. Caps and authorisation use sender_peer_did. */
|
|
74
83
|
author_did: string;
|
|
75
84
|
hlc: string;
|
|
76
85
|
mutation_jwt: string;
|
|
86
|
+
arrival_group_id: ColumnType<string | null, string | null | undefined, string | null>;
|
|
87
|
+
sender_peer_did: ColumnType<string | null, string | null | undefined, string | null>;
|
|
88
|
+
parked_at: ColumnType<number | null, number | null | undefined, number | null>;
|
|
77
89
|
status: string;
|
|
90
|
+
attempt_count: Generated<number>;
|
|
91
|
+
last_attempt_at: ColumnType<number | null, number | null | undefined, number | null>;
|
|
92
|
+
next_attempt_at: ColumnType<number | null, number | null | undefined, number | null>;
|
|
78
93
|
};
|
|
79
94
|
export type MutationLogEntry = Selectable<MutationLogTable>;
|
|
80
95
|
export type InsertMutationLogEntry = Insertable<MutationLogTable>;
|
|
96
|
+
/**
|
|
97
|
+
* One concrete rule as a document-leaf page selects by it: a model, the owners
|
|
98
|
+
* (null: any owner), and an optional window `[from, to)` over a date field.
|
|
99
|
+
*/
|
|
100
|
+
export type DocumentLeafRule = {
|
|
101
|
+
modelID: string;
|
|
102
|
+
owners: ReadonlyArray<string> | null;
|
|
103
|
+
dateField: string | null;
|
|
104
|
+
from: number | null;
|
|
105
|
+
to: number | null;
|
|
106
|
+
};
|
|
107
|
+
export type DocumentLeafPageParams = {
|
|
108
|
+
groupRead?: {
|
|
109
|
+
groupID: string;
|
|
110
|
+
circleIDs: Array<string>;
|
|
111
|
+
};
|
|
112
|
+
rules: ReadonlyArray<DocumentLeafRule>;
|
|
113
|
+
/** Exclusive lower document key; null starts at the first key. */
|
|
114
|
+
after: string | null;
|
|
115
|
+
/** Inclusive upper document key; null reads to the last key. */
|
|
116
|
+
through?: string | null;
|
|
117
|
+
limit: number;
|
|
118
|
+
};
|
|
119
|
+
/** A stored document matching a rule, with the IDs of its applied mutations, sorted. */
|
|
120
|
+
export type DocumentLeafRow = {
|
|
121
|
+
documentID: string;
|
|
122
|
+
owner: string;
|
|
123
|
+
/** The document was created on this device rather than received. */
|
|
124
|
+
authoredHere: boolean;
|
|
125
|
+
acceptedMutationIDs: Array<string>;
|
|
126
|
+
};
|
|
127
|
+
export type CatalogUseTable = {
|
|
128
|
+
owner_did: string;
|
|
129
|
+
catalog_id: string;
|
|
130
|
+
name: string;
|
|
131
|
+
rules: JSONValueColumn<Array<{
|
|
132
|
+
id: string;
|
|
133
|
+
models?: Array<string>;
|
|
134
|
+
owners?: Array<string>;
|
|
135
|
+
maxAge?: string;
|
|
136
|
+
maxAhead?: string;
|
|
137
|
+
dateField?: string;
|
|
138
|
+
}>>;
|
|
139
|
+
level: 'KNOWN' | 'OFFLINE' | 'SERVE_ONLY' | null;
|
|
140
|
+
followed: number;
|
|
141
|
+
};
|
|
142
|
+
export type DocumentRefTable = {
|
|
143
|
+
document_id: string;
|
|
144
|
+
ref: string;
|
|
145
|
+
displays: number;
|
|
146
|
+
retains: number;
|
|
147
|
+
};
|
|
148
|
+
export type CustodyScanTable = {
|
|
149
|
+
owner_did: string;
|
|
150
|
+
catalog_id: string;
|
|
151
|
+
after_document_id: string | null;
|
|
152
|
+
};
|
|
153
|
+
export type GCMarkTable = {
|
|
154
|
+
document_id: string;
|
|
155
|
+
digest: string;
|
|
156
|
+
marked_at: number;
|
|
157
|
+
};
|
|
158
|
+
export type CustodyNonceTable = {
|
|
159
|
+
nonce: string;
|
|
160
|
+
custodian: string;
|
|
161
|
+
assignment_digest: string;
|
|
162
|
+
expires_at: number;
|
|
163
|
+
};
|
|
164
|
+
export type CustodyReceiptTable = {
|
|
165
|
+
document_id: string;
|
|
166
|
+
custodian: string;
|
|
167
|
+
group_id: string;
|
|
168
|
+
custody_owner: string;
|
|
169
|
+
catalog_owner: string;
|
|
170
|
+
catalog_id: string;
|
|
171
|
+
assignment_digest: string;
|
|
172
|
+
head_digest: string;
|
|
173
|
+
mutation_digest: string;
|
|
174
|
+
received_at: number;
|
|
175
|
+
};
|
|
176
|
+
export type DocumentHoldTable = {
|
|
177
|
+
hold_id: string;
|
|
178
|
+
document_id: string;
|
|
179
|
+
created_by: string;
|
|
180
|
+
reason: string | null;
|
|
181
|
+
expires_at: number | null;
|
|
182
|
+
released_at: number | null;
|
|
183
|
+
};
|
|
184
|
+
export type DocumentScopeDateTable = {
|
|
185
|
+
document_id: string;
|
|
186
|
+
field: string;
|
|
187
|
+
scope_date: number;
|
|
188
|
+
};
|
|
189
|
+
export type SweptDocumentTable = {
|
|
190
|
+
document_id: string;
|
|
191
|
+
model_id: string;
|
|
192
|
+
owner: string;
|
|
193
|
+
created_at: number;
|
|
194
|
+
scope_date: number | null;
|
|
195
|
+
field_dates: string;
|
|
196
|
+
read_access: string | null;
|
|
197
|
+
mutation_digest: string;
|
|
198
|
+
swept_at: number;
|
|
199
|
+
in_scope: number;
|
|
200
|
+
scope_left_at: number;
|
|
201
|
+
};
|
|
202
|
+
export type ScopeIdentityTable = {
|
|
203
|
+
id: number;
|
|
204
|
+
reader_did: string;
|
|
205
|
+
default_read_level: AccessLevel;
|
|
206
|
+
};
|
|
207
|
+
export type CatalogScopeTickTable = {
|
|
208
|
+
id: number;
|
|
209
|
+
last_at: number;
|
|
210
|
+
};
|
|
211
|
+
export type CatalogScopeChangeTable = {
|
|
212
|
+
document_id: string;
|
|
213
|
+
version: number;
|
|
214
|
+
};
|
|
81
215
|
export type ClusterModelTable = {
|
|
82
216
|
model_id: string;
|
|
83
217
|
cluster_id: string;
|
|
@@ -108,45 +242,58 @@ export type UserModelAccessDefaultTable = {
|
|
|
108
242
|
export type UserModelAccessDefault = Selectable<UserModelAccessDefaultTable>;
|
|
109
243
|
export type InsertUserModelAccessDefault = Insertable<UserModelAccessDefaultTable>;
|
|
110
244
|
export type UpdateUserModelAccessDefault = Updateable<UserModelAccessDefaultTable>;
|
|
111
|
-
export type
|
|
245
|
+
export type GraphCatalogRecordTable = {
|
|
246
|
+
type: string;
|
|
247
|
+
owner: string;
|
|
112
248
|
id: string;
|
|
113
|
-
|
|
114
|
-
name: string;
|
|
115
|
-
description: string;
|
|
116
|
-
filter_criteria: JSONValueColumn<CatalogFilterCriteria>;
|
|
249
|
+
op_hash: string;
|
|
117
250
|
hlc: string;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
active: ColumnType<number | null, number | null | undefined, number | null>;
|
|
124
|
-
/**
|
|
125
|
-
* Provenance: the group this catalog was first discovered from, null for own
|
|
126
|
-
* catalogs. First-discovery only — never overwritten on re-discovery.
|
|
127
|
-
*/
|
|
128
|
-
source_group_id: ColumnType<string | null, string | null | undefined, string | null>;
|
|
129
|
-
/**
|
|
130
|
-
* Provenance: the circle whose `catalog_ids` first referenced this catalog
|
|
131
|
-
* (set only for invite-seeded discovery), null otherwise. First-discovery only.
|
|
132
|
-
*/
|
|
133
|
-
source_circle_id: ColumnType<string | null, string | null | undefined, string | null>;
|
|
134
|
-
/**
|
|
135
|
-
* The creator-signed `catalog:set` token that authenticated this catalog: own
|
|
136
|
-
* catalogs sign it at creation, discovered ones store the verified token that
|
|
137
|
-
* delivered them. Forwarded verbatim in invite seeds so a joiner re-verifies
|
|
138
|
-
* creator-binding (`ownerDID === iss`) with the same helper the broadcast
|
|
139
|
-
* receive path uses. Null for rows that predate token capture.
|
|
140
|
-
*/
|
|
141
|
-
signed_token: ColumnType<string | null, string | null | undefined, string | null>;
|
|
142
|
-
created_at: CreatedAtColumn;
|
|
143
|
-
updated_at: UpdatedAtColumn;
|
|
251
|
+
op_jwt: string;
|
|
252
|
+
payload: Uint8Array | null;
|
|
253
|
+
catalog_id: string | null;
|
|
254
|
+
group_id: string | null;
|
|
255
|
+
circle_id: string | null;
|
|
144
256
|
};
|
|
145
|
-
export type
|
|
146
|
-
export type InsertCatalog = Insertable<CatalogTable>;
|
|
147
|
-
export type UpdateCatalog = Updateable<CatalogTable>;
|
|
257
|
+
export type GraphCatalogRecordRow = Selectable<GraphCatalogRecordTable>;
|
|
148
258
|
export type GraphTables = {
|
|
149
|
-
|
|
259
|
+
kubun_graph_catalog_admitted_heads: {
|
|
260
|
+
catalog_id: string;
|
|
261
|
+
signed_record: string;
|
|
262
|
+
};
|
|
263
|
+
kubun_graph_catalog_drafts: {
|
|
264
|
+
catalog_id: string;
|
|
265
|
+
state: string;
|
|
266
|
+
};
|
|
267
|
+
kubun_graph_catalog_publications: {
|
|
268
|
+
catalog_id: string;
|
|
269
|
+
version_id: string;
|
|
270
|
+
};
|
|
271
|
+
kubun_graph_catalog_recipient_versions: {
|
|
272
|
+
catalog_id: string;
|
|
273
|
+
version_id: string;
|
|
274
|
+
signed_record: string;
|
|
275
|
+
};
|
|
276
|
+
kubun_graph_catalog_pending_heads: {
|
|
277
|
+
catalog_id: string;
|
|
278
|
+
head_version_id: string;
|
|
279
|
+
group_id: string | null;
|
|
280
|
+
retry_at: number;
|
|
281
|
+
attempts: number;
|
|
282
|
+
};
|
|
283
|
+
kubun_graph_access_default_records: Omit<GraphCatalogRecordTable, 'catalog_id' | 'group_id' | 'circle_id'>;
|
|
284
|
+
kubun_graph_catalog_records: GraphCatalogRecordTable;
|
|
285
|
+
kubun_graph_scope_changes: CatalogScopeChangeTable;
|
|
286
|
+
kubun_graph_catalog_scope_tick: CatalogScopeTickTable;
|
|
287
|
+
kubun_graph_scope_identity: ScopeIdentityTable;
|
|
288
|
+
kubun_graph_catalog_use: CatalogUseTable;
|
|
289
|
+
kubun_graph_document_refs: DocumentRefTable;
|
|
290
|
+
kubun_graph_document_holds: DocumentHoldTable;
|
|
291
|
+
kubun_graph_gc_marks: GCMarkTable;
|
|
292
|
+
kubun_graph_custody_scans: CustodyScanTable;
|
|
293
|
+
kubun_graph_custody_nonces: CustodyNonceTable;
|
|
294
|
+
kubun_graph_custody_receipts: CustodyReceiptTable;
|
|
295
|
+
kubun_graph_document_scope_dates: DocumentScopeDateTable;
|
|
296
|
+
kubun_graph_swept_documents: SweptDocumentTable;
|
|
150
297
|
kubun_graph_cluster_models: ClusterModelTable;
|
|
151
298
|
kubun_graph_clusters: ClusterDefinitionTable;
|
|
152
299
|
kubun_graph_document_models: DocumentModelTable;
|
|
@@ -154,6 +301,9 @@ export type GraphTables = {
|
|
|
154
301
|
kubun_graph_document_model_links: GraphDocumentModelTable;
|
|
155
302
|
kubun_graph_models: GraphModelTable;
|
|
156
303
|
kubun_graph_mutation_log: MutationLogTable;
|
|
304
|
+
kubun_graph_pending_groups: {
|
|
305
|
+
group_id: string;
|
|
306
|
+
};
|
|
157
307
|
kubun_graph_search_models: SearchModelTable;
|
|
158
308
|
kubun_graph_user_model_access_defaults: UserModelAccessDefaultTable;
|
|
159
309
|
[key: `k_${string}`]: DocumentTable;
|
|
@@ -165,6 +315,7 @@ export type DocumentParams = {
|
|
|
165
315
|
export type CreateDocumentParams = DocumentParams & {
|
|
166
316
|
owner: string;
|
|
167
317
|
unique: Uint8Array;
|
|
318
|
+
authoredHere?: boolean;
|
|
168
319
|
};
|
|
169
320
|
export type SaveDocumentParams = DocumentParams & {
|
|
170
321
|
existing: DocumentNode;
|
|
@@ -195,7 +346,7 @@ export type CreateGraphParams = {
|
|
|
195
346
|
export type AddDocumentModelParams = {
|
|
196
347
|
id: string;
|
|
197
348
|
graphModelID: string;
|
|
198
|
-
model:
|
|
349
|
+
model: DocumentModel;
|
|
199
350
|
};
|
|
200
351
|
export type GraphModelWithRecord = GraphModel & {
|
|
201
352
|
record: DocumentModelsRecord;
|
|
@@ -215,7 +366,10 @@ export type QueryDocumentsParams = ConnectionArguments & {
|
|
|
215
366
|
filter?: DocumentFilter;
|
|
216
367
|
orderBy?: DocumentOrderBy;
|
|
217
368
|
owner?: string;
|
|
218
|
-
|
|
369
|
+
catalogRef?: {
|
|
370
|
+
owner: string;
|
|
371
|
+
id: string;
|
|
372
|
+
};
|
|
219
373
|
};
|
|
220
374
|
export type CursorDocument = {
|
|
221
375
|
cursor: string;
|
|
@@ -238,6 +392,10 @@ export type SearchDocumentsParams = {
|
|
|
238
392
|
modelIDs: Array<string>;
|
|
239
393
|
first?: number;
|
|
240
394
|
offset?: number;
|
|
395
|
+
catalogRef?: {
|
|
396
|
+
owner: string;
|
|
397
|
+
id: string;
|
|
398
|
+
};
|
|
241
399
|
};
|
|
242
400
|
export type SearchDocumentResult = {
|
|
243
401
|
documentID: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubun/store-graph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"keywords": [],
|
|
5
5
|
"license": "see LICENSE.md",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -15,17 +15,21 @@
|
|
|
15
15
|
"LICENSE.md"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@
|
|
19
|
-
"@kubun/db
|
|
20
|
-
"@kubun/
|
|
21
|
-
"@kubun/
|
|
22
|
-
"@
|
|
23
|
-
"
|
|
18
|
+
"@kokuin/token": "^0.5.1",
|
|
19
|
+
"@kubun/db": "^0.18.0",
|
|
20
|
+
"@kubun/db-adapter": "^0.18.0",
|
|
21
|
+
"@kubun/id": "^0.18.0",
|
|
22
|
+
"@kubun/mutation": "^0.18.0",
|
|
23
|
+
"@kubun/protocol": "^0.18.0",
|
|
24
|
+
"@kubun/records": "^0.18.0",
|
|
25
|
+
"@noble/hashes": "^2.4.0",
|
|
26
|
+
"@sozai/codec": "^0.4.3",
|
|
27
|
+
"kysely": "^0.29.7"
|
|
24
28
|
},
|
|
25
29
|
"devDependencies": {
|
|
26
|
-
"@kubun/db-better-sqlite": "^0.
|
|
27
|
-
"@kubun/db-postgres": "^0.
|
|
28
|
-
"@testcontainers/postgresql": "^12.1
|
|
30
|
+
"@kubun/db-better-sqlite": "^0.18.0",
|
|
31
|
+
"@kubun/db-postgres": "^0.18.0",
|
|
32
|
+
"@testcontainers/postgresql": "^12.2.1"
|
|
29
33
|
},
|
|
30
34
|
"publishConfig": {
|
|
31
35
|
"access": "public"
|