@semiont/sdk 0.5.1 → 0.5.3

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
@@ -2,10 +2,9 @@ import * as rxjs from 'rxjs';
2
2
  import { Observable, BehaviorSubject, Subject } from 'rxjs';
3
3
  export { firstValueFrom, lastValueFrom } from 'rxjs';
4
4
  import * as _semiont_core from '@semiont/core';
5
- import { components, UserDID, paths, ResourceId, AnnotationId, BodyOperation, EventMap, ResourceDescriptor, Annotation, GraphConnection, Motivation, GatheredContext, JobId, ITransport, EventBus, IContentTransport, BaseUrl, AccessToken, SemiontError, ConnectionState, Selector } from '@semiont/core';
6
- export { AccessToken, Annotation, AnnotationId, BaseUrl, BodyItem, BodyOperation, ConnectionState, EntityType, EventMap, GatheredContext, IContentTransport, ITransport, Logger, Motivation, RefreshToken, ResourceDescriptor, ResourceId, SemiontError, UserId, accessToken, annotationId, baseUrl, entityType, refreshToken, resourceId, userId } from '@semiont/core';
7
- import { ActorVM } from '@semiont/api-client';
8
- export { APIError, APIErrorCode, ActorVM, ActorVMOptions, BusEvent, DEGRADED_THRESHOLD_MS, HttpContentTransport, HttpTransport, HttpTransportConfig, TokenRefresher, createActorVM } from '@semiont/api-client';
5
+ import { ResourceId, components, UserDID, paths, BackendDownload, ProgressEvent, AnnotationId, BodyOperation, EventMap, ResourceDescriptor, Annotation, TagSchema, GraphConnection, Motivation, GatheredContext, JobId, ITransport, EventBus, IContentTransport, IBackendOperations, BaseUrl, AccessToken, SemiontError, ConnectionState, Selector } from '@semiont/core';
6
+ export { AccessToken, Annotation, AnnotationId, BaseUrl, BodyItem, BodyOperation, ConnectionState, EntityType, EventMap, GatheredContext, IContentTransport, ITransport, Logger, Motivation, RefreshToken, ResourceDescriptor, ResourceId, SemiontError, TagCategory, TagSchema, UserId, accessToken, annotationId, baseUrl, entityType, refreshToken, resourceId, userId } from '@semiont/core';
7
+ export { APIError, HttpContentTransport, HttpTransport, HttpTransportConfig, TokenRefresher } from '@semiont/api-client';
9
8
 
10
9
  /**
11
10
  * Thenable Observable subclasses.
@@ -15,8 +14,8 @@ export { APIError, APIErrorCode, ActorVM, ActorVMOptions, BusEvent, DEGRADED_THR
15
14
  * lifecycle, generation progress) and cache reads (Browse live queries).
16
15
  *
17
16
  * The point: scripts can `await` the call directly without `lastValueFrom` /
18
- * `firstValueFrom` wrappers; reactive consumers (frontend view-models) keep
19
- * using `.subscribe(...)` and `.pipe(...)` exactly as before.
17
+ * `firstValueFrom` wrappers; reactive consumers keep using `.subscribe(...)`
18
+ * and `.pipe(...)` exactly as before.
20
19
  *
21
20
  * The asymmetric `.then()` semantics — last-value-on-completion for streams,
22
21
  * first-non-undefined-value for caches — is encoded by the subclass name. The
@@ -66,12 +65,48 @@ declare class CacheObservable<T> extends Observable<T | undefined> implements Pr
66
65
  * Observable per key (its B4 contract), so this preserves that contract
67
66
  * through the awaitable wrapping. Without the memo, every public-method
68
67
  * call would produce a fresh wrapper and break referential-equality
69
- * guarantees that React-side consumers depend on.
68
+ * guarantees that hook-style reactive consumers depend on.
70
69
  *
71
70
  * Backed by a `WeakMap`, so wrappers are GC'd when their source is.
72
71
  */
73
72
  static from<T>(source: Observable<T | undefined>): CacheObservable<T>;
74
73
  }
74
+ /**
75
+ * Discriminated phases of an upload's lifecycle.
76
+ *
77
+ * - `started` — emitted immediately on `yield.resource(...)` invocation, before any bytes flow.
78
+ * - `progress` — emitted as bytes flow over the wire. Wired by `HttpContentTransport`'s XHR path when a caller passes `onProgress` (or, transitively, when `yield.resource` is the caller — it always wires the hook so subscribers see byte counts). `bytesUploaded` and `totalBytes` carry the running counts; `totalBytes` may be 0 when the transport can't determine the total (rare, e.g. chunked encoding) — UI consumers should render an indeterminate state in that case.
79
+ * - `finished` — emitted on backend acknowledgement, carries the assigned `resourceId`.
80
+ *
81
+ * Failures surface as `Observable.error(...)` (typically an `APIError` from the transport's `errors$` Subject), not as a `phase: 'failed'` event — `subscribe`'s error callback handles them. Cancellation is honored: unsubscribing before `finished` aborts the in-flight HTTP request on the XHR path.
82
+ */
83
+ type UploadProgress = {
84
+ phase: 'started';
85
+ totalBytes: number;
86
+ } | {
87
+ phase: 'progress';
88
+ bytesUploaded: number;
89
+ totalBytes: number;
90
+ } | {
91
+ phase: 'finished';
92
+ resourceId: ResourceId;
93
+ };
94
+ /**
95
+ * Specialized `StreamObservable` for `yield.resource`. Subscribers see the
96
+ * full `UploadProgress` event sequence (started → optional progress → finished).
97
+ * Awaiting resolves specifically to `{ resourceId }` extracted from the
98
+ * `'finished'` event — preserving the pre-Phase-18 awaited shape so existing
99
+ * `await client.yield.resource(...)` callers don't need to narrow the union.
100
+ */
101
+ declare class UploadObservable extends Observable<UploadProgress> implements PromiseLike<{
102
+ resourceId: ResourceId;
103
+ }> {
104
+ then<R1 = {
105
+ resourceId: ResourceId;
106
+ }, R2 = never>(onfulfilled?: ((v: {
107
+ resourceId: ResourceId;
108
+ }) => R1 | PromiseLike<R1>) | null, onrejected?: ((e: unknown) => R2 | PromiseLike<R2>) | null): PromiseLike<R1 | R2>;
109
+ }
75
110
 
76
111
  /**
77
112
  * Verb Namespace Interfaces
@@ -101,7 +136,7 @@ declare class CacheObservable<T> extends Observable<T | undefined> implements Pr
101
136
  * does not propagate through pipe — by design).
102
137
  */
103
138
 
104
- type StoredEventResponse$2 = components['schemas']['StoredEventResponse'];
139
+ type StoredEventResponse$1 = components['schemas']['StoredEventResponse'];
105
140
  type GatherProgress = components['schemas']['GatherProgress'];
106
141
  type MatchSearchResult = components['schemas']['MatchSearchResult'];
107
142
  type JobProgress$2 = components['schemas']['JobProgress'];
@@ -168,7 +203,12 @@ interface GenerationOptions {
168
203
  storageUri: string;
169
204
  context: GatheredContext;
170
205
  prompt?: string;
206
+ /** Entity-type tags to stamp on the synthesized resource. Used both as a prompt bias for the generation worker and as the `entityTypes` set on the resulting resource (so `browse.resources({ entityType: ... })` queries can find it). */
207
+ entityTypes?: string[];
208
+ /** Annotation/resource body locale — language the generated resource is written in (typically the user's UI locale). */
171
209
  language?: string;
210
+ /** Source-resource locale — language of the resource the annotation lives on, used in the prompt so the LLM understands embedded source-context snippets. BCP-47. */
211
+ sourceLanguage?: string;
172
212
  temperature?: number;
173
213
  maxTokens?: number;
174
214
  }
@@ -179,7 +219,10 @@ interface MarkAssistOptions {
179
219
  instructions?: string;
180
220
  density?: number;
181
221
  tone?: string;
222
+ /** Annotation body locale — language the LLM should write generated body text in (comment text, assessment text, tag/reference body language stamp). BCP-47. */
182
223
  language?: string;
224
+ /** Source-resource locale — language of the content being analyzed, used in the prompt so the LLM analyzes non-English source correctly. BCP-47. */
225
+ sourceLanguage?: string;
183
226
  schemaId?: string;
184
227
  categories?: string[];
185
228
  }
