@fortemi/core 2026.6.3 → 2026.6.5

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/dist/index.d.ts CHANGED
@@ -131,7 +131,136 @@ declare class TypedEventBus {
131
131
  */
132
132
 
133
133
  type PersistenceMode = 'opfs' | 'idb' | 'memory';
134
- declare function createPGliteInstance(persistence: PersistenceMode, archiveName?: string): Promise<PGlite>;
134
+ interface CreatePGliteOptions {
135
+ /**
136
+ * Restore the instance from a physical data-dir snapshot (issue #187) — schema
137
+ * + rows + INDEXES in one binary load, with no migration / import / reindex.
138
+ * The blob comes from PGlite's `dumpDataDir`; see `dumpDbSnapshot`/`restoreDbSnapshot`.
139
+ * When set, callers MUST NOT run migrations — the restored dir already carries them.
140
+ */
141
+ loadDataDir?: Blob | File;
142
+ }
143
+ declare function createPGliteInstance(persistence: PersistenceMode, archiveName?: string, options?: CreatePGliteOptions): Promise<PGlite>;
144
+
145
+ /**
146
+ * Physical data-dir snapshot (issue #187).
147
+ *
148
+ * A *snapshot* is a binary dump of a populated PGlite data directory — schema +
149
+ * rows + INDEXES (including the HNSW vector index from migration 0004) — that
150
+ * restores in a single binary load with NO migration, NO shard import, and NO
151
+ * client-side HNSW build. It is the fast, pre-indexed, single-version restore
152
+ * option, complementary to logical Knowledge Shards (which are portable + mergeable
153
+ * but pay the import + reindex cost on every load).
154
+ *
155
+ * Named "snapshot" to stay distinct from:
156
+ * - `ArchiveManager` / `archiveName` — a *named persistence store* (idb/opfs namespace).
157
+ * - Knowledge Shards — logical, portable, mergeable interchange (`importShard`).
158
+ *
159
+ * Safety (the one real risk of the physical format): a Postgres data dir is coupled
160
+ * to the PGlite/pgvector version and the schema-migration head it was built with.
161
+ * Every snapshot carries a version stamp (a JSON sidecar); `restoreDbSnapshot`
162
+ * verifies compatibility BEFORE loading and fails fast (`DbSnapshotVersionError`) on
163
+ * mismatch, so a host can fall back to a shard import.
164
+ */
165
+
166
+ /** Snapshot meta envelope schema. */
167
+ declare const DB_SNAPSHOT_SCHEMA_VERSION: "fortemi.db-snapshot.v1";
168
+ /**
169
+ * PGlite version this build of @fortemi/core bundles and can safely restore a
170
+ * snapshot from. Kept in sync with the `@electric-sql/pglite` dependency; a unit
171
+ * test asserts it matches package.json so it can't silently drift.
172
+ */
173
+ declare const SUPPORTED_PGLITE_VERSION = "0.4.1";
174
+ /** Schema-migration head this build expects a restored snapshot to carry. */
175
+ declare const CURRENT_MIGRATION_HEAD: number;
176
+ type DbSnapshotCompression = 'none' | 'gzip' | 'auto';
177
+ interface DbSnapshotMeta {
178
+ schema_version: typeof DB_SNAPSHOT_SCHEMA_VERSION;
179
+ /** PGlite version the data dir was dumped from (data-dir format coupling). */
180
+ pglite_version: string;
181
+ /** pgvector extension version at dump time (advisory). */
182
+ pgvector_version: string | null;
183
+ /** Max applied migration version at dump time (schema coupling). */
184
+ migration_head: number;
185
+ /** ISO-8601 dump time. */
186
+ created_at: string;
187
+ /** @fortemi/core version that produced the snapshot (diagnostic only). */
188
+ fortemi_version?: string;
189
+ }
190
+ interface DbSnapshot {
191
+ /** The PGlite data-dir dump (gzip by default). Serve as a static asset. */
192
+ data: Blob | File;
193
+ /** Version stamp — serve alongside `data` as a `<name>.meta.json` sidecar. */
194
+ meta: DbSnapshotMeta;
195
+ }
196
+ /** Minimal shape `dumpDbSnapshot` needs — PGlite satisfies it structurally. */
197
+ interface DumpableDb {
198
+ query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<{
199
+ rows: T[];
200
+ }>;
201
+ dumpDataDir(compression?: DbSnapshotCompression): Promise<Blob | File>;
202
+ }
203
+ interface DumpDbSnapshotOptions {
204
+ /** Defaults to 'gzip'. */
205
+ compression?: DbSnapshotCompression;
206
+ /** Recorded in meta for diagnostics. */
207
+ fortemiVersion?: string;
208
+ /** Override the timestamp (tests / reproducible builds). */
209
+ createdAt?: string;
210
+ }
211
+ /**
212
+ * Dump a populated PGlite into a versioned snapshot. Build-time (Node), after the
213
+ * corpus is loaded and the HNSW index has been built once.
214
+ *
215
+ * Returns `{ data, meta }`: write `data` to e.g. `corpus.pgdata` and `meta` to
216
+ * `corpus.pgdata.meta.json` (the sidecar `restoreDbSnapshot(url)` looks for).
217
+ */
218
+ declare function dumpDbSnapshot(db: DumpableDb, options?: DumpDbSnapshotOptions): Promise<DbSnapshot>;
219
+ interface DbSnapshotExpectations {
220
+ migrationHead?: number;
221
+ pgliteVersion?: string;
222
+ /** When provided, a differing snapshot pgvector version is a warning, not a failure. */
223
+ pgvectorVersion?: string | null;
224
+ }
225
+ interface DbSnapshotCompat {
226
+ compatible: boolean;
227
+ /** Hard incompatibilities — restore must refuse. */
228
+ reasons: string[];
229
+ /** Advisory differences — restore proceeds. */
230
+ warnings: string[];
231
+ }
232
+ /**
233
+ * Verify a snapshot's version stamp against what this build supports. Pure —
234
+ * unit-testable with no PGlite. Hard gates: snapshot schema, migration head
235
+ * (exact), PGlite major.minor (data-dir format). pgvector is advisory.
236
+ */
237
+ declare function verifyDbSnapshotMeta(meta: DbSnapshotMeta, expected?: DbSnapshotExpectations): DbSnapshotCompat;
238
+ /** Thrown by `restoreDbSnapshot` when the snapshot is incompatible with this build. */
239
+ declare class DbSnapshotVersionError extends Error {
240
+ readonly reasons: string[];
241
+ readonly meta: DbSnapshotMeta;
242
+ constructor(reasons: string[], meta: DbSnapshotMeta);
243
+ }
244
+ type DbSnapshotSource = DbSnapshot | string | {
245
+ dataUrl: string;
246
+ metaUrl?: string;
247
+ };
248
+ interface RestoreDbSnapshotOptions {
249
+ /** Persistence for the restored instance. Defaults to 'memory' (read-only demos). */
250
+ persistence?: PersistenceMode;
251
+ archiveName?: string;
252
+ /** Verification expectations (defaults to this build's supported values). */
253
+ expectations?: DbSnapshotExpectations;
254
+ /** Injectable fetch (tests / non-browser). Defaults to global `fetch`. */
255
+ fetchImpl?: typeof fetch;
256
+ }
257
+ /**
258
+ * Restore a PGlite from a physical snapshot — verify the version stamp first,
259
+ * then load the data dir with **no migration / import / HNSW build**. Throws
260
+ * `DbSnapshotVersionError` on incompatibility (catch it to fall back to a shard
261
+ * import). The returned instance is ready to query; do NOT run migrations on it.
262
+ */
263
+ declare function restoreDbSnapshot(source: DbSnapshotSource, options?: RestoreDbSnapshotOptions): Promise<PGlite>;
135
264
 
136
265
  /**
137
266
  * Type-safe client for the PGlite Worker.
@@ -248,183 +377,933 @@ declare class PGliteWorkerStorageBackendFactory implements StorageBackendFactory
248
377
  }
249
378
 
250
379
  /**
251
- * Capability module system (ADR-002).
252
- * Tracks opt-in WASM module states. No WASM loaded by default (CAP-001).
380
+ * Shard format types — matches the fortemi server matric-shard specification.
253
381
  *
254
- * State machine (valid transitions):
255
- * unloaded -> loading (via enable)
256
- * loading -> ready (via markReady or successful loader)
257
- * loading -> error (via markError or failed loader)
258
- * ready -> disabled (via disable)
259
- * disabled -> loading (via enable, re-enable)
260
- * error -> loading (via enable, retry)
382
+ * A shard is a gzip-compressed tar archive (.shard) containing serialized
383
+ * knowledge data with a manifest for integrity verification.
261
384
  */
262
-
263
- type CapabilityState = 'unloaded' | 'loading' | 'ready' | 'error' | 'disabled';
264
- type CapabilityName = 'semantic' | 'llm' | 'audio' | 'vision' | 'pdf';
265
- declare class CapabilityManager {
266
- private events;
267
- private capabilities;
268
- private loaders;
269
- private progressMessages;
270
- constructor(events: TypedEventBus);
271
- /**
272
- * Register an async loader for a capability.
273
- * Called by enable(); if no loader is registered the capability transitions
274
- * directly to ready (useful for capabilities that require no async init).
275
- */
276
- registerLoader(name: CapabilityName, loader: () => Promise<void>): void;
277
- getState(name: CapabilityName): CapabilityState;
278
- isReady(name: CapabilityName): boolean;
279
- /**
280
- * Enable a capability.
281
- * Valid from: unloaded, disabled, error (retry).
282
- * Runs the registered loader if present; transitions to ready on success,
283
- * error on failure.
284
- */
285
- enable(name: CapabilityName): Promise<void>;
286
- /**
287
- * Disable a ready capability.
288
- * Valid from: ready only.
289
- */
290
- disable(name: CapabilityName): void;
291
- /**
292
- * Mark a loading capability as ready (external use, e.g. bridge protocol).
293
- * Valid from: loading only.
294
- */
295
- markReady(name: CapabilityName): void;
296
- /**
297
- * Mark a loading capability as errored (external use, e.g. bridge protocol).
298
- * Valid from: loading only.
299
- */
300
- markError(name: CapabilityName, error: string): void;
301
- /**
302
- * Report loading progress (0-100).
303
- * Emits capability.loading with progress if the capability is currently loading.
304
- * No-op if the capability is not in loading state.
305
- */
306
- reportProgress(name: CapabilityName, progress: number): void;
307
- /** Set a human-readable progress message for a loading capability */
308
- setProgress(name: CapabilityName, message: string): void;
309
- /** Get the current progress message for a capability */
310
- getProgress(name: CapabilityName): string | undefined;
311
- getError(name: CapabilityName): string | undefined;
312
- listAll(): Array<{
313
- name: CapabilityName;
314
- state: CapabilityState;
315
- }>;
316
- }
317
-
385
+ declare const CURRENT_SHARD_VERSION = "1.0.0";
386
+ declare const SHARD_FORMAT = "matric-shard";
387
+ /** Components that can appear in a shard archive. */
388
+ type ShardComponent = 'notes' | 'collections' | 'tags' | 'links' | 'embedding_sets' | 'embedding_set_members' | 'embedding_configs' | 'embeddings' | 'skos_schemes' | 'skos_concepts' | 'skos_relations' | 'note_skos_tags' | 'provenance_edges' | 'community_assignments' | 'communities' | 'graph_edges' | 'graph_sources';
318
389
  /**
319
- * Sequential SQL migration runner for DatabaseClient.
320
- * Tracks applied migrations in a schema_version table.
321
- * Each migration runs in a transaction; version updated atomically.
390
+ * Reference to one cluster file of a component split across addressable files
391
+ * (`notes/000.jsonl`, `notes/001.jsonl`, …). `offset`/`count` are the record
392
+ * range within the component, so an in-place reader fetches only the clusters a
393
+ * query needs — the shard analog of the AIWG chunk-manifest scan parts.
322
394
  */
323
-
324
- interface Migration {
325
- version: number;
326
- name: string;
327
- sql: string;
328
- }
329
- declare class MigrationRunner {
330
- private db;
331
- private events?;
332
- constructor(db: DatabaseClient, events?: TypedEventBus | undefined);
333
- ensureSchemaTable(): Promise<void>;
334
- getCurrentVersion(): Promise<number>;
335
- apply(migrations: Migration[]): Promise<number>;
336
- getAppliedMigrations(): Promise<Array<{
337
- version: number;
338
- name: string;
339
- }>>;
395
+ interface ShardClusterRef {
396
+ href: string;
397
+ offset: number;
398
+ count: number;
340
399
  }
341
-
342
- declare const allMigrations: Migration[];
343
-
344
400
  /**
345
- * Multi-archive manager for Fortemi.
346
- * Each archive is a separate PGlite instance with its own persistence path.
347
- * Migrations are applied automatically on open.
401
+ * Optional clustered layout (additive — absent on monolithic shards). When a
402
+ * component is present here, its records live in the listed cluster files instead
403
+ * of (or in addition to) the single `<component>.jsonl`. Both `importShard` and
404
+ * the in-place reader consume it; a monolithic shard omits `layout` entirely.
348
405
  */
349
-
350
- interface ArchiveInfo {
351
- name: string;
352
- createdAt: string;
406
+ interface ShardLayout {
407
+ clusters?: Partial<Record<ShardComponent, ShardClusterRef[]>>;
353
408
  }
354
- declare class ArchiveManager {
355
- private events?;
356
- private currentArchive;
357
- private db;
358
- private archives;
359
- private persistence;
360
- private backendFactory;
361
- constructor(persistenceOrFactory: PersistenceMode | StorageBackendFactory, events?: TypedEventBus | undefined, persistenceOverride?: PersistenceMode);
362
- getCurrentArchiveName(): string;
363
- getDb(): StorageBackend | null;
364
- open(archiveName?: string): Promise<StorageBackend>;
365
- create(archiveName: string): Promise<StorageBackend>;
366
- switchTo(archiveName: string): Promise<StorageBackend>;
367
- delete(archiveName: string): Promise<void>;
368
- listArchives(): ArchiveInfo[];
369
- close(): Promise<void>;
409
+ /** Manifest included in every shard as manifest.json. */
410
+ interface ShardManifest {
411
+ version: string;
412
+ matric_version: string;
413
+ format: typeof SHARD_FORMAT;
414
+ created_at: string;
415
+ components: ShardComponent[];
416
+ counts: Partial<Record<ShardComponent | 'community_sets', number>>;
417
+ checksums: Record<string, string>;
418
+ min_reader_version: string;
419
+ /** Clustered component layout for partial fetch (issue #189). Absent → monolithic. */
420
+ layout?: ShardLayout;
370
421
  }
371
-
372
- /**
373
- * Factory function for creating a FortemiCore instance.
374
- * All deployment modes use this entry point.
375
- */
376
-
377
- interface FortemiConfig {
378
- persistence: 'opfs' | 'idb' | 'memory';
379
- archiveName?: string;
422
+ /** Options for shard export. */
423
+ interface ExportOptions {
424
+ includeEmbeddings?: boolean;
425
+ /** Filter to specific collection (export only notes in this collection). */
426
+ collectionId?: string;
427
+ /** Filter to notes with this tag (e.g. 'app:research' for app-scoped export). */
428
+ tag?: string;
429
+ /** Export only these embedding sets and their member/vector rows. */
430
+ embeddingSetIds?: string[];
431
+ /** Preserve virtual selector materialization metadata and virtual member rows. */
432
+ includeMaterializedSelectors?: boolean;
433
+ /**
434
+ * When set to a positive integer, emit notes as clustered files
435
+ * (`notes/000.jsonl`, …) of this many records each, and record the layout in
436
+ * the manifest, so an in-place reader can fetch only the clusters it needs
437
+ * (issue #189). Absent → a single monolithic `notes.jsonl` (unchanged).
438
+ */
439
+ clusterNotesSize?: number;
380
440
  }
381
- interface FortemiCore {
382
- events: TypedEventBus;
383
- config: FortemiConfig;
384
- destroy(): void;
441
+ /** Conflict resolution strategy for shard import. */
442
+ type ConflictStrategy = 'skip' | 'replace' | 'error';
443
+ /** Options for shard import. */
444
+ interface ImportOptions {
445
+ conflictStrategy?: ConflictStrategy;
446
+ /** Rows processed between cooperative yields. Defaults to 250. */
447
+ batchSize?: number;
448
+ /** Progress callback for long-running import phases. */
449
+ onProgress?: (progress: ImportProgress) => void;
385
450
  }
386
- declare function createFortemi(config: FortemiConfig): FortemiCore;
387
-
388
- /**
389
- * Compute a SHA-256 content hash for the given byte array.
390
- *
391
- * Returns a string in `algorithm:hex` format to match the server-side
392
- * convention, e.g. `sha256:a3b4c5...` (64 hex characters after the prefix).
393
- *
394
- * @param data - Raw bytes to hash
395
- * @returns `'sha256:<64-char lowercase hex>'`
396
- */
397
- declare function computeHash(data: Uint8Array): string;
398
-
399
- interface SWRegistrationResult {
400
- registered: boolean;
401
- registration?: ServiceWorkerRegistration;
402
- error?: string;
451
+ type ImportProgressPhase = 'unpack' | 'validate' | 'collections' | 'notes' | 'skos' | 'links' | 'provenance' | 'embedding_sets' | 'embeddings' | 'embedding_set_members' | 'graph' | 'communities' | 'index';
452
+ interface ImportProgress {
453
+ phase: ImportProgressPhase;
454
+ done: number;
455
+ total: number;
403
456
  }
404
- declare function registerServiceWorker(swUrl?: string): Promise<SWRegistrationResult>;
405
-
406
- /**
407
- * REST route definitions for Service Worker.
408
- * These are pure functions that transform HTTP Request → tool input and tool output → Response.
409
- * The actual DB connection is injected at registration time.
410
- *
411
- * All routes currently return 503 Not Implemented — the DB wiring happens in a later issue.
412
- * The URL structure and request/response shapes are the valuable contract defined here.
413
- */
414
- interface RouteHandler {
415
- method: string;
416
- pattern: RegExp;
417
- handler: (request: Request, match: RegExpMatchArray, params: URLSearchParams) => Promise<Response>;
457
+ /** Per-entity import counts. */
458
+ interface ImportCounts {
459
+ notes: number;
460
+ collections: number;
461
+ tags: number;
462
+ links: number;
463
+ embedding_sets: number;
464
+ embedding_set_members: number;
465
+ embeddings: number;
466
+ skos_schemes: number;
467
+ skos_concepts: number;
468
+ skos_relations: number;
469
+ note_skos_tags: number;
470
+ provenance_edges: number;
471
+ graph_sources: number;
472
+ graph_edges: number;
473
+ community_sets: number;
474
+ communities: number;
475
+ community_assignments: number;
418
476
  }
419
- /**
420
- * Create route handlers.
421
- * db parameter will be injected when the SW gets access to PGlite.
422
- * For now, returns 503 Not Implemented for all routes.
423
- */
424
- declare function createRoutes(): RouteHandler[];
425
- /**
426
- * Match a request against the registered routes and return the first matching
427
- * handler, or null if no route matches.
477
+ /** Result of a shard import operation. */
478
+ interface ImportResult {
479
+ success: boolean;
480
+ counts: ImportCounts;
481
+ skipped: Partial<ImportCounts>;
482
+ warnings: string[];
483
+ errors: string[];
484
+ duration_ms: number;
485
+ }
486
+ /** Note as serialized in the shard JSONL. */
487
+ interface ShardNote {
488
+ id: string;
489
+ title: string | null;
490
+ original_content: string;
491
+ revised_content: string | null;
492
+ format: string;
493
+ source: string;
494
+ starred: boolean;
495
+ archived: boolean;
496
+ tags: string[];
497
+ created_at: string;
498
+ updated_at: string;
499
+ deleted_at: string | null;
500
+ }
501
+ /** Collection as serialized in the shard JSON array. */
502
+ interface ShardCollection {
503
+ id: string;
504
+ name: string;
505
+ description: string | null;
506
+ parent_id: string | null;
507
+ created_at: string;
508
+ note_count?: number;
509
+ }
510
+ /** Tag as serialized in the shard JSON array. */
511
+ interface ShardTag {
512
+ name: string;
513
+ created_at: string;
514
+ }
515
+ /** Link as serialized in the shard JSONL. */
516
+ interface ShardLink {
517
+ id: string;
518
+ from_note_id: string;
519
+ to_note_id: string;
520
+ kind: string;
521
+ score: number | null;
522
+ created_at: string;
523
+ metadata?: Record<string, unknown>;
524
+ }
525
+ /** Embedding set as serialized in the shard JSON array. */
526
+ interface ShardEmbeddingSet {
527
+ id: string;
528
+ name?: string;
529
+ purpose?: string | null;
530
+ model: string;
531
+ dimension: number;
532
+ kind?: 'physical' | 'filter' | 'virtual';
533
+ mode?: 'auto' | 'manual' | 'mixed' | null;
534
+ truncate_dimension?: number | null;
535
+ criteria?: Record<string, unknown> | null;
536
+ source?: Record<string, unknown> | null;
537
+ compatibility?: Record<string, unknown> | null;
538
+ materialization?: Record<string, unknown> | null;
539
+ freshness?: ShardArtifactFreshness | null;
540
+ created_at: string;
541
+ updated_at?: string;
542
+ }
543
+ /** Embedding set member as serialized in the shard JSONL. */
544
+ interface ShardEmbeddingSetMember {
545
+ embedding_set_id: string;
546
+ note_id: string;
547
+ embedding_id: string;
548
+ }
549
+ /** Embedding as serialized in the shard JSONL. */
550
+ interface ShardEmbedding {
551
+ id: string;
552
+ note_id: string;
553
+ embedding_set_id: string;
554
+ vector: number[];
555
+ created_at: string;
556
+ }
557
+ /** SKOS scheme as serialized in the shard JSON array. */
558
+ interface ShardSkosScheme {
559
+ id: string;
560
+ title: string;
561
+ description: string | null;
562
+ created_at: string;
563
+ updated_at: string;
564
+ }
565
+ /** SKOS concept as serialized in the shard JSON array. */
566
+ interface ShardSkosConcept {
567
+ id: string;
568
+ scheme_id: string;
569
+ pref_label: string;
570
+ alt_labels: string[];
571
+ definition: string | null;
572
+ created_at: string;
573
+ updated_at: string;
574
+ }
575
+ /** SKOS concept relation as serialized in the shard JSONL. */
576
+ interface ShardSkosRelation {
577
+ id: string;
578
+ source_concept_id: string;
579
+ target_concept_id: string;
580
+ relation_type: 'broader' | 'narrower' | 'related';
581
+ created_at: string;
582
+ }
583
+ /** Note-to-SKOS-concept assignment as serialized in the shard JSONL. */
584
+ interface ShardNoteSkosTag {
585
+ id: string;
586
+ note_id: string;
587
+ concept_id: string;
588
+ created_at: string;
589
+ }
590
+ /** Provenance edge as serialized in the shard JSONL. */
591
+ interface ShardProvenanceEdge {
592
+ id: string;
593
+ entity_type: string;
594
+ entity_id: string;
595
+ activity: string;
596
+ agent: string;
597
+ started_at: string;
598
+ ended_at: string | null;
599
+ attributes: Record<string, unknown> | null;
600
+ }
601
+ interface ShardArtifactFreshness {
602
+ status: 'fresh' | 'stale' | 'unknown';
603
+ checked_at?: string;
604
+ stale_reason?: string;
605
+ source_hashes?: {
606
+ notes?: string;
607
+ links?: string;
608
+ embeddings?: string;
609
+ embedding_set_members?: string;
610
+ virtual_set_definition?: string;
611
+ parameters?: string;
612
+ };
613
+ }
614
+
615
+ /**
616
+ * LinksRepository — bidirectional note link management.
617
+ *
618
+ * Responsibilities:
619
+ * - Create typed links between notes with duplicate prevention
620
+ * - Soft-delete links
621
+ * - Query outbound, inbound, and backlinks for a note
622
+ */
623
+
624
+ interface LinkRow {
625
+ id: string;
626
+ source_note_id: string;
627
+ target_note_id: string;
628
+ link_type: string;
629
+ confidence: number | null;
630
+ created_at: Date;
631
+ updated_at: Date | null;
632
+ deleted_at: Date | null;
633
+ }
634
+ declare class LinksRepository {
635
+ private db;
636
+ constructor(db: DatabaseClient);
637
+ create(sourceNoteId: string, targetNoteId: string, linkType?: string): Promise<LinkRow>;
638
+ get(id: string): Promise<LinkRow>;
639
+ listForNote(noteId: string): Promise<{
640
+ outbound: LinkRow[];
641
+ inbound: LinkRow[];
642
+ }>;
643
+ getBacklinks(noteId: string): Promise<string[]>;
644
+ delete(id: string): Promise<void>;
645
+ }
646
+
647
+ /**
648
+ * CollectionsRepository — folder/category management for notes.
649
+ *
650
+ * Responsibilities:
651
+ * - Create, read, update, and soft-delete collections
652
+ * - Prevent circular parent references
653
+ * - Assign and unassign notes from collections
654
+ * - Return flat list and shallow tree views
655
+ */
656
+
657
+ interface CollectionRow {
658
+ id: string;
659
+ name: string;
660
+ description: string | null;
661
+ parent_id: string | null;
662
+ position: number;
663
+ created_at: Date;
664
+ updated_at: Date;
665
+ deleted_at: Date | null;
666
+ }
667
+ interface CollectionCreateInput {
668
+ name: string;
669
+ description?: string;
670
+ parent_id?: string;
671
+ }
672
+ declare class CollectionsRepository {
673
+ private db;
674
+ constructor(db: DatabaseClient);
675
+ create(input: CollectionCreateInput): Promise<CollectionRow>;
676
+ get(id: string): Promise<CollectionRow>;
677
+ list(): Promise<CollectionRow[]>;
678
+ listTree(): Promise<Array<CollectionRow & {
679
+ children: CollectionRow[];
680
+ }>>;
681
+ update(id: string, fields: Partial<Pick<CollectionRow, 'name' | 'description' | 'parent_id' | 'position'>>): Promise<CollectionRow>;
682
+ delete(id: string): Promise<void>;
683
+ assignNote(collectionId: string, noteId: string): Promise<void>;
684
+ unassignNote(collectionId: string, noteId: string): Promise<void>;
685
+ getNotesInCollection(collectionId: string): Promise<string[]>;
686
+ }
687
+
688
+ /**
689
+ * Field mapper — converts between browser schema and shard (server) schema.
690
+ *
691
+ * The browser uses different field names than the server shard format.
692
+ * This module handles all rename transforms bidirectionally.
693
+ */
694
+
695
+ /** Browser-format note row from the export query (denormalized). */
696
+ interface BrowserNoteExport {
697
+ id: string;
698
+ title: string | null;
699
+ format: string;
700
+ source: string;
701
+ is_starred: boolean;
702
+ is_archived: boolean;
703
+ created_at: Date | string;
704
+ updated_at: Date | string;
705
+ deleted_at: Date | string | null;
706
+ original_content: string;
707
+ revised_content: string | null;
708
+ tags: string[];
709
+ }
710
+ /** Convert a browser note to shard format. */
711
+ declare function noteToShard(note: BrowserNoteExport): ShardNote;
712
+ /** Convert a shard note back to browser-insertable format. */
713
+ declare function noteFromShard(shard: ShardNote): BrowserNoteExport;
714
+ /** Convert a browser link to shard format. */
715
+ declare function linkToShard(link: LinkRow): ShardLink;
716
+ /** Convert a shard link back to browser-insertable format. */
717
+ declare function linkFromShard(shard: ShardLink): {
718
+ id: string;
719
+ source_note_id: string;
720
+ target_note_id: string;
721
+ link_type: string;
722
+ confidence: number | null;
723
+ created_at: string;
724
+ };
725
+ /** Convert a browser collection to shard format. */
726
+ declare function collectionToShard(collection: CollectionRow, noteCount?: number): ShardCollection;
727
+ /** Convert a shard collection back to browser-insertable format. */
728
+ declare function collectionFromShard(shard: ShardCollection): {
729
+ id: string;
730
+ name: string;
731
+ description: string | null;
732
+ parent_id: string | null;
733
+ created_at: string;
734
+ };
735
+ /**
736
+ * Convert SKOS concepts + note_tag associations into shard flat tag format.
737
+ * Shard tags are simple string arrays — deduplicated across all notes.
738
+ */
739
+ declare function tagsToShard(allTags: Array<{
740
+ name: string;
741
+ created_at: Date | string;
742
+ }>): ShardTag[];
743
+ /**
744
+ * Convert shard flat tags to browser format for insertion.
745
+ * Returns unique tag names ready for note_tag association.
746
+ */
747
+ declare function tagsFromShard(shardTags: ShardTag[]): string[];
748
+ /** Convert a browser embedding_set to shard format. */
749
+ declare function embeddingSetToShard(set: {
750
+ id: string;
751
+ name?: string;
752
+ purpose?: string | null;
753
+ model_name: string;
754
+ dimensions: number;
755
+ kind?: 'physical' | 'filter' | 'virtual';
756
+ mode?: 'auto' | 'manual' | 'mixed' | null;
757
+ truncate_dimension?: number | null;
758
+ criteria_json?: unknown | null;
759
+ source_json?: unknown | null;
760
+ compatibility_json?: unknown | null;
761
+ materialization_json?: unknown | null;
762
+ freshness_json?: unknown | null;
763
+ created_at: Date | string;
764
+ updated_at?: Date | string;
765
+ }): ShardEmbeddingSet;
766
+ /** Convert a shard embedding set back to browser format. */
767
+ declare function embeddingSetFromShard(shard: ShardEmbeddingSet): {
768
+ id: string;
769
+ name: string;
770
+ purpose: string | null;
771
+ model_name: string;
772
+ dimensions: number;
773
+ kind: 'physical' | 'filter' | 'virtual';
774
+ mode: 'auto' | 'manual' | 'mixed' | null;
775
+ truncate_dimension: number | null;
776
+ criteria_json: string | null;
777
+ source_json: string | null;
778
+ compatibility_json: string | null;
779
+ materialization_json: string | null;
780
+ freshness_json: string | null;
781
+ created_at: string;
782
+ updated_at: string | null;
783
+ };
784
+ /** Convert a browser embedding_set_member to shard format. */
785
+ declare function embeddingSetMemberToShard(member: {
786
+ embedding_set_id: string;
787
+ note_id: string;
788
+ embedding_id: string;
789
+ }): ShardEmbeddingSetMember;
790
+ /** Convert a browser embedding to shard format. */
791
+ declare function embeddingToShard(emb: {
792
+ id: string;
793
+ note_id: string;
794
+ embedding_set_id: string;
795
+ vector: string | number[];
796
+ created_at: Date | string;
797
+ }): ShardEmbedding;
798
+ /** Convert a shard embedding back to browser format. */
799
+ declare function embeddingFromShard(shard: ShardEmbedding): {
800
+ id: string;
801
+ note_id: string;
802
+ embedding_set_id: string;
803
+ vector: string;
804
+ created_at: string;
805
+ };
806
+ declare function skosSchemeToShard(scheme: {
807
+ id: string;
808
+ title: string;
809
+ description: string | null;
810
+ created_at: Date | string;
811
+ updated_at: Date | string;
812
+ }): ShardSkosScheme;
813
+ declare function skosConceptToShard(concept: {
814
+ id: string;
815
+ scheme_id: string;
816
+ pref_label: string;
817
+ alt_labels: string[] | string | null;
818
+ definition: string | null;
819
+ created_at: Date | string;
820
+ updated_at: Date | string;
821
+ }): ShardSkosConcept;
822
+ declare function skosRelationToShard(relation: {
823
+ id: string;
824
+ source_concept_id: string;
825
+ target_concept_id: string;
826
+ relation_type: 'broader' | 'narrower' | 'related';
827
+ created_at: Date | string;
828
+ }): ShardSkosRelation;
829
+ declare function noteSkosTagToShard(tag: {
830
+ id: string;
831
+ note_id: string;
832
+ concept_id: string;
833
+ created_at: Date | string;
834
+ }): ShardNoteSkosTag;
835
+ declare function provenanceEdgeToShard(edge: {
836
+ id: string;
837
+ entity_type: string;
838
+ entity_id: string;
839
+ activity: string;
840
+ agent: string;
841
+ started_at: Date | string;
842
+ ended_at: Date | string | null;
843
+ attributes: Record<string, unknown> | string | null;
844
+ }): ShardProvenanceEdge;
845
+
846
+ /**
847
+ * In-place Knowledge Shard reader (issue #189) — the static-file backend.
848
+ *
849
+ * A shard is already a self-describing bundle of formatted component files
850
+ * (`notes.jsonl`, `links.jsonl`, `note_skos_tags.jsonl`, `skos_concepts.json`, …)
851
+ * plus a `manifest.json`. `importShard` loads all of it into PGlite; this reader
852
+ * is the *second* access mode of the SAME format: open the manifest and query the
853
+ * component (or clustered) files directly, with NO PGlite — read-only, lightest.
854
+ *
855
+ * Capabilities (read-only): browse + get note, full-text + facet search, lazy
856
+ * links/tags/concepts + full record. Semantic is opt-in via a pluggable provider
857
+ * (none / brute-force cosine / prebuilt ANN snapshot) — see `StaticSemanticProvider`.
858
+ */
859
+
860
+ /** The public note shape — the same browser-insertable record `importShard` produces. */
861
+ type ShardReaderNote = BrowserNoteExport;
862
+ interface ShardSearchWeights {
863
+ title: number;
864
+ content: number;
865
+ tag: number;
866
+ }
867
+ interface ShardListOptions {
868
+ offset?: number;
869
+ limit?: number;
870
+ /** Include archived notes (default true). */
871
+ includeArchived?: boolean;
872
+ /** Include soft-deleted notes (default false). */
873
+ includeDeleted?: boolean;
874
+ }
875
+ interface ShardSearchOptions extends ShardListOptions {
876
+ /** AND-filter: note must carry every listed tag. */
877
+ tags?: string[];
878
+ /** OR-filter on note source. */
879
+ source?: string[];
880
+ rank?: boolean;
881
+ snippets?: boolean;
882
+ snippetLength?: number;
883
+ weights?: Partial<ShardSearchWeights>;
884
+ }
885
+ interface ShardSearchRankedNote {
886
+ note: ShardReaderNote;
887
+ rank: number;
888
+ snippet?: string;
889
+ }
890
+ interface ShardSearchResult {
891
+ items: ShardReaderNote[];
892
+ total: number;
893
+ facets: {
894
+ tags: Record<string, number>;
895
+ source: Record<string, number>;
896
+ };
897
+ rankedItems?: ShardSearchRankedNote[];
898
+ /** Cluster files fetched to serve this query (0 when served from cache). */
899
+ fetchedClusters: number;
900
+ }
901
+ interface ShardNoteFull {
902
+ note: ShardReaderNote;
903
+ links: ShardLink[];
904
+ concepts: ShardSkosConcept[];
905
+ }
906
+ /**
907
+ * Opt-in semantic search over static files. The reader stays text/facets-only
908
+ * unless a provider is supplied. Implementations span the tradeoff points:
909
+ * brute-force cosine over a small static vector set, or a prebuilt ANN snapshot
910
+ * for the full corpus. `prepare()` may lazily load whatever static asset it needs.
911
+ */
912
+ interface StaticSemanticProvider {
913
+ prepare?(store: ShardComponentStore): Promise<void>;
914
+ search(query: string, k: number): Promise<Array<{
915
+ id: string;
916
+ score: number;
917
+ }>>;
918
+ }
919
+ interface OpenShardOptions {
920
+ /** Static base URL when `source` is unpacked component files. */
921
+ baseUrl?: string;
922
+ fetchImpl?: typeof fetch;
923
+ /** Optional semantic provider; absent → `semantic()` returns []. */
924
+ semantic?: StaticSemanticProvider;
925
+ /** Bounds the cross-page search match cache (total cached note records). Default 5000. */
926
+ maxCachedMatches?: number;
927
+ }
928
+ /** Reads shard component/cluster files from a packed map or a static base URL. */
929
+ interface ShardComponentStore {
930
+ readonly manifest: ShardManifest;
931
+ read(filename: string): Promise<Uint8Array | undefined>;
932
+ }
933
+ type ShardReaderSource = Uint8Array | Blob | {
934
+ baseUrl: string;
935
+ fetchImpl?: typeof fetch;
936
+ };
937
+ interface ShardReader {
938
+ readonly manifest: ShardManifest;
939
+ listNotes(options?: ShardListOptions): Promise<{
940
+ items: ShardReaderNote[];
941
+ total: number;
942
+ }>;
943
+ getNote(id: string): Promise<ShardReaderNote | null>;
944
+ search(query: string, options?: ShardSearchOptions): Promise<ShardSearchResult>;
945
+ linksOf(id: string): Promise<ShardLink[]>;
946
+ conceptsOf(id: string): Promise<ShardSkosConcept[]>;
947
+ getNoteFull(id: string): Promise<ShardNoteFull | null>;
948
+ semantic(query: string, k?: number): Promise<Array<{
949
+ note: ShardReaderNote;
950
+ score: number;
951
+ }>>;
952
+ close(): void;
953
+ }
954
+ /**
955
+ * Open a Knowledge Shard for in-place, read-only query — NO PGlite. `source` is a
956
+ * packed tar.gz (`Uint8Array`/`Blob`) or a static base URL serving the unpacked
957
+ * component/cluster files. Honors `min_reader_version`: a shard that needs a newer
958
+ * reader than this build throws (the host should fall back to `importShard`).
959
+ */
960
+ declare function openShard(source: ShardReaderSource, options?: OpenShardOptions): Promise<ShardReader>;
961
+
962
+ /**
963
+ * Backend seam (#191) — a uniform tool-intent operation interface that lets the
964
+ * PGlite database backend (#187) and the static-file shard backend (#189) be
965
+ * selected and dispatched against the same way, plus a capability-negotiation
966
+ * API so a caller asks for the operations it needs and gets the lightest backend
967
+ * that provides them.
968
+ *
969
+ * The seam sits one level above SQL: every adapter exposes the same read
970
+ * operations (and optional write / semantic / full-content ops) regardless of
971
+ * whether the data lives in a queryable PGlite instance or a set of static shard
972
+ * files fetched over HTTP. A remote-server backend is a future adapter against
973
+ * this same interface — deliberately deferred. See
974
+ * `.aiwg/architecture/adr-backend-seam.md`.
975
+ */
976
+
977
+ /**
978
+ * Semantic-search tier a backend offers, in increasing capability:
979
+ * - `none` — no vector search (text / facets only)
980
+ * - `cosine-small` — brute-force cosine over a small static vector set (#189)
981
+ * - `ann-full` — prebuilt/queryable approximate-nearest-neighbour over the full
982
+ * corpus (PGlite + pgvector, or a prebuilt ANN snapshot)
983
+ * - `server` — delegated to a remote service (future remote backend)
984
+ */
985
+ type BackendSemanticTier = 'none' | 'cosine-small' | 'ann-full' | 'server';
986
+ /** Relative startup cost of bringing a backend online. */
987
+ type BackendStartupCost = 'instant' | 'index-build' | 'network';
988
+ /** What a backend can do — the unit of capability negotiation. */
989
+ interface BackendCapabilities {
990
+ /** Can answer list / get / search read operations. */
991
+ read: boolean;
992
+ /** Can mutate notes (manageNote). */
993
+ write: boolean;
994
+ /** Can merge external shards into its store. */
995
+ merge: boolean;
996
+ /** Coordinates concurrent multi-user writes. */
997
+ multiUser: boolean;
998
+ /** Highest semantic-search tier available. */
999
+ semantic: BackendSemanticTier;
1000
+ /** Relative cost to bring the backend online. */
1001
+ startupCost: BackendStartupCost;
1002
+ }
1003
+ /**
1004
+ * Backend-neutral note record. `source`/`starred`/`archived` are optional
1005
+ * because lean read paths (PGlite full-text search) do not return them; list,
1006
+ * get, and every shard path populate all fields.
1007
+ */
1008
+ interface BackendNote {
1009
+ id: string;
1010
+ title: string | null;
1011
+ tags: string[];
1012
+ createdAt: string;
1013
+ updatedAt: string;
1014
+ source?: string;
1015
+ starred?: boolean;
1016
+ archived?: boolean;
1017
+ }
1018
+ /** A note plus its current rendered content. */
1019
+ interface BackendNoteFull extends BackendNote {
1020
+ content: string;
1021
+ }
1022
+ /** One search hit — note plus optional rank/snippet when the backend ranks. */
1023
+ interface BackendSearchHit {
1024
+ note: BackendNote;
1025
+ rank?: number;
1026
+ snippet?: string;
1027
+ }
1028
+ /** Search response with optional facet counts. */
1029
+ interface BackendSearchResult {
1030
+ hits: BackendSearchHit[];
1031
+ total: number;
1032
+ facets?: {
1033
+ tags: Record<string, number>;
1034
+ source?: Record<string, number>;
1035
+ };
1036
+ }
1037
+ interface BackendListOptions {
1038
+ offset?: number;
1039
+ limit?: number;
1040
+ }
1041
+ interface BackendSearchQueryOptions extends BackendListOptions {
1042
+ /** AND-filter: note must carry every listed tag. */
1043
+ tags?: string[];
1044
+ /** OR-filter on note source. */
1045
+ source?: string[];
1046
+ }
1047
+ /**
1048
+ * Uniform tool-intent operation interface. Every backend implements the read
1049
+ * core; `getNoteFull`, `semantic`, and `manageNote` are optional and present
1050
+ * only on backends whose capabilities advertise them.
1051
+ */
1052
+ interface DataBackend {
1053
+ readonly id: string;
1054
+ readonly capabilities: BackendCapabilities;
1055
+ listNotes(options?: BackendListOptions): Promise<{
1056
+ items: BackendNote[];
1057
+ total: number;
1058
+ }>;
1059
+ getNote(id: string): Promise<BackendNote | null>;
1060
+ search(query: string, options?: BackendSearchQueryOptions): Promise<BackendSearchResult>;
1061
+ /** Lazy full content (present when capabilities.read). */
1062
+ getNoteFull?(id: string): Promise<BackendNoteFull | null>;
1063
+ /** Vector search (present when capabilities.semantic !== 'none'). */
1064
+ semantic?(query: string, k?: number): Promise<BackendSearchHit[]>;
1065
+ /** Write op (present when capabilities.write). */
1066
+ manageNote?(input: unknown): Promise<unknown>;
1067
+ }
1068
+ /** What a caller needs. Booleans require `true`; `semantic` is a minimum tier. */
1069
+ interface BackendRequest {
1070
+ read?: boolean;
1071
+ write?: boolean;
1072
+ merge?: boolean;
1073
+ multiUser?: boolean;
1074
+ /** Minimum acceptable semantic tier (a higher tier satisfies a lower request). */
1075
+ semantic?: BackendSemanticTier;
1076
+ }
1077
+ interface BackendCandidate {
1078
+ backend: DataBackend;
1079
+ /** Requested capabilities this backend cannot satisfy ([] = fully satisfies). */
1080
+ missing: string[];
1081
+ }
1082
+ interface BackendSelection {
1083
+ /** Chosen backend — fully-satisfying-and-lightest, else fewest-missing. Null only when no backends are available. */
1084
+ backend: DataBackend | null;
1085
+ capabilities: BackendCapabilities | null;
1086
+ /** Requested capabilities the chosen backend cannot satisfy. */
1087
+ missing: string[];
1088
+ /** Every candidate with its own missing set, ordered as evaluated. */
1089
+ candidates: BackendCandidate[];
1090
+ }
1091
+ /**
1092
+ * Pick the backend that best satisfies `request` from `available`. Prefers a
1093
+ * fully-satisfying backend with the lightest startup cost; if none fully
1094
+ * satisfy, returns the one missing the fewest capabilities (lightest on ties) so
1095
+ * the caller can degrade with eyes open via `selection.missing`.
1096
+ */
1097
+ declare function selectBackend(request: BackendRequest, available: DataBackend[]): BackendSelection;
1098
+ interface PGliteBackendOptions {
1099
+ id?: string;
1100
+ /** Whether embeddings exist so search can use the semantic path. */
1101
+ semanticAvailable?: boolean;
1102
+ }
1103
+ /**
1104
+ * Wrap a PGlite-backed `DatabaseClient` as a `DataBackend`. Read ops delegate to
1105
+ * the repositories; writes go through the `manageNote` tool. Advertises full
1106
+ * read+write+merge with `ann-full` semantic when embeddings are present.
1107
+ */
1108
+ declare function createPGliteBackend(db: DatabaseClient, options?: PGliteBackendOptions): DataBackend;
1109
+ interface ShardBackendOptions {
1110
+ id?: string;
1111
+ /** Declared semantic tier this shard provides (default `none`). Set to `cosine-small` when the reader has a vector provider. */
1112
+ semantic?: BackendSemanticTier;
1113
+ }
1114
+ /**
1115
+ * Wrap a `ShardReader` (#189) as a read-only `DataBackend`. Startup is instant
1116
+ * (no index build) and the semantic tier is whatever the reader's provider
1117
+ * offers — `none` for text/facets-only shards, `cosine-small` when a vector
1118
+ * provider is attached.
1119
+ */
1120
+ declare function createShardBackend(reader: ShardReader, options?: ShardBackendOptions): DataBackend;
1121
+
1122
+ /**
1123
+ * Capability module system (ADR-002).
1124
+ * Tracks opt-in WASM module states. No WASM loaded by default (CAP-001).
1125
+ *
1126
+ * State machine (valid transitions):
1127
+ * unloaded -> loading (via enable)
1128
+ * loading -> ready (via markReady or successful loader)
1129
+ * loading -> error (via markError or failed loader)
1130
+ * ready -> disabled (via disable)
1131
+ * disabled -> loading (via enable, re-enable)
1132
+ * error -> loading (via enable, retry)
1133
+ */
1134
+
1135
+ type CapabilityState = 'unloaded' | 'loading' | 'ready' | 'error' | 'disabled';
1136
+ type CapabilityName = 'semantic' | 'llm' | 'audio' | 'vision' | 'pdf';
1137
+ declare class CapabilityManager {
1138
+ private events;
1139
+ private capabilities;
1140
+ private loaders;
1141
+ private progressMessages;
1142
+ constructor(events: TypedEventBus);
1143
+ /**
1144
+ * Register an async loader for a capability.
1145
+ * Called by enable(); if no loader is registered the capability transitions
1146
+ * directly to ready (useful for capabilities that require no async init).
1147
+ */
1148
+ registerLoader(name: CapabilityName, loader: () => Promise<void>): void;
1149
+ getState(name: CapabilityName): CapabilityState;
1150
+ isReady(name: CapabilityName): boolean;
1151
+ /**
1152
+ * Enable a capability.
1153
+ * Valid from: unloaded, disabled, error (retry).
1154
+ * Runs the registered loader if present; transitions to ready on success,
1155
+ * error on failure.
1156
+ */
1157
+ enable(name: CapabilityName): Promise<void>;
1158
+ /**
1159
+ * Disable a ready capability.
1160
+ * Valid from: ready only.
1161
+ */
1162
+ disable(name: CapabilityName): void;
1163
+ /**
1164
+ * Mark a loading capability as ready (external use, e.g. bridge protocol).
1165
+ * Valid from: loading only.
1166
+ */
1167
+ markReady(name: CapabilityName): void;
1168
+ /**
1169
+ * Mark a loading capability as errored (external use, e.g. bridge protocol).
1170
+ * Valid from: loading only.
1171
+ */
1172
+ markError(name: CapabilityName, error: string): void;
1173
+ /**
1174
+ * Report loading progress (0-100).
1175
+ * Emits capability.loading with progress if the capability is currently loading.
1176
+ * No-op if the capability is not in loading state.
1177
+ */
1178
+ reportProgress(name: CapabilityName, progress: number): void;
1179
+ /** Set a human-readable progress message for a loading capability */
1180
+ setProgress(name: CapabilityName, message: string): void;
1181
+ /** Get the current progress message for a capability */
1182
+ getProgress(name: CapabilityName): string | undefined;
1183
+ getError(name: CapabilityName): string | undefined;
1184
+ listAll(): Array<{
1185
+ name: CapabilityName;
1186
+ state: CapabilityState;
1187
+ }>;
1188
+ }
1189
+
1190
+ /**
1191
+ * Sequential SQL migration runner for DatabaseClient.
1192
+ * Tracks applied migrations in a schema_version table.
1193
+ * Each migration runs in a transaction; version updated atomically.
1194
+ */
1195
+
1196
+ interface Migration {
1197
+ version: number;
1198
+ name: string;
1199
+ sql: string;
1200
+ }
1201
+ declare class MigrationRunner {
1202
+ private db;
1203
+ private events?;
1204
+ constructor(db: DatabaseClient, events?: TypedEventBus | undefined);
1205
+ ensureSchemaTable(): Promise<void>;
1206
+ getCurrentVersion(): Promise<number>;
1207
+ apply(migrations: Migration[]): Promise<number>;
1208
+ getAppliedMigrations(): Promise<Array<{
1209
+ version: number;
1210
+ name: string;
1211
+ }>>;
1212
+ }
1213
+
1214
+ declare const allMigrations: Migration[];
1215
+
1216
+ /**
1217
+ * Multi-archive manager for Fortemi.
1218
+ * Each archive is a separate PGlite instance with its own persistence path.
1219
+ * Migrations are applied automatically on open.
1220
+ */
1221
+
1222
+ interface ArchiveInfo {
1223
+ name: string;
1224
+ createdAt: string;
1225
+ }
1226
+ declare class ArchiveManager {
1227
+ private events?;
1228
+ private currentArchive;
1229
+ private db;
1230
+ private archives;
1231
+ private persistence;
1232
+ private backendFactory;
1233
+ constructor(persistenceOrFactory: PersistenceMode | StorageBackendFactory, events?: TypedEventBus | undefined, persistenceOverride?: PersistenceMode);
1234
+ getCurrentArchiveName(): string;
1235
+ getDb(): StorageBackend | null;
1236
+ open(archiveName?: string): Promise<StorageBackend>;
1237
+ /**
1238
+ * Adopt an already-created backend WITHOUT running migrations — for a backend
1239
+ * whose schema is already present, e.g. a PGlite restored from a physical
1240
+ * data-dir snapshot (issue #187, `restoreDbSnapshot`). Running migrations here
1241
+ * would be wrong: the restored dir already carries them (and the HNSW index).
1242
+ */
1243
+ adopt(backend: StorageBackend, archiveName?: string): Promise<StorageBackend>;
1244
+ create(archiveName: string): Promise<StorageBackend>;
1245
+ switchTo(archiveName: string): Promise<StorageBackend>;
1246
+ delete(archiveName: string): Promise<void>;
1247
+ listArchives(): ArchiveInfo[];
1248
+ close(): Promise<void>;
1249
+ }
1250
+
1251
+ /**
1252
+ * Factory function for creating a FortemiCore instance.
1253
+ * All deployment modes use this entry point.
1254
+ */
1255
+
1256
+ interface FortemiConfig {
1257
+ persistence: 'opfs' | 'idb' | 'memory';
1258
+ archiveName?: string;
1259
+ }
1260
+ interface FortemiCore {
1261
+ events: TypedEventBus;
1262
+ config: FortemiConfig;
1263
+ destroy(): void;
1264
+ }
1265
+ declare function createFortemi(config: FortemiConfig): FortemiCore;
1266
+
1267
+ /**
1268
+ * Compute a SHA-256 content hash for the given byte array.
1269
+ *
1270
+ * Returns a string in `algorithm:hex` format to match the server-side
1271
+ * convention, e.g. `sha256:a3b4c5...` (64 hex characters after the prefix).
1272
+ *
1273
+ * @param data - Raw bytes to hash
1274
+ * @returns `'sha256:<64-char lowercase hex>'`
1275
+ */
1276
+ declare function computeHash(data: Uint8Array): string;
1277
+
1278
+ interface SWRegistrationResult {
1279
+ registered: boolean;
1280
+ registration?: ServiceWorkerRegistration;
1281
+ error?: string;
1282
+ }
1283
+ declare function registerServiceWorker(swUrl?: string): Promise<SWRegistrationResult>;
1284
+
1285
+ /**
1286
+ * REST route definitions for Service Worker.
1287
+ * These are pure functions that transform HTTP Request → tool input and tool output → Response.
1288
+ * The actual DB connection is injected at registration time.
1289
+ *
1290
+ * All routes currently return 503 Not Implemented — the DB wiring happens in a later issue.
1291
+ * The URL structure and request/response shapes are the valuable contract defined here.
1292
+ */
1293
+ interface RouteHandler {
1294
+ method: string;
1295
+ pattern: RegExp;
1296
+ handler: (request: Request, match: RegExpMatchArray, params: URLSearchParams) => Promise<Response>;
1297
+ }
1298
+ /**
1299
+ * Create route handlers.
1300
+ * db parameter will be injected when the SW gets access to PGlite.
1301
+ * For now, returns 503 Not Implemented for all routes.
1302
+ */
1303
+ declare function createRoutes(): RouteHandler[];
1304
+ /**
1305
+ * Match a request against the registered routes and return the first matching
1306
+ * handler, or null if no route matches.
428
1307
  */
429
1308
  declare function matchRoute(routes: RouteHandler[], request: Request, url: URL): RouteHandler | null;
430
1309
 
@@ -1272,79 +2151,6 @@ declare class TagsRepository {
1272
2151
  }>>;
1273
2152
  }
1274
2153
 
1275
- /**
1276
- * CollectionsRepository — folder/category management for notes.
1277
- *
1278
- * Responsibilities:
1279
- * - Create, read, update, and soft-delete collections
1280
- * - Prevent circular parent references
1281
- * - Assign and unassign notes from collections
1282
- * - Return flat list and shallow tree views
1283
- */
1284
-
1285
- interface CollectionRow {
1286
- id: string;
1287
- name: string;
1288
- description: string | null;
1289
- parent_id: string | null;
1290
- position: number;
1291
- created_at: Date;
1292
- updated_at: Date;
1293
- deleted_at: Date | null;
1294
- }
1295
- interface CollectionCreateInput {
1296
- name: string;
1297
- description?: string;
1298
- parent_id?: string;
1299
- }
1300
- declare class CollectionsRepository {
1301
- private db;
1302
- constructor(db: DatabaseClient);
1303
- create(input: CollectionCreateInput): Promise<CollectionRow>;
1304
- get(id: string): Promise<CollectionRow>;
1305
- list(): Promise<CollectionRow[]>;
1306
- listTree(): Promise<Array<CollectionRow & {
1307
- children: CollectionRow[];
1308
- }>>;
1309
- update(id: string, fields: Partial<Pick<CollectionRow, 'name' | 'description' | 'parent_id' | 'position'>>): Promise<CollectionRow>;
1310
- delete(id: string): Promise<void>;
1311
- assignNote(collectionId: string, noteId: string): Promise<void>;
1312
- unassignNote(collectionId: string, noteId: string): Promise<void>;
1313
- getNotesInCollection(collectionId: string): Promise<string[]>;
1314
- }
1315
-
1316
- /**
1317
- * LinksRepository — bidirectional note link management.
1318
- *
1319
- * Responsibilities:
1320
- * - Create typed links between notes with duplicate prevention
1321
- * - Soft-delete links
1322
- * - Query outbound, inbound, and backlinks for a note
1323
- */
1324
-
1325
- interface LinkRow {
1326
- id: string;
1327
- source_note_id: string;
1328
- target_note_id: string;
1329
- link_type: string;
1330
- confidence: number | null;
1331
- created_at: Date;
1332
- updated_at: Date | null;
1333
- deleted_at: Date | null;
1334
- }
1335
- declare class LinksRepository {
1336
- private db;
1337
- constructor(db: DatabaseClient);
1338
- create(sourceNoteId: string, targetNoteId: string, linkType?: string): Promise<LinkRow>;
1339
- get(id: string): Promise<LinkRow>;
1340
- listForNote(noteId: string): Promise<{
1341
- outbound: LinkRow[];
1342
- inbound: LinkRow[];
1343
- }>;
1344
- getBacklinks(noteId: string): Promise<string[]>;
1345
- delete(id: string): Promise<void>;
1346
- }
1347
-
1348
2154
  /**
1349
2155
  * SkosRepository — SKOS taxonomy management (schemes, concepts, relations).
1350
2156
  *
@@ -1468,19 +2274,19 @@ declare const CaptureKnowledgeInputSchema: z.ZodObject<{
1468
2274
  }, {
1469
2275
  content: string;
1470
2276
  title?: string | undefined;
1471
- tags?: string[] | undefined;
1472
2277
  format?: "markdown" | "plain" | "html" | undefined;
2278
+ tags?: string[] | undefined;
1473
2279
  }>, "many">>;
1474
2280
  template: z.ZodOptional<z.ZodString>;
1475
2281
  variables: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
1476
2282
  }, "strip", z.ZodTypeAny, {
1477
2283
  source: string;
1478
2284
  format: "markdown" | "plain" | "html";
1479
- visibility: "private" | "public" | "shared";
2285
+ visibility: "private" | "shared" | "public";
1480
2286
  action: "create" | "bulk_create" | "from_template";
1481
2287
  title?: string | undefined;
1482
- tags?: string[] | undefined;
1483
2288
  archive_id?: string | undefined;
2289
+ tags?: string[] | undefined;
1484
2290
  content?: string | undefined;
1485
2291
  notes?: {
1486
2292
  format: "markdown" | "plain" | "html";
@@ -1494,16 +2300,16 @@ declare const CaptureKnowledgeInputSchema: z.ZodObject<{
1494
2300
  action: "create" | "bulk_create" | "from_template";
1495
2301
  source?: string | undefined;
1496
2302
  title?: string | undefined;
1497
- tags?: string[] | undefined;
1498
2303
  archive_id?: string | undefined;
1499
2304
  format?: "markdown" | "plain" | "html" | undefined;
1500
- visibility?: "private" | "public" | "shared" | undefined;
2305
+ visibility?: "private" | "shared" | "public" | undefined;
2306
+ tags?: string[] | undefined;
1501
2307
  content?: string | undefined;
1502
2308
  notes?: {
1503
2309
  content: string;
1504
2310
  title?: string | undefined;
1505
- tags?: string[] | undefined;
1506
2311
  format?: "markdown" | "plain" | "html" | undefined;
2312
+ tags?: string[] | undefined;
1507
2313
  }[] | undefined;
1508
2314
  template?: string | undefined;
1509
2315
  variables?: Record<string, string> | undefined;
@@ -1548,30 +2354,30 @@ declare const SearchInputSchema: z.ZodObject<{
1548
2354
  visibility: z.ZodOptional<z.ZodEnum<["private", "shared", "public"]>>;
1549
2355
  include_facets: z.ZodDefault<z.ZodBoolean>;
1550
2356
  }, "strip", z.ZodTypeAny, {
1551
- query: string;
1552
- offset: number;
1553
2357
  limit: number;
2358
+ offset: number;
1554
2359
  include_facets: boolean;
1555
2360
  mode: "text" | "semantic" | "hybrid";
2361
+ query: string;
1556
2362
  source?: string | undefined;
1557
- tags?: string[] | undefined;
1558
2363
  format?: "markdown" | "plain" | "html" | undefined;
1559
- visibility?: "private" | "public" | "shared" | undefined;
2364
+ visibility?: "private" | "shared" | "public" | undefined;
1560
2365
  is_starred?: boolean | undefined;
1561
2366
  is_archived?: boolean | undefined;
2367
+ tags?: string[] | undefined;
1562
2368
  collection_id?: string | undefined;
1563
2369
  date_from?: Date | undefined;
1564
2370
  date_to?: Date | undefined;
1565
2371
  }, {
1566
2372
  query: string;
1567
2373
  source?: string | undefined;
1568
- tags?: string[] | undefined;
1569
- offset?: number | undefined;
1570
2374
  format?: "markdown" | "plain" | "html" | undefined;
1571
- visibility?: "private" | "public" | "shared" | undefined;
2375
+ visibility?: "private" | "shared" | "public" | undefined;
1572
2376
  is_starred?: boolean | undefined;
1573
2377
  is_archived?: boolean | undefined;
2378
+ tags?: string[] | undefined;
1574
2379
  limit?: number | undefined;
2380
+ offset?: number | undefined;
1575
2381
  collection_id?: string | undefined;
1576
2382
  date_from?: Date | undefined;
1577
2383
  date_to?: Date | undefined;
@@ -1654,22 +2460,22 @@ declare const ListNotesInputSchema: z.ZodObject<{
1654
2460
  collection_id: z.ZodOptional<z.ZodString>;
1655
2461
  include_deleted: z.ZodOptional<z.ZodBoolean>;
1656
2462
  }, "strip", z.ZodTypeAny, {
1657
- sort: "title" | "updated_at" | "created_at";
1658
- offset: number;
2463
+ sort: "created_at" | "updated_at" | "title";
1659
2464
  limit: number;
2465
+ offset: number;
1660
2466
  order: "asc" | "desc";
1661
- tags?: string[] | undefined;
1662
2467
  is_starred?: boolean | undefined;
1663
2468
  is_archived?: boolean | undefined;
2469
+ tags?: string[] | undefined;
1664
2470
  include_deleted?: boolean | undefined;
1665
2471
  collection_id?: string | undefined;
1666
2472
  }, {
1667
- tags?: string[] | undefined;
1668
- sort?: "title" | "updated_at" | "created_at" | undefined;
1669
- offset?: number | undefined;
2473
+ sort?: "created_at" | "updated_at" | "title" | undefined;
1670
2474
  is_starred?: boolean | undefined;
1671
2475
  is_archived?: boolean | undefined;
2476
+ tags?: string[] | undefined;
1672
2477
  limit?: number | undefined;
2478
+ offset?: number | undefined;
1673
2479
  order?: "asc" | "desc" | undefined;
1674
2480
  include_deleted?: boolean | undefined;
1675
2481
  collection_id?: string | undefined;
@@ -1683,12 +2489,12 @@ declare const ManageTagsInputSchema: z.ZodObject<{
1683
2489
  tag: z.ZodOptional<z.ZodString>;
1684
2490
  }, "strip", z.ZodTypeAny, {
1685
2491
  action: "add" | "remove" | "list_for_note" | "list_all";
1686
- tag?: string | undefined;
1687
2492
  note_id?: string | undefined;
2493
+ tag?: string | undefined;
1688
2494
  }, {
1689
2495
  action: "add" | "remove" | "list_for_note" | "list_all";
1690
- tag?: string | undefined;
1691
2496
  note_id?: string | undefined;
2497
+ tag?: string | undefined;
1692
2498
  }>;
1693
2499
  type ManageTagsInput = z.infer<typeof ManageTagsInputSchema>;
1694
2500
  interface ManageTagsResult {
@@ -1710,18 +2516,18 @@ declare const ManageCollectionsInputSchema: z.ZodObject<{
1710
2516
  note_id: z.ZodOptional<z.ZodString>;
1711
2517
  }, "strip", z.ZodTypeAny, {
1712
2518
  action: "create" | "delete" | "list" | "assign" | "unassign" | "list_tree";
1713
- name?: string | undefined;
1714
2519
  collection_id?: string | undefined;
2520
+ note_id?: string | undefined;
2521
+ name?: string | undefined;
1715
2522
  description?: string | undefined;
1716
2523
  parent_id?: string | undefined;
1717
- note_id?: string | undefined;
1718
2524
  }, {
1719
2525
  action: "create" | "delete" | "list" | "assign" | "unassign" | "list_tree";
1720
- name?: string | undefined;
1721
2526
  collection_id?: string | undefined;
2527
+ note_id?: string | undefined;
2528
+ name?: string | undefined;
1722
2529
  description?: string | undefined;
1723
2530
  parent_id?: string | undefined;
1724
- note_id?: string | undefined;
1725
2531
  }>;
1726
2532
  type ManageCollectionsInput = z.infer<typeof ManageCollectionsInputSchema>;
1727
2533
  interface ManageCollectionsResult {
@@ -1792,10 +2598,10 @@ declare const ManageCapabilitiesInputSchema: z.ZodObject<{
1792
2598
  action: z.ZodEnum<["list", "enable", "disable", "status"]>;
1793
2599
  capability: z.ZodOptional<z.ZodString>;
1794
2600
  }, "strip", z.ZodTypeAny, {
1795
- action: "enable" | "disable" | "status" | "list";
2601
+ action: "status" | "enable" | "disable" | "list";
1796
2602
  capability?: string | undefined;
1797
2603
  }, {
1798
- action: "enable" | "disable" | "status" | "list";
2604
+ action: "status" | "enable" | "disable" | "list";
1799
2605
  capability?: string | undefined;
1800
2606
  }>;
1801
2607
  type ManageCapabilitiesInput = z.infer<typeof ManageCapabilitiesInputSchema>;
@@ -1897,16 +2703,16 @@ declare const ManageAttachmentsInputSchema: z.ZodObject<{
1897
2703
  display_name: z.ZodOptional<z.ZodString>;
1898
2704
  }, "strip", z.ZodTypeAny, {
1899
2705
  action: "delete" | "list" | "attach" | "get" | "get_blob";
1900
- filename?: string | undefined;
1901
2706
  note_id?: string | undefined;
2707
+ filename?: string | undefined;
1902
2708
  attachment_id?: string | undefined;
1903
2709
  data_base64?: string | undefined;
1904
2710
  mime_type?: string | undefined;
1905
2711
  display_name?: string | undefined;
1906
2712
  }, {
1907
2713
  action: "delete" | "list" | "attach" | "get" | "get_blob";
1908
- filename?: string | undefined;
1909
2714
  note_id?: string | undefined;
2715
+ filename?: string | undefined;
1910
2716
  attachment_id?: string | undefined;
1911
2717
  data_base64?: string | undefined;
1912
2718
  mime_type?: string | undefined;
@@ -2041,13 +2847,142 @@ declare function cosineSimilarity(a: number[], b: number[]): number;
2041
2847
  */
2042
2848
  declare function suggestTags(noteEmbedding: number[], tagEmbeddings: Map<string, number[]>, threshold?: number, maxTags?: number): string[];
2043
2849
 
2850
+ /**
2851
+ * Off-main-thread query-embedding transport for the semantic capability.
2852
+ *
2853
+ * The semantic capability consumes a single `EmbedFunction`
2854
+ * (`(texts: string[]) => Promise<number[][]>`). With `executionMode="worker"`
2855
+ * (#146) the PGlite DB + HNSW query run off the main thread, but a
2856
+ * main-thread `EmbedFunction` closure still blocks the UI: model load janks
2857
+ * first paint of search, and every per-query embed blocks input.
2858
+ *
2859
+ * This module lets the host run the embed function inside a Worker (or behind
2860
+ * a MessagePort) so semantic search is off-thread end-to-end. Core posts
2861
+ * `{ texts }` to the port and awaits `number[][]`; the host owns the worker,
2862
+ * the model, and the model params (so build-time corpus embeddings stay an
2863
+ * exact match: `Xenova/all-MiniLM-L6-v2`, fp32, `{ pooling:'mean', normalize:true }`,
2864
+ * 384-d).
2865
+ *
2866
+ * Two halves:
2867
+ * - {@link createWorkerEmbedFunction} — main-thread side. Wraps a transport
2868
+ * into an `EmbedFunction` that round-trips each request to the worker.
2869
+ * - {@link handleEmbedRequests} — worker side. Wires a host-owned
2870
+ * `(texts) => Promise<number[][]>` to the message protocol.
2871
+ *
2872
+ * The existing main-thread `registerSemanticCapability(manager, embedFn)` path
2873
+ * is unchanged. This transport is additive and opt-in.
2874
+ *
2875
+ * @implements #180 off-main-thread / pluggable query-embedding transport
2876
+ */
2877
+
2878
+ /**
2879
+ * Minimal transport contract satisfied by both `Worker` and `MessagePort`.
2880
+ * Core only needs to post messages and listen for replies.
2881
+ */
2882
+ interface EmbedTransportPort {
2883
+ postMessage(message: unknown): void;
2884
+ addEventListener(type: 'message', listener: (event: {
2885
+ data: unknown;
2886
+ }) => void): void;
2887
+ removeEventListener(type: 'message', listener: (event: {
2888
+ data: unknown;
2889
+ }) => void): void;
2890
+ /** MessagePort requires start() when using addEventListener; Worker does not. */
2891
+ start?(): void;
2892
+ }
2893
+ /** Message discriminators for the embed protocol. */
2894
+ declare const EMBED_REQUEST_KIND: "fortemi:embed:request";
2895
+ declare const EMBED_RESPONSE_KIND: "fortemi:embed:response";
2896
+ /** Request posted by core (main thread) to the worker. */
2897
+ interface EmbedRequestMessage {
2898
+ kind: typeof EMBED_REQUEST_KIND;
2899
+ id: number;
2900
+ texts: string[];
2901
+ }
2902
+ /** Reply posted by the worker back to core. Exactly one of `vectors`/`error`. */
2903
+ interface EmbedResponseMessage {
2904
+ kind: typeof EMBED_RESPONSE_KIND;
2905
+ id: number;
2906
+ vectors?: number[][];
2907
+ error?: string;
2908
+ }
2909
+ /** Options for the main-thread worker embed function. */
2910
+ interface EmbedWorkerOptions {
2911
+ /**
2912
+ * Per-request timeout in milliseconds. A request that receives no reply
2913
+ * within this window rejects with a timeout error. Set to `0` to disable.
2914
+ * Default: 30000 (30s).
2915
+ */
2916
+ timeoutMs?: number;
2917
+ }
2918
+ /**
2919
+ * Wrap a Worker/MessagePort transport into an `EmbedFunction` (main-thread side).
2920
+ *
2921
+ * Each `embed(texts)` call posts an {@link EmbedRequestMessage} with a unique id
2922
+ * and resolves when the matching {@link EmbedResponseMessage} arrives. The
2923
+ * message listener is attached immediately and removed by `dispose()`.
2924
+ *
2925
+ * @param port - A `Worker`, `MessagePort`, or any {@link EmbedTransportPort}.
2926
+ * @param options - Optional timeout configuration.
2927
+ * @returns The `embed` function and a `dispose` cleanup (removes the listener
2928
+ * and rejects any in-flight requests).
2929
+ *
2930
+ * @example
2931
+ * ```ts
2932
+ * const worker = new Worker(new URL('./queryEmbed.worker.ts', import.meta.url), { type: 'module' })
2933
+ * const { embed, dispose } = createWorkerEmbedFunction(worker)
2934
+ * setEmbedFunction(embed) // query + job embedding now run off-thread
2935
+ * // later: dispose(); worker.terminate()
2936
+ * ```
2937
+ */
2938
+ declare function createWorkerEmbedFunction(port: EmbedTransportPort, options?: EmbedWorkerOptions): {
2939
+ embed: EmbedFunction;
2940
+ dispose: () => void;
2941
+ };
2942
+ /**
2943
+ * Wire a host-owned embed function to the message protocol (worker side).
2944
+ *
2945
+ * Call this inside the worker (or behind a MessagePort) with the function that
2946
+ * loads the model and runs inference. It answers each {@link EmbedRequestMessage}
2947
+ * with an {@link EmbedResponseMessage}.
2948
+ *
2949
+ * @param port - The worker scope (`self`) or a `MessagePort`.
2950
+ * @param embed - The host embed function `(texts) => Promise<number[][]>`.
2951
+ * @returns A disposer that removes the listener.
2952
+ *
2953
+ * @example
2954
+ * ```ts
2955
+ * // queryEmbed.worker.ts
2956
+ * import { handleEmbedRequests } from '@fortemi/core'
2957
+ * import { pipeline } from '@huggingface/transformers'
2958
+ *
2959
+ * const extractor = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2')
2960
+ * handleEmbedRequests(self as unknown as EmbedTransportPort, async (texts) => {
2961
+ * const out = await Promise.all(
2962
+ * texts.map(async (t) => {
2963
+ * const r = await extractor(t, { pooling: 'mean', normalize: true })
2964
+ * return Array.from(r.data as Float32Array)
2965
+ * }),
2966
+ * )
2967
+ * return out
2968
+ * })
2969
+ * ```
2970
+ */
2971
+ declare function handleEmbedRequests(port: EmbedTransportPort, embed: EmbedFunction): () => void;
2972
+
2044
2973
  /**
2045
2974
  * Semantic capability loader — registers the embedding pipeline with CapabilityManager.
2046
2975
  *
2047
2976
  * In production (browser), this loads @huggingface/transformers in a Web Worker.
2048
2977
  * In tests, call registerSemanticCapability() with a mock embed function.
2049
2978
  *
2979
+ * Two registration paths, both additive:
2980
+ * - registerSemanticCapability(manager, embedFn) — main-thread embed closure.
2981
+ * - registerSemanticCapabilityWorker(manager, port) — off-main-thread embed
2982
+ * transport (#180), so semantic search runs off-thread end-to-end.
2983
+ *
2050
2984
  * @implements #62 semantic capability loader
2985
+ * @implements #180 off-main-thread / pluggable query-embedding transport
2051
2986
  */
2052
2987
 
2053
2988
  /**
@@ -2060,8 +2995,31 @@ declare function suggestTags(noteEmbedding: number[], tagEmbeddings: Map<string,
2060
2995
  */
2061
2996
  declare function registerSemanticCapability(manager: CapabilityManager, embedFn: EmbedFunction, onProgress?: (pct: number) => void): void;
2062
2997
  /**
2063
- * Unregister the semantic capability clears the embed function.
2064
- * Called when the capability is disabled.
2998
+ * Register the semantic capability backed by an off-main-thread transport (#180).
2999
+ *
3000
+ * The embed function round-trips each request to a host-owned Worker/MessagePort,
3001
+ * so model load and per-query inference never touch the main thread. The host
3002
+ * owns the worker and the model params (build-time corpus match stays exact).
3003
+ *
3004
+ * The loader runs when `capabilityManager.enable('semantic')` is invoked; the
3005
+ * message listener is attached then and removed on
3006
+ * {@link unregisterSemanticCapability} (i.e. on `disable`).
3007
+ *
3008
+ * @param manager - The CapabilityManager instance.
3009
+ * @param port - A `Worker`, `MessagePort`, or any {@link EmbedTransportPort}.
3010
+ * @param options - Optional transport options (e.g. per-request timeout).
3011
+ *
3012
+ * @example
3013
+ * ```ts
3014
+ * const worker = new Worker(new URL('./queryEmbed.worker.ts', import.meta.url), { type: 'module' })
3015
+ * registerSemanticCapabilityWorker(capabilityManager, worker)
3016
+ * await capabilityManager.enable('semantic') // off-thread end-to-end
3017
+ * ```
3018
+ */
3019
+ declare function registerSemanticCapabilityWorker(manager: CapabilityManager, port: EmbedTransportPort, options?: EmbedWorkerOptions): void;
3020
+ /**
3021
+ * Unregister the semantic capability — clears the embed function and tears down
3022
+ * any active off-main-thread transport. Called when the capability is disabled.
2065
3023
  */
2066
3024
  declare function unregisterSemanticCapability(): void;
2067
3025
 
@@ -2451,249 +3409,42 @@ interface PluginCspOptions {
2451
3409
  reportUri?: string;
2452
3410
  extraDirectives?: CspDirectives;
2453
3411
  }
2454
- interface PluginScriptPolicy {
2455
- allowedOrigins: string[];
2456
- allowedUrls?: string[];
2457
- requireSri?: boolean;
2458
- }
2459
- interface PluginScriptDescriptor {
2460
- url: string;
2461
- integrity?: string;
2462
- crossOrigin?: 'anonymous' | 'use-credentials';
2463
- }
2464
- interface LoadedPluginScript {
2465
- url: string;
2466
- integrity: string;
2467
- bytes: Uint8Array;
2468
- text: string;
2469
- }
2470
- interface CspViolationReport {
2471
- documentUri?: string;
2472
- violatedDirective?: string;
2473
- effectiveDirective?: string;
2474
- blockedUri?: string;
2475
- originalPolicy?: string;
2476
- disposition?: string;
2477
- sourceFile?: string;
2478
- lineNumber?: number;
2479
- columnNumber?: number;
2480
- raw: unknown;
2481
- }
2482
- declare function buildPluginCsp(options?: PluginCspOptions): string;
2483
- declare function computeSri(data: Uint8Array | ArrayBuffer, algorithm?: string): Promise<string>;
2484
- declare function verifySri(data: Uint8Array | ArrayBuffer, integrity: string): Promise<boolean>;
2485
- declare function isPluginScriptAllowed(url: string, policy: PluginScriptPolicy): boolean;
2486
- declare function fetchPluginScript(descriptor: PluginScriptDescriptor, policy: PluginScriptPolicy, fetchFn?: typeof fetch): Promise<LoadedPluginScript>;
2487
- declare function appendPluginScript(descriptor: PluginScriptDescriptor, policy: PluginScriptPolicy, doc?: Document): Promise<HTMLScriptElement>;
2488
- declare function parseCspReport(body: unknown): CspViolationReport;
2489
- declare function createCspReportHandler(onReport: (report: CspViolationReport) => void | Promise<void>): (request: Request) => Promise<Response>;
2490
-
2491
- /**
2492
- * Shard format types — matches the fortemi server matric-shard specification.
2493
- *
2494
- * A shard is a gzip-compressed tar archive (.shard) containing serialized
2495
- * knowledge data with a manifest for integrity verification.
2496
- */
2497
- declare const CURRENT_SHARD_VERSION = "1.0.0";
2498
- declare const SHARD_FORMAT = "matric-shard";
2499
- /** Components that can appear in a shard archive. */
2500
- type ShardComponent = 'notes' | 'collections' | 'tags' | 'links' | 'embedding_sets' | 'embedding_set_members' | 'embedding_configs' | 'embeddings' | 'skos_schemes' | 'skos_concepts' | 'skos_relations' | 'note_skos_tags' | 'provenance_edges' | 'community_assignments' | 'communities' | 'graph_edges' | 'graph_sources';
2501
- /** Manifest included in every shard as manifest.json. */
2502
- interface ShardManifest {
2503
- version: string;
2504
- matric_version: string;
2505
- format: typeof SHARD_FORMAT;
2506
- created_at: string;
2507
- components: ShardComponent[];
2508
- counts: Partial<Record<ShardComponent | 'community_sets', number>>;
2509
- checksums: Record<string, string>;
2510
- min_reader_version: string;
2511
- }
2512
- /** Options for shard export. */
2513
- interface ExportOptions {
2514
- includeEmbeddings?: boolean;
2515
- /** Filter to specific collection (export only notes in this collection). */
2516
- collectionId?: string;
2517
- /** Filter to notes with this tag (e.g. 'app:research' for app-scoped export). */
2518
- tag?: string;
2519
- /** Export only these embedding sets and their member/vector rows. */
2520
- embeddingSetIds?: string[];
2521
- /** Preserve virtual selector materialization metadata and virtual member rows. */
2522
- includeMaterializedSelectors?: boolean;
2523
- }
2524
- /** Conflict resolution strategy for shard import. */
2525
- type ConflictStrategy = 'skip' | 'replace' | 'error';
2526
- /** Options for shard import. */
2527
- interface ImportOptions {
2528
- conflictStrategy?: ConflictStrategy;
2529
- /** Rows processed between cooperative yields. Defaults to 250. */
2530
- batchSize?: number;
2531
- /** Progress callback for long-running import phases. */
2532
- onProgress?: (progress: ImportProgress) => void;
2533
- }
2534
- type ImportProgressPhase = 'unpack' | 'validate' | 'collections' | 'notes' | 'skos' | 'links' | 'provenance' | 'embedding_sets' | 'embeddings' | 'embedding_set_members' | 'graph' | 'communities' | 'index';
2535
- interface ImportProgress {
2536
- phase: ImportProgressPhase;
2537
- done: number;
2538
- total: number;
2539
- }
2540
- /** Per-entity import counts. */
2541
- interface ImportCounts {
2542
- notes: number;
2543
- collections: number;
2544
- tags: number;
2545
- links: number;
2546
- embedding_sets: number;
2547
- embedding_set_members: number;
2548
- embeddings: number;
2549
- skos_schemes: number;
2550
- skos_concepts: number;
2551
- skos_relations: number;
2552
- note_skos_tags: number;
2553
- provenance_edges: number;
2554
- graph_sources: number;
2555
- graph_edges: number;
2556
- community_sets: number;
2557
- communities: number;
2558
- community_assignments: number;
2559
- }
2560
- /** Result of a shard import operation. */
2561
- interface ImportResult {
2562
- success: boolean;
2563
- counts: ImportCounts;
2564
- skipped: Partial<ImportCounts>;
2565
- warnings: string[];
2566
- errors: string[];
2567
- duration_ms: number;
2568
- }
2569
- /** Note as serialized in the shard JSONL. */
2570
- interface ShardNote {
2571
- id: string;
2572
- title: string | null;
2573
- original_content: string;
2574
- revised_content: string | null;
2575
- format: string;
2576
- source: string;
2577
- starred: boolean;
2578
- archived: boolean;
2579
- tags: string[];
2580
- created_at: string;
2581
- updated_at: string;
2582
- deleted_at: string | null;
2583
- }
2584
- /** Collection as serialized in the shard JSON array. */
2585
- interface ShardCollection {
2586
- id: string;
2587
- name: string;
2588
- description: string | null;
2589
- parent_id: string | null;
2590
- created_at: string;
2591
- note_count?: number;
2592
- }
2593
- /** Tag as serialized in the shard JSON array. */
2594
- interface ShardTag {
2595
- name: string;
2596
- created_at: string;
2597
- }
2598
- /** Link as serialized in the shard JSONL. */
2599
- interface ShardLink {
2600
- id: string;
2601
- from_note_id: string;
2602
- to_note_id: string;
2603
- kind: string;
2604
- score: number | null;
2605
- created_at: string;
2606
- metadata?: Record<string, unknown>;
2607
- }
2608
- /** Embedding set as serialized in the shard JSON array. */
2609
- interface ShardEmbeddingSet {
2610
- id: string;
2611
- name?: string;
2612
- purpose?: string | null;
2613
- model: string;
2614
- dimension: number;
2615
- kind?: 'physical' | 'filter' | 'virtual';
2616
- mode?: 'auto' | 'manual' | 'mixed' | null;
2617
- truncate_dimension?: number | null;
2618
- criteria?: Record<string, unknown> | null;
2619
- source?: Record<string, unknown> | null;
2620
- compatibility?: Record<string, unknown> | null;
2621
- materialization?: Record<string, unknown> | null;
2622
- freshness?: ShardArtifactFreshness | null;
2623
- created_at: string;
2624
- updated_at?: string;
2625
- }
2626
- /** Embedding set member as serialized in the shard JSONL. */
2627
- interface ShardEmbeddingSetMember {
2628
- embedding_set_id: string;
2629
- note_id: string;
2630
- embedding_id: string;
2631
- }
2632
- /** Embedding as serialized in the shard JSONL. */
2633
- interface ShardEmbedding {
2634
- id: string;
2635
- note_id: string;
2636
- embedding_set_id: string;
2637
- vector: number[];
2638
- created_at: string;
2639
- }
2640
- /** SKOS scheme as serialized in the shard JSON array. */
2641
- interface ShardSkosScheme {
2642
- id: string;
2643
- title: string;
2644
- description: string | null;
2645
- created_at: string;
2646
- updated_at: string;
2647
- }
2648
- /** SKOS concept as serialized in the shard JSON array. */
2649
- interface ShardSkosConcept {
2650
- id: string;
2651
- scheme_id: string;
2652
- pref_label: string;
2653
- alt_labels: string[];
2654
- definition: string | null;
2655
- created_at: string;
2656
- updated_at: string;
2657
- }
2658
- /** SKOS concept relation as serialized in the shard JSONL. */
2659
- interface ShardSkosRelation {
2660
- id: string;
2661
- source_concept_id: string;
2662
- target_concept_id: string;
2663
- relation_type: 'broader' | 'narrower' | 'related';
2664
- created_at: string;
2665
- }
2666
- /** Note-to-SKOS-concept assignment as serialized in the shard JSONL. */
2667
- interface ShardNoteSkosTag {
2668
- id: string;
2669
- note_id: string;
2670
- concept_id: string;
2671
- created_at: string;
3412
+ interface PluginScriptPolicy {
3413
+ allowedOrigins: string[];
3414
+ allowedUrls?: string[];
3415
+ requireSri?: boolean;
2672
3416
  }
2673
- /** Provenance edge as serialized in the shard JSONL. */
2674
- interface ShardProvenanceEdge {
2675
- id: string;
2676
- entity_type: string;
2677
- entity_id: string;
2678
- activity: string;
2679
- agent: string;
2680
- started_at: string;
2681
- ended_at: string | null;
2682
- attributes: Record<string, unknown> | null;
3417
+ interface PluginScriptDescriptor {
3418
+ url: string;
3419
+ integrity?: string;
3420
+ crossOrigin?: 'anonymous' | 'use-credentials';
2683
3421
  }
2684
- interface ShardArtifactFreshness {
2685
- status: 'fresh' | 'stale' | 'unknown';
2686
- checked_at?: string;
2687
- stale_reason?: string;
2688
- source_hashes?: {
2689
- notes?: string;
2690
- links?: string;
2691
- embeddings?: string;
2692
- embedding_set_members?: string;
2693
- virtual_set_definition?: string;
2694
- parameters?: string;
2695
- };
3422
+ interface LoadedPluginScript {
3423
+ url: string;
3424
+ integrity: string;
3425
+ bytes: Uint8Array;
3426
+ text: string;
3427
+ }
3428
+ interface CspViolationReport {
3429
+ documentUri?: string;
3430
+ violatedDirective?: string;
3431
+ effectiveDirective?: string;
3432
+ blockedUri?: string;
3433
+ originalPolicy?: string;
3434
+ disposition?: string;
3435
+ sourceFile?: string;
3436
+ lineNumber?: number;
3437
+ columnNumber?: number;
3438
+ raw: unknown;
2696
3439
  }
3440
+ declare function buildPluginCsp(options?: PluginCspOptions): string;
3441
+ declare function computeSri(data: Uint8Array | ArrayBuffer, algorithm?: string): Promise<string>;
3442
+ declare function verifySri(data: Uint8Array | ArrayBuffer, integrity: string): Promise<boolean>;
3443
+ declare function isPluginScriptAllowed(url: string, policy: PluginScriptPolicy): boolean;
3444
+ declare function fetchPluginScript(descriptor: PluginScriptDescriptor, policy: PluginScriptPolicy, fetchFn?: typeof fetch): Promise<LoadedPluginScript>;
3445
+ declare function appendPluginScript(descriptor: PluginScriptDescriptor, policy: PluginScriptPolicy, doc?: Document): Promise<HTMLScriptElement>;
3446
+ declare function parseCspReport(body: unknown): CspViolationReport;
3447
+ declare function createCspReportHandler(onReport: (report: CspViolationReport) => void | Promise<void>): (request: Request) => Promise<Response>;
2697
3448
 
2698
3449
  /**
2699
3450
  * Minimal tar + gzip packing/unpacking for shard archives.
@@ -2735,164 +3486,6 @@ declare function validateChecksums(checksums: Record<string, string>, files: Map
2735
3486
  failures: string[];
2736
3487
  }>;
2737
3488
 
2738
- /**
2739
- * Field mapper — converts between browser schema and shard (server) schema.
2740
- *
2741
- * The browser uses different field names than the server shard format.
2742
- * This module handles all rename transforms bidirectionally.
2743
- */
2744
-
2745
- /** Browser-format note row from the export query (denormalized). */
2746
- interface BrowserNoteExport {
2747
- id: string;
2748
- title: string | null;
2749
- format: string;
2750
- source: string;
2751
- is_starred: boolean;
2752
- is_archived: boolean;
2753
- created_at: Date | string;
2754
- updated_at: Date | string;
2755
- deleted_at: Date | string | null;
2756
- original_content: string;
2757
- revised_content: string | null;
2758
- tags: string[];
2759
- }
2760
- /** Convert a browser note to shard format. */
2761
- declare function noteToShard(note: BrowserNoteExport): ShardNote;
2762
- /** Convert a shard note back to browser-insertable format. */
2763
- declare function noteFromShard(shard: ShardNote): BrowserNoteExport;
2764
- /** Convert a browser link to shard format. */
2765
- declare function linkToShard(link: LinkRow): ShardLink;
2766
- /** Convert a shard link back to browser-insertable format. */
2767
- declare function linkFromShard(shard: ShardLink): {
2768
- id: string;
2769
- source_note_id: string;
2770
- target_note_id: string;
2771
- link_type: string;
2772
- confidence: number | null;
2773
- created_at: string;
2774
- };
2775
- /** Convert a browser collection to shard format. */
2776
- declare function collectionToShard(collection: CollectionRow, noteCount?: number): ShardCollection;
2777
- /** Convert a shard collection back to browser-insertable format. */
2778
- declare function collectionFromShard(shard: ShardCollection): {
2779
- id: string;
2780
- name: string;
2781
- description: string | null;
2782
- parent_id: string | null;
2783
- created_at: string;
2784
- };
2785
- /**
2786
- * Convert SKOS concepts + note_tag associations into shard flat tag format.
2787
- * Shard tags are simple string arrays — deduplicated across all notes.
2788
- */
2789
- declare function tagsToShard(allTags: Array<{
2790
- name: string;
2791
- created_at: Date | string;
2792
- }>): ShardTag[];
2793
- /**
2794
- * Convert shard flat tags to browser format for insertion.
2795
- * Returns unique tag names ready for note_tag association.
2796
- */
2797
- declare function tagsFromShard(shardTags: ShardTag[]): string[];
2798
- /** Convert a browser embedding_set to shard format. */
2799
- declare function embeddingSetToShard(set: {
2800
- id: string;
2801
- name?: string;
2802
- purpose?: string | null;
2803
- model_name: string;
2804
- dimensions: number;
2805
- kind?: 'physical' | 'filter' | 'virtual';
2806
- mode?: 'auto' | 'manual' | 'mixed' | null;
2807
- truncate_dimension?: number | null;
2808
- criteria_json?: unknown | null;
2809
- source_json?: unknown | null;
2810
- compatibility_json?: unknown | null;
2811
- materialization_json?: unknown | null;
2812
- freshness_json?: unknown | null;
2813
- created_at: Date | string;
2814
- updated_at?: Date | string;
2815
- }): ShardEmbeddingSet;
2816
- /** Convert a shard embedding set back to browser format. */
2817
- declare function embeddingSetFromShard(shard: ShardEmbeddingSet): {
2818
- id: string;
2819
- name: string;
2820
- purpose: string | null;
2821
- model_name: string;
2822
- dimensions: number;
2823
- kind: 'physical' | 'filter' | 'virtual';
2824
- mode: 'auto' | 'manual' | 'mixed' | null;
2825
- truncate_dimension: number | null;
2826
- criteria_json: string | null;
2827
- source_json: string | null;
2828
- compatibility_json: string | null;
2829
- materialization_json: string | null;
2830
- freshness_json: string | null;
2831
- created_at: string;
2832
- updated_at: string | null;
2833
- };
2834
- /** Convert a browser embedding_set_member to shard format. */
2835
- declare function embeddingSetMemberToShard(member: {
2836
- embedding_set_id: string;
2837
- note_id: string;
2838
- embedding_id: string;
2839
- }): ShardEmbeddingSetMember;
2840
- /** Convert a browser embedding to shard format. */
2841
- declare function embeddingToShard(emb: {
2842
- id: string;
2843
- note_id: string;
2844
- embedding_set_id: string;
2845
- vector: string | number[];
2846
- created_at: Date | string;
2847
- }): ShardEmbedding;
2848
- /** Convert a shard embedding back to browser format. */
2849
- declare function embeddingFromShard(shard: ShardEmbedding): {
2850
- id: string;
2851
- note_id: string;
2852
- embedding_set_id: string;
2853
- vector: string;
2854
- created_at: string;
2855
- };
2856
- declare function skosSchemeToShard(scheme: {
2857
- id: string;
2858
- title: string;
2859
- description: string | null;
2860
- created_at: Date | string;
2861
- updated_at: Date | string;
2862
- }): ShardSkosScheme;
2863
- declare function skosConceptToShard(concept: {
2864
- id: string;
2865
- scheme_id: string;
2866
- pref_label: string;
2867
- alt_labels: string[] | string | null;
2868
- definition: string | null;
2869
- created_at: Date | string;
2870
- updated_at: Date | string;
2871
- }): ShardSkosConcept;
2872
- declare function skosRelationToShard(relation: {
2873
- id: string;
2874
- source_concept_id: string;
2875
- target_concept_id: string;
2876
- relation_type: 'broader' | 'narrower' | 'related';
2877
- created_at: Date | string;
2878
- }): ShardSkosRelation;
2879
- declare function noteSkosTagToShard(tag: {
2880
- id: string;
2881
- note_id: string;
2882
- concept_id: string;
2883
- created_at: Date | string;
2884
- }): ShardNoteSkosTag;
2885
- declare function provenanceEdgeToShard(edge: {
2886
- id: string;
2887
- entity_type: string;
2888
- entity_id: string;
2889
- activity: string;
2890
- agent: string;
2891
- started_at: Date | string;
2892
- ended_at: Date | string | null;
2893
- attributes: Record<string, unknown> | string | null;
2894
- }): ShardProvenanceEdge;
2895
-
2896
3489
  /**
2897
3490
  * Shard export pipeline — query all entities, serialize, pack into .shard archive.
2898
3491
  *
@@ -2928,6 +3521,172 @@ declare function exportShard(db: DatabaseClient, options?: ExportOptions): Promi
2928
3521
  */
2929
3522
  declare function importShard(db: DatabaseClient, data: Uint8Array | ArrayBuffer, options?: ImportOptions): Promise<ImportResult>;
2930
3523
 
2931
- declare const VERSION = "2026.6.2";
3524
+ /**
3525
+ * Pluggable semantic providers for the in-place shard reader (issue #189).
3526
+ *
3527
+ * The static-file tier is text/facets-only by default. Semantic is opt-in via a
3528
+ * `StaticSemanticProvider`, with three tradeoff points the host chooses from:
3529
+ *
3530
+ * 1. none — don't configure a provider (text/facets only). Lightest.
3531
+ * 2. cosine-small — `createCosineSemanticProvider`: brute-force cosine over a
3532
+ * small static vectors file. Zero prebuild; small corpora only.
3533
+ * 3. ANN-full — implement `StaticSemanticProvider` yourself over a prebuilt
3534
+ * ANN snapshot (HNSW / flat-IVF served as a static asset),
3535
+ * loading it in `prepare()` and querying it in `search()`.
3536
+ * The interface is the extension point; no ANN engine is
3537
+ * bundled here.
3538
+ */
3539
+
3540
+ /** A note id paired with its embedding vector, as stored in a static vectors file. */
3541
+ interface VectorEntry {
3542
+ id: string;
3543
+ vector: number[];
3544
+ }
3545
+ interface CosineSemanticProviderOptions {
3546
+ /**
3547
+ * Embeds the query into the SAME space as the corpus vectors. Host-owned so it
3548
+ * matches the build-time embedding model exactly (sync or async).
3549
+ */
3550
+ embedQuery: (query: string) => Promise<number[]> | number[];
3551
+ /**
3552
+ * JSONL file (one `{ id, vector }` per line) mapping note id → vector, served
3553
+ * as a static asset alongside the shard. Default `vectors.jsonl`.
3554
+ */
3555
+ vectorsFile?: string;
3556
+ /** Pre-supplied vectors — skips loading from the component store. */
3557
+ vectors?: VectorEntry[];
3558
+ }
3559
+ /**
3560
+ * Brute-force cosine semantic provider — the "cosine-small" tradeoff point. Loads
3561
+ * a static vectors file and scores the query embedding against every corpus
3562
+ * vector. Fine for small/demo corpora; for the full corpus, supply a prebuilt-ANN
3563
+ * `StaticSemanticProvider` instead.
3564
+ */
3565
+ declare function createCosineSemanticProvider(options: CosineSemanticProviderOptions): StaticSemanticProvider;
3566
+
3567
+ /**
3568
+ * Shard warm / prefetch API — pre-stage and (optionally) verify shard bytes
3569
+ * without building the index.
3570
+ *
3571
+ * Staged corpus loading (text-first, then opt-in summary vectors, then opt-in
3572
+ * full content) wants the operator's hard rule honored: **no blocking waits**.
3573
+ * The HNSW index build has to happen on the user's click (it is heavy and is
3574
+ * shown with progress — that is correct). The *download* of the shard bytes
3575
+ * does not: it can be warmed in the background on idle so the click is purely
3576
+ * the index build.
3577
+ *
3578
+ * fortemi-react is server-free and local-first — shards are **static assets**
3579
+ * (typically generated at build time and served as static files, or bundled
3580
+ * and handed in directly as bytes). `prefetchShard` warms those static bytes;
3581
+ * it does not assume any API/server. The eventual `importShard` reads the warm
3582
+ * bytes via {@link fromPrefetched}, so import is just the index build.
3583
+ *
3584
+ * Two-layer integrity:
3585
+ * - `prefetchShard(url, { expectedSha256 })` verifies the whole-archive SHA-256
3586
+ * against a build-time-known hash (emitted alongside the static shard).
3587
+ * - `importShard` still validates the per-file checksums inside the manifest
3588
+ * on import. Both layers share core's `sha256Hex`.
3589
+ *
3590
+ * @implements #181 prefetchShard / shard warm API
3591
+ */
3592
+ /** Options for {@link prefetchShard}. */
3593
+ interface PrefetchOptions {
3594
+ /**
3595
+ * Provide the shard bytes directly instead of fetching `url` — e.g. a
3596
+ * build-time-generated `.shard` imported as a bundled asset. The `url` is
3597
+ * still used as the warm-store key. When set, no network/disk fetch happens.
3598
+ */
3599
+ bytes?: ArrayBuffer | Uint8Array;
3600
+ /**
3601
+ * Compute the SHA-256 of the warmed bytes (stored on the result and in the
3602
+ * warm store). Implied when `expectedSha256` is set.
3603
+ */
3604
+ verify?: boolean;
3605
+ /**
3606
+ * Build-time-known SHA-256 (hex) of the whole shard archive. When set, the
3607
+ * warmed bytes are verified against it and a mismatch throws — nothing is
3608
+ * stored. Case-insensitive.
3609
+ */
3610
+ expectedSha256?: string;
3611
+ /**
3612
+ * Fetch implementation to use. Defaults to `globalThis.fetch`. Inject for
3613
+ * tests or non-standard environments.
3614
+ */
3615
+ fetchImpl?: typeof fetch;
3616
+ /**
3617
+ * Also persist the warmed bytes to the Cache Storage API so warmth survives
3618
+ * a reload. Feature-detected — a no-op when `caches` is unavailable (e.g.
3619
+ * Node, or a worker without Cache access).
3620
+ */
3621
+ useCacheStorage?: boolean;
3622
+ /** Cache Storage cache name. Default: `'fortemi-shards'`. */
3623
+ cacheName?: string;
3624
+ /** Abort signal forwarded to the fetch. */
3625
+ signal?: AbortSignal;
3626
+ }
3627
+ /** Result of a {@link prefetchShard} call. */
3628
+ interface PrefetchResult {
3629
+ /** The warm-store key (the `url` passed to prefetchShard). */
3630
+ url: string;
3631
+ /** The warmed shard bytes (also retrievable via {@link fromPrefetched}). */
3632
+ bytes: Uint8Array;
3633
+ /** Convenience: `bytes.byteLength`. */
3634
+ byteLength: number;
3635
+ /** SHA-256 hex of the warmed bytes when computed (`verify` or `expectedSha256`), else `undefined`. */
3636
+ sha256?: string;
3637
+ /** True when the bytes came from the Cache Storage API rather than a fresh fetch. */
3638
+ fromCache: boolean;
3639
+ }
3640
+ /**
3641
+ * Pre-stage shard bytes into the warm store without building the index.
3642
+ *
3643
+ * Resolution order for the bytes:
3644
+ * 1. `options.bytes` (a directly-provided / bundled asset), else
3645
+ * 2. the Cache Storage API (when `useCacheStorage` and a prior write exists), else
3646
+ * 3. `fetch(url)` of the static asset.
3647
+ *
3648
+ * Concurrent calls for the same `url` (without `options.bytes`) share a single
3649
+ * fetch. On `expectedSha256` mismatch the call throws and nothing is stored.
3650
+ *
3651
+ * @param url - Static asset URL (also the warm-store key).
3652
+ * @param options - See {@link PrefetchOptions}.
3653
+ * @returns The warm result (bytes are also retrievable via {@link fromPrefetched}).
3654
+ *
3655
+ * @example
3656
+ * ```ts
3657
+ * // Warm on idle so the user's opt-in click is just the index build.
3658
+ * requestIdleCallback(() => {
3659
+ * void prefetchShard('/shards/research.shard', { expectedSha256: RESEARCH_SHARD_SHA256 })
3660
+ * })
3661
+ * // ...later, on click:
3662
+ * await importShard(db, fromPrefetched('/shards/research.shard'), { onProgress })
3663
+ * ```
3664
+ */
3665
+ declare function prefetchShard(url: string, options?: PrefetchOptions): Promise<PrefetchResult>;
3666
+ /**
3667
+ * Return previously-warmed shard bytes for `url`, ready to hand to `importShard`.
3668
+ *
3669
+ * @throws If the url was not prefetched (call {@link prefetchShard} first).
3670
+ *
3671
+ * @example
3672
+ * ```ts
3673
+ * await importShard(db, fromPrefetched('/shards/research.shard'), { onProgress })
3674
+ * ```
3675
+ */
3676
+ declare function fromPrefetched(url: string): Uint8Array;
3677
+ /** Whether `url` has warm bytes in the in-memory store. */
3678
+ declare function isShardPrefetched(url: string): boolean;
3679
+ /** The computed SHA-256 (hex) of a warmed shard, if it was verified/hashed. */
3680
+ declare function getPrefetchedSha256(url: string): string | undefined;
3681
+ /**
3682
+ * Evict warm bytes from the in-memory store. With no argument, clears all.
3683
+ *
3684
+ * Note: this does not delete Cache Storage entries — those persist by design
3685
+ * (that is the cross-reload warmth). Manage the Cache Storage cache directly if
3686
+ * you need to evict it.
3687
+ */
3688
+ declare function clearPrefetchedShard(url?: string): void;
3689
+
3690
+ declare const VERSION = "2026.6.4";
2932
3691
 
2933
- export { type ArchiveInfo, ArchiveManager, type AttachInput, type AttachmentBlobRow, type AttachmentRow, AttachmentsRepository, type BlobStore, type BridgeCapability, type BridgeProviderInfo, type BrowserNoteExport, CURRENT_SHARD_VERSION, type CapabilityInfo, CapabilityManager, type CapabilityName, type CapabilityState, type CaptureKnowledgeInput, CaptureKnowledgeInputSchema, type CaptureKnowledgeResult, type CollectionCreateInput, type CollectionRow, CollectionsRepository, CommunitiesRepository, type CommunityAssignmentView, type CommunityCreateInput, type CommunityFilterDefinition, type CommunityGraph, type CommunityOptions, type CommunitySourceDescriptor, type CommunitySourceType, type CommunitySummary, type CompletionRequest, type CompletionResponse, type ConditionResult, type ConflictStrategy, type CooldownConfig, type CooldownEvent, type CspDirectiveName, type CspDirectives, type CspViolationReport, type DatabaseClient, type DiscoveredProvider, type DiscoveryOptions, type EmbedFunction, type EmbedRequest, type EmbedResponse, type EmbeddingCompatibilityPolicy, type EmbeddingSetCreateInput, type EmbeddingSetCriteria, type EmbeddingSetDescriptor, type EmbeddingSetEmbeddingInput, type EmbeddingSetFreshness, type EmbeddingSetKind, type EmbeddingSetMode, type EmbeddingSetRow, type EmbeddingSetSelector, EmbeddingSetsRepository, type EnqueueJobInput, type ErrorCategory, type EventMap, type ExportOptions, type FallbackEvent, FallbackRouter, type FallbackRouterConfig, type FortemiBridge, type FortemiBridgeCapabilities, type FortemiBridgeHost, type FortemiConfig, type FortemiCore, type FortemiInferenceRouter, type FortemiSecretStore, type FortemiToolDefinition, FortemiToolManifest, type GetNoteInput, GetNoteInputSchema, type GpuCapabilities, type GraphCommunity, type GraphEdge, type GraphNode, GraphRepository, type IDisposable, type ImportCounts, type ImportOptions, type ImportProgress, type ImportProgressPhase, type ImportResult, type InferenceCapabilities, type InferenceProvider, JOB_CAPABILITIES, JOB_PRIORITIES, type JobQueueOptions, JobQueueWorker, type JobStatus, type JobType, LOCAL_ENDPOINTS, type LinkRow, LinksRepository, type ListNotesInput, ListNotesInputSchema, type LlmCapabilityOptions, type LlmCompleteFn, type LoadedPluginScript, type LocalEndpoint, type ManageArchiveInput, ManageArchiveInputSchema, type ManageArchiveResult, type ManageAttachmentsInput, ManageAttachmentsInputSchema, type ManageAttachmentsResult, type ManageCapabilitiesInput, ManageCapabilitiesInputSchema, type ManageCapabilitiesResult, type ManageCollectionsInput, ManageCollectionsInputSchema, type ManageCollectionsResult, type ManageLinksInput, ManageLinksInputSchema, type ManageLinksResult, type ManageNoteInput, ManageNoteInputSchema, type ManageNoteResult, type ManageTagsInput, ManageTagsInputSchema, type ManageTagsResult, MemoryBlobStore, type Migration, MigrationRunner, type ModelCategory, type ModelFitResult, type ModelInfo, type NoteCreateInput, type NoteFull, type NoteListOptions, type NoteRevision, type NoteSummary, type NoteUpdateInput, NotesRepository, OpenAICompatibleProvider, type OpenAIProviderConfig, PGliteStorageBackend, PGliteStorageBackendFactory, PGliteWorkerClient, PGliteWorkerStorageBackend, PGliteWorkerStorageBackendFactory, type PGliteWorkerStorageBackendFactoryOptions, type PaginatedResult, type PersistenceMode, type PluginCspOptions, type PluginScriptDescriptor, type PluginScriptPolicy, type ProbeResult, type ProbeStatus, type ProviderCapabilities, ProviderRegistry, type ProviderTier, type QueryExecutor, type QueryResult, type RecommendedTier, type ResolvedEmbeddingRow, type ResolvedEmbeddingSet, type RouteHandler, SHARD_FORMAT, type SWRegistrationResult, type SearchFacets, type SearchInput, SearchInputSchema, type SearchOptions, SearchRepository, type SearchResponse, type SearchResult, type ShardCollection, type ShardComponent, type ShardEmbedding, type ShardEmbeddingSet, type ShardEmbeddingSetMember, type ShardLink, type ShardManifest, type ShardNote, type ShardNoteSkosTag, type ShardProvenanceEdge, type ShardSkosConcept, type ShardSkosRelation, type ShardSkosScheme, type ShardTag, type SimilarityGraphCacheKey, type SimilarityGraphOptions, type SimilarityGraphRequest, type SimilarityGraphResult, type SkosConcept, type SkosRelation, SkosRepository, type SkosScheme, type StorageBackend, type StorageBackendFactory, type StorageOpenRequest, type StorageTopology, type StreamChunk, TagsRepository, TransactionProxy, TypedEventBus, VERSION, type VirtualEmbeddingSetDefinition, type VirtualEmbeddingSetSource, type VirtualEmbeddingSetValidationError, type VirtualMaterializationPolicy, type VramTier, type WorkerRequest, type WorkerResponse, aiRevisionHandler, allMigrations, appendPluginScript, buildNoteConditions, buildPluginCsp, captureKnowledge, chunkText, classifyError, classifyModel, collectionFromShard, collectionToShard, computeHash, computeSri, conceptTaggingHandler, cosineSimilarity, createBlobStore, createCspReportHandler, createFortemi, createLegacyProvider, createPGliteInstance, createRoutes, defaultStorageBackendFactory, detectCommunities, detectGpuCapabilities, detectInferenceCapabilities, discoverLocalProviders, embeddingFromShard, embeddingGenerationHandler, embeddingSetFromShard, embeddingSetMemberToShard, embeddingSetToShard, embeddingToShard, enqueueFullWorkflow, enqueueJob, enqueueNoteCreationJobs, estimateModelFit, estimateVramMB, estimateVramTier, exportShard, fetchPluginScript, fortemiManifest, generateId, getEmbedFunction, getFortemiBridge, getFortemiSecretStore, getJobQueueStatus, getLlmFunction, getNote, hasFortemiSecureSecrets, importShard, isPluginScriptAllowed, linkFromShard, linkToShard, linkingHandler, listNotes, manageArchive, manageAttachments, manageCapabilities, manageCollections, manageLinks, manageNote, manageTags, matchRoute, noteFromShard, noteSkosTagToShard, noteToShard, packTarGz, parseCspReport, provenanceEdgeToShard, registerLlmCapability, registerSemanticCapability, registerServiceWorker, searchTool, selectLlmModel, setEmbedFunction, setLlmFunction, sha256Hex, skosConceptToShard, skosRelationToShard, skosSchemeToShard, suggestTags, tagsFromShard, tagsToShard, titleGenerationHandler, unpackTarGz, unregisterLlmCapability, unregisterSemanticCapability, validateChecksums, verifySri };
3692
+ export { type ArchiveInfo, ArchiveManager, type AttachInput, type AttachmentBlobRow, type AttachmentRow, AttachmentsRepository, type BackendCandidate, type BackendCapabilities, type BackendListOptions, type BackendNote, type BackendNoteFull, type BackendRequest, type BackendSearchHit, type BackendSearchQueryOptions, type BackendSearchResult, type BackendSelection, type BackendSemanticTier, type BackendStartupCost, type BlobStore, type BridgeCapability, type BridgeProviderInfo, type BrowserNoteExport, CURRENT_MIGRATION_HEAD, CURRENT_SHARD_VERSION, type CapabilityInfo, CapabilityManager, type CapabilityName, type CapabilityState, type CaptureKnowledgeInput, CaptureKnowledgeInputSchema, type CaptureKnowledgeResult, type CollectionCreateInput, type CollectionRow, CollectionsRepository, CommunitiesRepository, type CommunityAssignmentView, type CommunityCreateInput, type CommunityFilterDefinition, type CommunityGraph, type CommunityOptions, type CommunitySourceDescriptor, type CommunitySourceType, type CommunitySummary, type CompletionRequest, type CompletionResponse, type ConditionResult, type ConflictStrategy, type CooldownConfig, type CooldownEvent, type CosineSemanticProviderOptions, type CreatePGliteOptions, type CspDirectiveName, type CspDirectives, type CspViolationReport, DB_SNAPSHOT_SCHEMA_VERSION, type DataBackend, type DatabaseClient, type DbSnapshot, type DbSnapshotCompat, type DbSnapshotCompression, type DbSnapshotExpectations, type DbSnapshotMeta, type DbSnapshotSource, DbSnapshotVersionError, type DiscoveredProvider, type DiscoveryOptions, type DumpDbSnapshotOptions, type DumpableDb, EMBED_REQUEST_KIND, EMBED_RESPONSE_KIND, type EmbedFunction, type EmbedRequest, type EmbedRequestMessage, type EmbedResponse, type EmbedResponseMessage, type EmbedTransportPort, type EmbedWorkerOptions, type EmbeddingCompatibilityPolicy, type EmbeddingSetCreateInput, type EmbeddingSetCriteria, type EmbeddingSetDescriptor, type EmbeddingSetEmbeddingInput, type EmbeddingSetFreshness, type EmbeddingSetKind, type EmbeddingSetMode, type EmbeddingSetRow, type EmbeddingSetSelector, EmbeddingSetsRepository, type EnqueueJobInput, type ErrorCategory, type EventMap, type ExportOptions, type FallbackEvent, FallbackRouter, type FallbackRouterConfig, type FortemiBridge, type FortemiBridgeCapabilities, type FortemiBridgeHost, type FortemiConfig, type FortemiCore, type FortemiInferenceRouter, type FortemiSecretStore, type FortemiToolDefinition, FortemiToolManifest, type GetNoteInput, GetNoteInputSchema, type GpuCapabilities, type GraphCommunity, type GraphEdge, type GraphNode, GraphRepository, type IDisposable, type ImportCounts, type ImportOptions, type ImportProgress, type ImportProgressPhase, type ImportResult, type InferenceCapabilities, type InferenceProvider, JOB_CAPABILITIES, JOB_PRIORITIES, type JobQueueOptions, JobQueueWorker, type JobStatus, type JobType, LOCAL_ENDPOINTS, type LinkRow, LinksRepository, type ListNotesInput, ListNotesInputSchema, type LlmCapabilityOptions, type LlmCompleteFn, type LoadedPluginScript, type LocalEndpoint, type ManageArchiveInput, ManageArchiveInputSchema, type ManageArchiveResult, type ManageAttachmentsInput, ManageAttachmentsInputSchema, type ManageAttachmentsResult, type ManageCapabilitiesInput, ManageCapabilitiesInputSchema, type ManageCapabilitiesResult, type ManageCollectionsInput, ManageCollectionsInputSchema, type ManageCollectionsResult, type ManageLinksInput, ManageLinksInputSchema, type ManageLinksResult, type ManageNoteInput, ManageNoteInputSchema, type ManageNoteResult, type ManageTagsInput, ManageTagsInputSchema, type ManageTagsResult, MemoryBlobStore, type Migration, MigrationRunner, type ModelCategory, type ModelFitResult, type ModelInfo, type NoteCreateInput, type NoteFull, type NoteListOptions, type NoteRevision, type NoteSummary, type NoteUpdateInput, NotesRepository, OpenAICompatibleProvider, type OpenAIProviderConfig, type OpenShardOptions, type PGliteBackendOptions, PGliteStorageBackend, PGliteStorageBackendFactory, PGliteWorkerClient, PGliteWorkerStorageBackend, PGliteWorkerStorageBackendFactory, type PGliteWorkerStorageBackendFactoryOptions, type PaginatedResult, type PersistenceMode, type PluginCspOptions, type PluginScriptDescriptor, type PluginScriptPolicy, type PrefetchOptions, type PrefetchResult, type ProbeResult, type ProbeStatus, type ProviderCapabilities, ProviderRegistry, type ProviderTier, type QueryExecutor, type QueryResult, type RecommendedTier, type ResolvedEmbeddingRow, type ResolvedEmbeddingSet, type RestoreDbSnapshotOptions, type RouteHandler, SHARD_FORMAT, SUPPORTED_PGLITE_VERSION, type SWRegistrationResult, type SearchFacets, type SearchInput, SearchInputSchema, type SearchOptions, SearchRepository, type SearchResponse, type SearchResult, type ShardBackendOptions, type ShardClusterRef, type ShardCollection, type ShardComponent, type ShardComponentStore, type ShardEmbedding, type ShardEmbeddingSet, type ShardEmbeddingSetMember, type ShardLayout, type ShardLink, type ShardListOptions, type ShardManifest, type ShardNote, type ShardNoteFull, type ShardNoteSkosTag, type ShardProvenanceEdge, type ShardReader, type ShardReaderNote, type ShardReaderSource, type ShardSearchOptions, type ShardSearchRankedNote, type ShardSearchResult, type ShardSearchWeights, type ShardSkosConcept, type ShardSkosRelation, type ShardSkosScheme, type ShardTag, type SimilarityGraphCacheKey, type SimilarityGraphOptions, type SimilarityGraphRequest, type SimilarityGraphResult, type SkosConcept, type SkosRelation, SkosRepository, type SkosScheme, type StaticSemanticProvider, type StorageBackend, type StorageBackendFactory, type StorageOpenRequest, type StorageTopology, type StreamChunk, TagsRepository, TransactionProxy, TypedEventBus, VERSION, type VectorEntry, type VirtualEmbeddingSetDefinition, type VirtualEmbeddingSetSource, type VirtualEmbeddingSetValidationError, type VirtualMaterializationPolicy, type VramTier, type WorkerRequest, type WorkerResponse, aiRevisionHandler, allMigrations, appendPluginScript, buildNoteConditions, buildPluginCsp, captureKnowledge, chunkText, classifyError, classifyModel, clearPrefetchedShard, collectionFromShard, collectionToShard, computeHash, computeSri, conceptTaggingHandler, cosineSimilarity, createBlobStore, createCosineSemanticProvider, createCspReportHandler, createFortemi, createLegacyProvider, createPGliteBackend, createPGliteInstance, createRoutes, createShardBackend, createWorkerEmbedFunction, defaultStorageBackendFactory, detectCommunities, detectGpuCapabilities, detectInferenceCapabilities, discoverLocalProviders, dumpDbSnapshot, embeddingFromShard, embeddingGenerationHandler, embeddingSetFromShard, embeddingSetMemberToShard, embeddingSetToShard, embeddingToShard, enqueueFullWorkflow, enqueueJob, enqueueNoteCreationJobs, estimateModelFit, estimateVramMB, estimateVramTier, exportShard, fetchPluginScript, fortemiManifest, fromPrefetched, generateId, getEmbedFunction, getFortemiBridge, getFortemiSecretStore, getJobQueueStatus, getLlmFunction, getNote, getPrefetchedSha256, handleEmbedRequests, hasFortemiSecureSecrets, importShard, isPluginScriptAllowed, isShardPrefetched, linkFromShard, linkToShard, linkingHandler, listNotes, manageArchive, manageAttachments, manageCapabilities, manageCollections, manageLinks, manageNote, manageTags, matchRoute, noteFromShard, noteSkosTagToShard, noteToShard, openShard, packTarGz, parseCspReport, prefetchShard, provenanceEdgeToShard, registerLlmCapability, registerSemanticCapability, registerSemanticCapabilityWorker, registerServiceWorker, restoreDbSnapshot, searchTool, selectBackend, selectLlmModel, setEmbedFunction, setLlmFunction, sha256Hex, skosConceptToShard, skosRelationToShard, skosSchemeToShard, suggestTags, tagsFromShard, tagsToShard, titleGenerationHandler, unpackTarGz, unregisterLlmCapability, unregisterSemanticCapability, validateChecksums, verifyDbSnapshotMeta, verifySri };