@xnetjs/data 0.0.2 → 0.1.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/README.md +112 -0
- package/dist/account-MWNCH4GJ.js +12 -0
- package/dist/account-ledger-R2GAFJL6.js +38 -0
- package/dist/auth/index.d.ts +420 -0
- package/dist/auth/index.js +102 -0
- package/dist/budget-NN7P35XP.js +12 -0
- package/dist/canvas-6WYBNH53.js +10 -0
- package/dist/channel-AT3LQF4A.js +12 -0
- package/dist/chat-message-DSVO72B3.js +10 -0
- package/dist/chunk-2ZNJWIQG.js +84 -0
- package/dist/chunk-3J3HILXO.js +46 -0
- package/dist/chunk-3RUDVTMH.js +5543 -0
- package/dist/chunk-4EYKGTSQ.js +49 -0
- package/dist/chunk-53F4PRNC.js +32 -0
- package/dist/chunk-5EXHNXPL.js +48 -0
- package/dist/{chunk-BQBPA5HS.js → chunk-5HC5NO57.js} +16 -2
- package/dist/chunk-6KLGA6IR.js +47 -0
- package/dist/chunk-6OMG4I7M.js +41 -0
- package/dist/chunk-7PDRDSFH.js +69 -0
- package/dist/chunk-BQLQSWKZ.js +232 -0
- package/dist/chunk-BY5O6LNC.js +380 -0
- package/dist/chunk-DCTRX6II.js +40 -0
- package/dist/{chunk-VYR5GPJP.js → chunk-DWEXKD6E.js} +9 -3
- package/dist/chunk-EBNMV2VO.js +896 -0
- package/dist/chunk-FVEACSKE.js +102 -0
- package/dist/chunk-GU6THOAB.js +45 -0
- package/dist/chunk-H4GA4BBK.js +75 -0
- package/dist/chunk-IJ44LR7N.js +76 -0
- package/dist/chunk-J4ANIXIV.js +402 -0
- package/dist/chunk-JDFNMFOZ.js +45 -0
- package/dist/chunk-K7DOZWWT.js +1811 -0
- package/dist/chunk-KQAT4XBL.js +49 -0
- package/dist/chunk-KQUALW4O.js +183 -0
- package/dist/chunk-LYSWLCOI.js +47 -0
- package/dist/chunk-MBTUO3ZL.js +65 -0
- package/dist/chunk-NI4FHG2K.js +52 -0
- package/dist/chunk-OCMSAKWV.js +78 -0
- package/dist/chunk-OGJCRNGE.js +57 -0
- package/dist/chunk-OPPHF3TF.js +143 -0
- package/dist/{chunk-IDMBCRUC.js → chunk-OSAWNZVM.js} +1 -1
- package/dist/chunk-PMUQACPY.js +33 -0
- package/dist/chunk-PNESGUH5.js +63 -0
- package/dist/chunk-Q3IEGH4B.js +51 -0
- package/dist/chunk-QJW5LDP4.js +52 -0
- package/dist/chunk-QWFTRZQT.js +142 -0
- package/dist/{chunk-SZC345Z2.js → chunk-RL64OJJ5.js} +1025 -1110
- package/dist/chunk-S5RP5RKY.js +416 -0
- package/dist/chunk-S6U6TCMN.js +722 -0
- package/dist/chunk-SVNGSZZA.js +69 -0
- package/dist/chunk-T5AZAOG5.js +54 -0
- package/dist/chunk-TCTZW4A6.js +42 -0
- package/dist/chunk-U64CW73O.js +109 -0
- package/dist/chunk-UDWKWTAX.js +6526 -0
- package/dist/chunk-UQM3G5A2.js +148 -0
- package/dist/chunk-VQ7JHB67.js +57 -0
- package/dist/chunk-W7EBL7ZU.js +73 -0
- package/dist/chunk-WEPK7SZF.js +65 -0
- package/dist/chunk-XHEA5UER.js +75 -0
- package/dist/chunk-XMSKJ5PV.js +66 -0
- package/dist/chunk-XROI44ZP.js +64 -0
- package/dist/chunk-Y3S5SRVM.js +45 -0
- package/dist/chunk-YEFKQYKA.js +43 -0
- package/dist/chunk-YSUIXD2Y.js +105 -0
- package/dist/chunk-ZCOFZY5M.js +70 -0
- package/dist/chunk-ZLU4Y3O2.js +50 -0
- package/dist/chunk-ZPZ7XDA6.js +54 -0
- package/dist/chunk-ZZ6TWKGS.js +40 -0
- package/dist/clone-C0Jhk2UN.d.ts +2205 -0
- package/dist/comment-QSWYAQVS.js +10 -0
- package/dist/crm-L5RYAAF3.js +68 -0
- package/dist/dashboard-JMKTTRA7.js +10 -0
- package/dist/database/index.d.ts +882 -0
- package/dist/database/index.js +523 -0
- package/dist/database-GIXSPZJW.js +10 -0
- package/dist/database-field-3EPAMZUR.js +10 -0
- package/dist/database-row-6Q6TRVE4.js +10 -0
- package/dist/database-select-option-BBBJFLLH.js +10 -0
- package/dist/database-view-5PLSOBI2.js +10 -0
- package/dist/experiment-DOVOZ34Y.js +10 -0
- package/dist/external-item-P2E5X7BZ.js +14 -0
- package/dist/external-reference-7BSFF6SA.js +8 -0
- package/dist/feed-2IXHHP6O.js +12 -0
- package/dist/feed-item-DPE6LN7I.js +12 -0
- package/dist/folder-6KM3KYD5.js +21 -0
- package/dist/game-5AK5XWBR.js +50 -0
- package/dist/grant-WTQSNT5A.js +8 -0
- package/dist/grant-expiration-cleaner-CY6BcmlR.d.ts +249 -0
- package/dist/import-batch-IXBJLQPJ.js +12 -0
- package/dist/inbox-state-E5NSVOGP.js +12 -0
- package/dist/index.d.ts +224 -4548
- package/dist/index.js +2252 -4754
- package/dist/map-RG5Y3CPC.js +10 -0
- package/dist/media-asset-QTCGLIZA.js +8 -0
- package/dist/memory-PNRTMBZO.js +12 -0
- package/dist/metric-65SVOX5C.js +10 -0
- package/dist/milestone-XEO6ZGDG.js +12 -0
- package/dist/moderation-FFHETMRB.js +30 -0
- package/dist/observation-2Y3QKUXM.js +10 -0
- package/dist/page-2V27JGKJ.js +10 -0
- package/dist/posting-GBOSZCMZ.js +12 -0
- package/dist/profile-BLLDWIDK.js +8 -0
- package/dist/project-CQL5LN26.js +10 -0
- package/dist/query-ast-C3m6kZYv.d.ts +226 -0
- package/dist/reaction-T2DTJBBV.js +10 -0
- package/dist/registry-DunPv__d.d.ts +99 -0
- package/dist/saved-view-4R2DBCL3.js +10 -0
- package/dist/schema/index.d.ts +6489 -0
- package/dist/schema/index.js +677 -0
- package/dist/schema-extension-LNRF2YRD.js +18 -0
- package/dist/space-IJU24PBH.js +42 -0
- package/dist/space-membership-DEUMM7NV.js +14 -0
- package/dist/store/index.d.ts +518 -0
- package/dist/store/index.js +135 -0
- package/dist/store-DtIDjk7c.d.ts +355 -0
- package/dist/sync/awareness.d.ts +69 -0
- package/dist/sync/awareness.js +20 -0
- package/dist/system-ILHCZOVO.js +38 -0
- package/dist/tag-SKCHM3U5.js +16 -0
- package/dist/task-7AOBP7WC.js +16 -0
- package/dist/task-view-NUGKELJP.js +10 -0
- package/dist/transaction-ZDSEGDIR.js +12 -0
- package/dist/transcription-PSCLDAGX.js +12 -0
- package/dist/types-S-BJAKyK.d.ts +1576 -0
- package/dist/updates.d.ts +44 -0
- package/dist/updates.js +16 -0
- package/dist/user-widget-RLY2N46A.js +8 -0
- package/dist/view-types-DSde-uT_.d.ts +316 -0
- package/package.json +32 -9
- package/dist/canvas-HSIKIQFK.js +0 -7
- package/dist/chunk-2L5ZUGG5.js +0 -53
- package/dist/chunk-4MTS5KAQ.js +0 -22
- package/dist/chunk-GZHARFKC.js +0 -25
- package/dist/chunk-WKIKJTI2.js +0 -45
- package/dist/comment-277JD7DV.js +0 -7
- package/dist/database-W3KEHLI3.js +0 -7
- package/dist/database-row-3O2QSNZN.js +0 -7
- package/dist/grant-QVZ454YC.js +0 -7
- package/dist/page-O4WTOIEO.js +0 -7
- package/dist/task-SEKAYJH7.js +0 -7
|
@@ -0,0 +1,1576 @@
|
|
|
1
|
+
import { DID as DID$1, AuthAction, AuthDecision, AuthTrace, PolicyEvaluator, ContentId, SerializedAuthorization } from '@xnetjs/core';
|
|
2
|
+
import { PublicKeyResolver } from '@xnetjs/crypto';
|
|
3
|
+
import { SQLiteOperationStats } from '@xnetjs/sqlite';
|
|
4
|
+
import { Change, ChangeSigner } from '@xnetjs/sync';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Node - The universal container type for all data in xNet.
|
|
8
|
+
*
|
|
9
|
+
* A Node has only 4 universal fields. Everything else is defined by its schema.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Schema IRI - globally unique identifier for a schema.
|
|
13
|
+
* Format: xnet://<authority>/<name> or xnet://<authority>/<name>@<version>
|
|
14
|
+
*
|
|
15
|
+
* Examples:
|
|
16
|
+
* - xnet://xnet.fyi/Page (unversioned, treated as @1.0.0)
|
|
17
|
+
* - xnet://xnet.fyi/Task@1.0.0 (explicit version)
|
|
18
|
+
* - xnet://xnet.fyi/Task@2.0.0 (newer version)
|
|
19
|
+
* - xnet://acme-corp.com/Project@1.0.0 (organization schema)
|
|
20
|
+
* - xnet://did:key:z6Mk.../Recipe@1.0.0 (personal schema)
|
|
21
|
+
*/
|
|
22
|
+
type SchemaIRI = `xnet://${string}/${string}`;
|
|
23
|
+
/**
|
|
24
|
+
* Default version for schemas without explicit version.
|
|
25
|
+
*/
|
|
26
|
+
declare const DEFAULT_SCHEMA_VERSION = "1.0.0";
|
|
27
|
+
/**
|
|
28
|
+
* Parsed schema IRI components.
|
|
29
|
+
*/
|
|
30
|
+
interface ParsedSchemaIRI {
|
|
31
|
+
/** Full IRI including version */
|
|
32
|
+
iri: SchemaIRI;
|
|
33
|
+
/** Base IRI without version (e.g., xnet://xnet.fyi/Task) */
|
|
34
|
+
baseIRI: SchemaIRI;
|
|
35
|
+
/** Namespace (e.g., xnet://xnet.fyi/) */
|
|
36
|
+
namespace: string;
|
|
37
|
+
/** Schema name (e.g., Task) */
|
|
38
|
+
name: string;
|
|
39
|
+
/** Version (e.g., 1.0.0) - defaults to 1.0.0 if not present */
|
|
40
|
+
version: string;
|
|
41
|
+
/** Whether version was explicitly specified */
|
|
42
|
+
hasExplicitVersion: boolean;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Parse a SchemaIRI into its components.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* parseSchemaIRI('xnet://xnet.fyi/Task@2.0.0')
|
|
49
|
+
* // { baseIRI: 'xnet://xnet.fyi/Task', name: 'Task', version: '2.0.0', ... }
|
|
50
|
+
*
|
|
51
|
+
* parseSchemaIRI('xnet://xnet.fyi/Task')
|
|
52
|
+
* // { baseIRI: 'xnet://xnet.fyi/Task', name: 'Task', version: '1.0.0', hasExplicitVersion: false }
|
|
53
|
+
*/
|
|
54
|
+
declare function parseSchemaIRI(iri: SchemaIRI): ParsedSchemaIRI;
|
|
55
|
+
/**
|
|
56
|
+
* Build a versioned SchemaIRI from components.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* buildSchemaIRI('xnet://xnet.fyi/', 'Task', '2.0.0')
|
|
60
|
+
* // 'xnet://xnet.fyi/Task@2.0.0'
|
|
61
|
+
*/
|
|
62
|
+
declare function buildSchemaIRI(namespace: string, name: string, version?: string): SchemaIRI;
|
|
63
|
+
/**
|
|
64
|
+
* Normalize a SchemaIRI to always include version.
|
|
65
|
+
* Unversioned IRIs get @1.0.0 appended.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* normalizeSchemaIRI('xnet://xnet.fyi/Task')
|
|
69
|
+
* // 'xnet://xnet.fyi/Task@1.0.0'
|
|
70
|
+
*
|
|
71
|
+
* normalizeSchemaIRI('xnet://xnet.fyi/Task@2.0.0')
|
|
72
|
+
* // 'xnet://xnet.fyi/Task@2.0.0' (unchanged)
|
|
73
|
+
*/
|
|
74
|
+
declare function normalizeSchemaIRI(iri: SchemaIRI): SchemaIRI;
|
|
75
|
+
/**
|
|
76
|
+
* Get the base (unversioned) IRI from a SchemaIRI.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* getBaseSchemaIRI('xnet://xnet.fyi/Task@2.0.0')
|
|
80
|
+
* // 'xnet://xnet.fyi/Task'
|
|
81
|
+
*/
|
|
82
|
+
declare function getBaseSchemaIRI(iri: SchemaIRI): SchemaIRI;
|
|
83
|
+
/**
|
|
84
|
+
* Check if two SchemaIRIs refer to the same schema (ignoring version).
|
|
85
|
+
*/
|
|
86
|
+
declare function isSameSchema(iri1: SchemaIRI, iri2: SchemaIRI): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Get the version from a SchemaIRI.
|
|
89
|
+
*/
|
|
90
|
+
declare function getSchemaVersion(iri: SchemaIRI): string;
|
|
91
|
+
/**
|
|
92
|
+
* DID - Decentralized Identifier for user identity.
|
|
93
|
+
*/
|
|
94
|
+
type DID = `did:key:${string}`;
|
|
95
|
+
/**
|
|
96
|
+
* The minimal universal Node interface.
|
|
97
|
+
*
|
|
98
|
+
* Only 4 fields are universal - everything else is schema-defined:
|
|
99
|
+
* - id: Unique identifier
|
|
100
|
+
* - schemaId: What type of node (IRI)
|
|
101
|
+
* - createdAt: When created (for sync/attribution)
|
|
102
|
+
* - createdBy: Who created it (for sync/attribution)
|
|
103
|
+
*/
|
|
104
|
+
interface Node {
|
|
105
|
+
/** Unique identifier for this node */
|
|
106
|
+
id: string;
|
|
107
|
+
/** Schema IRI defining what type this node is */
|
|
108
|
+
schemaId: SchemaIRI;
|
|
109
|
+
/** Unix timestamp (ms) when this node was created */
|
|
110
|
+
createdAt: number;
|
|
111
|
+
/** DID of the user who created this node */
|
|
112
|
+
createdBy: DID;
|
|
113
|
+
/** All other fields are schema-defined */
|
|
114
|
+
[key: string]: unknown;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Type guard to check if a value is a valid Node.
|
|
118
|
+
*/
|
|
119
|
+
declare function isNode(value: unknown): value is Node;
|
|
120
|
+
/**
|
|
121
|
+
* Create a new node ID using nanoid.
|
|
122
|
+
*
|
|
123
|
+
* Node IDs are just unique identifiers - they don't need to be sortable
|
|
124
|
+
* (sorting is done by Lamport timestamps in the Change log).
|
|
125
|
+
*
|
|
126
|
+
* Default length is 21 characters, providing ~126 bits of randomness.
|
|
127
|
+
* URL-safe characters: A-Za-z0-9_-
|
|
128
|
+
*
|
|
129
|
+
* @param length - Optional length (default 21)
|
|
130
|
+
* @returns A unique node ID
|
|
131
|
+
*/
|
|
132
|
+
declare function createNodeId(length?: number): string;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Shared NodeStore query descriptor semantics.
|
|
136
|
+
*/
|
|
137
|
+
|
|
138
|
+
type SortDirection = 'asc' | 'desc';
|
|
139
|
+
type SystemOrderField = 'createdAt' | 'updatedAt';
|
|
140
|
+
type NodeQuerySpatialPoint = {
|
|
141
|
+
x: number;
|
|
142
|
+
y: number;
|
|
143
|
+
};
|
|
144
|
+
type NodeQuerySpatialRect = NodeQuerySpatialPoint & {
|
|
145
|
+
width: number;
|
|
146
|
+
height: number;
|
|
147
|
+
};
|
|
148
|
+
type NodeQuerySpatialPointFields = {
|
|
149
|
+
x: string;
|
|
150
|
+
y: string;
|
|
151
|
+
};
|
|
152
|
+
type NodeQuerySpatialRectFields = NodeQuerySpatialPointFields & {
|
|
153
|
+
width?: string;
|
|
154
|
+
height?: string;
|
|
155
|
+
};
|
|
156
|
+
type NodeQuerySpatialWindow = {
|
|
157
|
+
kind: 'window';
|
|
158
|
+
rect: NodeQuerySpatialRect;
|
|
159
|
+
fields: NodeQuerySpatialRectFields;
|
|
160
|
+
overscan?: number;
|
|
161
|
+
};
|
|
162
|
+
type NodeQuerySpatialRadius = {
|
|
163
|
+
kind: 'radius';
|
|
164
|
+
center: NodeQuerySpatialPoint;
|
|
165
|
+
radius: number;
|
|
166
|
+
fields: NodeQuerySpatialPointFields;
|
|
167
|
+
};
|
|
168
|
+
type NodeQuerySpatialFilter = NodeQuerySpatialWindow | NodeQuerySpatialRadius;
|
|
169
|
+
type NodeQuerySearchField = 'title' | 'content';
|
|
170
|
+
type NodeQuerySearchFilter = {
|
|
171
|
+
text: string;
|
|
172
|
+
fields?: NodeQuerySearchField[];
|
|
173
|
+
};
|
|
174
|
+
type NodeQueryMaterializedViewOptions = {
|
|
175
|
+
viewId: string;
|
|
176
|
+
maxAgeMs?: number;
|
|
177
|
+
forceRefresh?: boolean;
|
|
178
|
+
};
|
|
179
|
+
type NodeQueryPageCountMode = 'exact' | 'estimate' | 'none';
|
|
180
|
+
type NodeQueryPageOptions = {
|
|
181
|
+
first: number;
|
|
182
|
+
after?: string;
|
|
183
|
+
count?: NodeQueryPageCountMode;
|
|
184
|
+
};
|
|
185
|
+
type NodeQueryCursorOrderEntry = {
|
|
186
|
+
field: string;
|
|
187
|
+
direction: SortDirection;
|
|
188
|
+
value: unknown;
|
|
189
|
+
};
|
|
190
|
+
type NodeQueryCursor = {
|
|
191
|
+
version: 1;
|
|
192
|
+
schemaId: SchemaIRI;
|
|
193
|
+
order: NodeQueryCursorOrderEntry[];
|
|
194
|
+
nodeId: string;
|
|
195
|
+
};
|
|
196
|
+
interface NodeQueryOptions<P extends Record<string, PropertyBuilder> = Record<string, PropertyBuilder>> {
|
|
197
|
+
nodeId?: string;
|
|
198
|
+
where?: Partial<InferCreateProps<P>>;
|
|
199
|
+
includeDeleted?: boolean;
|
|
200
|
+
orderBy?: {
|
|
201
|
+
[K in keyof InferCreateProps<P> | SystemOrderField]?: SortDirection;
|
|
202
|
+
};
|
|
203
|
+
limit?: number;
|
|
204
|
+
offset?: number;
|
|
205
|
+
page?: NodeQueryPageOptions;
|
|
206
|
+
spatial?: NodeQuerySpatialFilter;
|
|
207
|
+
search?: string | NodeQuerySearchFilter;
|
|
208
|
+
materializedView?: string | NodeQueryMaterializedViewOptions;
|
|
209
|
+
}
|
|
210
|
+
interface NodeQueryDescriptor {
|
|
211
|
+
schemaId: SchemaIRI;
|
|
212
|
+
nodeId?: string;
|
|
213
|
+
where?: Record<string, unknown>;
|
|
214
|
+
includeDeleted: boolean;
|
|
215
|
+
orderBy?: Record<string, SortDirection>;
|
|
216
|
+
limit?: number;
|
|
217
|
+
offset?: number;
|
|
218
|
+
after?: string;
|
|
219
|
+
count?: NodeQueryPageCountMode;
|
|
220
|
+
spatial?: NodeQuerySpatialFilter;
|
|
221
|
+
search?: NodeQuerySearchFilter;
|
|
222
|
+
materializedView?: NodeQueryMaterializedViewOptions;
|
|
223
|
+
/**
|
|
224
|
+
* Authorization fingerprint stamped by `NodeStore` when a materialized view
|
|
225
|
+
* is read under an active read-authorization evaluator (exploration 0226).
|
|
226
|
+
* It is NOT part of the descriptor hash (it is stripped by
|
|
227
|
+
* `withoutNodeQueryMaterializedView`) — a change is reported as a distinct
|
|
228
|
+
* `'authz-changed'` refresh reason rather than `'descriptor-changed'`. Set
|
|
229
|
+
* internally by the store, never by callers.
|
|
230
|
+
*/
|
|
231
|
+
authFingerprint?: string;
|
|
232
|
+
}
|
|
233
|
+
interface NodeQueryPlanMetadata {
|
|
234
|
+
strategy: 'storage-query' | 'list-fallback' | 'auth-pushdown-candidates';
|
|
235
|
+
candidateNodeCount: number;
|
|
236
|
+
hydratedNodeCount: number;
|
|
237
|
+
returnedNodeCount: number;
|
|
238
|
+
durationMs: number;
|
|
239
|
+
sql?: string;
|
|
240
|
+
params?: unknown[];
|
|
241
|
+
postFilterReason?: string;
|
|
242
|
+
descriptorHash?: string;
|
|
243
|
+
adaptiveIndexNames?: string[];
|
|
244
|
+
candidateQueryDurationMs?: number;
|
|
245
|
+
usedIndexNames?: string[];
|
|
246
|
+
fullTableScan?: boolean;
|
|
247
|
+
queryPlanDetails?: string[];
|
|
248
|
+
availableIndexCount?: number;
|
|
249
|
+
adaptiveIndexCount?: number;
|
|
250
|
+
diagnosticsError?: string;
|
|
251
|
+
storageCapabilities?: NodeQueryStorageCapabilitiesMetadata;
|
|
252
|
+
candidateAccelerators?: string[];
|
|
253
|
+
spatialIndexKey?: string;
|
|
254
|
+
fullTextSearchQuery?: string;
|
|
255
|
+
materializedViewId?: string;
|
|
256
|
+
materializedCacheHit?: boolean;
|
|
257
|
+
materializedRefreshReason?: 'missing' | 'descriptor-changed' | 'authz-changed' | 'invalidated' | 'expired' | 'force-refresh';
|
|
258
|
+
materializedGeneratedAt?: number;
|
|
259
|
+
materializedInvalidatedAt?: number;
|
|
260
|
+
materializedRowCount?: number;
|
|
261
|
+
parityCheck?: NodeQueryParityCheckMetadata;
|
|
262
|
+
}
|
|
263
|
+
interface NodeQueryStorageCapabilitiesMetadata {
|
|
264
|
+
fullTextSearch: boolean;
|
|
265
|
+
rtree: boolean;
|
|
266
|
+
}
|
|
267
|
+
interface NodeQueryParityCheckMetadata {
|
|
268
|
+
strategy: 'exact' | 'skipped';
|
|
269
|
+
valid?: boolean;
|
|
270
|
+
reason?: string;
|
|
271
|
+
comparedNodeCount?: number;
|
|
272
|
+
expectedNodeCount?: number;
|
|
273
|
+
missingNodeIds?: string[];
|
|
274
|
+
extraNodeIds?: string[];
|
|
275
|
+
orderMismatch?: boolean;
|
|
276
|
+
}
|
|
277
|
+
interface NodeQueryResult {
|
|
278
|
+
nodes: NodeState[];
|
|
279
|
+
plan: NodeQueryPlanMetadata;
|
|
280
|
+
totalCount?: number;
|
|
281
|
+
}
|
|
282
|
+
declare function encodeNodeQueryCursor(descriptor: NodeQueryDescriptor, node: NodeState): string;
|
|
283
|
+
declare function decodeNodeQueryCursor(cursor: string): NodeQueryCursor | null;
|
|
284
|
+
declare function getNodeQuerySearchTokens(search: NodeQuerySearchFilter): string[];
|
|
285
|
+
declare function createNodeQueryDescriptor<P extends Record<string, PropertyBuilder>>(schemaId: SchemaIRI, options?: NodeQueryOptions<P>): NodeQueryDescriptor;
|
|
286
|
+
declare function nodeQueryDescriptorToOptions<P extends Record<string, PropertyBuilder> = Record<string, PropertyBuilder>>(descriptor: NodeQueryDescriptor): NodeQueryOptions<P>;
|
|
287
|
+
declare function serializeNodeQueryDescriptor(descriptor: NodeQueryDescriptor): string;
|
|
288
|
+
declare function matchesNodeQueryDescriptor(descriptor: NodeQueryDescriptor, node: NodeState | null | undefined): boolean;
|
|
289
|
+
declare function filterNodeQueryResults(nodes: NodeState[], descriptor: NodeQueryDescriptor): NodeState[];
|
|
290
|
+
declare function sortNodeQueryResults(nodes: NodeState[], descriptor: NodeQueryDescriptor): NodeState[];
|
|
291
|
+
declare function applyNodeQueryDescriptor(nodes: NodeState[], descriptor: NodeQueryDescriptor): NodeState[];
|
|
292
|
+
declare function nodeQueryDescriptorNeedsBoundedReload(descriptor: NodeQueryDescriptor): boolean;
|
|
293
|
+
declare function withoutNodeQueryPagination(descriptor: NodeQueryDescriptor): NodeQueryDescriptor;
|
|
294
|
+
declare function withoutNodeQueryMaterializedView(descriptor: NodeQueryDescriptor): NodeQueryDescriptor;
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Temp ID resolution for transactional node creation.
|
|
298
|
+
*
|
|
299
|
+
* Temp IDs are `~`-prefixed strings (e.g., `~parent`, `~comment`) that act as
|
|
300
|
+
* placeholders for node IDs in a transaction. The same temp ID used in multiple
|
|
301
|
+
* places within a transaction resolves to the same real nanoid.
|
|
302
|
+
*
|
|
303
|
+
* Resolution happens in two places:
|
|
304
|
+
* 1. **Operation IDs** — `create.options.id` and `update/delete/restore.nodeId`
|
|
305
|
+
* 2. **Relation properties** — any property with `definition.type === 'relation'`
|
|
306
|
+
* in the schema (requires SchemaRegistry access)
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```typescript
|
|
310
|
+
* await store.transaction([
|
|
311
|
+
* { type: 'create', options: { id: '~parent', schemaId: 'Task', properties: { title: 'P' } } },
|
|
312
|
+
* { type: 'create', options: { id: '~child', schemaId: 'Task', properties: { title: 'C', parent: '~parent' } } },
|
|
313
|
+
* ])
|
|
314
|
+
* // Returns: { tempIds: { '~parent': 'xK9mQ2...', '~child': 'pL3nR7...' }, ... }
|
|
315
|
+
* ```
|
|
316
|
+
*/
|
|
317
|
+
|
|
318
|
+
/** Prefix that identifies a temp ID. nanoid never produces `~`. */
|
|
319
|
+
declare const TEMP_ID_PREFIX = "~";
|
|
320
|
+
/**
|
|
321
|
+
* Check whether a string is a temp ID (starts with `~`).
|
|
322
|
+
*/
|
|
323
|
+
declare function isTempId(value: unknown): value is string;
|
|
324
|
+
/**
|
|
325
|
+
* Callback to look up a schema's relation property names by schema IRI.
|
|
326
|
+
* Returns the set of property keys that have `type === 'relation'`,
|
|
327
|
+
* or undefined if the schema is not available.
|
|
328
|
+
*/
|
|
329
|
+
type SchemaLookup = (schemaId: SchemaIRI) => Set<string> | undefined;
|
|
330
|
+
/**
|
|
331
|
+
* Build a SchemaLookup from a map of DefinedSchema objects.
|
|
332
|
+
* Caches the relation property sets for each schema IRI.
|
|
333
|
+
*/
|
|
334
|
+
declare function createSchemaLookup(getSchema: (iri: SchemaIRI) => DefinedSchema<Record<string, PropertyBuilder>> | undefined): SchemaLookup;
|
|
335
|
+
/**
|
|
336
|
+
* Build a PropertyLookup from a schema getter function.
|
|
337
|
+
* Returns the set of all property names defined in the schema.
|
|
338
|
+
* Caches results for performance.
|
|
339
|
+
*/
|
|
340
|
+
declare function createPropertyLookup(getSchema: (iri: SchemaIRI) => DefinedSchema<Record<string, PropertyBuilder>> | undefined): PropertyLookup;
|
|
341
|
+
/**
|
|
342
|
+
* Result of resolving temp IDs in a list of transaction operations.
|
|
343
|
+
*/
|
|
344
|
+
interface TempIdResolution {
|
|
345
|
+
/** The operations with all temp IDs replaced by real IDs */
|
|
346
|
+
operations: TransactionOperation[];
|
|
347
|
+
/** Map from temp ID → generated real ID (empty if no temp IDs were found) */
|
|
348
|
+
tempIds: Record<string, NodeId>;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Resolve all `~`-prefixed temp IDs in a list of transaction operations.
|
|
352
|
+
*
|
|
353
|
+
* Resolution order:
|
|
354
|
+
* 1. Scan all operations to collect temp IDs and generate real IDs
|
|
355
|
+
* 2. Replace temp IDs in operation `id` fields (create) and `nodeId` fields (update/delete/restore)
|
|
356
|
+
* 3. If a SchemaLookup is provided, replace temp IDs in `relation`-typed property values
|
|
357
|
+
*
|
|
358
|
+
* @param operations - The original transaction operations (not mutated)
|
|
359
|
+
* @param schemaLookup - Optional callback to get relation property names for a schema
|
|
360
|
+
* @returns Resolved operations and the temp ID → real ID mapping
|
|
361
|
+
*/
|
|
362
|
+
declare function resolveTempIds(operations: TransactionOperation[], schemaLookup?: SchemaLookup): TempIdResolution;
|
|
363
|
+
|
|
364
|
+
interface GrantRateLimiterOptions {
|
|
365
|
+
limitPerMinute?: number;
|
|
366
|
+
windowMs?: number;
|
|
367
|
+
now?: () => number;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Per-peer rate limiter for grant operations.
|
|
371
|
+
*
|
|
372
|
+
* Default policy: max 10 grant attempts per peer per minute.
|
|
373
|
+
*/
|
|
374
|
+
declare class GrantRateLimiter {
|
|
375
|
+
private readonly limitPerMinute;
|
|
376
|
+
private readonly windowMs;
|
|
377
|
+
private readonly now;
|
|
378
|
+
private readonly attemptsByPeer;
|
|
379
|
+
constructor(options?: GrantRateLimiterOptions);
|
|
380
|
+
allow(peerDid: DID$1): boolean;
|
|
381
|
+
reset(peerDid?: DID$1): void;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
declare const GRANT_SCHEMA_IRI: "xnet://xnet.fyi/Grant";
|
|
385
|
+
interface GrantNode {
|
|
386
|
+
id: string;
|
|
387
|
+
properties: Record<string, unknown>;
|
|
388
|
+
deleted: boolean;
|
|
389
|
+
}
|
|
390
|
+
interface GrantIndexStore {
|
|
391
|
+
list(options?: {
|
|
392
|
+
schemaId?: string;
|
|
393
|
+
includeDeleted?: boolean;
|
|
394
|
+
}): Promise<NodeState[]>;
|
|
395
|
+
subscribe(listener: (event: NodeChangeEvent) => void): () => void;
|
|
396
|
+
}
|
|
397
|
+
interface GrantIndexOptions {
|
|
398
|
+
schemaId?: string;
|
|
399
|
+
clock?: () => number;
|
|
400
|
+
}
|
|
401
|
+
declare function isGrantActive(grant: GrantNode, now?: number): boolean;
|
|
402
|
+
declare class GrantIndex {
|
|
403
|
+
private readonly store;
|
|
404
|
+
private byResourceAndGrantee;
|
|
405
|
+
private byResource;
|
|
406
|
+
private grantsById;
|
|
407
|
+
private unsubscribe;
|
|
408
|
+
private readonly schemaId;
|
|
409
|
+
private readonly clock;
|
|
410
|
+
constructor(store: GrantIndexStore, options?: GrantIndexOptions);
|
|
411
|
+
initialize(): Promise<void>;
|
|
412
|
+
findGrants(resource: string, grantee: DID$1): GrantNode[];
|
|
413
|
+
findGrantsForResource(resource: string): GrantNode[];
|
|
414
|
+
findAllGrantsForResource(resource: string): GrantNode[];
|
|
415
|
+
findGrantsForGrantee(grantee: DID$1): GrantNode[];
|
|
416
|
+
dispose(): void;
|
|
417
|
+
private loadGrantNodes;
|
|
418
|
+
private isGrantSchema;
|
|
419
|
+
private indexGrant;
|
|
420
|
+
private removeGrant;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
interface OfflineAuthPolicy {
|
|
424
|
+
/** Cache TTL for can() decisions in eventual mode. Default: 5 minutes. */
|
|
425
|
+
decisionCacheTTL: number;
|
|
426
|
+
/** Max staleness before operations must revalidate. Default: 1 hour. */
|
|
427
|
+
maxStaleness: number;
|
|
428
|
+
/** Re-validation strategy used on reconnect. */
|
|
429
|
+
revalidation: 'eager' | 'lazy' | 'hybrid';
|
|
430
|
+
/** Allow grant/revoke writes while offline. */
|
|
431
|
+
allowOfflineGrants: boolean;
|
|
432
|
+
}
|
|
433
|
+
declare const DEFAULT_OFFLINE_POLICY: OfflineAuthPolicy;
|
|
434
|
+
type RevocationConsistency = 'eventual' | 'strict';
|
|
435
|
+
interface RevocationConfig {
|
|
436
|
+
mode: RevocationConsistency;
|
|
437
|
+
maxStaleness: number;
|
|
438
|
+
}
|
|
439
|
+
declare function mergeOfflinePolicy(current: OfflineAuthPolicy, patch: Partial<OfflineAuthPolicy>): OfflineAuthPolicy;
|
|
440
|
+
|
|
441
|
+
type GrantStatus = 'active' | 'expired' | 'revoked' | 'all';
|
|
442
|
+
interface StoreAuthAPI {
|
|
443
|
+
can(input: {
|
|
444
|
+
action: AuthAction;
|
|
445
|
+
nodeId: string;
|
|
446
|
+
patch?: Record<string, unknown>;
|
|
447
|
+
}): Promise<AuthDecision>;
|
|
448
|
+
explain(input: {
|
|
449
|
+
action: AuthAction;
|
|
450
|
+
nodeId: string;
|
|
451
|
+
}): Promise<AuthTrace>;
|
|
452
|
+
grant(input: GrantInput): Promise<Grant>;
|
|
453
|
+
revoke(input: {
|
|
454
|
+
grantId: string;
|
|
455
|
+
}): Promise<void>;
|
|
456
|
+
listGrants(input: {
|
|
457
|
+
nodeId: string;
|
|
458
|
+
status?: GrantStatus;
|
|
459
|
+
}): Promise<Grant[]>;
|
|
460
|
+
listIssuedGrants(): Promise<Grant[]>;
|
|
461
|
+
listReceivedGrants(): Promise<Grant[]>;
|
|
462
|
+
getOfflinePolicy(): OfflineAuthPolicy;
|
|
463
|
+
setOfflinePolicy(policy: Partial<OfflineAuthPolicy>): void;
|
|
464
|
+
}
|
|
465
|
+
interface GrantInput {
|
|
466
|
+
to: DID$1;
|
|
467
|
+
actions: AuthAction[];
|
|
468
|
+
resource: string;
|
|
469
|
+
expiresIn?: string | number;
|
|
470
|
+
parentGrantId?: string;
|
|
471
|
+
}
|
|
472
|
+
interface Grant {
|
|
473
|
+
id: string;
|
|
474
|
+
issuer: DID$1;
|
|
475
|
+
grantee: DID$1;
|
|
476
|
+
resource: string;
|
|
477
|
+
resourceSchema: string;
|
|
478
|
+
actions: AuthAction[];
|
|
479
|
+
expiresAt: number;
|
|
480
|
+
revokedAt: number;
|
|
481
|
+
revokedBy?: DID$1;
|
|
482
|
+
ucanToken?: string;
|
|
483
|
+
proofDepth: number;
|
|
484
|
+
parentGrantId?: string;
|
|
485
|
+
}
|
|
486
|
+
interface StoreAuthStore {
|
|
487
|
+
create(options: {
|
|
488
|
+
schemaId: string;
|
|
489
|
+
properties: Record<string, unknown>;
|
|
490
|
+
}): Promise<{
|
|
491
|
+
id: string;
|
|
492
|
+
}>;
|
|
493
|
+
update(nodeId: string, options: {
|
|
494
|
+
properties: Record<string, unknown>;
|
|
495
|
+
}): Promise<unknown>;
|
|
496
|
+
get(nodeId: string): Promise<{
|
|
497
|
+
id: string;
|
|
498
|
+
createdBy: DID$1;
|
|
499
|
+
schemaId: string;
|
|
500
|
+
properties: Record<string, unknown>;
|
|
501
|
+
} | null>;
|
|
502
|
+
list(options?: {
|
|
503
|
+
schemaId?: string;
|
|
504
|
+
includeDeleted?: boolean;
|
|
505
|
+
}): Promise<Array<{
|
|
506
|
+
id: string;
|
|
507
|
+
schemaId: string;
|
|
508
|
+
properties: Record<string, unknown>;
|
|
509
|
+
}>>;
|
|
510
|
+
}
|
|
511
|
+
interface StoreAuthKeyManager {
|
|
512
|
+
getContentKey(resourceId: string): Promise<Uint8Array>;
|
|
513
|
+
addRecipient(input: {
|
|
514
|
+
resourceId: string;
|
|
515
|
+
recipient: DID$1;
|
|
516
|
+
contentKey: Uint8Array;
|
|
517
|
+
recipientPublicKey: Uint8Array;
|
|
518
|
+
}): Promise<void>;
|
|
519
|
+
rotateContentKey(resourceId: string, revokedRecipient: DID$1): Promise<void>;
|
|
520
|
+
}
|
|
521
|
+
interface StoreAuthOptions {
|
|
522
|
+
store: StoreAuthStore;
|
|
523
|
+
actorDid: DID$1;
|
|
524
|
+
signingKey: Uint8Array;
|
|
525
|
+
evaluator: PolicyEvaluator;
|
|
526
|
+
grantIndex?: GrantIndex;
|
|
527
|
+
publicKeyResolver?: PublicKeyResolver;
|
|
528
|
+
keyManager?: StoreAuthKeyManager;
|
|
529
|
+
rateLimiter?: GrantRateLimiter;
|
|
530
|
+
now?: () => number;
|
|
531
|
+
maxProofDepth?: number;
|
|
532
|
+
}
|
|
533
|
+
type StoreAuthErrorCode = 'AUTH_PERMISSION_DENIED' | 'AUTH_RATE_LIMIT_EXCEEDED' | 'AUTH_DELEGATION_DEPTH_EXCEEDED' | 'AUTH_DELEGATION_ESCALATION';
|
|
534
|
+
declare class StoreAuthError extends Error {
|
|
535
|
+
readonly code: StoreAuthErrorCode;
|
|
536
|
+
constructor(code: StoreAuthErrorCode, message: string);
|
|
537
|
+
}
|
|
538
|
+
declare class StoreAuth implements StoreAuthAPI {
|
|
539
|
+
private readonly options;
|
|
540
|
+
private readonly rateLimiter;
|
|
541
|
+
private readonly now;
|
|
542
|
+
private readonly maxProofDepth;
|
|
543
|
+
private offlinePolicy;
|
|
544
|
+
constructor(options: StoreAuthOptions);
|
|
545
|
+
can(input: {
|
|
546
|
+
action: AuthAction;
|
|
547
|
+
nodeId: string;
|
|
548
|
+
patch?: Record<string, unknown>;
|
|
549
|
+
}): Promise<AuthDecision>;
|
|
550
|
+
explain(input: {
|
|
551
|
+
action: AuthAction;
|
|
552
|
+
nodeId: string;
|
|
553
|
+
}): Promise<AuthTrace>;
|
|
554
|
+
grant(input: GrantInput): Promise<Grant>;
|
|
555
|
+
revoke(input: {
|
|
556
|
+
grantId: string;
|
|
557
|
+
}): Promise<void>;
|
|
558
|
+
listGrants(input: {
|
|
559
|
+
nodeId: string;
|
|
560
|
+
status?: GrantStatus;
|
|
561
|
+
}): Promise<Grant[]>;
|
|
562
|
+
listIssuedGrants(): Promise<Grant[]>;
|
|
563
|
+
listReceivedGrants(): Promise<Grant[]>;
|
|
564
|
+
getOfflinePolicy(): OfflineAuthPolicy;
|
|
565
|
+
setOfflinePolicy(policy: Partial<OfflineAuthPolicy>): void;
|
|
566
|
+
private matchesStatus;
|
|
567
|
+
private validateRevocation;
|
|
568
|
+
private assertDelegationAttenuation;
|
|
569
|
+
private computeProofDepth;
|
|
570
|
+
private cascadeRevocation;
|
|
571
|
+
private getGrantNodeOrThrow;
|
|
572
|
+
private loadGrantNodes;
|
|
573
|
+
private createDelegationUCAN;
|
|
574
|
+
private computeExpiration;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Schema Lens System - Bidirectional transformations between schema versions.
|
|
579
|
+
*
|
|
580
|
+
* A lens defines how to transform data from one schema version to another,
|
|
581
|
+
* enabling automatic migrations during read operations.
|
|
582
|
+
*
|
|
583
|
+
* @example
|
|
584
|
+
* ```typescript
|
|
585
|
+
* const taskV1toV2: SchemaLens = {
|
|
586
|
+
* source: 'xnet://xnet.fyi/Task@1.0.0',
|
|
587
|
+
* target: 'xnet://xnet.fyi/Task@2.0.0',
|
|
588
|
+
* forward: (data) => ({
|
|
589
|
+
* ...data,
|
|
590
|
+
* status: data.complete ? 'done' : 'todo',
|
|
591
|
+
* priority: data.priority ?? 'medium'
|
|
592
|
+
* }),
|
|
593
|
+
* backward: (data) => ({
|
|
594
|
+
* ...data,
|
|
595
|
+
* complete: data.status === 'done'
|
|
596
|
+
* }),
|
|
597
|
+
* lossless: false // priority is lost in backward transform
|
|
598
|
+
* }
|
|
599
|
+
*
|
|
600
|
+
* registry.register(taskV1toV2)
|
|
601
|
+
* const migrated = registry.transform(oldData, 'Task@1.0.0', 'Task@2.0.0')
|
|
602
|
+
* ```
|
|
603
|
+
*/
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* A bidirectional transformation between two schema versions.
|
|
607
|
+
*/
|
|
608
|
+
interface SchemaLens {
|
|
609
|
+
/** Source schema IRI (versioned) */
|
|
610
|
+
source: SchemaIRI;
|
|
611
|
+
/** Target schema IRI (versioned) */
|
|
612
|
+
target: SchemaIRI;
|
|
613
|
+
/** Transform data from source to target schema */
|
|
614
|
+
forward: (data: Record<string, unknown>) => Record<string, unknown>;
|
|
615
|
+
/** Transform data from target back to source schema */
|
|
616
|
+
backward: (data: Record<string, unknown>) => Record<string, unknown>;
|
|
617
|
+
/** Whether the transformation preserves all data (can round-trip without loss) */
|
|
618
|
+
lossless: boolean;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* A single lens operation (used by lens builders).
|
|
622
|
+
* Can be composed into a full SchemaLens.
|
|
623
|
+
*/
|
|
624
|
+
interface LensOperation {
|
|
625
|
+
/** Transform data forward */
|
|
626
|
+
forward: (data: Record<string, unknown>) => Record<string, unknown>;
|
|
627
|
+
/** Transform data backward */
|
|
628
|
+
backward: (data: Record<string, unknown>) => Record<string, unknown>;
|
|
629
|
+
/** Whether this operation is lossless (defaults to true) */
|
|
630
|
+
lossless?: boolean;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Result of a migration transformation.
|
|
634
|
+
*/
|
|
635
|
+
interface MigrationResult {
|
|
636
|
+
/** The transformed data */
|
|
637
|
+
data: Record<string, unknown>;
|
|
638
|
+
/** The path of lenses applied */
|
|
639
|
+
path: SchemaLens[];
|
|
640
|
+
/** Whether all transformations were lossless */
|
|
641
|
+
lossless: boolean;
|
|
642
|
+
/** Warnings about potential data loss */
|
|
643
|
+
warnings: string[];
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Error thrown when migration fails.
|
|
647
|
+
*/
|
|
648
|
+
declare class MigrationError extends Error {
|
|
649
|
+
readonly source?: SchemaIRI | undefined;
|
|
650
|
+
readonly target?: SchemaIRI | undefined;
|
|
651
|
+
constructor(message: string, source?: SchemaIRI | undefined, target?: SchemaIRI | undefined);
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Registry for schema lenses with pathfinding for multi-step migrations.
|
|
655
|
+
*
|
|
656
|
+
* The registry finds the shortest path between schema versions using BFS,
|
|
657
|
+
* allowing automatic migrations through intermediate versions.
|
|
658
|
+
*
|
|
659
|
+
* @example
|
|
660
|
+
* ```typescript
|
|
661
|
+
* const registry = new LensRegistry()
|
|
662
|
+
*
|
|
663
|
+
* // Register direct migrations
|
|
664
|
+
* registry.register(taskV1toV2)
|
|
665
|
+
* registry.register(taskV2toV3)
|
|
666
|
+
*
|
|
667
|
+
* // Can now migrate from v1 to v3 through v2
|
|
668
|
+
* const migrated = registry.transform(v1Data, 'Task@1.0.0', 'Task@3.0.0')
|
|
669
|
+
* ```
|
|
670
|
+
*/
|
|
671
|
+
declare class LensRegistry {
|
|
672
|
+
private lenses;
|
|
673
|
+
private pathCache;
|
|
674
|
+
/**
|
|
675
|
+
* Register a lens for transforming between two schema versions.
|
|
676
|
+
* Also registers the reverse transformation automatically.
|
|
677
|
+
*/
|
|
678
|
+
register(lens: SchemaLens): void;
|
|
679
|
+
/**
|
|
680
|
+
* Unregister a lens (and its reverse).
|
|
681
|
+
*/
|
|
682
|
+
unregister(source: SchemaIRI, target: SchemaIRI): boolean;
|
|
683
|
+
/**
|
|
684
|
+
* Get a direct lens between two schemas (if registered).
|
|
685
|
+
*/
|
|
686
|
+
get(source: SchemaIRI, target: SchemaIRI): SchemaLens | undefined;
|
|
687
|
+
/**
|
|
688
|
+
* Check if a direct lens exists between two schemas.
|
|
689
|
+
*/
|
|
690
|
+
has(source: SchemaIRI, target: SchemaIRI): boolean;
|
|
691
|
+
/**
|
|
692
|
+
* Find the shortest path of lenses between two schema versions.
|
|
693
|
+
* Uses BFS to find the optimal path through intermediate versions.
|
|
694
|
+
*
|
|
695
|
+
* @returns Array of lenses to apply in order, or null if no path exists
|
|
696
|
+
*/
|
|
697
|
+
findPath(from: SchemaIRI, to: SchemaIRI): SchemaLens[] | null;
|
|
698
|
+
/**
|
|
699
|
+
* Transform data from one schema version to another.
|
|
700
|
+
*
|
|
701
|
+
* @throws MigrationError if no path exists between schemas
|
|
702
|
+
*/
|
|
703
|
+
transform(data: Record<string, unknown>, from: SchemaIRI, to: SchemaIRI): Record<string, unknown>;
|
|
704
|
+
/**
|
|
705
|
+
* Transform data with detailed migration result.
|
|
706
|
+
*/
|
|
707
|
+
transformWithDetails(data: Record<string, unknown>, from: SchemaIRI, to: SchemaIRI): MigrationResult;
|
|
708
|
+
/**
|
|
709
|
+
* Check if a migration path exists between two schemas.
|
|
710
|
+
*/
|
|
711
|
+
canMigrate(from: SchemaIRI, to: SchemaIRI): boolean;
|
|
712
|
+
/**
|
|
713
|
+
* Check if a migration path is lossless (all transformations preserve data).
|
|
714
|
+
*/
|
|
715
|
+
isLossless(from: SchemaIRI, to: SchemaIRI): boolean;
|
|
716
|
+
/**
|
|
717
|
+
* Get all registered schema IRIs.
|
|
718
|
+
*/
|
|
719
|
+
getSchemas(): SchemaIRI[];
|
|
720
|
+
/**
|
|
721
|
+
* Clear all registered lenses and cached paths.
|
|
722
|
+
*/
|
|
723
|
+
clear(): void;
|
|
724
|
+
/**
|
|
725
|
+
* BFS pathfinding to find shortest lens path between schemas.
|
|
726
|
+
*/
|
|
727
|
+
private bfsPath;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Default global lens registry instance.
|
|
731
|
+
*/
|
|
732
|
+
declare const lensRegistry: LensRegistry;
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* NodeStore types - Event-sourced storage for Nodes
|
|
736
|
+
*
|
|
737
|
+
* The NodeStore manages Nodes using Change<T> from @xnetjs/sync.
|
|
738
|
+
* Each Node change is a Change with a NodePayload.
|
|
739
|
+
*
|
|
740
|
+
* Key design decisions:
|
|
741
|
+
* - No operation types (create-item, update-item, etc.) - just Changes
|
|
742
|
+
* - LWW conflict resolution using Lamport timestamps
|
|
743
|
+
* - Changes store sparse updates (only changed properties)
|
|
744
|
+
* - Materialized state computed by replaying Changes
|
|
745
|
+
*/
|
|
746
|
+
|
|
747
|
+
/** Unique identifier for a Node */
|
|
748
|
+
type NodeId = string;
|
|
749
|
+
/** Identifier for a property within a Node */
|
|
750
|
+
type PropertyKey = string;
|
|
751
|
+
/**
|
|
752
|
+
* Payload for a Node change.
|
|
753
|
+
*
|
|
754
|
+
* Contains the sparse set of properties that changed.
|
|
755
|
+
* First change for a nodeId implicitly creates the Node.
|
|
756
|
+
* Setting a property to `undefined` deletes it.
|
|
757
|
+
*/
|
|
758
|
+
interface NodePayload {
|
|
759
|
+
/** The Node being changed */
|
|
760
|
+
nodeId: NodeId;
|
|
761
|
+
/** Schema IRI (required on first change, optional on updates) */
|
|
762
|
+
schemaId?: SchemaIRI;
|
|
763
|
+
/** Changed properties (sparse - only what changed) */
|
|
764
|
+
properties: Record<PropertyKey, unknown>;
|
|
765
|
+
/** Soft delete flag (optional) */
|
|
766
|
+
deleted?: boolean;
|
|
767
|
+
}
|
|
768
|
+
/** A Change containing a NodePayload */
|
|
769
|
+
type NodeChange = Change<NodePayload>;
|
|
770
|
+
/**
|
|
771
|
+
* Timestamp metadata for a property value (for LWW resolution).
|
|
772
|
+
*/
|
|
773
|
+
interface PropertyTimestamp {
|
|
774
|
+
/** The Lamport logical time when this value was set */
|
|
775
|
+
lamport: number;
|
|
776
|
+
/** Author DID for LWW tiebreak */
|
|
777
|
+
author: DID$1;
|
|
778
|
+
/** Wall clock time (for display) */
|
|
779
|
+
wallTime: number;
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Materialized Node state with LWW metadata.
|
|
783
|
+
*
|
|
784
|
+
* This is computed by replaying all Changes for a nodeId.
|
|
785
|
+
*/
|
|
786
|
+
interface NodeState {
|
|
787
|
+
/** Node ID */
|
|
788
|
+
id: NodeId;
|
|
789
|
+
/** Schema IRI */
|
|
790
|
+
schemaId: SchemaIRI;
|
|
791
|
+
/** Current property values (after LWW resolution) */
|
|
792
|
+
properties: Record<PropertyKey, unknown>;
|
|
793
|
+
/** LWW timestamps per property (for conflict resolution) */
|
|
794
|
+
timestamps: Record<PropertyKey, PropertyTimestamp>;
|
|
795
|
+
/** Soft delete flag */
|
|
796
|
+
deleted: boolean;
|
|
797
|
+
/** When deleted (if deleted) */
|
|
798
|
+
deletedAt?: PropertyTimestamp;
|
|
799
|
+
/** Creation metadata */
|
|
800
|
+
createdAt: number;
|
|
801
|
+
createdBy: DID$1;
|
|
802
|
+
/** Last update metadata */
|
|
803
|
+
updatedAt: number;
|
|
804
|
+
updatedBy: DID$1;
|
|
805
|
+
/**
|
|
806
|
+
* Serialized CRDT document content (for nodes with document type).
|
|
807
|
+
* For Yjs: Uint8Array from Y.encodeStateAsUpdate()
|
|
808
|
+
* Use Y.applyUpdate(ydoc, documentContent) to hydrate.
|
|
809
|
+
*/
|
|
810
|
+
documentContent?: Uint8Array;
|
|
811
|
+
/**
|
|
812
|
+
* Unknown properties from future schema versions.
|
|
813
|
+
* Preserved on read and passed through on write for forward compatibility.
|
|
814
|
+
* These properties exist in the change log but aren't known to the current schema.
|
|
815
|
+
*/
|
|
816
|
+
_unknown?: Record<PropertyKey, unknown>;
|
|
817
|
+
/**
|
|
818
|
+
* The schema version that last wrote to this node.
|
|
819
|
+
* Used to detect when migrations might be needed.
|
|
820
|
+
*/
|
|
821
|
+
_schemaVersion?: string;
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Storage adapter interface for NodeStore.
|
|
825
|
+
*
|
|
826
|
+
* Implementations can use SQLite or memory.
|
|
827
|
+
* The adapter stores Changes and materialized NodeState.
|
|
828
|
+
*/
|
|
829
|
+
/**
|
|
830
|
+
* Filters a candidate node set down to the rows the current viewer may read.
|
|
831
|
+
* Only ever removes rows. Used by adapters to authorize a materialized view's
|
|
832
|
+
* id list once, at refresh time (exploration 0226).
|
|
833
|
+
*/
|
|
834
|
+
type NodeReadAuthorizer = (nodes: NodeState[]) => Promise<NodeState[]>;
|
|
835
|
+
/**
|
|
836
|
+
* A reload-stable version of the authorization-relevant control-plane state.
|
|
837
|
+
* `count` and `maxUpdatedAt` over grants and `/sys/authz/` resources change
|
|
838
|
+
* whenever any grant is added, modified, or removed.
|
|
839
|
+
*/
|
|
840
|
+
interface AuthorizationStateVersion {
|
|
841
|
+
count: number;
|
|
842
|
+
maxUpdatedAt: number;
|
|
843
|
+
}
|
|
844
|
+
interface NodeStorageAdapter {
|
|
845
|
+
/** Open/initialize the storage connection */
|
|
846
|
+
open?(): Promise<void>;
|
|
847
|
+
/** Close the storage connection */
|
|
848
|
+
close?(): Promise<void>;
|
|
849
|
+
/**
|
|
850
|
+
* Execute a batch of storage operations as one adapter-owned transaction.
|
|
851
|
+
*
|
|
852
|
+
* Storage implementations pass a transaction-scoped adapter to `fn`; writes
|
|
853
|
+
* through that adapter must not start their own nested transaction.
|
|
854
|
+
*/
|
|
855
|
+
withTransaction?<T>(fn: (storage: NodeStorageAdapter) => Promise<T>): Promise<T>;
|
|
856
|
+
appendChange(change: NodeChange): Promise<void>;
|
|
857
|
+
getChanges(nodeId: NodeId): Promise<NodeChange[]>;
|
|
858
|
+
getAllChanges(): Promise<NodeChange[]>;
|
|
859
|
+
/** Get changes with Lamport time greater than `since` */
|
|
860
|
+
getChangesSince(sinceLamport: number): Promise<NodeChange[]>;
|
|
861
|
+
getChangeByHash(hash: ContentId): Promise<NodeChange | null>;
|
|
862
|
+
getLastChange(nodeId: NodeId): Promise<NodeChange | null>;
|
|
863
|
+
/** Return the latest change for each requested node id. Missing nodes are omitted. */
|
|
864
|
+
getLastChangesByNodeId?(nodeIds: readonly NodeId[]): Promise<Map<NodeId, NodeChange>>;
|
|
865
|
+
/** Append multiple changes in one storage-owned write when supported. */
|
|
866
|
+
appendChanges?(changes: readonly NodeChange[]): Promise<void>;
|
|
867
|
+
getNode(id: NodeId): Promise<NodeState | null>;
|
|
868
|
+
/** Return existing materialized nodes in input order. Missing nodes are omitted. */
|
|
869
|
+
getNodes?(ids: readonly NodeId[]): Promise<NodeState[]>;
|
|
870
|
+
/** Return the subset of ids that currently exist in materialized storage. */
|
|
871
|
+
getExistingNodeIds?(ids: readonly NodeId[]): Promise<NodeId[]>;
|
|
872
|
+
/** Return all read state needed to plan a node batch in one adapter-owned preflight. */
|
|
873
|
+
getBatchPreflight?(ids: readonly NodeId[]): Promise<NodeBatchPreflightResult>;
|
|
874
|
+
setNode(node: NodeState, options?: SetNodeOptions): Promise<void>;
|
|
875
|
+
/** Import multiple materialized nodes in one storage-owned write when supported. */
|
|
876
|
+
importNodes?(nodes: readonly NodeState[], options?: ImportNodesOptions): Promise<void>;
|
|
877
|
+
/** Apply materialized nodes, signed changes, sync state, and batch indexes in one write. */
|
|
878
|
+
applyNodeBatch?(input: ApplyNodeBatchInput): Promise<ApplyNodeBatchResult>;
|
|
879
|
+
/** Rebuild secondary node indexes after an import that deferred index maintenance. */
|
|
880
|
+
rebuildIndexesForSchemas?(schemaIds: readonly SchemaIRI[], options?: RebuildNodeIndexesOptions): Promise<void>;
|
|
881
|
+
/**
|
|
882
|
+
* Refresh query-planner statistics (ANALYZE). Call after a bulk import:
|
|
883
|
+
* SQLite does not auto-maintain stats, so a large insert leaves the planner
|
|
884
|
+
* "out of sync" and reads may pick full scans over indexes (exploration 0184).
|
|
885
|
+
*/
|
|
886
|
+
analyze?(): Promise<void>;
|
|
887
|
+
/**
|
|
888
|
+
* Incremental planner maintenance (`PRAGMA optimize`) — ANALYZEs only the
|
|
889
|
+
* tables that drifted. Cheap; safe to call at idle and before close.
|
|
890
|
+
*/
|
|
891
|
+
optimize?(): Promise<void>;
|
|
892
|
+
deleteNode(id: NodeId): Promise<void>;
|
|
893
|
+
listNodes(options?: ListNodesOptions): Promise<NodeState[]>;
|
|
894
|
+
countNodes(options?: CountNodesOptions): Promise<number>;
|
|
895
|
+
queryNodes?(descriptor: NodeQueryDescriptor): Promise<NodeQueryResult>;
|
|
896
|
+
/**
|
|
897
|
+
* Inject the read-authorization filter the adapter applies before persisting
|
|
898
|
+
* a materialized view's id list (exploration 0226). `NodeStore` wires this to
|
|
899
|
+
* its `filterReadableNodes` so a materialization is authorized exactly once,
|
|
900
|
+
* at refresh time, and cache hits can be served without per-row re-checks.
|
|
901
|
+
* Pass `undefined` to clear it. Optional: adapters that don't implement it
|
|
902
|
+
* simply never materialize under authorization (the store falls back to the
|
|
903
|
+
* authorize-then-paginate path).
|
|
904
|
+
*/
|
|
905
|
+
setNodeReadAuthorizer?(authorizer: NodeReadAuthorizer | undefined): void;
|
|
906
|
+
/**
|
|
907
|
+
* A cheap, reload-stable version stamp of the authorization-relevant state
|
|
908
|
+
* (grants + `/sys/authz/` resources). Folded into the materialized view's
|
|
909
|
+
* auth fingerprint so any grant change invalidates cached views across
|
|
910
|
+
* reloads. Optional; when absent the store will not materialize under authz.
|
|
911
|
+
*/
|
|
912
|
+
getAuthorizationStateVersion?(): Promise<AuthorizationStateVersion>;
|
|
913
|
+
/** Optional runtime operation counters for import diagnostics. */
|
|
914
|
+
getOperationStats?(): Promise<SQLiteOperationStats | null> | SQLiteOperationStats | null;
|
|
915
|
+
/** Reset optional runtime operation counters before a focused measurement. */
|
|
916
|
+
resetOperationStats?(): Promise<void> | void;
|
|
917
|
+
getLastLamportTime(): Promise<number>;
|
|
918
|
+
setLastLamportTime(time: number): Promise<void>;
|
|
919
|
+
/**
|
|
920
|
+
* Per-room sync high-water mark (Lamport time) — the cursor a hub-sync
|
|
921
|
+
* provider has confirmed the hub durably stores. Persisting this stops the
|
|
922
|
+
* client replaying its entire change log on every reload (exploration 0206).
|
|
923
|
+
* Optional: adapters that don't implement it degrade to replay-from-0.
|
|
924
|
+
*/
|
|
925
|
+
getSyncCursor?(room: string): Promise<number>;
|
|
926
|
+
setSyncCursor?(room: string, lamport: number): Promise<void>;
|
|
927
|
+
/**
|
|
928
|
+
* Generic app-state key/value, stored in an FK-free table. Used for blobs
|
|
929
|
+
* that are *not* node documents (e.g. the sync registry's tracked-node set):
|
|
930
|
+
* writing those through {@link setDocumentContent} hits `yjs_state`'s
|
|
931
|
+
* `node_id → nodes(id)` foreign key and fails with SQLITE_CONSTRAINT_FOREIGNKEY
|
|
932
|
+
* (exploration 0227). Optional: callers fall back to document content when an
|
|
933
|
+
* adapter doesn't implement it.
|
|
934
|
+
*/
|
|
935
|
+
getAppState?(key: string): Promise<string | null>;
|
|
936
|
+
setAppState?(key: string, value: string): Promise<void>;
|
|
937
|
+
getDocumentContent(nodeId: NodeId): Promise<Uint8Array | null>;
|
|
938
|
+
setDocumentContent(nodeId: NodeId, content: Uint8Array): Promise<void>;
|
|
939
|
+
}
|
|
940
|
+
interface SetNodeOptions {
|
|
941
|
+
/**
|
|
942
|
+
* Whether storage may maintain plaintext property read indexes for this node.
|
|
943
|
+
* Encrypted NodeStore instances pass false and must rely on post-decryption
|
|
944
|
+
* query evaluation instead.
|
|
945
|
+
*/
|
|
946
|
+
indexProperties?: boolean;
|
|
947
|
+
}
|
|
948
|
+
interface ImportNodesOptions extends SetNodeOptions {
|
|
949
|
+
/**
|
|
950
|
+
* Skip secondary scalar/spatial/FTS/materialized maintenance for this write.
|
|
951
|
+
* Callers must rebuild affected schema indexes before relying on indexed
|
|
952
|
+
* queries again.
|
|
953
|
+
*/
|
|
954
|
+
deferIndexes?: boolean;
|
|
955
|
+
/**
|
|
956
|
+
* Treat the provided NodeState objects as the post-LWW materialized truth
|
|
957
|
+
* when updating secondary indexes. This avoids a per-node readback during
|
|
958
|
+
* import paths that already materialize against current storage state.
|
|
959
|
+
*/
|
|
960
|
+
trustMaterializedState?: boolean;
|
|
961
|
+
}
|
|
962
|
+
type RebuildNodeIndexesOptions = SetNodeOptions;
|
|
963
|
+
type NodeBatchIndexMode = 'eager' | 'touched' | 'defer-schema';
|
|
964
|
+
interface NodeBatchPreflightResult {
|
|
965
|
+
/** Existing materialized nodes keyed by node ID. Missing node IDs are omitted. */
|
|
966
|
+
nodesById: Map<NodeId, NodeState>;
|
|
967
|
+
/** Latest known change for each requested node ID. Missing node IDs are omitted. */
|
|
968
|
+
lastChangesByNodeId: Map<NodeId, NodeChange>;
|
|
969
|
+
}
|
|
970
|
+
interface ApplyNodeBatchInput extends SetNodeOptions {
|
|
971
|
+
/** Batch ID shared by all supplied changes. */
|
|
972
|
+
batchId: string;
|
|
973
|
+
/** Final materialized state for changed nodes. */
|
|
974
|
+
nodes: readonly NodeState[];
|
|
975
|
+
/** Signed changes to append after materialized nodes exist. */
|
|
976
|
+
changes: readonly NodeChange[];
|
|
977
|
+
/** Last Lamport time after applying the batch. */
|
|
978
|
+
lastLamportTime: number;
|
|
979
|
+
/** Schemas affected by the batch, used for index/view invalidation. */
|
|
980
|
+
affectedSchemaIds: readonly SchemaIRI[];
|
|
981
|
+
/**
|
|
982
|
+
* Secondary index strategy for this batch.
|
|
983
|
+
*
|
|
984
|
+
* - `eager`: maintain indexes through the normal per-node write path.
|
|
985
|
+
* - `touched`: skip per-node indexes, then rebuild only touched node indexes.
|
|
986
|
+
* - `defer-schema`: skip indexes so the caller can rebuild affected schemas later.
|
|
987
|
+
*/
|
|
988
|
+
indexMode: NodeBatchIndexMode;
|
|
989
|
+
}
|
|
990
|
+
interface ApplyNodeBatchResult {
|
|
991
|
+
/** Number of materialized node rows written or updated. */
|
|
992
|
+
nodeRowsWritten: number;
|
|
993
|
+
/** Number of property rows considered for write. */
|
|
994
|
+
propertyRowsWritten: number;
|
|
995
|
+
/** Number of change rows considered for append. */
|
|
996
|
+
changeRowsWritten: number;
|
|
997
|
+
/** Number of scalar index rows written. */
|
|
998
|
+
scalarRowsWritten: number;
|
|
999
|
+
/** Number of full-text index rows written. */
|
|
1000
|
+
ftsRowsWritten: number;
|
|
1001
|
+
}
|
|
1002
|
+
type NodeBatchNotificationMode = 'per-node' | 'batch' | 'silent';
|
|
1003
|
+
type NodeBatchSyncMode = 'normal' | 'defer';
|
|
1004
|
+
interface NodeBatchWritePolicy {
|
|
1005
|
+
/** Secondary index strategy for this batch. */
|
|
1006
|
+
indexMode: NodeBatchIndexMode;
|
|
1007
|
+
/** Live notification strategy after the batch is durable. */
|
|
1008
|
+
notificationMode: NodeBatchNotificationMode;
|
|
1009
|
+
/** Advisory sync strategy for runtimes that can coalesce outbound replication. */
|
|
1010
|
+
syncMode: NodeBatchSyncMode;
|
|
1011
|
+
}
|
|
1012
|
+
interface NodeBatchWriteTimings {
|
|
1013
|
+
/** Existing-node and parent-change lookup time. */
|
|
1014
|
+
preflightMs: number;
|
|
1015
|
+
/** In-memory materialization and change signing time. */
|
|
1016
|
+
materializeMs: number;
|
|
1017
|
+
/** Storage apply time, including indexes owned by the adapter. */
|
|
1018
|
+
applyMs: number;
|
|
1019
|
+
/** Listener notification time after the storage commit. */
|
|
1020
|
+
notifyMs: number;
|
|
1021
|
+
/** Full wall time for the batch write call. */
|
|
1022
|
+
totalMs: number;
|
|
1023
|
+
}
|
|
1024
|
+
interface DeterministicNodeBatchWriteInput {
|
|
1025
|
+
kind: 'deterministic-import';
|
|
1026
|
+
drafts: readonly DeterministicNodeImportDraft[];
|
|
1027
|
+
policy?: Partial<NodeBatchWritePolicy>;
|
|
1028
|
+
}
|
|
1029
|
+
interface OperationNodeBatchWriteInput {
|
|
1030
|
+
kind: 'operations';
|
|
1031
|
+
operations: readonly TransactionOperation[];
|
|
1032
|
+
policy?: Partial<NodeBatchWritePolicy>;
|
|
1033
|
+
}
|
|
1034
|
+
type NodeBatchWriteInput = DeterministicNodeBatchWriteInput | OperationNodeBatchWriteInput;
|
|
1035
|
+
interface NodeBatchWriteResult {
|
|
1036
|
+
/** The batch ID shared by all changes. */
|
|
1037
|
+
batchId: string;
|
|
1038
|
+
/** Number of drafts that created a node at the time they were applied. */
|
|
1039
|
+
created: number;
|
|
1040
|
+
/** Number of drafts that updated a node at the time they were applied. */
|
|
1041
|
+
updated: number;
|
|
1042
|
+
/** Final node IDs touched by the batch. */
|
|
1043
|
+
nodeIds: NodeId[];
|
|
1044
|
+
/** Schemas whose materialized nodes changed. */
|
|
1045
|
+
schemaIds: SchemaIRI[];
|
|
1046
|
+
/** Number of signed changes appended by the batch. */
|
|
1047
|
+
changeCount: number;
|
|
1048
|
+
/** Storage-level write counters when the adapter reports them. */
|
|
1049
|
+
storage?: ApplyNodeBatchResult;
|
|
1050
|
+
/** Phase timings for import diagnostics and progress UIs. */
|
|
1051
|
+
timings: NodeBatchWriteTimings;
|
|
1052
|
+
}
|
|
1053
|
+
interface NodeBatchChangeEvent {
|
|
1054
|
+
/** The batch ID shared by all changes. */
|
|
1055
|
+
batchId: string;
|
|
1056
|
+
/** Final node IDs touched by the batch. */
|
|
1057
|
+
nodeIds: NodeId[];
|
|
1058
|
+
/** Schemas whose materialized nodes changed. */
|
|
1059
|
+
schemaIds: SchemaIRI[];
|
|
1060
|
+
/** Number of drafts that created a node at the time they were applied. */
|
|
1061
|
+
created: number;
|
|
1062
|
+
/** Number of drafts that updated a node at the time they were applied. */
|
|
1063
|
+
updated: number;
|
|
1064
|
+
/** Number of signed changes appended by the batch. */
|
|
1065
|
+
changeCount: number;
|
|
1066
|
+
/** Whether this was a remote change batch from sync. */
|
|
1067
|
+
isRemote: boolean;
|
|
1068
|
+
/** Storage-level write counters when the adapter reports them. */
|
|
1069
|
+
storage?: ApplyNodeBatchResult;
|
|
1070
|
+
/** Phase timings for import diagnostics and progress UIs. */
|
|
1071
|
+
timings: NodeBatchWriteTimings;
|
|
1072
|
+
}
|
|
1073
|
+
interface ListNodesOptions {
|
|
1074
|
+
/** Filter by schema IRI */
|
|
1075
|
+
schemaId?: SchemaIRI;
|
|
1076
|
+
/** Include soft-deleted nodes */
|
|
1077
|
+
includeDeleted?: boolean;
|
|
1078
|
+
/** Sort by system metadata fields */
|
|
1079
|
+
orderBy?: Partial<Record<SystemOrderField, SortDirection>>;
|
|
1080
|
+
/** Limit results */
|
|
1081
|
+
limit?: number;
|
|
1082
|
+
/** Offset for pagination */
|
|
1083
|
+
offset?: number;
|
|
1084
|
+
}
|
|
1085
|
+
interface CountNodesOptions {
|
|
1086
|
+
/** Filter by schema IRI */
|
|
1087
|
+
schemaId?: SchemaIRI;
|
|
1088
|
+
/** Include soft-deleted nodes */
|
|
1089
|
+
includeDeleted?: boolean;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* Result of LWW conflict resolution for a property.
|
|
1093
|
+
*/
|
|
1094
|
+
interface ConflictResult {
|
|
1095
|
+
/** Which value won */
|
|
1096
|
+
winner: 'local' | 'remote';
|
|
1097
|
+
/** The property key */
|
|
1098
|
+
key: PropertyKey;
|
|
1099
|
+
/** The winning value */
|
|
1100
|
+
value: unknown;
|
|
1101
|
+
/** The winning timestamp */
|
|
1102
|
+
timestamp: PropertyTimestamp;
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Conflict detected during merge (for debugging/UI).
|
|
1106
|
+
*/
|
|
1107
|
+
interface MergeConflict {
|
|
1108
|
+
nodeId: NodeId;
|
|
1109
|
+
key: PropertyKey;
|
|
1110
|
+
localValue: unknown;
|
|
1111
|
+
localTimestamp: PropertyTimestamp;
|
|
1112
|
+
remoteValue: unknown;
|
|
1113
|
+
remoteTimestamp: PropertyTimestamp;
|
|
1114
|
+
resolved: 'local' | 'remote';
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Callback to get the known property names for a schema.
|
|
1118
|
+
* Used for unknown property preservation during version compatibility.
|
|
1119
|
+
* Returns the set of property names defined in the schema,
|
|
1120
|
+
* or undefined if the schema is not available (all properties treated as known).
|
|
1121
|
+
*/
|
|
1122
|
+
type PropertyLookup = (schemaId: SchemaIRI) => Set<string> | undefined;
|
|
1123
|
+
/**
|
|
1124
|
+
* Options for creating a NodeStore.
|
|
1125
|
+
*/
|
|
1126
|
+
interface NodeStoreOptions {
|
|
1127
|
+
/** Storage adapter */
|
|
1128
|
+
storage: NodeStorageAdapter;
|
|
1129
|
+
/** Author's DID */
|
|
1130
|
+
authorDID: DID$1;
|
|
1131
|
+
/** Ed25519 signing key */
|
|
1132
|
+
signingKey: Uint8Array;
|
|
1133
|
+
/**
|
|
1134
|
+
* Optional async change signer (e.g. `createWebCryptoChangeSigner` from
|
|
1135
|
+
* @xnetjs/sync, or a worker-backed signer). Signatures must be
|
|
1136
|
+
* byte-identical to the synchronous Ed25519 path. When omitted, changes
|
|
1137
|
+
* are signed synchronously with `signingKey` on the calling thread.
|
|
1138
|
+
*/
|
|
1139
|
+
changeSigner?: ChangeSigner;
|
|
1140
|
+
/**
|
|
1141
|
+
* Optional schema lookup for temp ID resolution in relation properties.
|
|
1142
|
+
* When provided, `transaction()` will resolve `~`-prefixed temp IDs in
|
|
1143
|
+
* properties whose schema type is `'relation'`.
|
|
1144
|
+
* Without this, temp IDs are only resolved in operation ID fields.
|
|
1145
|
+
*/
|
|
1146
|
+
schemaLookup?: SchemaLookup;
|
|
1147
|
+
/**
|
|
1148
|
+
* Optional property lookup for unknown property preservation.
|
|
1149
|
+
* When provided, properties not in the schema are stored in `_unknown`.
|
|
1150
|
+
* Without this, all properties are stored as known properties.
|
|
1151
|
+
*/
|
|
1152
|
+
propertyLookup?: PropertyLookup;
|
|
1153
|
+
/**
|
|
1154
|
+
* Optional lens registry for automatic schema migrations.
|
|
1155
|
+
* When provided, nodes are automatically migrated to the target schema
|
|
1156
|
+
* version on read (getWithMigration). Without this, nodes are returned as-is.
|
|
1157
|
+
*/
|
|
1158
|
+
lensRegistry?: LensRegistry;
|
|
1159
|
+
/** Optional authorization evaluator used for mutation gating. */
|
|
1160
|
+
authEvaluator?: PolicyEvaluator;
|
|
1161
|
+
/**
|
|
1162
|
+
* Optional transparent node content cipher.
|
|
1163
|
+
*
|
|
1164
|
+
* When provided, NodeStore writes encrypted node payload snapshots via
|
|
1165
|
+
* `setDocumentContent()` and decrypts them on read paths.
|
|
1166
|
+
*/
|
|
1167
|
+
nodeContentCipher?: NodeContentCipher;
|
|
1168
|
+
/**
|
|
1169
|
+
* Optional cache for per-node content keys used by `nodeContentCipher`.
|
|
1170
|
+
*
|
|
1171
|
+
* This avoids expensive key unwraps on repeated reads.
|
|
1172
|
+
*/
|
|
1173
|
+
contentKeyCache?: ContentKeyCache;
|
|
1174
|
+
/**
|
|
1175
|
+
* Optional lookup for properties that can change node recipients.
|
|
1176
|
+
* When provided, update paths only trigger recipient recomputation hooks
|
|
1177
|
+
* if one of these properties is changed.
|
|
1178
|
+
*/
|
|
1179
|
+
authRelevantPropertyLookup?: (schemaId: SchemaIRI) => Set<string> | undefined;
|
|
1180
|
+
/**
|
|
1181
|
+
* Optional callback triggered when an update touches auth-relevant properties.
|
|
1182
|
+
* Integrators can use this to recompute recipients and rotate keys.
|
|
1183
|
+
*/
|
|
1184
|
+
onRecipientsMayNeedRecompute?: (context: {
|
|
1185
|
+
nodeId: NodeId;
|
|
1186
|
+
schemaId: SchemaIRI;
|
|
1187
|
+
changedProperties: string[];
|
|
1188
|
+
}) => Promise<void> | void;
|
|
1189
|
+
/**
|
|
1190
|
+
* Optional callback for rejected unauthorized remote changes.
|
|
1191
|
+
* Remote unauthorized changes are rejected silently and never applied.
|
|
1192
|
+
*/
|
|
1193
|
+
onUnauthorizedRemoteChange?: (context: {
|
|
1194
|
+
change: NodeChange;
|
|
1195
|
+
action: AuthAction;
|
|
1196
|
+
decision: AuthDecision;
|
|
1197
|
+
}) => void;
|
|
1198
|
+
/** Optional high-level authorization API attached as `store.auth`. */
|
|
1199
|
+
auth?: StoreAuthAPI;
|
|
1200
|
+
/**
|
|
1201
|
+
* Optional telemetry collector for tracking CRUD operations, errors, and performance.
|
|
1202
|
+
* When provided, NodeStore will report:
|
|
1203
|
+
* - Performance metrics for create/update/delete/list operations
|
|
1204
|
+
* - Usage metrics for operation counts
|
|
1205
|
+
* - Crash reports for errors
|
|
1206
|
+
*
|
|
1207
|
+
* Compatible with @xnetjs/telemetry TelemetryCollector.
|
|
1208
|
+
*/
|
|
1209
|
+
telemetry?: {
|
|
1210
|
+
reportPerformance(metricName: string, durationMs: number, codeNamespace?: string): void;
|
|
1211
|
+
reportUsage(metricName: string, value: number): void;
|
|
1212
|
+
reportCrash(error: Error, context?: {
|
|
1213
|
+
codeNamespace?: string;
|
|
1214
|
+
}): void;
|
|
1215
|
+
reportSecurityEvent(eventName: string, severity: 'low' | 'medium' | 'high' | 'critical'): void;
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Cache for per-node content keys used during transparent decrypt/encrypt flows.
|
|
1220
|
+
*/
|
|
1221
|
+
interface ContentKeyCache {
|
|
1222
|
+
get(nodeId: NodeId): Uint8Array | undefined;
|
|
1223
|
+
set(nodeId: NodeId, key: Uint8Array): void;
|
|
1224
|
+
delete(nodeId: NodeId): void;
|
|
1225
|
+
clear?(): void;
|
|
1226
|
+
}
|
|
1227
|
+
/**
|
|
1228
|
+
* Pluggable cipher for transparent node payload encryption.
|
|
1229
|
+
*/
|
|
1230
|
+
interface NodeContentCipher {
|
|
1231
|
+
encrypt(input: {
|
|
1232
|
+
nodeId: NodeId;
|
|
1233
|
+
schemaId: SchemaIRI;
|
|
1234
|
+
content: Uint8Array;
|
|
1235
|
+
cachedContentKey?: Uint8Array;
|
|
1236
|
+
}): Promise<{
|
|
1237
|
+
encryptedContent: Uint8Array;
|
|
1238
|
+
contentKey?: Uint8Array;
|
|
1239
|
+
}>;
|
|
1240
|
+
decrypt(input: {
|
|
1241
|
+
nodeId: NodeId;
|
|
1242
|
+
schemaId: SchemaIRI;
|
|
1243
|
+
encryptedContent: Uint8Array;
|
|
1244
|
+
cachedContentKey?: Uint8Array;
|
|
1245
|
+
}): Promise<{
|
|
1246
|
+
content: Uint8Array;
|
|
1247
|
+
contentKey?: Uint8Array;
|
|
1248
|
+
}>;
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Options for creating a Node.
|
|
1252
|
+
*/
|
|
1253
|
+
interface CreateNodeOptions$1 {
|
|
1254
|
+
/** Optional ID (generated if not provided) */
|
|
1255
|
+
id?: NodeId;
|
|
1256
|
+
/** Schema IRI */
|
|
1257
|
+
schemaId: SchemaIRI;
|
|
1258
|
+
/** Initial property values */
|
|
1259
|
+
properties: Record<PropertyKey, unknown>;
|
|
1260
|
+
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Options for updating a Node.
|
|
1263
|
+
*/
|
|
1264
|
+
interface UpdateNodeOptions {
|
|
1265
|
+
/** Changed properties (sparse) */
|
|
1266
|
+
properties: Record<PropertyKey, unknown>;
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* A deterministic node import draft.
|
|
1270
|
+
*
|
|
1271
|
+
* Intended for importers that already know stable node IDs and want one
|
|
1272
|
+
* signed change per draft while avoiding per-node storage transactions.
|
|
1273
|
+
*/
|
|
1274
|
+
interface DeterministicNodeImportDraft {
|
|
1275
|
+
/** Stable node ID to create or update */
|
|
1276
|
+
id: NodeId;
|
|
1277
|
+
/** Schema IRI used when the node does not already exist */
|
|
1278
|
+
schemaId: SchemaIRI;
|
|
1279
|
+
/** Properties to merge with LWW semantics */
|
|
1280
|
+
properties: Record<PropertyKey, unknown>;
|
|
1281
|
+
}
|
|
1282
|
+
interface ImportDeterministicNodesOptions {
|
|
1283
|
+
/**
|
|
1284
|
+
* Secondary index strategy for this import. Defaults to `touched`, which is
|
|
1285
|
+
* optimized for bulk imports when storage supports `applyNodeBatch()`.
|
|
1286
|
+
*/
|
|
1287
|
+
indexMode?: NodeBatchIndexMode;
|
|
1288
|
+
/**
|
|
1289
|
+
* Skip secondary index maintenance for this chunk. Call
|
|
1290
|
+
* `NodeStore.rebuildIndexesForSchemas()` for the affected schemas before
|
|
1291
|
+
* relying on indexed queries.
|
|
1292
|
+
*
|
|
1293
|
+
* @deprecated Prefer `indexMode: 'defer-schema'`.
|
|
1294
|
+
*/
|
|
1295
|
+
deferIndexes?: boolean;
|
|
1296
|
+
}
|
|
1297
|
+
interface ImportDeterministicNodesResult {
|
|
1298
|
+
/** The batch ID shared by all imported changes */
|
|
1299
|
+
batchId: string;
|
|
1300
|
+
/** Number of drafts that created a node at the time they were applied */
|
|
1301
|
+
created: number;
|
|
1302
|
+
/** Number of drafts that updated a node at the time they were applied */
|
|
1303
|
+
updated: number;
|
|
1304
|
+
/** Final materialized state for each changed node */
|
|
1305
|
+
nodes: NodeState[];
|
|
1306
|
+
/** All signed changes created for the import */
|
|
1307
|
+
changes: NodeChange[];
|
|
1308
|
+
/** Schemas whose materialized nodes changed */
|
|
1309
|
+
affectedSchemaIds: SchemaIRI[];
|
|
1310
|
+
/** Storage-level write counters when the adapter reports them. */
|
|
1311
|
+
storage?: ApplyNodeBatchResult;
|
|
1312
|
+
/** Phase timings for import diagnostics and progress UIs. */
|
|
1313
|
+
timings: NodeBatchWriteTimings;
|
|
1314
|
+
}
|
|
1315
|
+
/**
|
|
1316
|
+
* A single operation within a transaction.
|
|
1317
|
+
*/
|
|
1318
|
+
type TransactionOperation = {
|
|
1319
|
+
type: 'create';
|
|
1320
|
+
options: CreateNodeOptions$1;
|
|
1321
|
+
} | {
|
|
1322
|
+
type: 'update';
|
|
1323
|
+
nodeId: NodeId;
|
|
1324
|
+
options: UpdateNodeOptions;
|
|
1325
|
+
} | {
|
|
1326
|
+
type: 'delete';
|
|
1327
|
+
nodeId: NodeId;
|
|
1328
|
+
} | {
|
|
1329
|
+
type: 'restore';
|
|
1330
|
+
nodeId: NodeId;
|
|
1331
|
+
};
|
|
1332
|
+
/**
|
|
1333
|
+
* Result of a transaction execution.
|
|
1334
|
+
* Returns the affected nodes in the same order as operations.
|
|
1335
|
+
*/
|
|
1336
|
+
interface TransactionResult {
|
|
1337
|
+
/** The batch ID shared by all changes */
|
|
1338
|
+
batchId: string;
|
|
1339
|
+
/** Results for each operation (NodeState or null for delete) */
|
|
1340
|
+
results: (NodeState | null)[];
|
|
1341
|
+
/** All changes created in this transaction */
|
|
1342
|
+
changes: NodeChange[];
|
|
1343
|
+
/** Map from temp ID → generated real ID (empty if no temp IDs were used) */
|
|
1344
|
+
tempIds: Record<string, NodeId>;
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* Event emitted when a Node changes.
|
|
1348
|
+
*/
|
|
1349
|
+
interface NodeChangeEvent {
|
|
1350
|
+
/** The change that was applied */
|
|
1351
|
+
change: NodeChange;
|
|
1352
|
+
/** The node state before the change was applied */
|
|
1353
|
+
previousNode: NodeState | null;
|
|
1354
|
+
/** The resulting Node state */
|
|
1355
|
+
node: NodeState | null;
|
|
1356
|
+
/** Whether this was a remote change (from sync) */
|
|
1357
|
+
isRemote: boolean;
|
|
1358
|
+
}
|
|
1359
|
+
/**
|
|
1360
|
+
* Listener for Node change events.
|
|
1361
|
+
*/
|
|
1362
|
+
type NodeChangeListener = (event: NodeChangeEvent) => void;
|
|
1363
|
+
type NodeBatchChangeListener = (event: NodeBatchChangeEvent) => void;
|
|
1364
|
+
/**
|
|
1365
|
+
* Options for getWithMigration.
|
|
1366
|
+
*/
|
|
1367
|
+
interface GetWithMigrationOptions {
|
|
1368
|
+
/** Target schema IRI to migrate to (required) */
|
|
1369
|
+
targetSchemaId: SchemaIRI;
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Information about a migration that was applied.
|
|
1373
|
+
*/
|
|
1374
|
+
interface MigrationInfo {
|
|
1375
|
+
/** The original schema IRI of the stored data */
|
|
1376
|
+
from: SchemaIRI;
|
|
1377
|
+
/** The target schema IRI */
|
|
1378
|
+
to: SchemaIRI;
|
|
1379
|
+
/** Whether the migration preserved all data (no data loss) */
|
|
1380
|
+
lossless: boolean;
|
|
1381
|
+
/** Warnings about potential data loss */
|
|
1382
|
+
warnings: string[];
|
|
1383
|
+
}
|
|
1384
|
+
/**
|
|
1385
|
+
* Result of getWithMigration.
|
|
1386
|
+
*/
|
|
1387
|
+
interface MigratedNodeState extends NodeState {
|
|
1388
|
+
/**
|
|
1389
|
+
* Migration info if the node was migrated from a different schema version.
|
|
1390
|
+
* Undefined if no migration was needed.
|
|
1391
|
+
*/
|
|
1392
|
+
_migrationInfo?: MigrationInfo;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* Schema types for xNet's code-first schema system.
|
|
1397
|
+
*/
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Property type identifiers.
|
|
1401
|
+
*/
|
|
1402
|
+
type PropertyType = 'text' | 'number' | 'checkbox' | 'json' | 'date' | 'dateRange' | 'select' | 'multiSelect' | 'person' | 'relation' | 'rollup' | 'formula' | 'url' | 'email' | 'phone' | 'file' | 'created' | 'updated' | 'createdBy';
|
|
1403
|
+
/**
|
|
1404
|
+
* Base property definition stored in a schema.
|
|
1405
|
+
*/
|
|
1406
|
+
interface PropertyDefinition {
|
|
1407
|
+
/** Property IRI (e.g., 'xnet://xnet.fyi/Task#title') */
|
|
1408
|
+
'@id': string;
|
|
1409
|
+
/** Property name */
|
|
1410
|
+
name: string;
|
|
1411
|
+
/** Property type */
|
|
1412
|
+
type: PropertyType;
|
|
1413
|
+
/** Whether this property is required */
|
|
1414
|
+
required: boolean;
|
|
1415
|
+
/** Type-specific configuration */
|
|
1416
|
+
config?: Record<string, unknown>;
|
|
1417
|
+
/**
|
|
1418
|
+
* When true, this property is schema-defined and structurally locked: the
|
|
1419
|
+
* universal/extension grid must not let the user rename, retype, or delete
|
|
1420
|
+
* the column (values stay editable). Set by `buildEffectiveSchema` on the
|
|
1421
|
+
* core properties of a schema that is being extended; user-added extension
|
|
1422
|
+
* fields are never readonly. Absent/false for ordinary schema properties.
|
|
1423
|
+
*/
|
|
1424
|
+
readonly?: boolean;
|
|
1425
|
+
}
|
|
1426
|
+
/**
|
|
1427
|
+
* A property builder returned by property helper functions.
|
|
1428
|
+
* Contains both the definition and runtime validation/coercion.
|
|
1429
|
+
*/
|
|
1430
|
+
interface PropertyBuilder<T = unknown> {
|
|
1431
|
+
/** The property definition for schema storage */
|
|
1432
|
+
definition: Omit<PropertyDefinition, '@id' | 'name'>;
|
|
1433
|
+
/** Validate a value against this property type */
|
|
1434
|
+
validate(value: unknown): value is T;
|
|
1435
|
+
/** Coerce a value to this property type (returns null if invalid) */
|
|
1436
|
+
coerce(value: unknown): T | null;
|
|
1437
|
+
/** TypeScript type marker (never used at runtime) */
|
|
1438
|
+
_type: T;
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* CRDT document type for collaborative content.
|
|
1442
|
+
*
|
|
1443
|
+
* When a schema specifies a document type, nodes of that schema
|
|
1444
|
+
* have an associated CRDT document that syncs via the CRDT's
|
|
1445
|
+
* native protocol (e.g., y-webrtc for Yjs).
|
|
1446
|
+
*
|
|
1447
|
+
* - 'yjs': Yjs Y.Doc for collaborative rich text, canvas, etc.
|
|
1448
|
+
* - 'automerge': Automerge document (future support)
|
|
1449
|
+
*/
|
|
1450
|
+
type DocumentType = 'yjs' | 'automerge';
|
|
1451
|
+
/**
|
|
1452
|
+
* Schema definition stored as JSON-LD.
|
|
1453
|
+
*/
|
|
1454
|
+
interface Schema {
|
|
1455
|
+
/** Schema IRI */
|
|
1456
|
+
'@id': SchemaIRI;
|
|
1457
|
+
/** Type marker for JSON-LD */
|
|
1458
|
+
'@type': 'xnet://xnet.fyi/Schema';
|
|
1459
|
+
/** Human-readable name */
|
|
1460
|
+
name: string;
|
|
1461
|
+
/** Namespace for this schema */
|
|
1462
|
+
namespace: string;
|
|
1463
|
+
/**
|
|
1464
|
+
* Schema version in semver format.
|
|
1465
|
+
* Included in IRI as `@version` suffix.
|
|
1466
|
+
*/
|
|
1467
|
+
version: string;
|
|
1468
|
+
/**
|
|
1469
|
+
* Previous schema IRI to migrate from.
|
|
1470
|
+
* Used for automatic migration path discovery.
|
|
1471
|
+
*/
|
|
1472
|
+
migrateFrom?: SchemaIRI;
|
|
1473
|
+
/** Property definitions */
|
|
1474
|
+
properties: PropertyDefinition[];
|
|
1475
|
+
/** Parent schema IRI (for inheritance) */
|
|
1476
|
+
extends?: SchemaIRI;
|
|
1477
|
+
/**
|
|
1478
|
+
* CRDT document type for collaborative content.
|
|
1479
|
+
* When set, nodes of this schema have an associated CRDT document
|
|
1480
|
+
* that syncs separately from properties (which use LWW).
|
|
1481
|
+
*/
|
|
1482
|
+
document?: DocumentType;
|
|
1483
|
+
/**
|
|
1484
|
+
* Authorization rules for this schema.
|
|
1485
|
+
* Defines roles, action permissions, and access control policies.
|
|
1486
|
+
* When present, nodes of this schema are encrypted and access is controlled.
|
|
1487
|
+
*/
|
|
1488
|
+
authorization?: SerializedAuthorization;
|
|
1489
|
+
}
|
|
1490
|
+
/**
|
|
1491
|
+
* Validation result from schema validation.
|
|
1492
|
+
*/
|
|
1493
|
+
interface ValidationResult {
|
|
1494
|
+
valid: boolean;
|
|
1495
|
+
errors: ValidationError[];
|
|
1496
|
+
}
|
|
1497
|
+
/**
|
|
1498
|
+
* A single validation error.
|
|
1499
|
+
*/
|
|
1500
|
+
interface ValidationError {
|
|
1501
|
+
path: string;
|
|
1502
|
+
message: string;
|
|
1503
|
+
value?: unknown;
|
|
1504
|
+
}
|
|
1505
|
+
/**
|
|
1506
|
+
* Options for creating a node from a schema.
|
|
1507
|
+
*/
|
|
1508
|
+
interface CreateNodeOptions {
|
|
1509
|
+
/** Override the generated ID */
|
|
1510
|
+
id?: string;
|
|
1511
|
+
/** The creator's DID */
|
|
1512
|
+
createdBy: DID;
|
|
1513
|
+
/** Override the creation timestamp */
|
|
1514
|
+
createdAt?: number;
|
|
1515
|
+
}
|
|
1516
|
+
/**
|
|
1517
|
+
* A defined schema with runtime methods.
|
|
1518
|
+
*/
|
|
1519
|
+
interface DefinedSchema<TProperties extends Record<string, PropertyBuilder> = Record<string, PropertyBuilder>> {
|
|
1520
|
+
/** The schema definition (JSON-LD compatible) */
|
|
1521
|
+
schema: Schema;
|
|
1522
|
+
/** Validate a node against this schema */
|
|
1523
|
+
validate(node: unknown): ValidationResult;
|
|
1524
|
+
/** Create a new node of this schema type */
|
|
1525
|
+
create(properties: InferCreateProps<TProperties>, options: CreateNodeOptions): InferNode<TProperties>;
|
|
1526
|
+
/** Type guard - check if a node matches this schema */
|
|
1527
|
+
is(node: Node): node is InferNode<TProperties>;
|
|
1528
|
+
/** Schema IRI for type inference */
|
|
1529
|
+
readonly _schemaId: SchemaIRI;
|
|
1530
|
+
/** Property builders for type inference */
|
|
1531
|
+
readonly _properties: TProperties;
|
|
1532
|
+
}
|
|
1533
|
+
/**
|
|
1534
|
+
* Infer the TypeScript type from a property builder.
|
|
1535
|
+
*/
|
|
1536
|
+
type InferPropertyType<B> = B extends PropertyBuilder<infer T> ? T : never;
|
|
1537
|
+
/**
|
|
1538
|
+
* Infer required properties from a record of property builders.
|
|
1539
|
+
*/
|
|
1540
|
+
type RequiredKeys<P extends Record<string, PropertyBuilder>> = {
|
|
1541
|
+
[K in keyof P]: P[K]['definition']['required'] extends true ? K : never;
|
|
1542
|
+
}[keyof P];
|
|
1543
|
+
/**
|
|
1544
|
+
* Infer optional properties from a record of property builders.
|
|
1545
|
+
*/
|
|
1546
|
+
type OptionalKeys<P extends Record<string, PropertyBuilder>> = {
|
|
1547
|
+
[K in keyof P]: P[K]['definition']['required'] extends true ? never : K;
|
|
1548
|
+
}[keyof P];
|
|
1549
|
+
/**
|
|
1550
|
+
* Infer the properties type from property builders.
|
|
1551
|
+
*/
|
|
1552
|
+
type InferProperties<P extends Record<string, PropertyBuilder>> = {
|
|
1553
|
+
[K in RequiredKeys<P>]: InferPropertyType<P[K]>;
|
|
1554
|
+
} & {
|
|
1555
|
+
[K in OptionalKeys<P>]?: InferPropertyType<P[K]>;
|
|
1556
|
+
};
|
|
1557
|
+
/**
|
|
1558
|
+
* Infer the create props (what you pass to create()).
|
|
1559
|
+
* Same as InferProperties but allows undefined for optional fields.
|
|
1560
|
+
*/
|
|
1561
|
+
type InferCreateProps<P extends Record<string, PropertyBuilder>> = {
|
|
1562
|
+
[K in RequiredKeys<P>]: InferPropertyType<P[K]>;
|
|
1563
|
+
} & {
|
|
1564
|
+
[K in OptionalKeys<P>]?: InferPropertyType<P[K]> | undefined;
|
|
1565
|
+
};
|
|
1566
|
+
/**
|
|
1567
|
+
* Infer the full Node type from property builders.
|
|
1568
|
+
*/
|
|
1569
|
+
type InferNode<P extends Record<string, PropertyBuilder>> = {
|
|
1570
|
+
id: string;
|
|
1571
|
+
schemaId: SchemaIRI;
|
|
1572
|
+
createdAt: number;
|
|
1573
|
+
createdBy: DID;
|
|
1574
|
+
} & InferProperties<P>;
|
|
1575
|
+
|
|
1576
|
+
export { type PropertyKey as $, createNodeId as A, type PropertyType as B, type CreateNodeOptions$1 as C, type DefinedSchema as D, type PropertyDefinition as E, type ValidationError as F, type GetWithMigrationOptions as G, type CreateNodeOptions as H, type InferCreateProps as I, type InferPropertyType as J, type InferProperties as K, type ListNodesOptions as L, type MigratedNodeState as M, type NodeQueryPageCountMode as N, type OfflineAuthPolicy as O, type PropertyBuilder as P, type InferNode as Q, type SchemaLens as R, type SchemaIRI as S, type TransactionOperation as T, type UpdateNodeOptions as U, type ValidationResult as V, type LensOperation as W, type MigrationResult as X, MigrationError as Y, LensRegistry as Z, lensRegistry as _, type Schema as a, type StoreAuthKeyManager as a$, type NodePayload as a0, type PropertyTimestamp as a1, type SetNodeOptions as a2, type ImportNodesOptions as a3, type RebuildNodeIndexesOptions as a4, type ApplyNodeBatchInput as a5, type ApplyNodeBatchResult as a6, type NodeBatchIndexMode as a7, type NodeBatchNotificationMode as a8, type NodeBatchSyncMode as a9, createNodeQueryDescriptor as aA, encodeNodeQueryCursor as aB, decodeNodeQueryCursor as aC, nodeQueryDescriptorToOptions as aD, serializeNodeQueryDescriptor as aE, matchesNodeQueryDescriptor as aF, filterNodeQueryResults as aG, sortNodeQueryResults as aH, applyNodeQueryDescriptor as aI, getNodeQuerySearchTokens as aJ, nodeQueryDescriptorNeedsBoundedReload as aK, withoutNodeQueryPagination as aL, withoutNodeQueryMaterializedView as aM, isTempId as aN, TEMP_ID_PREFIX as aO, resolveTempIds as aP, createSchemaLookup as aQ, type SchemaLookup as aR, type TempIdResolution as aS, StoreAuth as aT, GrantRateLimiter as aU, GRANT_SCHEMA_IRI as aV, isGrantActive as aW, DEFAULT_OFFLINE_POLICY as aX, mergeOfflinePolicy as aY, type StoreAuthOptions as aZ, type StoreAuthStore as a_, type NodeBatchPreflightResult as aa, type DeterministicNodeBatchWriteInput as ab, type NodeBatchWritePolicy as ac, type NodeBatchWriteTimings as ad, type CountNodesOptions as ae, type NodeQuerySpatialPoint as af, type NodeQuerySpatialRect as ag, type NodeQuerySpatialPointFields as ah, type NodeQuerySpatialRectFields as ai, type NodeQuerySpatialWindow as aj, type NodeQuerySpatialRadius as ak, type NodeQuerySpatialFilter as al, type NodeQuerySearchField as am, type NodeQuerySearchFilter as an, type NodeQueryMaterializedViewOptions as ao, type NodeQueryPageOptions as ap, type NodeQueryCursorOrderEntry as aq, type NodeQueryCursor as ar, type NodeQueryOptions as as, type NodeQueryPlanMetadata as at, type NodeQueryParityCheckMetadata as au, type ConflictResult as av, type NodeBatchChangeEvent as aw, type NodeContentCipher as ax, type ContentKeyCache as ay, type MigrationInfo as az, type ParsedSchemaIRI as b, type GrantInput as b0, type Grant as b1, StoreAuthError as b2, type StoreAuthErrorCode as b3, type GrantNode as b4, type GrantIndexStore as b5, type GrantIndexOptions as b6, type RevocationConsistency as b7, type RevocationConfig as b8, type GrantRateLimiterOptions as b9, type DocumentType as ba, DEFAULT_SCHEMA_VERSION as bb, parseSchemaIRI as bc, buildSchemaIRI as bd, normalizeSchemaIRI as be, getBaseSchemaIRI as bf, isSameSchema as bg, getSchemaVersion as bh, type NodeReadAuthorizer as bi, type AuthorizationStateVersion as bj, type OperationNodeBatchWriteInput as bk, type PropertyLookup as bl, createPropertyLookup as bm, type SortDirection as c, type SystemOrderField as d, type StoreAuthAPI as e, type NodeStoreOptions as f, type NodeStorageAdapter as g, type NodeState as h, type NodeId as i, type NodeQueryDescriptor as j, type NodeQueryResult as k, type TransactionResult as l, type DeterministicNodeImportDraft as m, type ImportDeterministicNodesOptions as n, type ImportDeterministicNodesResult as o, type NodeBatchWriteInput as p, type NodeBatchWriteResult as q, type NodeChange as r, type MergeConflict as s, type NodeChangeListener as t, type NodeBatchChangeListener as u, type NodeChangeEvent as v, GrantIndex as w, type Node as x, type DID as y, isNode as z };
|