@@ -256,8 +299,9 @@ interface BrowseNamespace$1 {
256
299
  annotations(resourceId: ResourceId): CacheObservable<Annotation[]>;
257
300
  annotation(resourceId: ResourceId, annotationId: AnnotationId): CacheObservable<Annotation>;
258
301
  entityTypes(): CacheObservable<string[]>;
302
+ tagSchemas(): CacheObservable<TagSchema[]>;
259
303
  referencedBy(resourceId: ResourceId): CacheObservable<ReferencedByEntry[]>;
260
- events(resourceId: ResourceId): CacheObservable<StoredEventResponse$2[]>;
304
+ events(resourceId: ResourceId): CacheObservable<StoredEventResponse$1[]>;
261
305
  resourceContent(resourceId: ResourceId): Promise<string>;
262
306
  resourceRepresentation(resourceId: ResourceId, options?: {
263
307
  accept?: string;
@@ -271,7 +315,7 @@ interface BrowseNamespace$1 {
271
315
  stream: ReadableStream<Uint8Array>;
272
316
  contentType: string;
273
317
  }>;
274
- resourceEvents(resourceId: ResourceId): Promise<StoredEventResponse$2[]>;
318
+ resourceEvents(resourceId: ResourceId): Promise<StoredEventResponse$1[]>;
275
319
  annotationHistory(resourceId: ResourceId, annotationId: AnnotationId): Promise<AnnotationHistoryResponse>;
276
320
  connections(resourceId: ResourceId): Promise<GraphConnection[]>;
277
321
  backlinks(resourceId: ResourceId): Promise<Annotation[]>;
@@ -281,7 +325,43 @@ interface BrowseNamespace$1 {
281
325
  navigateReference(resourceId: ResourceId): void;
282
326
  }
283
327
  /**
284
- * Markannotation CRUD, entity types, AI assist
328
+ * Frameschema-layer flow (the eighth flow).
329
+ *
330
+ * Frame operates on the KB's conceptual vocabulary — what *kinds* of
331
+ * things exist (entity types) and, in the future, what taxonomies are
332
+ * recognized (tag schemas), what relations are typed (predicate types),
333
+ * and how schemas are imported (ontology I/O). The other seven flows
334
+ * (yield, mark, match, bind, gather, browse, beckon) operate on
335
+ * content; Frame operates on the schema layer that content is expressed
336
+ * in.
337
+ *
338
+ * MVP scope is small: entity-type vocabulary writes only. Live reads of
339
+ * the entity-type vocabulary stay on Browse (`browse.entityTypes()` is
340
+ * a `CacheObservable<string[]>` consumed by 8+ call sites). Frame owns
341
+ * writes; Browse owns reads — the same asymmetry that already holds for
342
+ * resources and annotations.
343
+ *
344
+ * Backend actor: Stower
345
+ * Event prefix: frame:*
346
+ */
347
+ interface FrameNamespace$1 {
348
+ /** Add a single entity type to the KB's vocabulary. Idempotent — adding an existing type is a no-op. */
349
+ addEntityType(type: string): Promise<void>;
350
+ /** Add multiple entity types in one call. Convenience over a loop of `addEntityType`. */
351
+ addEntityTypes(types: string[]): Promise<void>;
352
+ /**
353
+ * Register a tag schema with the KB's runtime registry.
354
+ *
355
+ * Most-recent registration of a given `schema.id` wins; identical
356
+ * re-registrations are silent, differing content overwrites the
357
+ * existing entry and logs a warning. KBs typically call this at
358
+ * session/skill startup so the schema is available for `mark.assist`
359
+ * with motivation `tagging` and surfaces in `browse.tagSchemas()`.
360
+ */
361
+ addTagSchema(schema: TagSchema): Promise<void>;
362
+ }
363
+ /**
364
+ * Mark — annotation CRUD, AI assist, resource lifecycle
285
365
  *
286
366
  * Commands return Promises that resolve on HTTP acceptance (202).
287
367
  * Results appear on browse Observables via bus gateway.
@@ -291,17 +371,15 @@ interface BrowseNamespace$1 {
291
371
  * Event prefix: mark:*
292
372
  */
293
373
  interface MarkNamespace$1 {
294
- annotation(resourceId: ResourceId, input: CreateAnnotationInput): Promise<{
374
+ annotation(input: CreateAnnotationInput): Promise<{
295
375
  annotationId: AnnotationId;
296
376
  }>;
297
377
  delete(resourceId: ResourceId, annotationId: AnnotationId): Promise<void>;
298
- entityType(type: string): Promise<void>;
299
- entityTypes(types: string[]): Promise<void>;
300
378
  archive(resourceId: ResourceId): Promise<void>;
301
379
  unarchive(resourceId: ResourceId): Promise<void>;
302
380
  assist(resourceId: ResourceId, motivation: Motivation, options: MarkAssistOptions): StreamObservable<MarkAssistEvent>;
303
381
  request(selector: components['schemas']['MarkRequestedEvent']['selector'], motivation: Motivation): void;
304
- /** Fire-and-forget variant of `assist` — mark-vm orchestrates the call and its progress Observable. */
382
+ /** Fire-and-forget variant of `assist` — mark-state-unit orchestrates the call and its progress Observable. */
305
383
  requestAssist(motivation: Motivation, options: MarkAssistOptions, correlationId?: string): void;
306
384
  /** Submit the currently pending annotation with its selector and optional body. */
307
385
  submit(input: components['schemas']['MarkSubmitEvent']): void;
@@ -339,7 +417,7 @@ interface BindNamespace$1 {
339
417
  * Event prefix: gather:*
340
418
  */
341
419
  interface GatherNamespace$1 {
342
- annotation(annotationId: AnnotationId, resourceId: ResourceId, options?: {
420
+ annotation(resourceId: ResourceId, annotationId: AnnotationId, options?: {
343
421
  contextWindow?: number;
344
422
  }): StreamObservable<GatherAnnotationProgress>;
345
423
  resource(resourceId: ResourceId, options?: {
@@ -360,7 +438,7 @@ interface MatchNamespace$1 {
360
438
  limit?: number;
361
439
  useSemanticScoring?: boolean;
362
440
  }): StreamObservable<MatchSearchProgress>;
363
- /** Fire-and-forget variant: match-vm orchestrates the call and its result Observable. */
441
+ /** Fire-and-forget variant: match-state-unit orchestrates the call and its result Observable. */
364
442
  requestSearch(input: components['schemas']['MatchSearchRequest']): void;
365
443
  }
366
444
  /**
@@ -373,9 +451,7 @@ interface MatchNamespace$1 {
373
451
  * Event prefix: yield:*
374
452
  */
375
453
  interface YieldNamespace$1 {
376
- resource(data: CreateResourceInput): Promise<{
377
- resourceId: string;
378
- }>;
454
+ resource(data: CreateResourceInput): UploadObservable;
379
455
  fromAnnotation(resourceId: ResourceId, annotationId: AnnotationId, options: GenerationOptions): StreamObservable<YieldGenerationEvent>;
380
456
  cloneToken(resourceId: ResourceId): Promise<{
381
457
  token: string;
@@ -383,7 +459,7 @@ interface YieldNamespace$1 {
383
459
  }>;
384
460
  fromToken(token: string): Promise<ResourceDescriptor>;
385
461
  createFromToken(options: CreateFromTokenOptions): Promise<{
386
- resourceId: string;
462
+ resourceId: ResourceId;
387
463
  }>;
388
464
  /** UI signal: user invoked the clone action from the resource-info panel. */
389
465
  clone(): void;
@@ -398,7 +474,7 @@ interface YieldNamespace$1 {
398
474
  * Event prefix: beckon:*
399
475
  */
400
476
  interface BeckonNamespace$1 {
401
- attention(annotationId: AnnotationId, resourceId: ResourceId): void;
477
+ attention(resourceId: ResourceId, annotationId: AnnotationId): void;
402
478
  hover(annotationId: AnnotationId | null): void;
403
479
  sparkle(annotationId: AnnotationId): void;
404
480
  }
@@ -420,7 +496,7 @@ interface JobNamespace$1 {
420
496
  timeout?: number;
421
497
  onProgress?: (status: JobStatusResponse$1) => void;
422
498
  }): Promise<JobStatusResponse$1>;
423
- cancel(jobId: JobId, type: string): Promise<void>;
499
+ cancelByType(jobType: 'annotation' | 'generation'): Promise<void>;
424
500
  /** UI signal: cancel all active jobs of a given type (e.g. "annotation"). */
425
501
  cancelRequest(jobType: 'annotation' | 'generation'): void;
426
502
  }
@@ -451,31 +527,21 @@ interface AdminNamespace$1 {
451
527
  oauthConfig(): Promise<OAuthConfigResponse$1>;
452
528
  healthCheck(): Promise<ResponseContent<paths['/api/health']['get']>>;
453
529
  status(): Promise<ResponseContent<paths['/api/status']['get']>>;
454
- backup(): Promise<Response>;
455
- restore(file: File, onProgress?: (event: {
456
- phase: string;
457
- message?: string;
458
- result?: Record<string, unknown>;
459
- }) => void): Promise<{
460
- phase: string;
461
- message?: string;
462
- result?: Record<string, unknown>;
463
- }>;
530
+ backup(): Promise<BackendDownload>;
531
+ /**
532
+ * Restore from a backup archive. Returns a `StreamObservable` that
533
+ * emits each `ProgressEvent` as the operation runs (`'started'`,
534
+ * `'parsing'`, `'importing'`, ..., `'complete'`). Subscribers see
535
+ * every step; awaiters get the final event via the PromiseLike sugar.
536
+ */
537
+ restore(file: File): StreamObservable<ProgressEvent>;
464
538
  exportKnowledgeBase(params?: {
465
539
  includeArchived?: boolean;
466
- }): Promise<Response>;
467
- importKnowledgeBase(file: File, onProgress?: (event: {
468
- phase: string;
469
- message?: string;
470
- result?: Record<string, unknown>;
471
- }) => void): Promise<{
472
- phase: string;
473
- message?: string;
474
- result?: Record<string, unknown>;
475
- }>;
540
+ }): Promise<BackendDownload>;
541
+ importKnowledgeBase(file: File): StreamObservable<ProgressEvent>;
476
542
  }
477
543
 
478
- type StoredEventResponse$1 = components['schemas']['StoredEventResponse'];
544
+ type StoredEventResponse = components['schemas']['StoredEventResponse'];
479
545
  type ResourceListFilters = {
480
546
  limit?: number;
481
547
  archived?: boolean;
@@ -498,6 +564,7 @@ declare class BrowseNamespace implements BrowseNamespace$1 {
498
564
  private readonly annotationDetailCache;
499
565
  private readonly annotationResources;
500
566
  private readonly entityTypesCache;
567
+ private readonly tagSchemasCache;
501
568
  private readonly referencedByCache;
502
569
  private readonly resourceEventsCache;
503
570
  /** Filter-blob memory so `invalidateResourceLists` can replay per-key. */
@@ -518,8 +585,9 @@ declare class BrowseNamespace implements BrowseNamespace$1 {
518
585
  annotations(resourceId: ResourceId): CacheObservable<Annotation[]>;
519
586
  annotation(resourceId: ResourceId, annotationId: AnnotationId): CacheObservable<Annotation>;
520
587
  entityTypes(): CacheObservable<string[]>;
588
+ tagSchemas(): CacheObservable<TagSchema[]>;
521
589
  referencedBy(resourceId: ResourceId): CacheObservable<ReferencedByEntry[]>;
522
- events(resourceId: ResourceId): CacheObservable<StoredEventResponse$1[]>;
590
+ events(resourceId: ResourceId): CacheObservable<StoredEventResponse[]>;
523
591
  resourceContent(resourceId: ResourceId): Promise<string>;
524
592
  resourceRepresentation(resourceId: ResourceId, options?: {
525
593
  accept?: string;
@@ -533,7 +601,7 @@ declare class BrowseNamespace implements BrowseNamespace$1 {
533
601
  stream: ReadableStream<Uint8Array>;
534
602
  contentType: string;
535
603
  }>;
536
- resourceEvents(resourceId: ResourceId): Promise<StoredEventResponse$1[]>;
604
+ resourceEvents(resourceId: ResourceId): Promise<StoredEventResponse[]>;
537
605
  annotationHistory(resourceId: ResourceId, annotationId: AnnotationId): Promise<AnnotationHistoryResponse>;
538
606
  connections(_resourceId: ResourceId): Promise<GraphConnection[]>;
539
607
  backlinks(_resourceId: ResourceId): Promise<Annotation[]>;
@@ -546,6 +614,7 @@ declare class BrowseNamespace implements BrowseNamespace$1 {
546
614
  invalidateResourceDetail(id: ResourceId): void;
547
615
  invalidateResourceLists(): void;
548
616
  invalidateEntityTypes(): void;
617
+ invalidateTagSchemas(): void;
549
618
  invalidateReferencedBy(resourceId: ResourceId): void;
550
619
  invalidateResourceEvents(resourceId: ResourceId): void;
551
620
  updateAnnotationInPlace(resourceId: ResourceId, annotation: Annotation): void;
@@ -582,12 +651,10 @@ declare class MarkNamespace implements MarkNamespace$1 {
582
651
  private readonly transport;
583
652
  private readonly bus;
584
653
  constructor(transport: ITransport, bus: EventBus);
585
- annotation(resourceId: ResourceId, input: CreateAnnotationInput): Promise<{
654
+ annotation(input: CreateAnnotationInput): Promise<{
586
655
  annotationId: AnnotationId;
587
656
  }>;
588
657
  delete(resourceId: ResourceId, annotationId: AnnotationId): Promise<void>;
589
- entityType(type: string): Promise<void>;
590
- entityTypes(types: string[]): Promise<void>;
591
658
  archive(resourceId: ResourceId): Promise<void>;
592
659
  unarchive(resourceId: ResourceId): Promise<void>;
593
660
  assist(resourceId: ResourceId, motivation: Motivation, options: MarkAssistOptions): StreamObservable<MarkAssistEvent>;
@@ -615,7 +682,7 @@ declare class GatherNamespace implements GatherNamespace$1 {
615
682
  private readonly transport;
616
683
  private readonly bus;
617
684
  constructor(transport: ITransport, bus: EventBus);
618
- annotation(annotationId: AnnotationId, resourceId: ResourceId, options?: {
685
+ annotation(resourceId: ResourceId, annotationId: AnnotationId, options?: {
619
686
  contextWindow?: number;
620
687
  }): StreamObservable<GatherAnnotationProgress>;
621
688
  resource(_resourceId: ResourceId, _options?: {
@@ -639,9 +706,7 @@ declare class YieldNamespace implements YieldNamespace$1 {
639
706
  private readonly bus;
640
707
  private readonly content;
641
708
  constructor(transport: ITransport, bus: EventBus, content: IContentTransport);
642
- resource(data: CreateResourceInput): Promise<{
643
- resourceId: string;
644
- }>;
709
+ resource(data: CreateResourceInput): UploadObservable;
645
710
  fromAnnotation(resourceId: ResourceId, annotationId: AnnotationId, options: GenerationOptions): StreamObservable<YieldGenerationEvent>;
646
711
  cloneToken(resourceId: ResourceId): Promise<{
647
712
  token: string;
@@ -649,7 +714,7 @@ declare class YieldNamespace implements YieldNamespace$1 {
649
714
  }>;
650
715
  fromToken(token: string): Promise<ResourceDescriptor>;
651
716
  createFromToken(options: CreateFromTokenOptions): Promise<{
652
- resourceId: string;
717
+ resourceId: ResourceId;
653
718
  }>;
654
719
  clone(): void;
655
720
  }
@@ -658,11 +723,39 @@ declare class BeckonNamespace implements BeckonNamespace$1 {
658
723
  private readonly transport;
659
724
  private readonly bus;
660
725
  constructor(transport: ITransport, bus: EventBus);
661
- attention(annotationId: AnnotationId, resourceId: ResourceId): void;
726
+ attention(resourceId: ResourceId, annotationId: AnnotationId): void;
662
727
  hover(annotationId: AnnotationId | null): void;
663
728
  sparkle(annotationId: AnnotationId): void;
664
729
  }
665
730
 
731
+ /**
732
+ * FrameNamespace — the eighth flow's surface.
733
+ *
734
+ * Frame operates on the KB's **schema layer** — the conceptual vocabulary
735
+ * the other seven flows are expressed in. Where yield/mark/match/bind/
736
+ * gather/browse/beckon act on content (resources, annotations, references,
737
+ * attention), Frame acts on what *kinds* of things exist: entity types,
738
+ * eventually tag schemas, relation/predicate types, ontology imports.
739
+ *
740
+ * The MVP owns a single primitive — entity-type vocabulary writes on the
741
+ * `frame:add-entity-type` channel. See `docs/protocol/flows/FRAME.md`
742
+ * for the per-flow contract.
743
+ *
744
+ * Live reads of the entity-type vocabulary stay on Browse
745
+ * (`browse.entityTypes()` is a `CacheObservable<string[]>`). Frame owns
746
+ * writes; Browse owns reads. The asymmetry is intentional — re-implementing
747
+ * Browse's cache primitives on Frame for a single read would duplicate
748
+ * machinery without benefit.
749
+ */
750
+
751
+ declare class FrameNamespace implements FrameNamespace$1 {
752
+ private readonly transport;
753
+ constructor(transport: ITransport);
754
+ addEntityType(type: string): Promise<void>;
755
+ addEntityTypes(types: string[]): Promise<void>;
756
+ addTagSchema(schema: TagSchema): Promise<void>;
757
+ }
758
+
666
759
  type JobStatusResponse = components['schemas']['JobStatusResponse'];
667
760
  declare class JobNamespace implements JobNamespace$1 {
668
761
  private readonly transport;
@@ -686,19 +779,19 @@ declare class JobNamespace implements JobNamespace$1 {
686
779
  timeout?: number;
687
780
  onProgress?: (status: JobStatusResponse) => void;
688
781
  }): Promise<JobStatusResponse>;
689
- cancel(_jobId: JobId, type: string): Promise<void>;
782
+ cancelByType(jobType: 'annotation' | 'generation'): Promise<void>;
690
783
  cancelRequest(jobType: 'annotation' | 'generation'): void;
691
784
  }
692
785
 
693
786
  /**
694
- * AuthNamespace — authentication. Pure wire, no bus.
787
+ * AuthNamespace — authentication. Backend ops only; no bus.
695
788
  */
696
789
 
697
790
  type AuthResponse = components['schemas']['AuthResponse'];
698
791
  type TokenRefreshResponse = components['schemas']['TokenRefreshResponse'];
699
792
  declare class AuthNamespace implements AuthNamespace$1 {
700
- private readonly transport;
701
- constructor(transport: ITransport);
793
+ private readonly backend;
794
+ constructor(backend: IBackendOperations);
702
795
  password(emailStr: string, passwordStr: string): Promise<AuthResponse>;
703
796
  google(credential: string): Promise<AuthResponse>;
704
797
  refresh(token: string): Promise<TokenRefreshResponse>;
@@ -714,42 +807,26 @@ declare class AuthNamespace implements AuthNamespace$1 {
714
807
  }
715
808
 
716
809
  /**
717
- * AdminNamespace — administration. Pure wire, no bus.
810
+ * AdminNamespace — administration. Backend ops only; no bus.
718
811
  */
719
812
 
720
813
  type AdminUserStatsResponse = components['schemas']['AdminUserStatsResponse'];
721
814
  type OAuthConfigResponse = components['schemas']['OAuthConfigResponse'];
722
815
  declare class AdminNamespace implements AdminNamespace$1 {
723
- private readonly transport;
724
- constructor(transport: ITransport);
816
+ private readonly backend;
817
+ constructor(backend: IBackendOperations);
725
818
  users(): Promise<User[]>;
726
819
  userStats(): Promise<AdminUserStatsResponse>;
727
820
  updateUser(userId: UserDID, data: RequestContent<paths['/api/admin/users/{id}']['patch']>): Promise<User>;
728
821
  oauthConfig(): Promise<OAuthConfigResponse>;
729
822
  healthCheck(): Promise<ResponseContent<paths['/api/health']['get']>>;
730
823
  status(): Promise<ResponseContent<paths['/api/status']['get']>>;
731
- backup(): Promise<Response>;
732
- restore(file: File, onProgress?: (event: {
733
- phase: string;
734
- message?: string;
735
- result?: Record<string, unknown>;
736
- }) => void): Promise<{
737
- phase: string;
738
- message?: string;
739
- result?: Record<string, unknown>;
740
- }>;
824
+ backup(): Promise<BackendDownload>;
825
+ restore(file: File): StreamObservable<ProgressEvent>;
741
826
  exportKnowledgeBase(params?: {
742
827
  includeArchived?: boolean;
743
- }): Promise<Response>;
744
- importKnowledgeBase(file: File, onProgress?: (event: {
745
- phase: string;
746
- message?: string;
747
- result?: Record<string, unknown>;
748
- }) => void): Promise<{
749
- phase: string;
750
- message?: string;
751
- result?: Record<string, unknown>;
752
- }>;
828
+ }): Promise<BackendDownload>;
829
+ importKnowledgeBase(file: File): StreamObservable<ProgressEvent>;
753
830
  }
754
831
 
755
832
  declare class SemiontClient {
@@ -770,6 +847,7 @@ declare class SemiontClient {
770
847
  */
771
848
  readonly bus: EventBus;
772
849
  readonly baseUrl: BaseUrl;
850
+ readonly frame: FrameNamespace;
773
851
  readonly browse: BrowseNamespace;
774
852
  readonly mark: MarkNamespace;
775
853
  readonly bind: BindNamespace;
@@ -778,8 +856,8 @@ declare class SemiontClient {
778
856
  readonly yield: YieldNamespace;
779
857
  readonly beckon: BeckonNamespace;
780
858
  readonly job: JobNamespace;
781
- readonly auth: AuthNamespace;
782
- readonly admin: AdminNamespace;
859
+ readonly auth: AuthNamespace | undefined;
860
+ readonly admin: AdminNamespace | undefined;
783
861
  /**
784
862
  * The client *owns* its bus. The constructor creates a fresh `EventBus`
785
863
  * and hands it to the transport via `transport.bridgeInto(this.bus)`.
@@ -792,8 +870,14 @@ declare class SemiontClient {
792
870
  * Callers do not pass a bus in. If they need to interact with the bus
793
871
  * (e.g. for tests or to subscribe to arbitrary channels), they read it
794
872
  * back via `client.bus`.
873
+ *
874
+ * `backend` is optional. When provided, the `auth` and `admin`
875
+ * namespaces are constructed against it; when omitted, they're
876
+ * `undefined`. For HTTP setups this is conventionally the same
877
+ * `HttpTransport` instance that's also passed as `transport` (HTTP
878
+ * implements both `ITransport` and `IBackendOperations`).
795
879
  */
796
- constructor(transport: ITransport, content: IContentTransport);
880
+ constructor(transport: ITransport, content: IContentTransport, backend?: IBackendOperations);
797
881
  /** Transport-level connection state. HTTP reflects SSE health; local is always 'connected'. */
798
882
  get state$(): rxjs.Observable<_semiont_core.ConnectionState>;
799
883
  subscribeToResource(resourceId: ResourceId): () => void;
@@ -807,9 +891,10 @@ declare class SemiontClient {
807
891
  * Use this for one-shot scripts, CLI commands, or any consumer that
808
892
  * doesn't need to drive the token from outside (no manual refresh,
809
893
  * no cross-tab sync). For long-running scripts that need refresh,
810
- * use `SemiontSession.fromHttp(...)` instead it owns the same
811
- * transport/client wiring plus the proactive-refresh + storage
812
- * machinery.
894
+ * use `SemiontSession.fromHttp(...)` (with a token already on hand)
895
+ * or `SemiontSession.signInHttp(...)` (credentials-first) instead
896
+ * either owns the same transport/client wiring plus the
897
+ * proactive-refresh + storage machinery.
813
898
  *
814
899
  * Strings are accepted for `baseUrl` and `token`; they are branded
815
900
  * via `baseUrl()` / `accessToken()` from `@semiont/core` automatically.
@@ -823,9 +908,9 @@ declare class SemiontClient {
823
908
  }): SemiontClient;
824
909
  /**
825
910
  * Async factory for the credentials-first script case. Builds a
826
- * transient transport, calls `auth.password(email, password)` to
827
- * acquire an access token, and returns the wired client with the
828
- * token populated.
911
+ * transient HTTP transport, calls `auth.password(email, password)`
912
+ * to acquire an access token, and returns the wired client with
913
+ * the token populated.
829
914
  *
830
915
  * This is the right entry point for skills, CLI scripts, and any
831
916
  * consumer that starts with email + password rather than a JWT
@@ -834,13 +919,19 @@ declare class SemiontClient {
834
919
  * `fromHttp({ baseUrl, token })` instead.
835
920
  *
836
921
  * For long-running scripts that need refresh, use
837
- * `SemiontSession.signIn(...)` — same credentials shape, plus the
838
- * session machinery for proactive refresh and persistence.
922
+ * `SemiontSession.signInHttp(...)` — same credentials shape, plus
923
+ * the session machinery for proactive refresh and persistence.
924
+ *
925
+ * Named `signInHttp` because email+password authentication is
926
+ * inherently an HTTP-shaped operation in the current backend; an
927
+ * in-process `LocalTransport` doesn't have a credentials login
928
+ * path. Non-HTTP transports construct the client directly from
929
+ * their package's transport instance.
839
930
  *
840
931
  * Throws if authentication fails. The transient client is disposed
841
932
  * before the throw, so no resources leak on failure.
842
933
  */
843
- static signIn(opts: {
934
+ static signInHttp(opts: {
844
935
  baseUrl: BaseUrl | string;
845
936
  email: string;
846
937
  password: string;
@@ -864,76 +955,49 @@ interface BusRequestPrimitive {
864
955
  declare function busRequest<TResult>(bus: BusRequestPrimitive, emitChannel: string, payload: Record<string, unknown>, resultChannel: string, failureChannel: string, timeoutMs?: number): Promise<TResult>;
865
956
 
866
957
  /**
867
- * RxJS-native read-through cache primitive.
868
- *
869
- * Behavioral contract: packages/sdk/docs/CACHE-SEMANTICS.md (B1–B13).
870
- *
871
- * Framework-agnostic: no React, no dependency on any namespace. Used by
872
- * `BrowseNamespace` to back its per-key stores, but equally usable from
873
- * CLI, MCP, or worker code.
874
- *
875
- * Shape:
876
- * - `observe(key)`: returns an Observable<V | undefined> that triggers
877
- * a fetch on first subscription for a missing key, dedup-joins any
878
- * concurrent fetch, and emits the stored value thereafter.
879
- * - `invalidate(key)`: stale-while-revalidate — keeps the current
880
- * value visible to observers, clears the in-flight guard, starts a
881
- * fresh fetch. If the previous fetch was orphaned (SSE torn down,
882
- * response lost), this is how the cache recovers.
883
- * - `remove(key)`: drops the cache entry entirely. Used for entity
884
- * deletions (B13a). No refetch.
885
- * - `set(key, value)`: writes through without a fetch. Used when a
886
- * bus event carries the new value inline (B13b).
887
- * - `invalidateAll()`: per-key SWR refetch of every currently-cached
888
- * entry. Used by gap-detection paths.
889
- * - `dispose()`: completes the store so observers unsubscribe.
890
- *
891
- * What's deliberately out:
892
- * - No subscriber ref-counting / GC of unobserved keys. The per-key
893
- * observable memo grows with the set of observed keys for the cache's
894
- * lifetime (B11). Acceptable given cache lifetime == client lifetime.
895
- * - No TTL / cacheTime. Entries are evicted only by explicit remove.
896
- * - No retry / backoff. A failing fetch leaves the cache unchanged
897
- * (B6); the caller drives retry via invalidate.
898
- */
899
-
900
- interface Cache<K, V> {
901
- /** Observable stream of the value at `key`. Triggers a fetch if not cached. */
902
- observe(key: K): Observable<V | undefined>;
903
- /** Synchronous snapshot of the current value, without triggering a fetch. */
904
- get(key: K): V | undefined;
905
- /** Iterator of currently-cached keys. For invalidateAll and diagnostics. */
906
- keys(): K[];
907
- /**
908
- * Mark the entry stale and refetch. Keeps the previous value visible
909
- * to observers during the refetch (stale-while-revalidate).
910
- */
911
- invalidate(key: K): void;
912
- /** Drop the entry from the cache. No refetch. */
913
- remove(key: K): void;
914
- /** Write-through: set the value directly without a fetch. */
915
- set(key: K, value: V): void;
916
- /** Per-key SWR refetch of every currently-cached entry. */
917
- invalidateAll(): void;
918
- /** Release the underlying subject. Observers complete. */
919
- dispose(): void;
920
- }
921
- declare function createCache<K, V>(fetchFn: (key: K) => Promise<V>): Cache<K, V>;
922
-
923
- /**
924
- * KnowledgeBase — a connection to a Semiont backend instance.
958
+ * KnowledgeBase a connection to a Semiont knowledge system.
959
+ *
960
+ * The KB type itself is uniform. The transport-shape variation lives in
961
+ * the nested `endpoint` field, which is a discriminated union:
925
962
  *
926
- * Each KB has its own JWT, its own API base URL, and its own session.
927
- * The user is "authenticated against KB X" — never globally authenticated.
963
+ * - `endpoint.kind === 'http'` — a remote backend reached over HTTP+SSE.
964
+ * Carries `host`/`port`/`protocol`.
965
+ * - `endpoint.kind === 'local'` — an in-process knowledge system reached
966
+ * via `LocalTransport` from
967
+ * `@semiont/make-meaning`. Carries an
968
+ * opaque `kbId` identifying the local
969
+ * instance to the host process.
970
+ *
971
+ * Code that doesn't know how to make a transport (`SemiontSession`,
972
+ * `SemiontBrowser`, the frontend KB list UI) treats `KnowledgeBase` as
973
+ * uniform and never inspects `endpoint`. Code that *does* construct
974
+ * transports (the transport-factory passed to `SemiontBrowser`,
975
+ * `kbBackendUrl` for HTTP URL construction) inspects `endpoint.kind`
976
+ * and dispatches.
977
+ *
978
+ * Each KB has its own session, its own credentials (where applicable),
979
+ * and its own JWT (HTTP only). The user is "authenticated against KB X" —
980
+ * never globally authenticated.
928
981
  */
982
+ /** Fields shared by every KB regardless of endpoint kind. */
929
983
  interface KnowledgeBase {
930
984
  id: string;
931
985
  label: string;
986
+ email: string;
987
+ gitBranch?: string;
988
+ endpoint: KbEndpoint;
989
+ }
990
+ type KbEndpoint = HttpEndpoint | LocalEndpoint;
991
+ interface HttpEndpoint {
992
+ kind: 'http';
932
993
  host: string;
933
994
  port: number;
934
995
  protocol: 'http' | 'https';
935
- email: string;
936
- gitBranch?: string;
996
+ }
997
+ interface LocalEndpoint {
998
+ kind: 'local';
999
+ /** Opaque identifier for the in-process KB instance the host has loaded. */
1000
+ kbId: string;
937
1001
  }
938
1002
  /**
939
1003
  * Input shape for adding a new KB. The id is generated by the provider.
@@ -944,6 +1008,46 @@ type NewKnowledgeBase = Omit<KnowledgeBase, 'id'>;
944
1008
  * presence and validity of the JWT in session storage.
945
1009
  */
946
1010
  type KbSessionStatus = 'authenticated' | 'expired' | 'signed-out' | 'unreachable';
1011
+ /**
1012
+ * Construct a `KnowledgeBase` for an HTTP-backed Semiont backend without
1013
+ * spelling out the nested `endpoint` literal. Convenience for tests,
1014
+ * worker bootstraps, and one-off scripts.
1015
+ *
1016
+ * ```ts
1017
+ * const kb = httpKb({
1018
+ * id: 'my-watcher',
1019
+ * label: 'My Watcher',
1020
+ * email: 'me@example.com',
1021
+ * host: 'localhost',
1022
+ * port: 4000,
1023
+ * protocol: 'http',
1024
+ * });
1025
+ * ```
1026
+ *
1027
+ * Equivalent to:
1028
+ *
1029
+ * ```ts
1030
+ * const kb: KnowledgeBase = {
1031
+ * id, label, email,
1032
+ * endpoint: { kind: 'http', host, port, protocol },
1033
+ * };
1034
+ * ```
1035
+ *
1036
+ * UI hosts that have a structured form (host / port / protocol pickers)
1037
+ * already construct the literal directly — they don't need this helper.
1038
+ * Local-endpoint KBs construct the literal directly too; the local
1039
+ * endpoint shape (`{ kind: 'local', kbId }`) is one line and doesn't
1040
+ * earn a helper.
1041
+ */
1042
+ declare function httpKb(opts: {
1043
+ id: string;
1044
+ label: string;
1045
+ email: string;
1046
+ host: string;
1047
+ port: number;
1048
+ protocol: 'http' | 'https';
1049
+ gitBranch?: string;
1050
+ }): KnowledgeBase;
947
1051
 
948
1052
  /**
949
1053
  * Session-level error surface. Emitted on `SemiontBrowser.error$` for
@@ -1012,7 +1116,7 @@ declare class InMemorySessionStorage implements SessionStorage {
1012
1116
  *
1013
1117
  * Headless by design. Runs in browsers, CLIs, workers, and tests.
1014
1118
  * UI-specific state (session-expired/permission-denied modals) lives
1015
- * in `FrontendSessionSignals`, which wraps a session — the session
1119
+ * in `SessionSignals`, which wraps a session — the session
1016
1120
  * itself has no modal observables, no user-facing notifications.
1017
1121
  *
1018
1122
  * Auth is parameterized via callbacks passed at construction:
@@ -1028,9 +1132,9 @@ declare class InMemorySessionStorage implements SessionStorage {
1028
1132
  * worker omits this (service principals have no user record).
1029
1133
  *
1030
1134
  * - `onAuthFailed(message)` — optional. Invoked when refresh
1031
- * terminally fails (expired token, no recovery possible). The
1032
- * frontend wires this to `FrontendSessionSignals.notifySessionExpired`
1033
- * so the modal surfaces; headless consumers typically just log.
1135
+ * terminally fails (expired token, no recovery possible). UI hosts
1136
+ * typically wire this to `SessionSignals.notifySessionExpired` so a
1137
+ * modal surfaces; headless consumers typically just log.
1034
1138
  *
1035
1139
  * Persistence goes through a `SessionStorage` adapter provided at
1036
1140
  * construction — the session never touches `localStorage` or `window`
@@ -1082,6 +1186,18 @@ declare class SemiontSession {
1082
1186
  readonly token$: BehaviorSubject<AccessToken | null>;
1083
1187
  readonly user$: BehaviorSubject<UserInfo | null>;
1084
1188
  readonly streamState$: Observable<ConnectionState>;
1189
+ /**
1190
+ * Stream of `SemiontError` instances surfaced by the underlying transport
1191
+ * just before they're thrown to the caller. For `HttpTransport` this is
1192
+ * an `APIError` (status-coded); other transports emit their own subclass.
1193
+ * Surfaced here so a host layer (e.g. `SemiontBrowser`) can route by
1194
+ * `err.code` to global notifications without every call site handling
1195
+ * errors itself. Headless consumers can subscribe for logging.
1196
+ *
1197
+ * Re-published from `client.transport.errors$` per the `ITransport`
1198
+ * contract — the session is purely a passthrough.
1199
+ */
1200
+ readonly errors$: Observable<SemiontError>;
1085
1201
  /** Resolves after the initial validation round-trip completes (success or failure). */
1086
1202
  readonly ready: Promise<void>;
1087
1203
  private readonly storage;
@@ -1156,11 +1272,11 @@ declare class SemiontSession {
1156
1272
  }): SemiontSession;
1157
1273
  /**
1158
1274
  * Async factory for the credentials-first long-running script case.
1159
- * Builds the transport stack, calls `auth.password(email, password)`
1160
- * to acquire access + refresh tokens, persists them via the storage
1161
- * adapter, wires a default `refresh` callback that exchanges the
1162
- * refresh token via `auth.refresh(...)`, and returns the ready
1163
- * session.
1275
+ * Builds the HTTP transport stack, calls `auth.password(email,
1276
+ * password)` to acquire access + refresh tokens, persists them via
1277
+ * the storage adapter, wires a default `refresh` callback that
1278
+ * exchanges the refresh token via `auth.refresh(...)`, and returns
1279
+ * the ready session.
1164
1280
  *
1165
1281
  * The consumer-supplied `refresh` callback becomes optional — only
1166
1282
  * needed for non-standard refresh flows (worker-pool shared secret,
@@ -1173,10 +1289,16 @@ declare class SemiontSession {
1173
1289
  * trampling each other's tokens. The factory does not synthesize a
1174
1290
  * default; the consumer makes the choice.
1175
1291
  *
1292
+ * Named `signInHttp` because email+password authentication is
1293
+ * inherently an HTTP-shaped operation in the current backend; an
1294
+ * in-process `LocalTransport` doesn't have a credentials login
1295
+ * path. Non-HTTP transports construct the session directly from
1296
+ * their package's transport instance.
1297
+ *
1176
1298
  * Throws on auth failure with no resources leaked. On success, the
1177
1299
  * returned session's `ready` promise has already resolved.
1178
1300
  */
1179
- static signIn(opts: {
1301
+ static signInHttp(opts: {
1180
1302
  kb: KnowledgeBase;
1181
1303
  storage: SessionStorage;
1182
1304
  baseUrl: BaseUrl | string;
@@ -1211,36 +1333,33 @@ interface OpenResource {
1211
1333
  }
1212
1334
 
1213
1335
  /**
1214
- * FrontendSessionSignalsmodal state that belongs to the UI, not
1215
- * the session itself.
1336
+ * SessionSignalsUI-facing notification state that belongs to the host
1337
+ * surface, not to the session itself.
1216
1338
  *
1217
1339
  * `SemiontSession` is a headless per-backend client + token + user
1218
1340
  * holder. It can run in any process: browser, worker, CLI, test. But
1219
- * the session-expired / permission-denied *modals* only make sense
1220
- * in a UI context. Keeping those observables on `SemiontSession`
1221
- * meant workers and CLIs carried four dead BehaviorSubjects that
1222
- * nothing would ever fire.
1341
+ * the session-expired / permission-denied *notifications* are inherently
1342
+ * a UI-host concern. Keeping those observables on `SemiontSession` meant
1343
+ * workers and CLIs carried four dead BehaviorSubjects that nothing would
1344
+ * ever fire.
1223
1345
  *
1224
- * `FrontendSessionSignals` owns the modal state and has no hard
1225
- * reference to a session. `SemiontBrowser` constructs one alongside
1226
- * every frontend session and wires:
1346
+ * `SessionSignals` owns the notification state and has no hard reference
1347
+ * to a session. A UI host (e.g. `SemiontBrowser`) constructs one alongside
1348
+ * every active session and wires:
1227
1349
  *
1228
1350
  * - `session.onAuthFailed` → `signals.notifySessionExpired` so
1229
- * proactive-refresh failures surface as modals
1230
- * - `notify` module handlers → the active signals' methods so
1231
- * external callers (e.g. React Query's QueryCache.onError) can
1232
- * trigger the modals without touching the session
1351
+ * proactive-refresh failures surface as a notification
1233
1352
  *
1234
- * React consumers that need modal state subscribe here; consumers
1235
- * that need bus/HTTP access continue to subscribe to the session.
1353
+ * UI consumers that need to render modal/banner state subscribe here;
1354
+ * consumers that need bus/HTTP access continue to subscribe to the session.
1236
1355
  *
1237
1356
  * Session auth-state cleanup (clearing token, clearing storage) is
1238
1357
  * the session's own responsibility inside `refresh()` — by the time
1239
1358
  * `notifySessionExpired` runs, the session has already torn down.
1240
- * Signals only surfaces the modal.
1359
+ * Signals only surfaces the notification.
1241
1360
  */
1242
1361
 
1243
- declare class FrontendSessionSignals {
1362
+ declare class SessionSignals {
1244
1363
  readonly sessionExpiredAt$: BehaviorSubject<number | null>;
1245
1364
  readonly sessionExpiredMessage$: BehaviorSubject<string | null>;
1246
1365
  readonly permissionDeniedAt$: BehaviorSubject<number | null>;
@@ -1253,14 +1372,46 @@ declare class FrontendSessionSignals {
1253
1372
  dispose(): void;
1254
1373
  }
1255
1374
 
1375
+ /**
1376
+ * SessionFactory — the injection point that lets `SemiontBrowser` stay
1377
+ * transport-agnostic.
1378
+ *
1379
+ * The browser knows how to manage the *lifecycle* of an active session
1380
+ * (track it in `activeSession$`, dispose on KB switch, serialize
1381
+ * overlapping activations) but does not know how to *construct* one —
1382
+ * because that's where transport choice lives. The construction step
1383
+ * is parameterized via this factory.
1384
+ *
1385
+ * The HTTP factory is provided by `createHttpSessionFactory`. A
1386
+ * future in-process variant from `@semiont/make-meaning` would expose
1387
+ * its own factory.
1388
+ */
1389
+
1390
+ interface SessionFactoryOptions {
1391
+ /** The KB the session is being constructed for. */
1392
+ kb: KnowledgeBase;
1393
+ /** Persistence adapter — same one the browser uses. */
1394
+ storage: SessionStorage;
1395
+ /** Modal-signal sink for auth-failed / permission-denied notifications. */
1396
+ signals: SessionSignals;
1397
+ /** Receives session-level errors (auth-failed, refresh-exhausted, ...). */
1398
+ onError: (err: SemiontSessionError) => void;
1399
+ }
1400
+ type SessionFactory = (opts: SessionFactoryOptions) => SemiontSession;
1401
+
1256
1402
  /**
1257
1403
  * SemiontBrowser — top-level app-facing container for non-KB state.
1258
1404
  *
1259
1405
  * Holds the list of configured KBs, the active KB selection, the active
1260
1406
  * SemiontSession, the identity token, the open-resources list, and a
1261
- * session-level error stream. Module-scoped singleton survives every
1262
- * React re-render, remount, and route change. `SemiontProvider` hands
1263
- * the singleton to the React tree; `useSemiont()` returns it.
1407
+ * session-level error stream. Held as a process-wide instance for the
1408
+ * host's lifetime see `getBrowser()` in `registry.ts` for the canonical
1409
+ * accessor.
1410
+ *
1411
+ * Transport-agnostic: the browser orchestrates session *lifecycle* but
1412
+ * delegates session *construction* to a `SessionFactory` injected at
1413
+ * construction. HTTP-backed apps pass `createHttpSessionFactory()` from
1414
+ * `@semiont/sdk`; in-process apps pass their own factory.
1264
1415
  *
1265
1416
  * Persistence goes through a `SessionStorage` adapter provided at
1266
1417
  * construction — the browser never touches `localStorage` or `window`
@@ -1270,6 +1421,14 @@ declare class FrontendSessionSignals {
1270
1421
  interface SemiontBrowserConfig {
1271
1422
  /** Persistence adapter. The browser reads/writes all persisted state via this. */
1272
1423
  storage: SessionStorage;
1424
+ /**
1425
+ * Builds a `SemiontSession` for a KB. The browser is transport-
1426
+ * agnostic — every HTTP-vs-local construction concern lives in the
1427
+ * factory. HTTP-backed apps pass `createHttpSessionFactory()` from
1428
+ * `@semiont/sdk`; a future in-process variant from `@semiont/make-meaning`
1429
+ * would expose its own factory.
1430
+ */
1431
+ sessionFactory: SessionFactory;
1273
1432
  }
1274
1433
  declare class SemiontBrowser {
1275
1434
  readonly kbs$: BehaviorSubject<KnowledgeBase[]>;
@@ -1281,9 +1440,9 @@ declare class SemiontBrowser {
1281
1440
  * non-null when `activeSession$` is non-null, always null when it
1282
1441
  * is. Extracted from the session itself so headless sessions
1283
1442
  * (workers, CLIs, tests) don't carry dead modal observables.
1284
- * See [FrontendSessionSignals](./frontend-session-signals.ts).
1443
+ * See [SessionSignals](./session-signals.ts).
1285
1444
  */
1286
- readonly activeSignals$: BehaviorSubject<FrontendSessionSignals | null>;
1445
+ readonly activeSignals$: BehaviorSubject<SessionSignals | null>;
1287
1446
  /**
1288
1447
  * True while a session is actively being constructed (setActiveKb /
1289
1448
  * signIn in flight, awaiting `session.ready`). Distinguishes the
@@ -1297,6 +1456,7 @@ declare class SemiontBrowser {
1297
1456
  readonly error$: Subject<SemiontSessionError>;
1298
1457
  readonly identityToken$: BehaviorSubject<string | null>;
1299
1458
  private readonly storage;
1459
+ private readonly sessionFactory;
1300
1460
  /**
1301
1461
  * App-scoped EventBus. Hosts UI-shell events that must work regardless
1302
1462
  * of whether a KB session is active: panel toggles, sidebar state,
@@ -1305,18 +1465,9 @@ declare class SemiontBrowser {
1305
1465
  * (mark:*, beckon:*, gather:*, match:*, bind:*, yield:*, browse:click).
1306
1466
  */
1307
1467
  private readonly eventBus;
1308
- private unregisterNotify;
1309
1468
  private unsubscribeStorage;
1310
1469
  private disposed;
1311
1470
  private activating;
1312
- /**
1313
- * Per-KB in-flight refresh dedup. Simultaneous 401s for the same
1314
- * KB converge on a single `/api/tokens/refresh` network call.
1315
- * Was previously module-scoped in `refresh.ts`; moved here when
1316
- * that file was deleted — SemiontBrowser is a singleton so the
1317
- * scoping is equivalent.
1318
- */
1319
- private readonly inFlightRefreshes;
1320
1471
  constructor(config: SemiontBrowserConfig);
1321
1472
  /** Emit an event on the browser's app-scoped bus. */
1322
1473
  emit<K extends keyof EventMap>(channel: K, payload: EventMap[K]): void;
@@ -1325,14 +1476,25 @@ declare class SemiontBrowser {
1325
1476
  /** Read-only observable for an app-scoped channel. */
1326
1477
  stream<K extends keyof EventMap>(channel: K): Observable<EventMap[K]>;
1327
1478
  /**
1328
- * Set the app-level identity token (from NextAuth's useSession).
1329
- * Called at the root layout via a single `useEffect`. No other site
1330
- * in the codebase should call this.
1479
+ * Set the app-level identity token. Sourced from whatever the host
1480
+ * environment uses for OAuth sessions (e.g. NextAuth in a browser app).
1481
+ * Should be called once from the host's startup-and-on-change site;
1482
+ * no other code should write to this slot.
1331
1483
  */
1332
1484
  setIdentityToken(token: string | null): void;
1333
1485
  addKb(input: NewKnowledgeBase, access: string, refresh: string): KnowledgeBase;
1334
1486
  removeKb(id: string): void;
1335
- updateKb(id: string, updates: Partial<KnowledgeBase>): void;
1487
+ /**
1488
+ * Patch a KB in the list. Restricted to the common, endpoint-agnostic
1489
+ * fields (`label`, `email`, `gitBranch`) — the `endpoint` shape isn't
1490
+ * editable in place; remove and re-add to change the connection
1491
+ * target.
1492
+ */
1493
+ updateKb(id: string, updates: {
1494
+ label?: string;
1495
+ email?: string;
1496
+ gitBranch?: string;
1497
+ }): void;
1336
1498
  /**
1337
1499
  * Read the locally-stored credential status for a KB. Pure / synchronous —
1338
1500
  * does not subscribe to context changes. Used by KB-list UI to color status
@@ -1367,46 +1529,45 @@ declare class SemiontBrowser {
1367
1529
  removeOpenResource(id: string): void;
1368
1530
  updateOpenResourceName(id: string, name: string): void;
1369
1531
  reorderOpenResources(oldIndex: number, newIndex: number): void;
1370
- /**
1371
- * Refresh the active KB's access token. Returns the new token on
1372
- * success, null on failure. Concurrent calls for the same KB
1373
- * dedupe through `inFlightRefreshes`, so simultaneous 401s trigger
1374
- * only one `/api/tokens/refresh` round trip.
1375
- *
1376
- * Uses a throwaway `SemiontClient` with no `tokenRefresher` —
1377
- * a refresh call returning 401 would otherwise re-enter this
1378
- * function infinitely.
1379
- */
1380
- private performRefresh;
1381
- /**
1382
- * Validate an access token by calling `auth.me` on a throwaway
1383
- * client. The session uses this once at startup to populate
1384
- * `user$`; 401 triggers a refresh-then-retry inside the session.
1385
- *
1386
- * The throwaway transport is seeded with the specific token to
1387
- * validate so the request actually carries it (HttpTransport
1388
- * sources `Authorization` from its `token$`).
1389
- */
1390
- private performValidate;
1391
1532
  dispose(): Promise<void>;
1392
1533
  }
1393
1534
 
1394
1535
  /**
1395
- * Module-scoped singleton for SemiontBrowser. Constructed lazily on first
1396
- * `getBrowser()` call, survives every React re-render, remount, and route
1397
- * change.
1398
- *
1399
- * The caller provides a `SessionStorage` implementation there is no
1400
- * default here because storage-backend selection is environment-specific
1401
- * (browsers use `WebBrowserStorage`, CLI uses a filesystem adapter,
1402
- * tests use `InMemorySessionStorage`). The first call to `getBrowser`
1403
- * wins; subsequent calls return the cached instance regardless of the
1404
- * storage passed.
1536
+ * createHttpSessionFactory the default `SessionFactory` for HTTP-backed
1537
+ * KBs. Owns every HTTP-specific construction concern that used to live in
1538
+ * `SemiontBrowser`: building `HttpTransport`/`HttpContentTransport`,
1539
+ * wiring the `tokenRefresher` callback, deduplicating concurrent 401
1540
+ * refresh round trips, and invoking the auth endpoints for token refresh
1541
+ * and user-validate.
1542
+ *
1543
+ * Returned as a closure so a single `inFlightRefreshes` map is shared
1544
+ * across every session this factory builds the dedup is meaningful
1545
+ * across concurrent session reactivations for the same KB id.
1546
+ */
1547
+
1548
+ declare function createHttpSessionFactory(): SessionFactory;
1549
+
1550
+ /**
1551
+ * Process-wide accessor for `SemiontBrowser`. Constructed lazily on the
1552
+ * first `getBrowser()` call and held for the host's lifetime — a single
1553
+ * instance owns the KB list, identity token, and active-session state,
1554
+ * so callers throughout the host get the same view of "which KB am I
1555
+ * talking to right now" regardless of where they pick it up.
1556
+ *
1557
+ * The caller provides a `SessionStorage` implementation and a
1558
+ * `SessionFactory` — both are environment-specific (browsers use
1559
+ * `WebBrowserStorage` + `createHttpSessionFactory()`, CLI/embedded
1560
+ * hosts use a filesystem adapter and possibly a local-process
1561
+ * factory, tests use `InMemorySessionStorage` and stubs). The first
1562
+ * call to `getBrowser` wins; subsequent calls return the cached
1563
+ * instance regardless of the options passed.
1405
1564
  */
1406
1565
 
1407
1566
  interface GetBrowserOptions {
1408
1567
  /** Persistence adapter used to construct the singleton on first call. */
1409
1568
  storage: SessionStorage;
1569
+ /** Session factory used to build a `SemiontSession` per active KB. */
1570
+ sessionFactory: SessionFactory;
1410
1571
  }
1411
1572
  declare function getBrowser(options: GetBrowserOptions): SemiontBrowser;
1412
1573
 
@@ -1433,16 +1594,45 @@ interface StoredSession {
1433
1594
  declare function setStoredSession(storage: SessionStorage, kbId: string, session: StoredSession): void;
1434
1595
  declare function defaultProtocol(host: string): 'http' | 'https';
1435
1596
  declare function isValidHostname(host: string): boolean;
1436
- declare function kbBackendUrl(kb: KnowledgeBase): string;
1437
-
1438
- declare function notifySessionExpired(message?: string): void;
1439
- declare function notifyPermissionDenied(message?: string): void;
1597
+ /**
1598
+ * Build the wire URL for an HTTP KB endpoint. HTTP-shaped helper —
1599
+ * lives next to the KB list machinery because the frontend Panel needs
1600
+ * it for the auth round-trip when adding a KB. Code that holds a
1601
+ * uniform `KnowledgeBase` should not call this; it should hand the KB
1602
+ * to a transport factory and let the factory inspect `endpoint.kind`.
1603
+ */
1604
+ declare function kbBackendUrl(endpoint: HttpEndpoint): string;
1440
1605
 
1441
- interface ViewModel {
1606
+ /**
1607
+ * Marker for the state-unit pattern: a stateful, lifecycled object with an
1608
+ * RxJS-shaped public surface, constructed by a factory function
1609
+ * (`createFooStateUnit`), with internal state held in a closure.
1610
+ *
1611
+ * The structural contract is `dispose()` — the rest of the pattern
1612
+ * (closure-based identity, Observable public surface, internal Subjects
1613
+ * exposed as `.asObservable()` views, no leaked subscriptions, composition
1614
+ * by parameter rather than ownership) is convention enforced by review,
1615
+ * not the type system.
1616
+ *
1617
+ * See `packages/sdk/docs/STATE-UNITS.md` for the full axioms and rationale.
1618
+ */
1619
+ interface StateUnit {
1620
+ /**
1621
+ * Idempotent, total teardown. Completes every Subject the unit owns,
1622
+ * unsubscribes every internal subscription, releases timers / abort
1623
+ * controllers / network handles. Safe to call multiple times — the
1624
+ * second call is a no-op.
1625
+ */
1442
1626
  dispose(): void;
1443
1627
  }
1628
+ /**
1629
+ * Compose multiple disposers into a single `dispose()` call. Accepts either
1630
+ * a `StateUnit` (whose `dispose()` will be invoked) or a plain teardown
1631
+ * function. The returned object is itself disposable; call its `dispose()`
1632
+ * once to tear down everything that was added.
1633
+ */
1444
1634
  declare function createDisposer(): {
1445
- add(vm: ViewModel | (() => void)): void;
1635
+ add(item: StateUnit | (() => void)): void;
1446
1636
  dispose(): void;
1447
1637
  };
1448
1638
 
@@ -1452,10 +1642,9 @@ declare function createDisposer(): {
1452
1642
  * A debounced-search RxJS pipeline factory. Combines an input Subject with a
1453
1643
  * downstream fetch function and emits typed `{ results, isSearching }` state.
1454
1644
  *
1455
- * Designed to be created once per component instance via React's
1456
- * `useState(() => createSearchPipeline(...))` lazy initializer, then consumed
1457
- * via `useObservable(pipeline.state$)`. The pipeline holds no React state and
1458
- * has no React imports — it's pure RxJS, unit-testable without a renderer.
1645
+ * Designed to be created once per consumer instance and held for its lifetime
1646
+ * (e.g. by a view layer's lazy initializer), then observed via `state$`. The
1647
+ * pipeline is pure RxJS unit-testable without any view-layer dependency.
1459
1648
  *
1460
1649
  * The fetch function is expected to return `Observable<T[] | undefined>`,
1461
1650
  * matching the cache-miss-then-data shape of `BrowseNamespace` Observables:
@@ -1468,13 +1657,13 @@ interface SearchState<T> {
1468
1657
  isSearching: boolean;
1469
1658
  }
1470
1659
  interface SearchPipeline<T> {
1471
- /** Latest query string. Bind to a controlled input via `useObservable`. */
1660
+ /** Latest query string. Bind to a controlled input. */
1472
1661
  query$: Observable<string>;
1473
1662
  /** Latest search state — results plus a loading flag. */
1474
1663
  state$: Observable<SearchState<T>>;
1475
1664
  /** Push a new query value. Triggers the debounced fetch. */
1476
1665
  setQuery(value: string): void;
1477
- /** Tear down the input Subject. Call from `useEffect` cleanup. */
1666
+ /** Tear down the input Subject. Call from the consumer's cleanup hook. */
1478
1667
  dispose(): void;
1479
1668
  }
1480
1669
  interface SearchPipelineOptions {
@@ -1485,13 +1674,34 @@ interface SearchPipelineOptions {
1485
1674
  }
1486
1675
  declare function createSearchPipeline<T>(fetch: (query: string) => Observable<T[] | undefined>, options?: SearchPipelineOptions): SearchPipeline<T>;
1487
1676
 
1488
- interface BeckonVM extends ViewModel {
1677
+ /**
1678
+ * WorkerBus — minimal channel-bus surface that worker-side adapters
1679
+ * (e.g. `JobClaimAdapter` in `@semiont/jobs`, `SmelterActorStateUnit` in
1680
+ * `@semiont/make-meaning`) need.
1681
+ *
1682
+ * Transport-neutral by design. HTTP `ActorStateUnit` (from `@semiont/api-client`)
1683
+ * satisfies it directly; an in-process worker can pass a small shim around
1684
+ * an `EventBus` with a `() => Promise<void>` `emit` that calls into the
1685
+ * actor system.
1686
+ *
1687
+ * `addChannels` is optional because in-process buses receive every emit
1688
+ * implicitly — only HTTP needs to widen its SSE subscription set to
1689
+ * include worker-only channels (`job:queued`, `yield:created`, etc.).
1690
+ */
1691
+
1692
+ interface WorkerBus {
1693
+ on$<T = Record<string, unknown>>(channel: string): Observable<T>;
1694
+ emit(channel: string, payload: Record<string, unknown>): Promise<void>;
1695
+ addChannels?(channels: readonly string[]): void;
1696
+ }
1697
+
1698
+ interface BeckonStateUnit extends StateUnit {
1489
1699
  hoveredAnnotationId$: Observable<AnnotationId | null>;
1490
1700
  hover(annotationId: AnnotationId | null): void;
1491
1701
  focus(annotationId: AnnotationId): void;
1492
1702
  sparkle(annotationId: AnnotationId): void;
1493
1703
  }
1494
- declare function createBeckonVM(client: SemiontClient): BeckonVM;
1704
+ declare function createBeckonStateUnit(client: SemiontClient): BeckonStateUnit;
1495
1705
  /** Default milliseconds the mouse must dwell before beckon:hover is emitted. */
1496
1706
  declare const HOVER_DELAY_MS = 150;
1497
1707
  type EmitHover = (annotationId: AnnotationId | null) => void;
@@ -1502,372 +1712,48 @@ interface HoverHandlers {
1502
1712
  }
1503
1713
  declare function createHoverHandlers(emit: EmitHover, delayMs: number): HoverHandlers;
1504
1714
 
1505
- /**
1506
- * ShellVM — app-shell state: which toolbar panel is open, tab-bar
1507
- * coordination helpers, scroll-to-annotation signals. Lives on
1508
- * `SemiontBrowser`'s app-scoped bus (not the per-session client bus)
1509
- * because panel toggles and shell chrome must work regardless of
1510
- * whether a KB session is active.
1511
- *
1512
- * Channels: `panel:toggle`, `panel:open`, `panel:close`.
1513
- */
1514
-
1515
- type ToolbarPanelType = 'history' | 'info' | 'annotations' | 'settings' | 'collaboration' | 'user' | 'jsonld' | 'knowledge-base';
1516
- declare const COMMON_PANELS: readonly ToolbarPanelType[];
1517
- declare const RESOURCE_PANELS: readonly ToolbarPanelType[];
1518
- interface ShellVM extends ViewModel {
1519
- activePanel$: Observable<ToolbarPanelType | null>;
1520
- scrollToAnnotationId$: Observable<string | null>;
1521
- panelInitialTab$: Observable<{
1522
- tab: string;
1523
- generation: number;
1524
- } | null>;
1525
- openPanel(panel: string): void;
1526
- closePanel(): void;
1527
- togglePanel(panel: string): void;
1528
- onScrollCompleted(): void;
1529
- }
1530
- interface ShellVMOptions {
1531
- initialPanel?: ToolbarPanelType | null;
1532
- onPanelChange?: (panel: ToolbarPanelType | null) => void;
1533
- }
1534
- declare function createShellVM(browser: SemiontBrowser, options?: ShellVMOptions): ShellVM;
1535
-
1536
- interface GatherVM extends ViewModel {
1715
+ interface GatherStateUnit extends StateUnit {
1537
1716
  context$: Observable<GatheredContext | null>;
1538
1717
  loading$: Observable<boolean>;
1539
1718
  error$: Observable<Error | null>;
1540
1719
  annotationId$: Observable<AnnotationId | null>;
1541
1720
  }
1542
- declare function createGatherVM(client: SemiontClient, resourceId: ResourceId): GatherVM;
1721
+ declare function createGatherStateUnit(client: SemiontClient, resourceId: ResourceId): GatherStateUnit;
1543
1722
 
1544
- interface MatchVM extends ViewModel {
1723
+ interface MatchStateUnit extends StateUnit {
1545
1724
  }
1546
- declare function createMatchVM(client: SemiontClient, _resourceId: ResourceId): MatchVM;
1725
+ declare function createMatchStateUnit(client: SemiontClient, _resourceId: ResourceId): MatchStateUnit;
1547
1726
 
1548
1727
  type JobProgress$1 = components['schemas']['JobProgress'];
1549
1728
  interface GenerateDocumentOptions {
1550
1729
  title: string;
1551
1730
  storageUri: string;
1552
1731
  prompt?: string;
1732
+ /** Body locale — language the generated resource is written in. Falls back to the state unit's UI locale when unset. */
1553
1733
  language?: string;
1734
+ /** Source-resource locale — language of the resource the annotation lives on. Forwarded to the prompt for context-snippet awareness. BCP-47. */
1735
+ sourceLanguage?: string;
1554
1736
  temperature?: number;
1555
1737
  maxTokens?: number;
1556
1738
  context: GatheredContext;
1557
1739
  }
1558
- interface YieldVM extends ViewModel {
1740
+ interface YieldStateUnit extends StateUnit {
1559
1741
  isGenerating$: Observable<boolean>;
1560
1742
  progress$: Observable<JobProgress$1 | null>;
1561
1743
  generate(referenceId: string, options: GenerateDocumentOptions): void;
1562
1744
  }
1563
- declare function createYieldVM(client: SemiontClient, resourceId: ResourceId, locale: string): YieldVM;
1745
+ declare function createYieldStateUnit(client: SemiontClient, resourceId: ResourceId, locale: string): YieldStateUnit;
1564
1746
 
1565
1747
  type JobProgress = components['schemas']['JobProgress'];
1566
1748
  interface PendingAnnotation {
1567
1749
  selector: Selector | Selector[];
1568
1750
  motivation: Motivation;
1569
1751
  }
1570
- interface MarkVM extends ViewModel {
1752
+ interface MarkStateUnit extends StateUnit {
1571
1753
  pendingAnnotation$: Observable<PendingAnnotation | null>;
1572
1754
  assistingMotivation$: Observable<Motivation | null>;
1573
1755
  progress$: Observable<JobProgress | null>;
1574
1756
  }
1575
- declare function createMarkVM(client: SemiontClient, resourceId: ResourceId): MarkVM;
1576
-
1577
- interface DiscoverVM extends ViewModel {
1578
- browse: ShellVM;
1579
- search: SearchPipeline<ResourceDescriptor>;
1580
- recentResources$: Observable<ResourceDescriptor[]>;
1581
- entityTypes$: Observable<string[]>;
1582
- isLoadingRecent$: Observable<boolean>;
1583
- }
1584
- declare function createDiscoverVM(client: SemiontClient, browse: ShellVM): DiscoverVM;
1585
-
1586
- interface EntityTagsVM extends ViewModel {
1587
- browse: ShellVM;
1588
- entityTypes$: Observable<string[]>;
1589
- isLoading$: Observable<boolean>;
1590
- newTag$: Observable<string>;
1591
- error$: Observable<string>;
1592
- isAdding$: Observable<boolean>;
1593
- setNewTag(value: string): void;
1594
- addTag(): Promise<void>;
1595
- }
1596
- declare function createEntityTagsVM(client: SemiontClient, browse: ShellVM): EntityTagsVM;
1597
-
1598
- interface ImportPreview {
1599
- format: string;
1600
- version: number;
1601
- sourceUrl: string;
1602
- stats: Record<string, number>;
1603
- }
1604
- interface ExchangeVM extends ViewModel {
1605
- browse: ShellVM;
1606
- selectedFile$: Observable<File | null>;
1607
- preview$: Observable<ImportPreview | null>;
1608
- importPhase$: Observable<string | null>;
1609
- importMessage$: Observable<string | undefined>;
1610
- importResult$: Observable<Record<string, unknown> | undefined>;
1611
- isExporting$: Observable<boolean>;
1612
- isImporting$: Observable<boolean>;
1613
- selectFile(file: File): void;
1614
- cancelImport(): void;
1615
- doExport(): Promise<{
1616
- blob: Blob;
1617
- filename: string;
1618
- }>;
1619
- doImport(): Promise<void>;
1620
- }
1621
- declare function createExchangeVM(browse: ShellVM, exportFn: (params?: {
1622
- includeArchived?: boolean;
1623
- }) => Promise<Response>, importFn: (file: File, options?: {
1624
- onProgress?: (event: {
1625
- phase: string;
1626
- message?: string;
1627
- result?: Record<string, unknown>;
1628
- }) => void;
1629
- }) => Promise<{
1630
- phase: string;
1631
- message?: string;
1632
- result?: Record<string, unknown>;
1633
- }>): ExchangeVM;
1634
-
1635
- interface AdminUsersVM extends ViewModel {
1636
- browse: ShellVM;
1637
- users$: Observable<unknown[]>;
1638
- stats$: Observable<unknown | null>;
1639
- usersLoading$: Observable<boolean>;
1640
- statsLoading$: Observable<boolean>;
1641
- updateUser(id: string, data: {
1642
- isAdmin?: boolean;
1643
- isActive?: boolean;
1644
- }): Promise<void>;
1645
- }
1646
- declare function createAdminUsersVM(client: SemiontClient, browse: ShellVM): AdminUsersVM;
1647
-
1648
- interface AdminSecurityVM extends ViewModel {
1649
- browse: ShellVM;
1650
- providers$: Observable<unknown[]>;
1651
- allowedDomains$: Observable<string[]>;
1652
- isLoading$: Observable<boolean>;
1653
- }
1654
- declare function createAdminSecurityVM(client: SemiontClient, browse: ShellVM): AdminSecurityVM;
1655
-
1656
- interface WelcomeVM extends ViewModel {
1657
- userData$: Observable<{
1658
- termsAcceptedAt?: string;
1659
- } | null>;
1660
- isProcessing$: Observable<boolean>;
1661
- acceptTerms(): Promise<void>;
1662
- }
1663
- declare function createWelcomeVM(client: SemiontClient): WelcomeVM;
1664
-
1665
- interface ResourceLoaderVM extends ViewModel {
1666
- resource$: Observable<ResourceDescriptor | undefined>;
1667
- isLoading$: Observable<boolean>;
1668
- invalidate(): void;
1669
- }
1670
- declare function createResourceLoaderVM(client: SemiontClient, resourceId: ResourceId): ResourceLoaderVM;
1671
-
1672
- interface SessionVM extends ViewModel {
1673
- isLoggingOut$: Observable<boolean>;
1674
- logout(): Promise<void>;
1675
- }
1676
- declare function createSessionVM(client: SemiontClient): SessionVM;
1677
-
1678
- interface SmelterEvent {
1679
- type: string;
1680
- resourceId?: string;
1681
- payload: Record<string, unknown>;
1682
- }
1683
- interface SmelterActorVMOptions {
1684
- baseUrl: string;
1685
- token: string;
1686
- reconnectMs?: number;
1687
- }
1688
- interface SmelterActorVM extends ViewModel {
1689
- events$: Observable<SmelterEvent>;
1690
- state$: Observable<ConnectionState>;
1691
- emit(channel: string, payload: Record<string, unknown>): Promise<void>;
1692
- start(): void;
1693
- stop(): void;
1694
- }
1695
- declare function createSmelterActorVM(options: SmelterActorVMOptions): SmelterActorVM;
1696
-
1697
- /**
1698
- * Job Claim Adapter — worker-side job lifecycle glue on top of a
1699
- * shared `ActorVM`.
1700
- *
1701
- * Replaces the old `WorkerVM`, which owned its own actor and
1702
- * duplicated the SSE connection that `SemiontClient` already held.
1703
- * Workers now construct a `SemiontSession` normally (one actor, one
1704
- * SSE connection) and use this adapter to attach job-claim behaviour
1705
- * on top of `session.client.actor`.
1706
- *
1707
- * The adapter is intentionally thin: it subscribes to `job:queued`
1708
- * on the actor, claims jobs via the existing request-response
1709
- * protocol (`job:claim` → `job:claimed` / `job:claim-failed`), and
1710
- * exposes observables for job orchestration. It does **not** own
1711
- * the actor, has no HTTP concerns, and has no modal state.
1712
- */
1713
-
1714
- interface JobAssignment {
1715
- jobId: string;
1716
- type: string;
1717
- resourceId: string;
1718
- }
1719
- interface ActiveJob {
1720
- jobId: string;
1721
- type: string;
1722
- resourceId: string;
1723
- userId: string;
1724
- params: Record<string, unknown>;
1725
- }
1726
- interface JobClaimAdapterOptions {
1727
- /** Shared actor (typically `session.client.actor`). */
1728
- actor: ActorVM;
1729
- /**
1730
- * Job types this worker can process. Jobs of other types that
1731
- * arrive on `job:queued` are ignored. Empty array = accept any.
1732
- */
1733
- jobTypes: string[];
1734
- }
1735
- interface JobClaimAdapter {
1736
- /** Currently-claimed job, or null when idle. */
1737
- readonly activeJob$: Observable<ActiveJob | null>;
1738
- /** True while a claim is in flight or a job is being processed. */
1739
- readonly isProcessing$: Observable<boolean>;
1740
- /** Monotonically-incrementing count of successfully-completed jobs. */
1741
- readonly jobsCompleted$: Observable<number>;
1742
- /** Stream of job failures (including claim-failed and processing errors). */
1743
- readonly errors$: Observable<{
1744
- jobId: string;
1745
- error: string;
1746
- }>;
1747
- /**
1748
- * Subscribe to `job:queued` events (adding the channel to the actor
1749
- * if not already subscribed) and begin claiming matching jobs.
1750
- * Idempotent — calling `start()` twice is a no-op.
1751
- */
1752
- start(): void;
1753
- /** Stop claiming new jobs. Does not cancel an in-flight job. */
1754
- stop(): void;
1755
- /** Signal successful completion of `activeJob$`. */
1756
- completeJob(): void;
1757
- /** Signal failure of `activeJob$`. Emits on `errors$`. */
1758
- failJob(jobId: string, error: string): void;
1759
- /** Release observables. Does not dispose the shared actor. */
1760
- dispose(): void;
1761
- }
1762
- /**
1763
- * Attach job-claim behaviour to a shared `ActorVM`.
1764
- */
1765
- declare function createJobClaimAdapter(options: JobClaimAdapterOptions): JobClaimAdapter;
1766
-
1767
- interface Job {
1768
- jobId: string;
1769
- type: string;
1770
- status: string;
1771
- resourceId: string;
1772
- /** DID of the user who initiated the job (audit). */
1773
- userId: string;
1774
- created: string;
1775
- startedAt?: string;
1776
- completedAt?: string;
1777
- error?: string;
1778
- progress?: Record<string, unknown>;
1779
- result?: Record<string, unknown>;
1780
- }
1781
- interface JobQueueVM extends ViewModel {
1782
- jobs$: Observable<Job[]>;
1783
- pendingByType$: Observable<Map<string, number>>;
1784
- runningJobs$: Observable<Job[]>;
1785
- jobCreated$: Observable<Job>;
1786
- jobCompleted$: Observable<Job>;
1787
- jobFailed$: Observable<Job>;
1788
- }
1789
- declare function createJobQueueVM(client: SemiontClient): JobQueueVM;
1790
-
1791
- interface AnnotationGroups {
1792
- highlights: Annotation[];
1793
- comments: Annotation[];
1794
- assessments: Annotation[];
1795
- references: Annotation[];
1796
- tags: Annotation[];
1797
- }
1798
- type StoredEventResponse = components['schemas']['StoredEventResponse'];
1799
- interface WizardState {
1800
- open: boolean;
1801
- annotationId: string | null;
1802
- resourceId: string | null;
1803
- defaultTitle: string;
1804
- entityTypes: string[];
1805
- }
1806
- interface ResourceViewerPageVM extends ViewModel {
1807
- beckon: BeckonVM;
1808
- browse: ShellVM;
1809
- mark: MarkVM;
1810
- gather: GatherVM;
1811
- yield: YieldVM;
1812
- annotations$: Observable<Annotation[]>;
1813
- annotationGroups$: Observable<AnnotationGroups>;
1814
- entityTypes$: Observable<string[]>;
1815
- events$: Observable<StoredEventResponse[]>;
1816
- referencedBy$: Observable<ReferencedByEntry[]>;
1817
- content$: Observable<string>;
1818
- contentLoading$: Observable<boolean>;
1819
- mediaToken$: Observable<string | null>;
1820
- wizard$: Observable<WizardState>;
1821
- closeWizard(): void;
1822
- }
1823
- declare function createResourceViewerPageVM(client: SemiontClient, resourceId: ResourceId, locale: string, browse: ShellVM, options?: {
1824
- mediaType?: string;
1825
- }): ResourceViewerPageVM;
1826
-
1827
- type ComposeMode = 'new' | 'clone' | 'reference';
1828
- interface ComposeParams {
1829
- mode?: string | undefined;
1830
- token?: string | undefined;
1831
- annotationUri?: string | undefined;
1832
- sourceDocumentId?: string | undefined;
1833
- name?: string | undefined;
1834
- entityTypes?: string | undefined;
1835
- storedContext?: string | undefined;
1836
- }
1837
- interface CloneData {
1838
- sourceResource: ResourceDescriptor;
1839
- sourceContent: string;
1840
- }
1841
- interface ReferenceData {
1842
- annotationUri: string;
1843
- sourceDocumentId: string;
1844
- name: string;
1845
- entityTypes: string[];
1846
- }
1847
- interface SaveResourceParams {
1848
- mode: ComposeMode;
1849
- name: string;
1850
- storageUri: string;
1851
- content?: string;
1852
- file?: File;
1853
- format?: string;
1854
- charset?: string;
1855
- entityTypes?: string[];
1856
- language: string;
1857
- archiveOriginal?: boolean;
1858
- annotationUri?: string;
1859
- sourceDocumentId?: string;
1860
- }
1861
- interface ComposePageVM extends ViewModel {
1862
- browse: ShellVM;
1863
- mode$: Observable<ComposeMode>;
1864
- loading$: Observable<boolean>;
1865
- cloneData$: Observable<CloneData | null>;
1866
- referenceData$: Observable<ReferenceData | null>;
1867
- gatheredContext$: Observable<GatheredContext | null>;
1868
- entityTypes$: Observable<string[]>;
1869
- save(params: SaveResourceParams): Promise<string>;
1870
- }
1871
- declare function createComposePageVM(client: SemiontClient, browse: ShellVM, params: ComposeParams, auth?: AccessToken): ComposePageVM;
1757
+ declare function createMarkStateUnit(client: SemiontClient, resourceId: ResourceId): MarkStateUnit;
1872
1758
 
1873
- export { type ActiveJob, AdminNamespace, type AdminSecurityVM, type AdminUsersVM, type AnnotationGroups, type AnnotationHistoryResponse, AuthNamespace, BeckonNamespace, type BeckonVM, BindNamespace, BrowseNamespace, BusRequestError, type BusRequestErrorCode, type BusRequestPrimitive, COMMON_PANELS, type Cache, CacheObservable, type CloneData, type ComposeMode, type ComposePageVM, type ComposeParams, type CreateAnnotationInput, type CreateFromTokenOptions, type CreateResourceInput, type DiscoverVM, type EntityTagsVM, type ExchangeVM, FrontendSessionSignals, type GatherAnnotationProgress, GatherNamespace, type GatherVM, type GenerateDocumentOptions, type GenerationOptions, type GetBrowserOptions, HOVER_DELAY_MS, type HoverHandlers, type ImportPreview, InMemorySessionStorage, type Job, type JobAssignment, type JobClaimAdapter, type JobClaimAdapterOptions, JobNamespace, type JobQueueVM, type KbSessionStatus, type KnowledgeBase, type MarkAssistEvent, type MarkAssistOptions, type MarkAssistProgress, MarkNamespace, type MarkVM, MatchNamespace, type MatchSearchProgress, type MatchVM, type NewKnowledgeBase, type OpenResource, type PendingAnnotation, RESOURCE_PANELS, type ReferenceData, type ReferencedByEntry, type RequestContent, type ResourceLoaderVM, type ResourceViewerPageVM, type ResponseContent, type SaveResourceParams, type SearchPipeline, type SearchPipelineOptions, type SearchState, SemiontBrowser, type SemiontBrowserConfig, SemiontClient, SemiontSession, type SemiontSessionConfig, SemiontSessionError, type SemiontSessionErrorCode, type SessionStorage, type SessionVM, type ShellVM, type ShellVMOptions, type SmelterActorVM, type SmelterActorVMOptions, type SmelterEvent, type StoredSession, StreamObservable, type ToolbarPanelType, type User, type UserInfo, type ViewModel, type WelcomeVM, type WizardState, type YieldGenerationEvent, YieldNamespace, type YieldVM, busRequest, createAdminSecurityVM, createAdminUsersVM, createBeckonVM, createCache, createComposePageVM, createDiscoverVM, createDisposer, createEntityTagsVM, createExchangeVM, createGatherVM, createHoverHandlers, createJobClaimAdapter, createJobQueueVM, createMarkVM, createMatchVM, createResourceLoaderVM, createResourceViewerPageVM, createSearchPipeline, createSessionVM, createShellVM, createSmelterActorVM, createWelcomeVM, createYieldVM, defaultProtocol, getBrowser, isValidHostname, kbBackendUrl, notifyPermissionDenied, notifySessionExpired, setStoredSession };
1759
+ export { AdminNamespace, type AnnotationHistoryResponse, AuthNamespace, BeckonNamespace, type BeckonStateUnit, BindNamespace, BrowseNamespace, BusRequestError, type BusRequestErrorCode, type BusRequestPrimitive, CacheObservable, type CreateAnnotationInput, type CreateFromTokenOptions, type CreateResourceInput, FrameNamespace, type GatherAnnotationProgress, GatherNamespace, type GatherStateUnit, type GenerateDocumentOptions, type GenerationOptions, type GetBrowserOptions, HOVER_DELAY_MS, type HoverHandlers, type HttpEndpoint, InMemorySessionStorage, JobNamespace, type KbEndpoint, type KbSessionStatus, type KnowledgeBase, type LocalEndpoint, type MarkAssistEvent, type MarkAssistOptions, type MarkAssistProgress, MarkNamespace, type MarkStateUnit, MatchNamespace, type MatchSearchProgress, type MatchStateUnit, type NewKnowledgeBase, type OpenResource, type PendingAnnotation, type ReferencedByEntry, type RequestContent, type ResponseContent, type SearchPipeline, type SearchPipelineOptions, type SearchState, SemiontBrowser, type SemiontBrowserConfig, SemiontClient, SemiontSession, type SemiontSessionConfig, SemiontSessionError, type SemiontSessionErrorCode, type SessionFactory, type SessionFactoryOptions, SessionSignals, type SessionStorage, type StateUnit, type StoredSession, StreamObservable, UploadObservable, type UploadProgress, type User, type UserInfo, type WorkerBus, type YieldGenerationEvent, YieldNamespace, type YieldStateUnit, busRequest, createBeckonStateUnit, createDisposer, createGatherStateUnit, createHoverHandlers, createHttpSessionFactory, createMarkStateUnit, createMatchStateUnit, createSearchPipeline, createYieldStateUnit, defaultProtocol, getBrowser, httpKb, isValidHostname, kbBackendUrl, setStoredSession };