@asaidimu/utils-workspace 2.0.0 → 2.1.1

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/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { QueryFilter, PaginationOptions } from '@asaidimu/query';
2
+ import { IndexDefinition, SchemaDefinition, SchemaChange, DataTransform } from '@asaidimu/anansi';
3
+
1
4
  type UUID = string;
2
5
  type Timestamp = string;
3
6
  type URI = string;
@@ -29,7 +32,7 @@ type WorkspaceError = {
29
32
  };
30
33
  interface Settings {
31
34
  language: string;
32
- defaultRole: string;
35
+ defaultRole?: string;
33
36
  prompt?: string;
34
37
  }
35
38
  interface Project {
@@ -61,8 +64,7 @@ type ResolvedBlob = {
61
64
  };
62
65
  /**
63
66
  * Full registry entry for a blob. BlobRef is a Pick of this type, so
64
- * a BlobRecord is always assignable to BlobRef. BlobSummary has been
65
- * removed — callers that previously used BlobSummary use BlobRecord directly.
67
+ * a BlobRecord is always assignable to BlobRef.
66
68
  */
67
69
  interface BlobRecord {
68
70
  sha256: SHA256;
@@ -124,11 +126,26 @@ interface Turn {
124
126
  role: TurnRole;
125
127
  blocks: ContentBlock[];
126
128
  timestamp: Timestamp;
129
+ /**
130
+ * The name of the role active when this turn was recorded.
131
+ * Snapshot so history is stable even if the role is later renamed.
132
+ */
127
133
  roleSnapshot?: string;
134
+ /**
135
+ * Parent pointer. Null for root turns.
136
+ * This is plain data stored on the document — the DAG is reconstructed
137
+ * in memory by TurnTree.buildNodeGraph() at session open time.
138
+ */
128
139
  parent: {
129
140
  id: UUID;
130
141
  version: number;
131
142
  } | null;
143
+ /**
144
+ * Partition key. Stored on the Turn document so Collection.filter
145
+ * can retrieve all turns for a session in a single query.
146
+ * Not present on Turn objects used purely in memory (e.g. dirty buffer).
147
+ */
148
+ sessionId?: UUID;
132
149
  }
133
150
  interface TurnNode {
134
151
  id: UUID;
@@ -145,63 +162,53 @@ interface TurnNode {
145
162
  children: Record<number, UUID[]>;
146
163
  }
147
164
  interface BranchInfo {
148
- /** All sibling versions at this level, in insertion order. */
149
165
  versions: number[];
150
- /** Index of this turn within siblings (0-based). */
151
166
  currentIndex: number;
152
- /** Convenience: number of siblings (siblings.length). */
153
167
  total: number;
154
- /** True when there is a branch to the left. */
155
168
  hasPrev: boolean;
156
- /** True when there is a branch to the right. */
157
169
  hasNext: boolean;
158
170
  }
159
- interface RoleSummary {
171
+ interface Role {
160
172
  name: string;
161
173
  label: string;
162
174
  description?: string;
163
- preferences: number;
175
+ persona: string;
176
+ preferences: UUID[];
164
177
  }
165
- interface PreferenceSummary {
178
+ interface Preference {
166
179
  id: UUID;
180
+ content: string;
167
181
  topics: string[];
168
182
  timestamp: Timestamp;
169
- snippet?: string;
170
183
  }
171
- interface ContextSummary {
184
+ type ContextContent = {
185
+ kind: 'text';
186
+ value: string;
187
+ } | {
188
+ kind: 'json';
189
+ value: unknown;
190
+ } | {
191
+ kind: 'blob';
192
+ sha256: SHA256;
193
+ mediaType: BlobMediaType;
194
+ sizeBytes: number;
195
+ filename?: string;
196
+ } | {
197
+ kind: 'remote';
198
+ uri: URI;
199
+ mediaType?: BlobMediaType;
200
+ };
201
+ interface Context {
172
202
  key: string;
173
203
  topics: string[];
204
+ content: ContextContent;
174
205
  timestamp: Timestamp;
175
- mime?: string;
176
- size?: number;
177
- preview?: string;
178
- source?: string;
179
206
  metadata?: Record<string, any>;
180
207
  }
181
- interface TopicIndex {
182
- topic: string;
183
- contextKeys: string[];
184
- preferences: UUID[];
185
- metadata?: {
186
- created?: Timestamp;
187
- updated?: Timestamp;
188
- entries?: number;
189
- };
190
- }
191
- interface Workspace {
192
- id: UUID;
193
- settings: Settings;
194
- project: Project;
195
- index: Index;
196
- }
197
- interface Index {
198
- format: string;
199
- roles: Record<string, RoleSummary>;
200
- preferences: Record<UUID, PreferenceSummary>;
201
- context: Record<string, ContextSummary>;
202
- sessions: Record<UUID, SessionMeta>;
203
- topics: Record<string, TopicIndex>;
204
- }
208
+ /**
209
+ * SessionMeta is stored as a document in the 'session' collection.
210
+ * The head pointer lives here — no separate session_heads store needed.
211
+ */
205
212
  interface SessionMeta {
206
213
  id: UUID;
207
214
  label: string;
@@ -218,69 +225,64 @@ interface SessionMeta {
218
225
  version: number;
219
226
  } | null;
220
227
  }
221
- interface Role {
222
- id: UUID;
228
+ interface RoleSummary {
223
229
  name: string;
224
230
  label: string;
225
- persona: string;
226
231
  description?: string;
227
- preferences: UUID[];
232
+ /** Number of preference IDs listed on the role. */
233
+ preferences: number;
228
234
  }
229
- interface Preference {
235
+ interface PreferenceSummary {
230
236
  id: UUID;
231
- content: string;
232
237
  topics: string[];
233
238
  timestamp: Timestamp;
239
+ snippet?: string;
234
240
  }
235
- interface Context {
241
+ interface ContextSummary {
236
242
  key: string;
237
- content: ContextContent;
238
243
  topics: string[];
239
244
  timestamp: Timestamp;
245
+ mime?: string;
246
+ size?: number;
247
+ preview?: string;
248
+ source?: string;
240
249
  metadata?: Record<string, any>;
241
- remoteIds?: Record<string, string>;
242
- refCount?: number;
243
250
  }
244
- type ContextContent = {
245
- kind: 'text';
246
- value: string;
247
- } | {
248
- kind: 'json';
249
- value: object;
250
- } | {
251
- kind: 'blob';
252
- } & BlobRef | {
253
- kind: 'remote';
254
- uri: URI;
255
- mediaType: BlobMediaType;
256
- };
257
- interface Session$1 {
258
- id: UUID;
259
- label: string;
260
- role: string;
261
- topics: string[];
251
+ interface TopicIndex {
252
+ topic: string;
253
+ contextKeys: string[];
262
254
  preferences: UUID[];
263
- turns: Turn[];
264
- metadata: {
255
+ metadata?: {
265
256
  created?: Timestamp;
266
257
  updated?: Timestamp;
258
+ entries?: number;
267
259
  };
268
260
  }
261
+ interface Index {
262
+ roles: Record<string, RoleSummary>;
263
+ preferences: Record<UUID, PreferenceSummary>;
264
+ context: Record<string, ContextSummary>;
265
+ sessions: Record<UUID, SessionMeta>;
266
+ topics: Record<string, TopicIndex>;
267
+ blobs: Record<SHA256, BlobRecord>;
268
+ }
269
+ interface Workspace {
270
+ id: UUID;
271
+ settings: Settings;
272
+ project: Project;
273
+ index: Index;
274
+ }
269
275
  interface WorkspaceBundle {
270
276
  format: 'aiworkspace/4.0';
271
277
  workspace: Workspace;
272
278
  roles: Record<string, Role>;
273
279
  preferences: Record<UUID, Preference>;
274
280
  context: Record<string, Context>;
275
- sessions: Record<UUID, Session$1>;
281
+ sessions: Record<UUID, SessionMeta & {
282
+ turns: Turn[];
283
+ }>;
276
284
  blobs: Record<SHA256, BlobRecord>;
277
285
  }
278
- interface TranscriptWindow {
279
- sessionId: UUID;
280
- turns: Turn[];
281
- flushedCount: number;
282
- hasMore: boolean;
283
- }
284
286
  interface EffectiveSession {
285
287
  session: SessionMeta;
286
288
  role: Role;
@@ -293,7 +295,6 @@ interface CacheConfig {
293
295
  roles?: number;
294
296
  preferences?: number;
295
297
  context?: number;
296
- transcriptWindows?: number;
297
298
  }
298
299
  interface FlushConfig {
299
300
  maxBufferSize: number;
@@ -302,7 +303,6 @@ interface FlushConfig {
302
303
  interface ContentStoreConfig {
303
304
  cache?: CacheConfig;
304
305
  flush?: FlushConfig;
305
- transcriptWindowSize?: number;
306
306
  }
307
307
  interface BaseCommand {
308
308
  type: string;
@@ -452,14 +452,16 @@ interface DeleteSession extends BaseCommand {
452
452
  }
453
453
  interface RegisterBlob extends BaseCommand {
454
454
  type: 'blob:register';
455
- payload: BlobRecord;
455
+ payload: {
456
+ data: Uint8Array;
457
+ mediaType: BlobMediaType;
458
+ filename?: string;
459
+ };
456
460
  }
457
- interface RecordBlobRemoteId extends BaseCommand {
458
- type: 'blob:remote_id';
461
+ interface RetainBlob extends BaseCommand {
462
+ type: 'blob:retain';
459
463
  payload: {
460
464
  sha256: SHA256;
461
- providerId: string;
462
- fileId: string;
463
465
  };
464
466
  }
465
467
  interface ReleaseBlob extends BaseCommand {
@@ -468,7 +470,22 @@ interface ReleaseBlob extends BaseCommand {
468
470
  sha256: SHA256;
469
471
  };
470
472
  }
471
- type Command = CreateWorkspace | AddRole | UpdateRole | DeleteRole | AddPreference | UpdatePreference | DeletePreference | CreateSession | AddContext | UpdateContext | DeleteContext | AddTurn | EditTurn | BranchTurn | DeleteTurn | SwitchRole | AddSessionTopics | OverrideSessionPreferences | ForkSession | DeleteSession | RegisterBlob | RecordBlobRemoteId | ReleaseBlob;
473
+ interface PurgeBlob extends BaseCommand {
474
+ type: 'blob:purge';
475
+ payload: {
476
+ sha256: SHA256;
477
+ };
478
+ }
479
+ interface RecordBlobRemoteId extends BaseCommand {
480
+ type: 'blob:record_remote_id';
481
+ payload: {
482
+ sha256: SHA256;
483
+ providerId: string;
484
+ fileId: string;
485
+ };
486
+ }
487
+ type BlobCommand = RegisterBlob | RetainBlob | ReleaseBlob | PurgeBlob | RecordBlobRemoteId;
488
+ type Command = CreateWorkspace | AddRole | UpdateRole | DeleteRole | AddPreference | UpdatePreference | DeletePreference | CreateSession | AddContext | UpdateContext | DeleteContext | AddTurn | EditTurn | BranchTurn | DeleteTurn | SwitchRole | AddSessionTopics | OverrideSessionPreferences | ForkSession | DeleteSession | BlobCommand;
472
489
  interface TokenBudget {
473
490
  total: number;
474
491
  estimator?: (text: string) => number;
@@ -486,7 +503,7 @@ interface ContextRelevanceConfig {
486
503
  freshnessHalfLifeDays?: number;
487
504
  }
488
505
  /**
489
- * BuiltTurn has been removed. Prompt.transcript.turns is now Turn[].
506
+ * Prompt.transcript.turns is Turn[].
490
507
  * Synthetic turns produced by PromptAssembler (summary blocks, truncation
491
508
  * notices, referential attachments) carry generated UUIDs and version 0,
492
509
  * with parent: null. They are ephemeral — never stored, never patched.
@@ -515,36 +532,448 @@ interface Prompt {
515
532
  warnings: string[];
516
533
  conflicts: PreferenceConflict[];
517
534
  }
535
+ interface TranscriptWindow {
536
+ sessionId: UUID;
537
+ turns: Turn[];
538
+ flushedCount: number;
539
+ hasMore: boolean;
540
+ }
518
541
 
519
- interface ContentStorage {
520
- saveRole(role: Role): Promise<void>;
521
- loadRole(name: string): Promise<Role | null>;
522
- deleteRole(name: string): Promise<void>;
523
- savePreference(preference: Preference): Promise<void>;
524
- loadPreference(id: UUID): Promise<Preference | null>;
525
- deletePreference(id: UUID): Promise<void>;
526
- saveContext(context: Context): Promise<void>;
527
- loadContext(key: string): Promise<Context | null>;
528
- loadContextBatch(keys: string[]): Promise<Map<string, Context>>;
529
- deleteContext(key: string): Promise<void>;
530
- saveTurn(sessionId: UUID, turn: Turn): Promise<void>;
531
- loadTurn(sessionId: UUID, turnId: UUID, version: number): Promise<Turn | null>;
532
- loadAllTurns(sessionId: UUID): Promise<Turn[]>;
533
- deleteTurn(sessionId: UUID, turnId: UUID, version: number): Promise<void>;
534
- setSessionHead(sessionId: UUID, head: {
535
- id: UUID;
536
- version: number;
537
- } | null): Promise<void>;
538
- getSessionHead(sessionId: UUID): Promise<{
539
- id: UUID;
540
- version: number;
541
- } | null>;
542
- storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
543
- loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
544
- deleteBytes(sha256: SHA256): Promise<void>;
545
- exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
542
+ /**
543
+ * Buffers write operations across one or more stores and commits them atomically.
544
+ *
545
+ * ## How atomicity works
546
+ *
547
+ * ### IndexedDB stores (same database)
548
+ * At commit time, TransactionContext collects the names of every IDB store that
549
+ * received operations, then opens a **single** `IDBTransaction` spanning all of
550
+ * them via `ConnectionManager.openTransaction`. Each store's `executeInTransaction`
551
+ * receives that shared transaction object and performs its writes against it
552
+ * without opening a new transaction of its own. IDB commits or aborts the
553
+ * entire multi-store transaction as one unit.
554
+ *
555
+ * ### MemoryStore
556
+ * MemoryStore's `executeInTransaction` receives `null` for the shared transaction.
557
+ * It applies ops against an internal staging map and returns. If a later
558
+ * participant fails, TransactionContext calls `rollbackMemory` on each
559
+ * MemoryStore that already applied its staged ops. MemoryStore restores its
560
+ * pre-transaction snapshot.
561
+ *
562
+ * ### Mixed (IDB + Memory in the same transaction)
563
+ * All IDB stores are committed first as a single atomic IDB transaction, then
564
+ * each MemoryStore is committed. If a MemoryStore fails after IDB has already
565
+ * committed, the IDB side cannot be rolled back — this is an inherent limitation
566
+ * of mixing two different storage engines. In practice the schema store is
567
+ * always MemoryStore-or-IDB consistently, so mixed transactions should not arise
568
+ * in normal usage.
569
+ */
570
+ declare class TransactionContext {
571
+ readonly id: string;
572
+ /**
573
+ * Flat list of every operation staged so far, in the order they were added.
574
+ * We keep the store reference alongside the op so commit() can group them.
575
+ */
576
+ private staged;
577
+ private done;
578
+ constructor();
579
+ /**
580
+ * Stages a single write operation against a store.
581
+ * Does NOT touch the store — no I/O happens until commit().
582
+ */
583
+ addOp<T extends Record<string, any>>(store: Store<T>, type: "put" | "delete" | "add", data: any): Promise<void>;
584
+ /**
585
+ * Commits all staged operations atomically.
586
+ *
587
+ * For IDB stores: opens one shared IDBTransaction across all participating
588
+ * stores, then dispatches ops to each store's executeInTransaction.
589
+ * For MemoryStores: dispatches sequentially; rolls back on failure.
590
+ */
591
+ commit(): Promise<void>;
592
+ /**
593
+ * Discards all staged operations. No I/O has occurred so there is nothing
594
+ * to undo — we simply clear the buffer.
595
+ */
596
+ rollback(): void;
597
+ /**
598
+ * Opens ONE IDBTransaction across all participating IDB stores and lets
599
+ * each store execute its ops against the shared transaction handle.
600
+ *
601
+ * We obtain the IDBDatabase from the first store (they all share the same
602
+ * ConnectionManager / database) and open the transaction ourselves so that
603
+ * the commit/abort lifecycle belongs entirely to this method.
604
+ */
605
+ private commitIDB;
606
+ /**
607
+ * Commits MemoryStore groups sequentially.
608
+ * Maintains a list of stores that have already applied their ops; if any
609
+ * store throws, all previously-applied stores are rolled back via the
610
+ * store-level `_rollbackMemory(snapshot)` escape hatch.
611
+ */
612
+ private commitMemory;
613
+ completed(): boolean;
546
614
  }
547
615
 
616
+ interface CursorCallbackResult<T> {
617
+ value: T | null;
618
+ done: boolean;
619
+ offset?: number;
620
+ }
621
+ /**
622
+ * Callback function for cursor iteration over store records.
623
+ *
624
+ * @template T - The type of records stored.
625
+ * @param value - The current record value (cloned, not a live reference).
626
+ * @param key - The key (ID) of the current record.
627
+ * @param cursor - The underlying cursor object (implementation-specific; may be `null` in memory adapters).
628
+ * @returns A promise resolving to an object indicating whether iteration should stop,
629
+ * and an optional offset to advance.
630
+ */
631
+ type CursorCallback<T> = (value: T, key: string | number, cursor: any) => Promise<CursorCallbackResult<T>>;
632
+ /**
633
+ * A generic representation of a key range, replacing the browser-specific IDBKeyRange.
634
+ */
635
+ interface StoreKeyRange {
636
+ lower?: any;
637
+ upper?: any;
638
+ lowerOpen?: boolean;
639
+ upperOpen?: boolean;
640
+ }
641
+ /**
642
+ * A single buffered operation staged inside a TransactionContext.
643
+ * Kept intentionally minimal — the context only needs to know what to
644
+ * replay against a store during commit.
645
+ */
646
+ type BufferedOperation<T> = {
647
+ type: "add" | "put";
648
+ data: T | T[];
649
+ } | {
650
+ type: "delete";
651
+ data: string | number | (string | number)[];
652
+ };
653
+ /**
654
+ * Storage adapter interface for a single object store (collection).
655
+ *
656
+ * Stores own their indexes. Index lifecycle (create, drop) and index-aware reads
657
+ * (findByIndex) are part of this contract so that both MemoryStore and IndexedDBStore
658
+ * implement them natively — MemoryStore via in-memory index maps, IndexedDB via its
659
+ * native index mechanism.
660
+ *
661
+ * @template T - The type of objects stored. Must include the key path property.
662
+ */
663
+ interface Store<T extends Record<string, any> = Record<string, any>> {
664
+ /**
665
+ * Returns the name of this store (the IDB object store / collection name).
666
+ * Used by TransactionContext to group operations and open a correctly-scoped
667
+ * multi-store IDB transaction at commit time.
668
+ */
669
+ name(): string;
670
+ /**
671
+ * Opens the store, ensuring underlying storage structures exist.
672
+ */
673
+ open(): Promise<void>;
674
+ /**
675
+ * Adds one or more records to the store.
676
+ * If a record does not have a value for the store's key path, an automatic
677
+ * key may be assigned. Throws if a record with the same key already exists.
678
+ */
679
+ add(data: T | T[]): Promise<string | number | (string | number)[]>;
680
+ /**
681
+ * Removes all records from the store without destroying index structures.
682
+ */
683
+ clear(): Promise<void>;
684
+ /**
685
+ * Returns the total number of records in the store.
686
+ */
687
+ count(): Promise<number>;
688
+ /**
689
+ * Deletes one or more records by their keys.
690
+ */
691
+ delete(id: string | number | (string | number)[]): Promise<void>;
692
+ /**
693
+ * Retrieves a single record by its primary key.
694
+ */
695
+ getById(id: string | number): Promise<T | undefined>;
696
+ /**
697
+ * Retrieves the first record matching an exact index key (point lookup).
698
+ * Useful for unique indexes — returns the single matching record or undefined.
699
+ *
700
+ * @param indexName - The name of the index to query.
701
+ * @param key - The exact key value to look up.
702
+ */
703
+ getByIndex(indexName: string, key: any): Promise<T | undefined>;
704
+ /**
705
+ * Retrieves all records from a named index, optionally filtered by a key range.
706
+ * Use this for range scans over an index (e.g. all records where age >= 18).
707
+ *
708
+ * @param indexName - The name of the index to query.
709
+ * @param keyRange - Optional range to filter results.
710
+ */
711
+ getByKeyRange(indexName: string, keyRange?: StoreKeyRange): Promise<T[]>;
712
+ /**
713
+ * Retrieves all records from the store without index involvement.
714
+ */
715
+ getAll(): Promise<T[]>;
716
+ /**
717
+ * Inserts or replaces a record. Validates OCC if a record with the same key exists.
718
+ */
719
+ put(data: T): Promise<string | number>;
720
+ /**
721
+ * Iterates over records using a cursor, allowing early termination and skipping.
722
+ *
723
+ * @param callback - Invoked for each record; return `{ done: true }` to stop,
724
+ * `{ offset: n }` to skip ahead n records.
725
+ * @param direction - Iteration order.
726
+ * @param keyRange - Optional range to restrict iteration.
727
+ */
728
+ cursor(callback: CursorCallback<T>, direction?: "forward" | "backward", keyRange?: StoreKeyRange): Promise<T | null>;
729
+ /**
730
+ * Executes a batch of write operations atomically within this store.
731
+ * All operations succeed or fail together.
732
+ *
733
+ * Used for standalone (single-store) atomic writes. For cross-store atomicity,
734
+ * use executeInTransaction instead.
735
+ */
736
+ batch(operations: Array<{
737
+ type: "add" | "put";
738
+ data: T | T[];
739
+ } | {
740
+ type: "delete";
741
+ data: string | number | (string | number)[];
742
+ }>): Promise<void>;
743
+ /**
744
+ * Registers a new index on the store. Idempotent — no-op if the index already exists.
745
+ * For IndexedDB, this triggers a database version upgrade.
746
+ * For MemoryStore, this builds the index map from existing records.
747
+ *
748
+ * @param definition - The full index definition from the schema.
749
+ */
750
+ createIndex(definition: IndexDefinition): Promise<void>;
751
+ /**
752
+ * Removes a named index from the store.
753
+ * For IndexedDB, this triggers a database version upgrade.
754
+ * For MemoryStore, this drops the in-memory index map.
755
+ *
756
+ * @param name - The index name as declared in IndexDefinition.name.
757
+ */
758
+ dropIndex(name: string): Promise<void>;
759
+ /**
760
+ * Returns all records matching an exact index key.
761
+ * Unlike getByIndex (which returns only the first match), this returns all matches —
762
+ * essential for non-unique indexes where multiple records share the same indexed value.
763
+ *
764
+ * @param indexName - The name of the index to query.
765
+ * @param value - The exact value to look up.
766
+ */
767
+ findByIndex(indexName: string, value: any): Promise<T[]>;
768
+ /**
769
+ * Executes a set of buffered operations as part of a cross-store atomic transaction.
770
+ *
771
+ * For IndexedDBStore: `sharedTx` is the single IDBTransaction opened across all
772
+ * participating stores. Operations are applied directly to `sharedTx.objectStore(name)`
773
+ * without opening a new transaction — IDB commits or aborts the whole thing atomically.
774
+ *
775
+ * For MemoryStore: `sharedTx` is null. The store applies ops against its own staging
776
+ * area. The caller (TransactionContext) is responsible for coordinating rollback across
777
+ * all MemoryStores if any participant fails.
778
+ *
779
+ * This method must NOT open, commit, or abort any transaction itself.
780
+ *
781
+ * @param ops - The buffered operations to apply.
782
+ * @param sharedTx - The shared IDBTransaction (IndexedDB only), or null (MemoryStore).
783
+ */
784
+ executeInTransaction(ops: BufferedOperation<T>[], sharedTx: IDBTransaction | null): Promise<void>;
785
+ }
786
+ interface Collection<T> {
787
+ /**
788
+ * Finds a single document matching the query.
789
+ */
790
+ find: (query: QueryFilter<T>) => Promise<Document<T> | null>;
791
+ /**
792
+ * Lists documents with pagination. Returns an AsyncIterator so consumers can
793
+ * wrap it in their own iteration protocol (e.g. for-await-of via AsyncIterable).
794
+ */
795
+ list: (query: PaginationOptions) => Promise<AsyncIterator<Document<T>[]>>;
796
+ /**
797
+ * Filters all documents matching the query.
798
+ */
799
+ filter: (query: QueryFilter<T>) => Promise<Document<T>[]>;
800
+ /**
801
+ * Creates a new document in the collection.
802
+ *
803
+ * When a TransactionContext is provided the initial store.add is buffered into
804
+ * the transaction rather than written immediately. The document is returned in
805
+ * its fully initialised in-memory state regardless — callers can use it before
806
+ * the transaction commits.
807
+ *
808
+ * @param initial - The initial data for the document.
809
+ * @param tx - Optional transaction to buffer the write into.
810
+ */
811
+ create: (initial: T, tx?: TransactionContext) => Promise<Document<T>>;
812
+ /**
813
+ * Subscribes to collection-level events.
814
+ */
815
+ subscribe: (event: CollectionEventType | TelemetryEventType, callback: (event: CollectionEvent<T> | TelemetryEvent) => void) => () => void;
816
+ /**
817
+ * Validates data against the collection's schema.
818
+ */
819
+ validate(data: Record<string, any>): Promise<{
820
+ value?: any;
821
+ issues: Array<{
822
+ message: string;
823
+ path: Array<string>;
824
+ }>;
825
+ }>;
826
+ invalidate(): void;
827
+ }
828
+ /**
829
+ * Event payload for Collection events.
830
+ */
831
+ type CollectionEventType = "document:create" | "collection:read" | "migration:start" | "migration:end";
832
+ type CollectionEvent<T> = {
833
+ type: CollectionEventType;
834
+ document?: T;
835
+ model?: string;
836
+ method?: keyof Collection<T>;
837
+ metadata?: Record<string, unknown>;
838
+ timestamp: number;
839
+ };
840
+ interface Database {
841
+ /**
842
+ * Opens an existing collection by name.
843
+ */
844
+ collection: <T>(schemaName: string) => Promise<Collection<T>>;
845
+ /**
846
+ * Creates a new collection from a schema definition.
847
+ */
848
+ createCollection: <T>(schema: SchemaDefinition) => Promise<Collection<T>>;
849
+ /**
850
+ * Deletes a collection and its schema record.
851
+ */
852
+ deleteCollection: (schemaName: string) => Promise<boolean>;
853
+ /**
854
+ * Updates an existing collection's schema record.
855
+ */
856
+ updateCollection: (schema: SchemaDefinition) => Promise<boolean>;
857
+ /**
858
+ * Migrates an existing collection's data and schema definition.
859
+ * Processes data in a streaming fashion to avoid loading the full collection
860
+ * into memory.
861
+ */
862
+ migrateCollection: <T>(name: string, opts: CollectionMigrationOptions, batchSize?: number) => Promise<Collection<T>>;
863
+ /**
864
+ * Executes a callback within a TransactionContext.
865
+ * Writes buffered inside the callback are flushed atomically on commit.
866
+ * If the callback throws, the buffer is discarded (no writes are flushed).
867
+ */
868
+ transaction: (callback: (tx: TransactionContext) => Promise<void>) => Promise<void>;
869
+ /**
870
+ * Subscribes to database-level events.
871
+ */
872
+ subscribe: (event: DatabaseEventType | "telemetry", callback: (event: DatabaseEvent | TelemetryEvent) => void) => () => void;
873
+ /**
874
+ * Releases in-memory references and event bus subscriptions.
875
+ * Does not delete any persisted data.
876
+ */
877
+ close: () => void;
878
+ clear: () => Promise<void>;
879
+ /**
880
+ * Ensures a collection exists; creates it if it doesn't. Idempotent.
881
+ */
882
+ ensureCollection: (schema: SchemaDefinition) => Promise<void>;
883
+ /**
884
+ * Ensures multiple collections exist; creates any that don't. Idempotent.
885
+ */
886
+ setupCollections: (schemas: SchemaDefinition[]) => Promise<void>;
887
+ }
888
+ type CollectionMigrationOptions = {
889
+ changes: SchemaChange<any>[];
890
+ description: string;
891
+ rollback?: SchemaChange<any>[];
892
+ transform?: string | DataTransform<any, any>;
893
+ };
894
+ type DatabaseEventType = "collection:create" | "collection:delete" | "collection:update" | "collection:read" | "migrate";
895
+ type DatabaseEvent = {
896
+ type: DatabaseEventType;
897
+ schema?: SchemaDefinition | Partial<SchemaDefinition>;
898
+ timestamp: number;
899
+ };
900
+ type Document<T> = {
901
+ readonly [K in keyof T]: T[K];
902
+ } & {
903
+ $id?: string;
904
+ $created?: string | Date;
905
+ $updated?: string | Date;
906
+ $version?: number;
907
+ read: () => Promise<boolean>;
908
+ save: (tx?: TransactionContext) => Promise<boolean>;
909
+ update: (props: Partial<T>, tx?: TransactionContext) => Promise<boolean>;
910
+ delete: (tx?: TransactionContext) => Promise<boolean>;
911
+ subscribe: (event: DocumentEventType | TelemetryEventType, callback: (event: DocumentEvent<T> | TelemetryEvent) => void) => () => void;
912
+ state(): T;
913
+ };
914
+ type DocumentEventType = "document:create" | "document:write" | "document:update" | "document:delete" | "document:read";
915
+ type DocumentEvent<T> = {
916
+ type: DocumentEventType;
917
+ data?: Partial<T>;
918
+ timestamp: number;
919
+ };
920
+ type TelemetryEventType = "telemetry";
921
+ type TelemetryEvent = {
922
+ type: TelemetryEventType;
923
+ method: string;
924
+ timestamp: number;
925
+ source: any;
926
+ metadata: {
927
+ args: any[];
928
+ performance: {
929
+ durationMs: number;
930
+ };
931
+ source: {
932
+ level: "database" | "collection" | "document";
933
+ collection?: string;
934
+ document?: string;
935
+ };
936
+ result?: {
937
+ type: "array" | string;
938
+ size?: number;
939
+ };
940
+ error: {
941
+ message: string;
942
+ name: string;
943
+ stack?: string;
944
+ } | null;
945
+ };
946
+ };
947
+
948
+ interface WorkspaceDatabase {
949
+ /**
950
+ * Open the database. Registers core schemas followed by any extension
951
+ * schemas supplied by the caller (domain plugins).
952
+ *
953
+ * Idempotent — safe to call multiple times; subsequent calls are no-ops
954
+ * if the database is already open.
955
+ */
956
+ open(extensionSchemas?: SchemaDefinition[]): Promise<void>;
957
+ /**
958
+ * Access a collection by schema name.
959
+ * Throws if the schema has not been registered.
960
+ */
961
+ collection<T>(schemaName: string): Promise<Collection<T>>;
962
+ /**
963
+ * Close the database connection.
964
+ */
965
+ close(): void;
966
+ }
967
+ declare function createWorkspaceDatabase(db: Database): WorkspaceDatabase;
968
+ declare const COLLECTIONS: {
969
+ readonly ROLE: "role";
970
+ readonly PREFERENCE: "preference";
971
+ readonly CONTEXT: "context";
972
+ readonly SESSION: "session";
973
+ readonly TURN: "turn";
974
+ };
975
+ type CollectionName = typeof COLLECTIONS[keyof typeof COLLECTIONS];
976
+
548
977
  /**
549
978
  * Utility type for representing partial updates to the state, allowing deep nesting.
550
979
  * It makes all properties optional and applies the same transformation recursively
@@ -560,65 +989,14 @@ declare function del<T>(): T;
560
989
  declare const merge: <T extends object>(original: T, changes: DeepPartial<T> | symbol) => T;
561
990
  declare function ok<T>(value: T): Result<T, never>;
562
991
  declare function err<E = WorkspaceError>(error: E): Result<never, E>;
563
-
564
- interface IndexedDBConfig {
565
- dbName?: string;
566
- }
567
- declare class IndexedDBStorage implements ContentStorage {
568
- private readonly dbName;
569
- private db;
570
- constructor(config?: IndexedDBConfig);
571
- open(): Promise<void>;
572
- private createSchema;
573
- close(): void;
574
- deleteDatabase(): Promise<void>;
575
- private getDB;
576
- private readTx;
577
- private writeTx;
578
- saveRole(role: Role): Promise<void>;
579
- loadRole(name: string): Promise<Role | null>;
580
- deleteRole(name: string): Promise<void>;
581
- savePreference(preference: Preference): Promise<void>;
582
- loadPreference(id: UUID): Promise<Preference | null>;
583
- deletePreference(id: UUID): Promise<void>;
584
- saveContext(context: Context): Promise<void>;
585
- loadContext(key: string): Promise<Context | null>;
586
- loadContextBatch(keys: string[]): Promise<Map<string, Context>>;
587
- deleteContext(key: string): Promise<void>;
588
- saveTurn(sessionId: UUID, turn: Turn): Promise<void>;
589
- loadTurn(sessionId: UUID, turnId: UUID, version: number): Promise<Turn | null>;
590
- loadAllTurns(sessionId: UUID): Promise<Turn[]>;
591
- deleteTurn(sessionId: UUID, turnId: UUID, version: number): Promise<void>;
592
- setSessionHead(sessionId: UUID, head: {
593
- id: UUID;
594
- version: number;
595
- } | null): Promise<void>;
596
- getSessionHead(sessionId: UUID): Promise<{
597
- id: UUID;
598
- version: number;
599
- } | null>;
600
- storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
601
- loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
602
- deleteBytes(sha256: SHA256): Promise<void>;
603
- exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
604
- saveWorkspace(state: Workspace): Promise<void>;
605
- loadWorkspace(): Promise<Workspace | null>;
606
- exportBundle(): Promise<{
607
- roles: Record<string, Role>;
608
- preferences: Record<UUID, Preference>;
609
- context: Record<string, Context>;
610
- transcripts: Record<UUID, Turn[]>;
611
- workspace: Workspace | null;
612
- }>;
613
- importBundle(data: {
614
- roles: Record<string, Role>;
615
- preferences: Record<UUID, Preference>;
616
- context: Record<string, Context>;
617
- transcripts: Record<UUID, Turn[]>;
618
- workspace?: Workspace;
619
- }): Promise<void>;
620
- private getAllFromStore;
621
- }
992
+ declare function omitNullUndefined<T extends Record<string, any>>(obj: T): Partial<T>;
993
+ declare function createSimpleWorkspace({ name, owner, language }: {
994
+ name: string;
995
+ language: string;
996
+ owner: string;
997
+ }): Workspace;
998
+ declare function extractBlobRecord(patch: DeepPartial<Workspace>): BlobRecord | null;
999
+ declare function extractBlobRef(record: BlobRecord): BlobRef;
622
1000
 
623
1001
  /**
624
1002
  * Persistence contract for binary blob content and blob registry records.
@@ -672,19 +1050,26 @@ interface TurnRef {
672
1050
  version: number;
673
1051
  }
674
1052
  declare class TurnTree {
675
- private readonly storage;
676
- constructor(storage: ContentStorage);
1053
+ private readonly db;
1054
+ constructor(db: WorkspaceDatabase);
1055
+ private turns;
1056
+ private sessions;
1057
+ /**
1058
+ * Compound filter for a specific (sessionId, id, version) tuple.
1059
+ * Uses only declared schema fields — never $id.
1060
+ */
1061
+ private turnFilter;
1062
+ getHead(sessionId: UUID): Promise<TurnRef | null>;
1063
+ setHead(sessionId: UUID, head: TurnRef | null): Promise<void>;
677
1064
  append(sessionId: UUID, turn: Turn): Promise<Turn>;
678
- appendBatch(sessionId: UUID, turns: Turn[]): Promise<void>;
1065
+ appendBatch(sessionId: UUID, turns: Turn[], finalHead: TurnRef | null): Promise<void>;
679
1066
  replaceVersion(sessionId: UUID, newTurn: Turn): Promise<void>;
680
1067
  branch(sessionId: UUID, newTurn: Turn): Promise<void>;
1068
+ loadAllTurns(sessionId: UUID): Promise<Turn[]>;
681
1069
  getActiveChain(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<Turn[]>;
682
- countChained(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<number>;
683
1070
  buildNodeGraph(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<Record<UUID, TurnNode>>;
684
1071
  deleteSubtree(sessionId: UUID, turnId: UUID, version: number, newHead: TurnRef | null): Promise<void>;
685
1072
  copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
686
- getHead(sessionId: UUID): Promise<TurnRef | null>;
687
- setHead(sessionId: UUID, head: TurnRef | null): Promise<void>;
688
1073
  }
689
1074
 
690
1075
  declare function computeSHA256(data: Uint8Array): Promise<SHA256>;
@@ -741,29 +1126,55 @@ declare class BlobStore {
741
1126
  }
742
1127
 
743
1128
  declare class ContentStore {
744
- private readonly storage;
745
- private readonly tree;
746
- private readonly cache;
747
- constructor(storage: ContentStorage, config?: ContentStoreConfig);
1129
+ private readonly db;
1130
+ readonly tree: TurnTree;
1131
+ readonly blobs: BlobStore;
1132
+ private readonly roleCache;
1133
+ private readonly preferenceCache;
1134
+ private readonly contextCache;
1135
+ /**
1136
+ * Called after any blob registry change with the sha256 and updated
1137
+ * BlobRecord (null on deletion). Wire this to your state manager to
1138
+ * keep Index.blobs current.
1139
+ *
1140
+ * ContentStore sets this on BlobStore.onRegistryChanged internally.
1141
+ * Consumers set this property to receive the forwarded notifications.
1142
+ */
1143
+ onBlobRegistryChanged?: (sha256: SHA256, record: BlobRecord | null) => void;
1144
+ private constructor();
1145
+ static create(db: WorkspaceDatabase, blobStorage: BlobStorage, config?: ContentStoreConfig): Promise<ContentStore>;
1146
+ private init;
748
1147
  getTurnTree(): TurnTree;
749
1148
  getRole(name: string): Promise<Result<Role, WorkspaceError>>;
750
- getPreference(id: UUID): Promise<Result<Preference, WorkspaceError>>;
751
- getContext(key: string): Promise<Result<Context, WorkspaceError>>;
752
- getContextByTopics(indexState: Index, topics: string[]): Promise<Context[]>;
753
1149
  saveRole(role: Role): Promise<void>;
754
- savePreference(preference: Preference): Promise<void>;
755
- saveContext(context: Context): Promise<void>;
756
1150
  deleteRole(name: string): Promise<void>;
1151
+ getPreference(id: UUID): Promise<Result<Preference, WorkspaceError>>;
1152
+ savePreference(preference: Preference): Promise<void>;
757
1153
  deletePreference(id: UUID): Promise<void>;
1154
+ getContext(key: string): Promise<Result<Context, WorkspaceError>>;
1155
+ saveContext(context: Context): Promise<void>;
758
1156
  deleteContext(key: string): Promise<void>;
1157
+ getContextByTopics(indexState: Index, topics: string[]): Promise<Context[]>;
1158
+ saveSession(meta: SessionMeta): Promise<void>;
1159
+ updateSessionMeta(sessionId: UUID, patch: DeepPartial<SessionMeta>): Promise<void>;
1160
+ deleteSession(sessionId: UUID): Promise<void>;
1161
+ registerBlob(data: Uint8Array, mediaType: BlobMediaType, filename?: string): Promise<Result<BlobRef, WorkspaceError>>;
1162
+ retainBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1163
+ releaseBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1164
+ purgeBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1165
+ recordBlobRemoteId(sha256: SHA256, providerId: string, fileId: string): Promise<Result<void, WorkspaceError>>;
1166
+ getBlobRecord(sha256: SHA256): BlobRecord | null;
1167
+ getAllBlobRecords(): Record<SHA256, BlobRecord>;
1168
+ /**
1169
+ * Returns the blob resolver function expected by PromptBuilder.
1170
+ * Closes over the internal BlobStore — no BlobStore reference leaks out.
1171
+ */
1172
+ getBlobResolver(): BlobStore['resolveRefs'];
759
1173
  recordTurn(sessionId: UUID, turn: Turn): Promise<Result<void, WorkspaceError>>;
760
1174
  editTurn(sessionId: UUID, turnId: UUID, newBlocks: ContentBlock[], newVersion: number, roleSnapshot?: string): Promise<Result<void, WorkspaceError>>;
761
1175
  branchTurn(sessionId: UUID, newTurn: Turn): Promise<Result<void, WorkspaceError>>;
762
1176
  deleteTurnSubtree(sessionId: UUID, turnId: UUID, version: number, newHead: TurnRef | null): Promise<Result<void, WorkspaceError>>;
763
1177
  copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
764
- storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
765
- loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
766
- deleteBytes(sha256: SHA256): Promise<void>;
767
1178
  resolveSession(workspace: Workspace, sessionId: UUID, transcript?: Turn[]): Promise<Result<EffectiveSession, WorkspaceError>>;
768
1179
  }
769
1180
 
@@ -771,6 +1182,12 @@ declare function workspaceReducer({ index: state }: Workspace, command: Command)
771
1182
 
772
1183
  declare class WorkspaceManager {
773
1184
  private readonly contentStore;
1185
+ /**
1186
+ * Called when BlobStore triggers a registry change outside of a dispatch()
1187
+ * call — e.g. eagerEviction deleting a blob on release. The caller should
1188
+ * merge this patch into their Workspace.
1189
+ */
1190
+ onWorkspacePatch?: (patch: DeepPartial<Workspace>) => void;
774
1191
  constructor(contentStore: ContentStore);
775
1192
  reduce(workspace: Workspace, command: Command): Result<DeepPartial<Workspace>, WorkspaceError>;
776
1193
  dispatch(workspace: Workspace, command: Command): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
@@ -902,18 +1319,6 @@ declare function buildTurnNode(turn: Turn, children?: UUID[]): TurnNode;
902
1319
  interface SessionManagerConfig {
903
1320
  flush?: Partial<FlushConfig>;
904
1321
  }
905
- /**
906
- * Returned by SessionManager.open().
907
- *
908
- * session — the live Session instance. Store this in your component or
909
- * module; pass it to every subsequent session.* call.
910
- *
911
- * patch — a DeepPartial<Workspace> that the caller should merge into
912
- * their Workspace immediately after open(). Currently empty
913
- * (the Workspace index already holds SessionMeta), but present
914
- * for forward compatibility — future versions may update head
915
- * or flushedTurnCount as part of opening.
916
- */
917
1322
  interface OpenResult {
918
1323
  session: Session;
919
1324
  patch: DeepPartial<Workspace>;
@@ -928,4 +1333,71 @@ declare class SessionManager {
928
1333
  get workspace(): WorkspaceManager;
929
1334
  }
930
1335
 
931
- export { type AddContext, type AddPreference, type AddRole, type AddSessionTopics, type AddTurn, type BaseCommand, type BlobMediaType, type BlobRecord, type BlobRef, type BlobStorage, BlobStore, type BlobStoreConfig, type BranchInfo, type BranchTurn, type CacheConfig, type Command, type ContentBlock, type ContentStorage, ContentStore, type ContentStoreConfig, type Context, type ContextContent, type ContextRelevanceConfig, type ContextSummary, type CreateSession, type CreateWorkspace, type DeleteContext, type DeletePreference, type DeleteRole, type DeleteSession, type DeleteTurn, type DocumentBlock, type DocumentMediaType, type EditTurn, type EffectiveSession, type FlushConfig, type ForkSession, type ImageBlock, type ImageMediaType, type Index, type IndexedDBConfig, IndexedDBStorage, type OpenResult, type OverrideSessionPreferences, type Preference, type PreferenceConflict, type PreferenceSummary, type Project, type Prompt, PromptBuilder, type RecordBlobRemoteId, type RegisterBlob, type ReleaseBlob, type ResolvedBlob, type Result, type Role, type RoleSummary, type RoleTransitionBlock, type SHA256, Session, SessionManager, type SessionManagerConfig, type SessionMeta, type Settings, type SummaryBlock, type SwitchRole, type TextBlock, type ThinkingBlock, type Timestamp, type TokenBudget, type ToolResultBlock, type ToolUseBlock, type TopicIndex, type TranscriptWindow, type Turn, type TurnNode, type TurnRef, type TurnRole, TurnTree, type URI, type UUID, type UpdateContext, type UpdatePreference, type UpdateRole, type Workspace, type WorkspaceBundle, type WorkspaceError, WorkspaceManager, buildTurnNode, computeSHA256, del, err, merge, ok, workspaceReducer };
1336
+ /**
1337
+ * In-process implementation backed by plain Maps.
1338
+ * Suitable for development, testing, and server-side runtimes without
1339
+ * access to IndexedDB.
1340
+ */
1341
+ declare class MemoryBlobStorage implements BlobStorage {
1342
+ private readonly bytes;
1343
+ private readonly records;
1344
+ storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
1345
+ loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
1346
+ hasBytes(sha256: SHA256): Promise<boolean>;
1347
+ deleteBytes(sha256: SHA256): Promise<void>;
1348
+ saveRecord(record: BlobRecord): Promise<void>;
1349
+ loadRecord(sha256: SHA256): Promise<BlobRecord | null>;
1350
+ deleteRecord(sha256: SHA256): Promise<void>;
1351
+ listRecords(): Promise<BlobRecord[]>;
1352
+ exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
1353
+ /**
1354
+ * Atomic register for MemoryBlobStorage — sequential ops are atomic
1355
+ * in a single-threaded JS runtime, so this is equivalent to two separate
1356
+ * calls, but we implement it for interface consistency.
1357
+ */
1358
+ registerBlob(record: BlobRecord, data: Uint8Array): Promise<void>;
1359
+ }
1360
+
1361
+ interface IndexedDBBlobConfig {
1362
+ /** Name of the IndexedDB database. Defaults to 'aiworkspace-blobs'. */
1363
+ dbName?: string;
1364
+ }
1365
+ /**
1366
+ * IndexedDB-backed blob storage.
1367
+ *
1368
+ * Bytes are stored as raw Uint8Array — IndexedDB handles binary natively,
1369
+ * no base64 encoding at rest. This is important for large files.
1370
+ *
1371
+ * Transaction discipline: never await inside an active transaction.
1372
+ * All multi-step operations chain synchronous IDB request handlers
1373
+ * inside a single Promise.
1374
+ */
1375
+ declare class IndexedDBBlobStorage implements BlobStorage {
1376
+ private readonly dbName;
1377
+ private db;
1378
+ constructor(config?: IndexedDBBlobConfig);
1379
+ open(): Promise<void>;
1380
+ private createSchema;
1381
+ close(): void;
1382
+ deleteDatabase(): Promise<void>;
1383
+ private getDB;
1384
+ private readTx;
1385
+ private writeTx;
1386
+ storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
1387
+ loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
1388
+ hasBytes(sha256: SHA256): Promise<boolean>;
1389
+ deleteBytes(sha256: SHA256): Promise<void>;
1390
+ saveRecord(record: BlobRecord): Promise<void>;
1391
+ loadRecord(sha256: SHA256): Promise<BlobRecord | null>;
1392
+ deleteRecord(sha256: SHA256): Promise<void>;
1393
+ listRecords(): Promise<BlobRecord[]>;
1394
+ exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
1395
+ /**
1396
+ * Atomically stores bytes and saves a record together.
1397
+ * Preferred over calling storeBytes + saveRecord separately when both
1398
+ * are new — avoids a window where bytes exist without a record.
1399
+ */
1400
+ registerBlob(record: BlobRecord, data: Uint8Array): Promise<void>;
1401
+ }
1402
+
1403
+ export { type AddContext, type AddPreference, type AddRole, type AddSessionTopics, type AddTurn, type BaseCommand, type BlobCommand, type BlobMediaType, type BlobRecord, type BlobRef, type BlobStorage, BlobStore, type BlobStoreConfig, type BranchInfo, type BranchTurn, COLLECTIONS, type CacheConfig, type CollectionName, type Command, type ContentBlock, ContentStore, type ContentStoreConfig, type Context, type ContextContent, type ContextRelevanceConfig, type ContextSummary, type CreateSession, type CreateWorkspace, type DeleteContext, type DeletePreference, type DeleteRole, type DeleteSession, type DeleteTurn, type DocumentBlock, type DocumentMediaType, type EditTurn, type EffectiveSession, type FlushConfig, type ForkSession, type ImageBlock, type ImageMediaType, type Index, type IndexedDBBlobConfig, IndexedDBBlobStorage, MemoryBlobStorage, type OpenResult, type OverrideSessionPreferences, type Preference, type PreferenceConflict, type PreferenceSummary, type Project, type Prompt, PromptBuilder, type PurgeBlob, type RecordBlobRemoteId, type RegisterBlob, type ReleaseBlob, type ResolvedBlob, type Result, type RetainBlob, type Role, type RoleSummary, type RoleTransitionBlock, type SHA256, Session, SessionManager, type SessionManagerConfig, type SessionMeta, type Settings, type SummaryBlock, type SwitchRole, type TextBlock, type ThinkingBlock, type Timestamp, type TokenBudget, type ToolResultBlock, type ToolUseBlock, type TopicIndex, type TranscriptWindow, type Turn, type TurnNode, type TurnRef, type TurnRole, TurnTree, type URI, type UUID, type UpdateContext, type UpdatePreference, type UpdateRole, type Workspace, type WorkspaceBundle, type WorkspaceDatabase, type WorkspaceError, WorkspaceManager, buildTurnNode, computeSHA256, createSimpleWorkspace, createWorkspaceDatabase, del, err, extractBlobRecord, extractBlobRef, merge, ok, omitNullUndefined, workspaceReducer };