@asaidimu/utils-workspace 2.0.0 → 2.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/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { QueryFilter, PaginationOptions } from '@asaidimu/query';
2
+ import { 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,35 +532,455 @@ 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
+ declare class TransactionContext {
543
+ readonly id: string;
544
+ private buffer;
545
+ private committed;
546
+ constructor();
547
+ addOp(store: Store<any>, type: "put" | "delete", data: any): void;
548
+ commit(): Promise<void>;
549
+ rollback(): void;
550
+ }
551
+
552
+ interface CursorCallbackResult<T> {
553
+ value: T | null;
554
+ done: boolean;
555
+ offset?: number;
556
+ }
557
+ /**
558
+ * Callback function for cursor iteration over store records.
559
+ *
560
+ * @template T - The type of records stored.
561
+ * @param value - The current record value (cloned, not a live reference).
562
+ * @param key - The key (ID) of the current record.
563
+ * @param cursor - The underlying cursor object (implementation‑specific; may be `null` in memory adapters).
564
+ * @returns A promise that resolves to an object indicating whether iteration should stop, and an optional offset to advance.
565
+ */
566
+ type CursorCallback<T> = (value: T, key: string | number, cursor: any) => Promise<CursorCallbackResult<T>>;
567
+ /**
568
+ * A generic representation of a key range, replacing the browser-specific IDBKeyRange.
569
+ */
570
+ interface StoreKeyRange {
571
+ lower?: any;
572
+ upper?: any;
573
+ lowerOpen?: boolean;
574
+ upperOpen?: boolean;
575
+ }
576
+ /**
577
+ * Storage adapter interface for a single object store (collection).
578
+ *
579
+ * This interface abstracts all low‑level persistence operations, allowing
580
+ * different backends (IndexedDB, memory, remote, etc.) to be used interchangeably.
581
+ * All methods return promises and operate on clones of data to prevent
582
+ * unintended mutations.
583
+ *
584
+ * @template T - The type of objects stored in this store. Must include the key path property.
585
+ */
586
+ interface Store<T = any> {
587
+ /**
588
+ * Adds one or more records to the store.
589
+ *
590
+ * If a record does not have a value for the store's key path, an automatic
591
+ * key (e.g., auto‑incremented number) may be assigned. The store's key path
592
+ * property is then updated on the added record(s).
593
+ *
594
+ * @param data - A single record or an array of records to add.
595
+ * @returns A promise that resolves to:
596
+ * - the key(s) of the added record(s) – a single key if `data` was a single record,
597
+ * or an array of keys if `data` was an array.
598
+ * @throws {Error} If any record lacks the key path property and auto‑keying is not supported,
599
+ * or if a record with the same key already exists.
600
+ */
601
+ add(data: T | T[]): Promise<string | number | (string | number)[]>;
602
+ /**
603
+ * Removes all records from the store.
604
+ *
605
+ * @returns A promise that resolves when the store is cleared.
606
+ * @throws {Error} If the operation fails (e.g., store is closed).
607
+ */
608
+ clear(): Promise<void>;
609
+ /**
610
+ * Returns the total number of records in the store.
611
+ *
612
+ * @returns A promise that resolves to the record count.
613
+ * @throws {Error} If the operation fails.
614
+ */
615
+ count(): Promise<number>;
616
+ /**
617
+ * Deletes one or more records by their keys.
618
+ *
619
+ * @param id - A single key or an array of keys to delete.
620
+ * @returns A promise that resolves when the records are deleted.
621
+ * @throws {Error} If any key is `undefined` or the operation fails.
622
+ */
623
+ delete(id: string | number | (string | number)[]): Promise<void>;
624
+ /**
625
+ * Retrieves a single record by its primary key.
626
+ *
627
+ * @param id - The key of the record to retrieve.
628
+ * @returns A promise that resolves to the record (cloned) if found, otherwise `undefined`.
629
+ * @throws {Error} If the key is `undefined` or the operation fails.
630
+ */
631
+ getById(id: string | number): Promise<T | undefined>;
632
+ /**
633
+ * Retrieves a single record by an index and index key.
634
+ *
635
+ * @param index - The name of the index to query.
636
+ * @param key - The exact key value to look up in the index.
637
+ * @returns A promise that resolves to the first matching record (cloned), or `undefined` if none.
638
+ * @throws {Error} If the index does not exist, the key is `undefined`, or the operation fails.
639
+ */
640
+ getByIndex(index: string, key: any): Promise<T | undefined>;
641
+ /**
642
+ * Retrieves multiple records from an index, optionally within a key range.
643
+ *
644
+ * @param index - The name of the index to query.
645
+ * @param keyRange - Optional `StoreKeyRange` to filter results. If omitted, all records are returned.
646
+ * @returns A promise that resolves to an array of matching records (each cloned).
647
+ * @throws {Error} If the index does not exist or the operation fails.
648
+ */
649
+ getByKeyRange(index: string, keyRange?: StoreKeyRange): Promise<T[]>;
650
+ /**
651
+ * Retrieves all records from the store.
652
+ *
653
+ * @returns A promise that resolves to an array of all records (each cloned).
654
+ * @throws {Error} If the operation fails.
655
+ */
656
+ getAll(): Promise<T[]>;
657
+ /**
658
+ * Inserts or replaces a record.
659
+ *
660
+ * If a record with the same key already exists, it is replaced.
661
+ * The record must contain the store's key path property.
662
+ *
663
+ * @param data - The record to store.
664
+ * @returns A promise that resolves to the key of the stored record.
665
+ * @throws {Error} If the record lacks the key path property or the operation fails.
666
+ */
667
+ put(data: T): Promise<string | number>;
668
+ /**
669
+ * Iterates over records using a cursor, allowing early termination and skipping.
670
+ *
671
+ * The callback is invoked for each record in iteration order. The callback
672
+ * can control the iteration by returning `{ done: true }` to stop, or
673
+ * `{ offset: n }` to skip ahead `n` records.
674
+ *
675
+ * @param callback - Function called for each record.
676
+ * @param direction - Iteration direction: `"forward"` (ascending keys) or `"backward"` (descending keys).
677
+ * @param keyRange - An optional StoreKeyRange to start from specific points.
678
+ * @returns A promise that resolves to the last record processed (or `null` if none).
679
+ * @throws {Error} If the callback throws or the operation fails.
680
+ */
681
+ cursor(callback: CursorCallback<T>, direction?: "forward" | "backward", keyRange?: StoreKeyRange): Promise<T | null>;
682
+ /**
683
+ * Executes a batch of write operations atomically.
684
+ *
685
+ * All operations in the batch succeed or fail together. This is useful for
686
+ * maintaining consistency when multiple writes are required.
687
+ *
688
+ * @param operations - An array of operations. Each operation can be:
689
+ * - `{ type: "add" | "put", data: T | T[] }`
690
+ * - `{ type: "delete", data: string | number | (string | number)[] }`
691
+ * @returns A promise that resolves when the batch is committed.
692
+ * @throws {Error} If any operation fails or the batch cannot be completed.
693
+ */
694
+ batch(operations: Array<{
695
+ type: "add" | "put";
696
+ data: T | T[];
697
+ } | {
698
+ type: "delete";
699
+ data: string | number | (string | number)[];
700
+ }>): Promise<void>;
701
+ open(): Promise<void>;
702
+ }
703
+ interface Collection<T> {
704
+ /**
705
+ * Finds a single document matching the query.
706
+ * @param query - The query to execute.
707
+ * @returns A promise resolving to the matching document or `null` if not found.
708
+ */
709
+ find: (query: QueryFilter<T>) => Promise<Document<T> | null>;
710
+ /**
711
+ * Lists documents based on the provided query.
712
+ * @param query - The query to list documents (supports pagination and sorting).
713
+ * @returns A promise resolving to an array of documents.
714
+ */
715
+ list: (query: PaginationOptions) => Promise<AsyncIterator<Document<T>[]>>;
716
+ /**
717
+ * Filters documents based on the provided query.
718
+ * @param query - The query to filter documents.
719
+ * @returns A promise resolving to an array of matching documents.
720
+ */
721
+ filter: (query: QueryFilter<T>) => Promise<Document<T>[]>;
722
+ /**
723
+ * Creates a new document in the schema.
724
+ * @param initial - The initial data for the document.
725
+ * @returns A promise resolving to the created document.
726
+ */
727
+ create: (initial: T) => Promise<Document<T>>;
728
+ /**
729
+ * Subscribes to schema-level events (e.g., "create", "update", "delete", "access").
730
+ * @param event - The event type to subscribe to.
731
+ * @param callback - The function to call when the event occurs.
732
+ * @returns A promise resolving to an unsubscribe function.
733
+ */
734
+ subscribe: (event: CollectionEventType | TelemetryEventType, callback: (event: CollectionEvent<T> | TelemetryEvent) => void) => Promise<() => void>;
735
+ /**
736
+ * Validate data
737
+ * @param data - The data to validate
738
+ * @returns An object containing validation results
739
+ */
740
+ validate(data: Record<string, any>): Promise<{
741
+ value?: any;
742
+ issues: Array<{
743
+ message: string;
744
+ path: Array<string>;
745
+ }>;
746
+ }>;
546
747
  }
748
+ /**
749
+ * Event payload for DocumentCursor events.
750
+ */
751
+ type CollectionEventType = "document:create" | "collection:read" | "migration:start" | "migration:end";
752
+ type CollectionEvent<T> = {
753
+ type: CollectionEventType;
754
+ document?: T;
755
+ model?: string;
756
+ method?: keyof Collection<T>;
757
+ metadata?: Record<string, unknown>;
758
+ timestamp: number;
759
+ };
760
+ interface Database {
761
+ /**
762
+ * Accesses a schema model by name.
763
+ * @param schemaName - The name of the schema to access.
764
+ * @returns A promise resolving to the schema's DocumentCursor.
765
+ * @throws DatabaseError
766
+ */
767
+ collection: <T>(schemaName: string) => Promise<Collection<T>>;
768
+ /**
769
+ * Creates a new schema model.
770
+ * @param schema - The schema definition.
771
+ * @returns A promise resolving to the created schema's DocumentCursor.
772
+ * @throws DatabaseError
773
+ */
774
+ createCollection: <T>(schema: SchemaDefinition) => Promise<Collection<T>>;
775
+ /**
776
+ * Deletes a schema by name.
777
+ * @param schemaName - The name of the schema to delete.
778
+ * @returns A promise resolving to `true` if successful, or `false` if an error occurs.
779
+ * @throws DatabaseError
780
+ */
781
+ deleteCollection: (schemaName: string) => Promise<boolean>;
782
+ /**
783
+ * Updates an existing schema.
784
+ * @param schema - The updated schema definition.
785
+ * @returns A promise resolving to `true` if successful, or `false` if an error occurs.
786
+ * @throws DatabaseError
787
+ */
788
+ updateCollection: (schema: SchemaDefinition) => Promise<boolean>;
789
+ /**
790
+ * Migrates an existing collection's data and updates its schema definition metadata.
791
+ * This function processes data in a streaming fashion to prevent loading
792
+ * the entire collection into memory.
793
+ *
794
+ * It will:
795
+ * 1. Verify the target collection exists.
796
+ * 2. Retrieve the collection's current schema definition from a metadata store ($index).
797
+ * 3. Initialize a `MigrationEngine` with this schema.
798
+ * 4. Allow a callback to define specific data transformations using the `MigrationEngine`.
799
+ * 5. **Crucially, it uses `migrationEngine.dryRun()` to get the `newSchema` that results**
800
+ * **from the transformations defined in the callback.**
801
+ * 6. Execute these transformations by streaming data from the collection,
802
+ * through the `MigrationEngine`, and back into the same collection.
803
+ * 7. Finally, update the schema definition for the collection in the `$index` metadata store
804
+ * to reflect this `newSchema`.
805
+ * All these steps for data and metadata updates happen within a single atomic IndexedDB transaction.
806
+ *
807
+ * Note: This function focuses solely on *data transformation* and *metadata updates*.
808
+ * It does NOT handle structural IndexedDB changes like adding/removing physical indexes or object stores,
809
+ * which still require an `onupgradeneeded` event (i.e., a database version upgrade).
810
+ *
811
+ * @param name - The name of the collection (IndexedDB object store) to migrate.
812
+ * @param {Object} opts - Options for the new migration
813
+ * @param {SchemaChange<any>[]} opts.changes - Array of schema changes
814
+ * @param {string} opts.description - Description of the migration
815
+ * @param {SchemaChange<any>[]} [opts.rollback] - Optional rollback changes
816
+ * @param {DataTransform<any, any>} [opts.transform] - Optional data transform
817
+ * @returns A Promise resolving to `true` if the migration completes successfully,
818
+ * @throws {DatabaseError} If the collection does not exist, its schema metadata is missing,
819
+ * or any IndexedDB operation/streaming fails critically.
820
+ */
821
+ migrateCollection: (name: string, opts: CollectionMigrationOptions, batchSize?: number) => Promise<boolean>;
822
+ /**
823
+ * Subscribes to database-level events (e.g., "schemaAdded", "schemaDeleted", "schemaAccessed", "migrate").
824
+ * @param event - The event type to subscribe to.
825
+ * @param callback - The function to call when the event occurs.
826
+ * @returns A promise resolving to an unsubscribe function.
827
+ */
828
+ subscribe: (event: DatabaseEventType | "telemetry", callback: (event: DatabaseEvent | TelemetryEvent) => void) => Promise<() => void>;
829
+ /**
830
+ * Closes the connection to the database
831
+ */
832
+ close: () => void;
833
+ /**
834
+ * Ensures a collection exists; creates it if it doesn't.
835
+ * Idempotent – safe to call multiple times.
836
+ * @param schema - The schema definition for the collection.
837
+ * @returns A promise that resolves when the collection exists.
838
+ * @throws {DatabaseError} If validation fails or an unexpected error occurs.
839
+ */
840
+ ensureCollection: (schema: SchemaDefinition) => Promise<void>;
841
+ /**
842
+ * Ensures multiple collections exist; creates any that don't.
843
+ * Idempotent – safe to call multiple times.
844
+ * @param schemas - An array of schema definitions.
845
+ * @returns A promise that resolves when all collections exist.
846
+ * @throws {DatabaseError} If any schema validation fails or an unexpected error occurs.
847
+ */
848
+ setupCollections: (schemas: SchemaDefinition[]) => Promise<void>;
849
+ }
850
+ type CollectionMigrationOptions = {
851
+ changes: SchemaChange<any>[];
852
+ description: string;
853
+ rollback?: SchemaChange<any>[];
854
+ transform?: string | DataTransform<any, any>;
855
+ };
856
+ /**
857
+ * Event payload for Database events.
858
+ */
859
+ type DatabaseEventType = "collection:create" | "collection:delete" | "collection:update" | "collection:read" | "migrate";
860
+ type DatabaseEvent = {
861
+ type: DatabaseEventType;
862
+ schema?: SchemaDefinition | Partial<SchemaDefinition>;
863
+ timestamp: number;
864
+ };
865
+ type Document<T> = {
866
+ readonly [K in keyof T]: T[K];
867
+ } & {
868
+ /**
869
+ * Unique identifier for the document (assigned automatically if not provided).
870
+ */
871
+ $id?: string;
872
+ /**
873
+ * Timestamp of document creation (ISO string or Date).
874
+ */
875
+ $created?: string | Date;
876
+ /**
877
+ * Timestamp of last document update (ISO string or Date).
878
+ */
879
+ $updated?: string | Date;
880
+ /**
881
+ * Version number incremented on each change (used for optimistic concurrency control).
882
+ */
883
+ $version?: number;
884
+ /**
885
+ * Fetches the latest data from the database and updates the document instance.
886
+ * @returns A promise resolving to `true` if successful, or `false` if an error occurs.
887
+ */
888
+ read: () => Promise<boolean>;
889
+ /**
890
+ * Saves the current document state to the database.
891
+ * Normally called automatically by `update()` or `delete()`, but can be used manually.
892
+ * @returns A promise resolving to `true` if successful, or `false` if an error occurs.
893
+ */
894
+ save: (tx?: TransactionContext) => Promise<boolean>;
895
+ /**
896
+ * Updates the document with the provided properties.
897
+ * @param props - Partial object containing the fields to update.
898
+ * @returns A promise resolving to `true` if successful, or `false` if an error occurs.
899
+ */
900
+ update: (props: Partial<T>) => Promise<boolean>;
901
+ /**
902
+ * Deletes the document from the database.
903
+ * @returns A promise resolving to `true` if successful, or `false` if an error occurs.
904
+ */
905
+ delete: () => Promise<boolean>;
906
+ /**
907
+ * Subscribes to document events (e.g., "update", "delete", "access").
908
+ * @param event - The event type to subscribe to.
909
+ * @param callback - The function to call when the event occurs.
910
+ * @returns An unsubscribe function.
911
+ */
912
+ subscribe: (event: DocumentEventType | TelemetryEventType, callback: (event: DocumentEvent<T> | TelemetryEvent) => void) => () => void;
913
+ /**
914
+ * Returns a plain object containing only the user-defined data (without system fields like $id, $version, etc.).
915
+ * @returns The current user data.
916
+ */
917
+ state(): T;
918
+ };
919
+ /**
920
+ * Event payload for DocumentModel events.
921
+ */
922
+ type DocumentEventType = "document:create" | "document:write" | "document:update" | "document:delete" | "document:read";
923
+ type DocumentEvent<T> = {
924
+ type: DocumentEventType;
925
+ data?: Partial<T>;
926
+ timestamp: number;
927
+ };
928
+ type TelemetryEventType = "telemetry";
929
+ type TelemetryEvent = {
930
+ type: TelemetryEventType;
931
+ method: string;
932
+ timestamp: number;
933
+ source: any;
934
+ metadata: {
935
+ args: any[];
936
+ performance: {
937
+ durationMs: number;
938
+ };
939
+ source: {
940
+ level: "database" | "collection" | "document";
941
+ collection?: string;
942
+ document?: string;
943
+ };
944
+ result?: {
945
+ type: 'array' | string;
946
+ size?: number;
947
+ };
948
+ error: {
949
+ message: string;
950
+ name: string;
951
+ stack?: string;
952
+ } | null;
953
+ };
954
+ };
955
+
956
+ interface WorkspaceDatabase {
957
+ /**
958
+ * Open the database. Registers core schemas followed by any extension
959
+ * schemas supplied by the caller (domain plugins).
960
+ *
961
+ * Idempotent — safe to call multiple times; subsequent calls are no-ops
962
+ * if the database is already open.
963
+ */
964
+ open(extensionSchemas?: SchemaDefinition[]): Promise<void>;
965
+ /**
966
+ * Access a collection by schema name.
967
+ * Throws if the schema has not been registered.
968
+ */
969
+ collection<T>(schemaName: string): Promise<Collection<T>>;
970
+ /**
971
+ * Close the database connection.
972
+ */
973
+ close(): void;
974
+ }
975
+ declare function createWorkspaceDatabase(db: Database): WorkspaceDatabase;
976
+ declare const COLLECTIONS: {
977
+ readonly ROLE: "role";
978
+ readonly PREFERENCE: "preference";
979
+ readonly CONTEXT: "context";
980
+ readonly SESSION: "session";
981
+ readonly TURN: "turn";
982
+ };
983
+ type CollectionName = typeof COLLECTIONS[keyof typeof COLLECTIONS];
547
984
 
548
985
  /**
549
986
  * Utility type for representing partial updates to the state, allowing deep nesting.
@@ -560,65 +997,14 @@ declare function del<T>(): T;
560
997
  declare const merge: <T extends object>(original: T, changes: DeepPartial<T> | symbol) => T;
561
998
  declare function ok<T>(value: T): Result<T, never>;
562
999
  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
- }
1000
+ declare function omitNullUndefined<T extends Record<string, any>>(obj: T): Partial<T>;
1001
+ declare function createSimpleWorkspace({ name, owner, language }: {
1002
+ name: string;
1003
+ language: string;
1004
+ owner: string;
1005
+ }): Workspace;
1006
+ declare function extractBlobRecord(patch: DeepPartial<Workspace>): BlobRecord | null;
1007
+ declare function extractBlobRef(record: BlobRecord): BlobRef;
622
1008
 
623
1009
  /**
624
1010
  * Persistence contract for binary blob content and blob registry records.
@@ -672,19 +1058,26 @@ interface TurnRef {
672
1058
  version: number;
673
1059
  }
674
1060
  declare class TurnTree {
675
- private readonly storage;
676
- constructor(storage: ContentStorage);
1061
+ private readonly db;
1062
+ constructor(db: WorkspaceDatabase);
1063
+ private turns;
1064
+ private sessions;
1065
+ /**
1066
+ * Compound filter for a specific (sessionId, id, version) tuple.
1067
+ * Uses only declared schema fields — never $id.
1068
+ */
1069
+ private turnFilter;
1070
+ getHead(sessionId: UUID): Promise<TurnRef | null>;
1071
+ setHead(sessionId: UUID, head: TurnRef | null): Promise<void>;
677
1072
  append(sessionId: UUID, turn: Turn): Promise<Turn>;
678
- appendBatch(sessionId: UUID, turns: Turn[]): Promise<void>;
1073
+ appendBatch(sessionId: UUID, turns: Turn[], finalHead: TurnRef | null): Promise<void>;
679
1074
  replaceVersion(sessionId: UUID, newTurn: Turn): Promise<void>;
680
1075
  branch(sessionId: UUID, newTurn: Turn): Promise<void>;
1076
+ loadAllTurns(sessionId: UUID): Promise<Turn[]>;
681
1077
  getActiveChain(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<Turn[]>;
682
- countChained(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<number>;
683
1078
  buildNodeGraph(sessionId: UUID, dirtyBuffer?: readonly Turn[]): Promise<Record<UUID, TurnNode>>;
684
1079
  deleteSubtree(sessionId: UUID, turnId: UUID, version: number, newHead: TurnRef | null): Promise<void>;
685
1080
  copyTranscript(sourceSessionId: UUID, targetSessionId: UUID): Promise<void>;
686
- getHead(sessionId: UUID): Promise<TurnRef | null>;
687
- setHead(sessionId: UUID, head: TurnRef | null): Promise<void>;
688
1081
  }
689
1082
 
690
1083
  declare function computeSHA256(data: Uint8Array): Promise<SHA256>;
@@ -741,29 +1134,55 @@ declare class BlobStore {
741
1134
  }
742
1135
 
743
1136
  declare class ContentStore {
744
- private readonly storage;
745
- private readonly tree;
746
- private readonly cache;
747
- constructor(storage: ContentStorage, config?: ContentStoreConfig);
1137
+ private readonly db;
1138
+ readonly tree: TurnTree;
1139
+ readonly blobs: BlobStore;
1140
+ private readonly roleCache;
1141
+ private readonly preferenceCache;
1142
+ private readonly contextCache;
1143
+ /**
1144
+ * Called after any blob registry change with the sha256 and updated
1145
+ * BlobRecord (null on deletion). Wire this to your state manager to
1146
+ * keep Index.blobs current.
1147
+ *
1148
+ * ContentStore sets this on BlobStore.onRegistryChanged internally.
1149
+ * Consumers set this property to receive the forwarded notifications.
1150
+ */
1151
+ onBlobRegistryChanged?: (sha256: SHA256, record: BlobRecord | null) => void;
1152
+ private constructor();
1153
+ static create(db: WorkspaceDatabase, blobStorage: BlobStorage, config?: ContentStoreConfig): Promise<ContentStore>;
1154
+ private init;
748
1155
  getTurnTree(): TurnTree;
749
1156
  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
1157
  saveRole(role: Role): Promise<void>;
754
- savePreference(preference: Preference): Promise<void>;
755
- saveContext(context: Context): Promise<void>;
756
1158
  deleteRole(name: string): Promise<void>;
1159
+ getPreference(id: UUID): Promise<Result<Preference, WorkspaceError>>;
1160
+ savePreference(preference: Preference): Promise<void>;
757
1161
  deletePreference(id: UUID): Promise<void>;
1162
+ getContext(key: string): Promise<Result<Context, WorkspaceError>>;
1163
+ saveContext(context: Context): Promise<void>;
758
1164
  deleteContext(key: string): Promise<void>;
1165
+ getContextByTopics(indexState: Index, topics: string[]): Promise<Context[]>;
1166
+ saveSession(meta: SessionMeta): Promise<void>;
1167
+ updateSessionMeta(sessionId: UUID, patch: DeepPartial<SessionMeta>): Promise<void>;
1168
+ deleteSession(sessionId: UUID): Promise<void>;
1169
+ registerBlob(data: Uint8Array, mediaType: BlobMediaType, filename?: string): Promise<Result<BlobRef, WorkspaceError>>;
1170
+ retainBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1171
+ releaseBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1172
+ purgeBlob(sha256: SHA256): Promise<Result<void, WorkspaceError>>;
1173
+ recordBlobRemoteId(sha256: SHA256, providerId: string, fileId: string): Promise<Result<void, WorkspaceError>>;
1174
+ getBlobRecord(sha256: SHA256): BlobRecord | null;
1175
+ getAllBlobRecords(): Record<SHA256, BlobRecord>;
1176
+ /**
1177
+ * Returns the blob resolver function expected by PromptBuilder.
1178
+ * Closes over the internal BlobStore — no BlobStore reference leaks out.
1179
+ */
1180
+ getBlobResolver(): BlobStore['resolveRefs'];
759
1181
  recordTurn(sessionId: UUID, turn: Turn): Promise<Result<void, WorkspaceError>>;
760
1182
  editTurn(sessionId: UUID, turnId: UUID, newBlocks: ContentBlock[], newVersion: number, roleSnapshot?: string): Promise<Result<void, WorkspaceError>>;
761
1183
  branchTurn(sessionId: UUID, newTurn: Turn): Promise<Result<void, WorkspaceError>>;
762
1184
  deleteTurnSubtree(sessionId: UUID, turnId: UUID, version: number, newHead: TurnRef | null): Promise<Result<void, WorkspaceError>>;
763
1185
  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
1186
  resolveSession(workspace: Workspace, sessionId: UUID, transcript?: Turn[]): Promise<Result<EffectiveSession, WorkspaceError>>;
768
1187
  }
769
1188
 
@@ -771,6 +1190,12 @@ declare function workspaceReducer({ index: state }: Workspace, command: Command)
771
1190
 
772
1191
  declare class WorkspaceManager {
773
1192
  private readonly contentStore;
1193
+ /**
1194
+ * Called when BlobStore triggers a registry change outside of a dispatch()
1195
+ * call — e.g. eagerEviction deleting a blob on release. The caller should
1196
+ * merge this patch into their Workspace.
1197
+ */
1198
+ onWorkspacePatch?: (patch: DeepPartial<Workspace>) => void;
774
1199
  constructor(contentStore: ContentStore);
775
1200
  reduce(workspace: Workspace, command: Command): Result<DeepPartial<Workspace>, WorkspaceError>;
776
1201
  dispatch(workspace: Workspace, command: Command): Promise<Result<DeepPartial<Workspace>, WorkspaceError>>;
@@ -902,18 +1327,6 @@ declare function buildTurnNode(turn: Turn, children?: UUID[]): TurnNode;
902
1327
  interface SessionManagerConfig {
903
1328
  flush?: Partial<FlushConfig>;
904
1329
  }
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
1330
  interface OpenResult {
918
1331
  session: Session;
919
1332
  patch: DeepPartial<Workspace>;
@@ -928,4 +1341,71 @@ declare class SessionManager {
928
1341
  get workspace(): WorkspaceManager;
929
1342
  }
930
1343
 
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 };
1344
+ /**
1345
+ * In-process implementation backed by plain Maps.
1346
+ * Suitable for development, testing, and server-side runtimes without
1347
+ * access to IndexedDB.
1348
+ */
1349
+ declare class MemoryBlobStorage implements BlobStorage {
1350
+ private readonly bytes;
1351
+ private readonly records;
1352
+ storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
1353
+ loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
1354
+ hasBytes(sha256: SHA256): Promise<boolean>;
1355
+ deleteBytes(sha256: SHA256): Promise<void>;
1356
+ saveRecord(record: BlobRecord): Promise<void>;
1357
+ loadRecord(sha256: SHA256): Promise<BlobRecord | null>;
1358
+ deleteRecord(sha256: SHA256): Promise<void>;
1359
+ listRecords(): Promise<BlobRecord[]>;
1360
+ exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
1361
+ /**
1362
+ * Atomic register for MemoryBlobStorage — sequential ops are atomic
1363
+ * in a single-threaded JS runtime, so this is equivalent to two separate
1364
+ * calls, but we implement it for interface consistency.
1365
+ */
1366
+ registerBlob(record: BlobRecord, data: Uint8Array): Promise<void>;
1367
+ }
1368
+
1369
+ interface IndexedDBBlobConfig {
1370
+ /** Name of the IndexedDB database. Defaults to 'aiworkspace-blobs'. */
1371
+ dbName?: string;
1372
+ }
1373
+ /**
1374
+ * IndexedDB-backed blob storage.
1375
+ *
1376
+ * Bytes are stored as raw Uint8Array — IndexedDB handles binary natively,
1377
+ * no base64 encoding at rest. This is important for large files.
1378
+ *
1379
+ * Transaction discipline: never await inside an active transaction.
1380
+ * All multi-step operations chain synchronous IDB request handlers
1381
+ * inside a single Promise.
1382
+ */
1383
+ declare class IndexedDBBlobStorage implements BlobStorage {
1384
+ private readonly dbName;
1385
+ private db;
1386
+ constructor(config?: IndexedDBBlobConfig);
1387
+ open(): Promise<void>;
1388
+ private createSchema;
1389
+ close(): void;
1390
+ deleteDatabase(): Promise<void>;
1391
+ private getDB;
1392
+ private readTx;
1393
+ private writeTx;
1394
+ storeBytes(sha256: SHA256, data: Uint8Array): Promise<void>;
1395
+ loadBytes(sha256: SHA256): Promise<Uint8Array | null>;
1396
+ hasBytes(sha256: SHA256): Promise<boolean>;
1397
+ deleteBytes(sha256: SHA256): Promise<void>;
1398
+ saveRecord(record: BlobRecord): Promise<void>;
1399
+ loadRecord(sha256: SHA256): Promise<BlobRecord | null>;
1400
+ deleteRecord(sha256: SHA256): Promise<void>;
1401
+ listRecords(): Promise<BlobRecord[]>;
1402
+ exportAllBytes(): Promise<Array<[SHA256, Uint8Array]>>;
1403
+ /**
1404
+ * Atomically stores bytes and saves a record together.
1405
+ * Preferred over calling storeBytes + saveRecord separately when both
1406
+ * are new — avoids a window where bytes exist without a record.
1407
+ */
1408
+ registerBlob(record: BlobRecord, data: Uint8Array): Promise<void>;
1409
+ }
1410
+
1411
+ 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 };