@semiont/sdk 0.4.22 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,42 +26,54 @@ npm install @semiont/sdk
26
26
 
27
27
  ## Quick start (HTTP)
28
28
 
29
+ For one-shot scripts, `SemiontClient.signIn(...)` is the credentials-first one-line construction:
30
+
29
31
  ```ts
30
- import {
31
- SemiontSession,
32
- InMemorySessionStorage,
33
- setStoredSession,
34
- type KnowledgeBase,
35
- } from '@semiont/sdk';
36
- import { accessToken } from '@semiont/core';
37
- import { firstValueFrom } from 'rxjs';
38
- import { filter } from 'rxjs/operators';
32
+ import { SemiontClient } from '@semiont/sdk';
33
+
34
+ const semiont = await SemiontClient.signIn({
35
+ baseUrl: 'http://localhost:4000',
36
+ email: 'me@example.com',
37
+ password: 'pwd',
38
+ });
39
+
40
+ const resources = await semiont.browse.resources({ limit: 10 });
41
+ console.log(resources);
42
+
43
+ semiont.dispose();
44
+ ```
45
+
46
+ For long-running scripts that need to survive token expiry, use `SemiontSession.signIn(...)` — same credentials shape, plus proactive refresh, validation, storage-adapter wiring, and disposal. `kb` is required; its `id` is the storage key for this session, so distinct scripts must use distinct ids:
47
+
48
+ ```ts
49
+ import { SemiontSession, InMemorySessionStorage, type KnowledgeBase } from '@semiont/sdk';
39
50
 
40
51
  const kb: KnowledgeBase = {
41
- id: 'local',
42
- label: 'Local Backend',
52
+ id: 'my-watcher',
53
+ label: 'My Watcher',
43
54
  protocol: 'http',
44
55
  host: 'localhost',
45
56
  port: 4000,
46
57
  email: 'me@example.com',
47
58
  };
48
59
 
49
- const storage = new InMemorySessionStorage();
50
- setStoredSession(storage, kb.id, {
51
- access: accessToken('your-jwt'),
52
- refresh: '',
60
+ const session = await SemiontSession.signIn({
61
+ kb,
62
+ storage: new InMemorySessionStorage(),
63
+ baseUrl: 'http://localhost:4000',
64
+ email: 'me@example.com',
65
+ password: 'pwd',
53
66
  });
54
67
 
55
- const session = await SemiontSession.create({ kb, storage });
68
+ // session.client is the same SemiontClient surface; the session manages
69
+ // the token$ lifecycle around it (default refresh callback wired automatically).
70
+ const resources = await session.client.browse.resources({ limit: 10 });
56
71
 
57
- const resources = await firstValueFrom(
58
- session.client.browse.resources({ limit: 10 }).pipe(
59
- filter((r): r is NonNullable<typeof r> => r !== undefined),
60
- ),
61
- );
62
- console.log(resources);
72
+ await session.dispose();
63
73
  ```
64
74
 
75
+ If you already have an access token (CLI cached-token path, env-var token, embedded auth flow), use `SemiontClient.fromHttp({ baseUrl, token })` or `SemiontSession.fromHttp({ baseUrl, token, storage, kb, refresh, ... })` to skip the auth round-trip.
76
+
65
77
  ## Quick start (in-process)
66
78
 
67
79
  When you want the SDK without an HTTP backend — e.g. in a CLI, a unit test, or an Electron-style desktop app — wire `LocalTransport` directly to a knowledge system:
@@ -86,23 +98,25 @@ const client = new SemiontClient(
86
98
  );
87
99
  ```
88
100
 
89
- Same `SemiontClient`, same verb namespaces — no network involved.
101
+ Same `SemiontClient`, same verb namespaces — no network involved. There is no `fromLocal` factory because the in-process transport's dependencies (knowledgeSystem, eventBus, userId) are not boilerplate the SDK can hide.
90
102
 
91
103
  ## Verb namespaces
92
104
 
93
- All ten namespaces hang off `SemiontClient`. Each method either returns a `Promise` (one-shot RPC-style operations) or an `Observable` (streaming subscriptions). The bus is invisible to callers — channel strings, correlation IDs, and reconnection are internal.
105
+ All ten namespaces hang off `SemiontClient`. Methods that return data return either a `Promise<T>` (atomic ops like `mark.archive`) or an awaitable Observable subclass — `StreamObservable<T>` for streams (`mark.assist`, `gather.annotation`, `match.search`, `yield.fromAnnotation`) and `CacheObservable<T>` for live queries (`browse.*`). Both subclasses implement `PromiseLike<T>`, so consumers can `await` them directly. Reactive consumers can `.subscribe(...)` exactly as with a plain Observable. The bus is invisible to callers — channel strings, correlation IDs, and reconnection are internal.
94
106
 
95
107
  ```ts
96
- // Browse — read the knowledge graph.
97
- await client.browse.resources({ limit: 10 });
108
+ // Browse — live queries; await yields the loaded value, subscribe yields
109
+ // loading-then-loaded.
110
+ const resources = await client.browse.resources({ limit: 10 });
98
111
  client.browse.resource(resourceId).subscribe(/* ... */);
99
112
 
100
- // Mark / Bind — create and modify annotations.
113
+ // Mark / Bind — atomic operations return Promise<T>.
101
114
  const { annotationId } = await client.mark.annotation(rid, request);
102
115
  await client.bind.body(rid, aid, [{ op: 'add', item: { /* W3C body */ } }]);
103
116
 
104
- // Gather / Match — assemble context and run semantic search.
105
- const ctx = await lastValueFrom(client.gather.annotation(aid, rid));
117
+ // Gather / Match — bounded streams; await yields the final value, subscribe
118
+ // yields every progress emission.
119
+ const ctx = await client.gather.annotation(aid, rid);
106
120
  client.match.search(rid, refId, ctx, { limit: 10 }).subscribe(/* ... */);
107
121
 
108
122
  // Yield — author new resources.
@@ -116,9 +130,17 @@ client.beckon.hover(annotationId);
116
130
 
117
131
  The verb-by-verb walkthroughs live in [docs/flows](https://github.com/The-AI-Alliance/semiont/tree/main/docs/flows).
118
132
 
133
+ `.pipe(...)` returns a plain `Observable<T>` — once you compose with RxJS operators you've explicitly entered RxJS land, and `lastValueFrom` from `rxjs` is the right bridge. The `firstValueFrom`/`lastValueFrom` re-exports from `@semiont/sdk` stay available for that case.
134
+
135
+ ## Documentation
136
+
137
+ - [`docs/Usage.md`](https://github.com/The-AI-Alliance/semiont/blob/main/packages/sdk/docs/Usage.md) — per-namespace tour with concrete examples for Browse, Mark, Bind, Gather, Match, Yield, Beckon, Auth, Admin, Job, plus SSE and error handling.
138
+ - [`docs/CACHE-SEMANTICS.md`](https://github.com/The-AI-Alliance/semiont/blob/main/packages/sdk/docs/CACHE-SEMANTICS.md) — the cache primitive's behavioral contract.
139
+ - [`docs/protocol/TRANSPORT-CONTRACT.md`](https://github.com/The-AI-Alliance/semiont/blob/main/docs/protocol/TRANSPORT-CONTRACT.md) — the transport interface every `ITransport` must honor.
140
+
119
141
  ## Behavioral contract
120
142
 
121
- The guarantees every `ITransport` implementation must honor — what `subscribe()` does on disconnect, what `LastEventId` replay must look like, what `puts` must be idempotent — are documented in [packages/core/docs/TRANSPORT-CONTRACT.md](https://github.com/The-AI-Alliance/semiont/blob/main/packages/core/docs/TRANSPORT-CONTRACT.md). HTTP-specific guarantees (the `/bus/emit` gateway, SSE reconnect, `Last-Event-ID` replay window) live alongside the backend at [apps/backend/docs/TRANSPORT.md](https://github.com/The-AI-Alliance/semiont/blob/main/apps/backend/docs/TRANSPORT.md).
143
+ The guarantees every `ITransport` implementation must honor — what `subscribe()` does on disconnect, what `LastEventId` replay must look like, what `puts` must be idempotent — are documented in [docs/protocol/TRANSPORT-CONTRACT.md](https://github.com/The-AI-Alliance/semiont/blob/main/docs/protocol/TRANSPORT-CONTRACT.md). HTTP-specific guarantees (the `/bus/emit` gateway, SSE reconnect, `Last-Event-ID` replay window) live in [docs/protocol/TRANSPORT-HTTP.md](https://github.com/The-AI-Alliance/semiont/blob/main/docs/protocol/TRANSPORT-HTTP.md).
122
144
 
123
145
  When implementing a new transport (gRPC, WebSocket, IPC, …), implement those interfaces from `@semiont/core` directly — there is no inheritance from `HttpTransport`.
124
146
 
package/dist/index.d.ts CHANGED
@@ -1,28 +1,104 @@
1
1
  import * as rxjs from 'rxjs';
2
2
  import { Observable, BehaviorSubject, Subject } from 'rxjs';
3
+ export { firstValueFrom, lastValueFrom } from 'rxjs';
3
4
  import * as _semiont_core from '@semiont/core';
4
- import { components, UserDID, paths, ResourceId, AnnotationId, BodyOperation, EventMap, ResourceDescriptor, Annotation, GraphConnection, Motivation, GatheredContext, JobId, ITransport, EventBus, IContentTransport, BaseUrl, AccessToken, ConnectionState, Selector } from '@semiont/core';
5
- export { ConnectionState, Logger } 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';
6
7
  import { ActorVM } from '@semiont/api-client';
7
- export { APIError, ActorVM, ActorVMOptions, BusEvent, DEGRADED_THRESHOLD_MS, HttpContentTransport, HttpTransport, HttpTransportConfig, TokenRefresher, createActorVM } from '@semiont/api-client';
8
+ export { APIError, APIErrorCode, ActorVM, ActorVMOptions, BusEvent, DEGRADED_THRESHOLD_MS, HttpContentTransport, HttpTransport, HttpTransportConfig, TokenRefresher, createActorVM } from '@semiont/api-client';
9
+
10
+ /**
11
+ * Thenable Observable subclasses.
12
+ *
13
+ * Two thin Observable subclasses that also implement `PromiseLike<T>`. Used as
14
+ * the public return type of namespace methods that emit streams (job
15
+ * lifecycle, generation progress) and cache reads (Browse live queries).
16
+ *
17
+ * 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.
20
+ *
21
+ * The asymmetric `.then()` semantics — last-value-on-completion for streams,
22
+ * first-non-undefined-value for caches — is encoded by the subclass name. The
23
+ * docstring on the namespace method tells the consumer which one applies.
24
+ *
25
+ * `.pipe(...)` returns a plain `Observable<T>` (RxJS doesn't propagate
26
+ * subclasses through `pipe`). Once you compose, you've explicitly entered
27
+ * RxJS land; `lastValueFrom` from `rxjs` is the right bridge there.
28
+ */
29
+
30
+ /**
31
+ * Bounded Observable stream — emits zero-or-more progress values, then a
32
+ * final value on completion. Used by job-lifecycle methods like
33
+ * `mark.assist`, `gather.annotation`, `match.search`, `yield.fromAnnotation`.
34
+ *
35
+ * Awaiting resolves to the **last** emitted value (via `lastValueFrom`).
36
+ * Subscribing yields every emission, ending in `complete`.
37
+ */
38
+ declare class StreamObservable<T> extends Observable<T> implements PromiseLike<T> {
39
+ then<R1 = T, R2 = never>(onfulfilled?: ((v: T) => R1 | PromiseLike<R1>) | null, onrejected?: ((e: unknown) => R2 | PromiseLike<R2>) | null): PromiseLike<R1 | R2>;
40
+ /** Wrap an existing Observable's subscribe behavior in a StreamObservable. */
41
+ static from<T>(source: Observable<T>): StreamObservable<T>;
42
+ }
43
+ /**
44
+ * Multicast cache observable — emits `undefined` while the underlying value
45
+ * is loading, then the value, then re-emits when bus events invalidate the
46
+ * cache entry. Used by Browse live-query methods (`browse.resource`,
47
+ * `browse.annotations`, etc.).
48
+ *
49
+ * Awaiting resolves to the **first non-undefined** value (waits past the
50
+ * loading state). Subscribing yields the full sequence including the
51
+ * initial `undefined`, so reactive consumers can render a loading state.
52
+ *
53
+ * The class is parameterized as `CacheObservable<T>` even though the
54
+ * stream's element type is `T | undefined` — `T` is what the consumer
55
+ * gets from `await`, and that's the contract we want to advertise. The
56
+ * `Observable<T | undefined>` shape leaks through `.subscribe` and
57
+ * `.pipe` in the natural way.
58
+ */
59
+ declare class CacheObservable<T> extends Observable<T | undefined> implements PromiseLike<T> {
60
+ then<R1 = T, R2 = never>(onfulfilled?: ((v: T) => R1 | PromiseLike<R1>) | null, onrejected?: ((e: unknown) => R2 | PromiseLike<R2>) | null): PromiseLike<R1 | R2>;
61
+ /**
62
+ * Wrap an existing Observable's subscribe behavior in a `CacheObservable`.
63
+ *
64
+ * Memoizes on source identity: passing the same `source` returns the same
65
+ * wrapper instance. The Browse cache primitive already returns a stable
66
+ * Observable per key (its B4 contract), so this preserves that contract
67
+ * through the awaitable wrapping. Without the memo, every public-method
68
+ * call would produce a fresh wrapper and break referential-equality
69
+ * guarantees that React-side consumers depend on.
70
+ *
71
+ * Backed by a `WeakMap`, so wrappers are GC'd when their source is.
72
+ */
73
+ static from<T>(source: Observable<T | undefined>): CacheObservable<T>;
74
+ }
8
75
 
9
76
  /**
10
77
  * Verb Namespace Interfaces
11
78
  *
12
- * These interfaces define the public API of the Semiont api-client,
13
- * organized by the 7 domain flows (Browse, Mark, Bind, Gather, Match,
14
- * Yield, Beckon) plus infrastructure namespaces (Job, Auth, Admin).
79
+ * These interfaces define the public API of `@semiont/sdk`, organized by
80
+ * the 7 domain flows (Browse, Mark, Bind, Gather, Match, Yield, Beckon)
81
+ * plus infrastructure namespaces (Job, Auth, Admin).
15
82
  *
16
- * Each namespace maps 1:1 to a flow. Each flow maps to a clear actor
17
- * on the backend. The frontend calls `client.mark.annotation()` and the
18
- * proxy handles HTTP, auth, SSE, and caching internally.
83
+ * Each namespace maps 1:1 to a flow. Each flow maps to a clear actor on
84
+ * the backend. The frontend calls `client.mark.annotation()` and the
85
+ * client handles HTTP, auth, SSE, and caching internally.
19
86
  *
20
87
  * Return type conventions:
21
- * - Browse live queries → Observable (bus gateway driven, cached)
22
- * - Browse one-shot reads Promise (fetch once, no cache)
23
- * - Commands (mark, bind, yield.resource) → Promise (fire-and-forget)
24
- * - Long-running ops (gather, match, yield.fromAnnotation, mark.assist) → Observable (progress + result)
25
- * - Ephemeral signals (beckon) void
88
+ * - Browse live queries → `CacheObservable<T>` (bus-driven, cached;
89
+ * subscribe yields `T | undefined`, await yields `T` after first load)
90
+ * - Browse one-shot reads`Promise<T>` (fetch once, no cache)
91
+ * - Commands (mark, bind, yield.resource) → `Promise<T>` (atomic ops)
92
+ * - Long-running ops (gather, match, yield.fromAnnotation, mark.assist)
93
+ * → `StreamObservable<T>` (progress + result; subscribe yields every
94
+ * emit, await yields the last one)
95
+ * - Ephemeral signals (beckon) → `void`
96
+ *
97
+ * `StreamObservable` and `CacheObservable` are `Observable` subclasses
98
+ * that also implement `PromiseLike<T>` — `await client.X.Y(...)` works
99
+ * directly without `lastValueFrom`/`firstValueFrom` wrappers.
100
+ * `.pipe(...)` returns a plain `Observable<T>` (the thenable subclass
101
+ * does not propagate through pipe — by design).
26
102
  */
27
103
 
28
104
  type StoredEventResponse$2 = components['schemas']['StoredEventResponse'];
@@ -171,17 +247,17 @@ type YieldGenerationEvent = {
171
247
  * Event prefix: browse:*
172
248
  */
173
249
  interface BrowseNamespace$1 {
174
- resource(resourceId: ResourceId): Observable<ResourceDescriptor | undefined>;
250
+ resource(resourceId: ResourceId): CacheObservable<ResourceDescriptor>;
175
251
  resources(filters?: {
176
252
  limit?: number;
177
253
  archived?: boolean;
178
254
  search?: string;
179
- }): Observable<ResourceDescriptor[] | undefined>;
180
- annotations(resourceId: ResourceId): Observable<Annotation[] | undefined>;
181
- annotation(resourceId: ResourceId, annotationId: AnnotationId): Observable<Annotation | undefined>;
182
- entityTypes(): Observable<string[] | undefined>;
183
- referencedBy(resourceId: ResourceId): Observable<ReferencedByEntry[] | undefined>;
184
- events(resourceId: ResourceId): Observable<StoredEventResponse$2[] | undefined>;
255
+ }): CacheObservable<ResourceDescriptor[]>;
256
+ annotations(resourceId: ResourceId): CacheObservable<Annotation[]>;
257
+ annotation(resourceId: ResourceId, annotationId: AnnotationId): CacheObservable<Annotation>;
258
+ entityTypes(): CacheObservable<string[]>;
259
+ referencedBy(resourceId: ResourceId): CacheObservable<ReferencedByEntry[]>;
260
+ events(resourceId: ResourceId): CacheObservable<StoredEventResponse$2[]>;
185
261
  resourceContent(resourceId: ResourceId): Promise<string>;
186
262
  resourceRepresentation(resourceId: ResourceId, options?: {
187
263
  accept?: string;
@@ -216,14 +292,14 @@ interface BrowseNamespace$1 {
216
292
  */
217
293
  interface MarkNamespace$1 {
218
294
  annotation(resourceId: ResourceId, input: CreateAnnotationInput): Promise<{
219
- annotationId: string;
295
+ annotationId: AnnotationId;
220
296
  }>;
221
297
  delete(resourceId: ResourceId, annotationId: AnnotationId): Promise<void>;
222
298
  entityType(type: string): Promise<void>;
223
299
  entityTypes(types: string[]): Promise<void>;
224
300
  archive(resourceId: ResourceId): Promise<void>;
225
301
  unarchive(resourceId: ResourceId): Promise<void>;
226
- assist(resourceId: ResourceId, motivation: Motivation, options: MarkAssistOptions): Observable<MarkAssistEvent>;
302
+ assist(resourceId: ResourceId, motivation: Motivation, options: MarkAssistOptions): StreamObservable<MarkAssistEvent>;
227
303
  request(selector: components['schemas']['MarkRequestedEvent']['selector'], motivation: Motivation): void;
228
304
  /** Fire-and-forget variant of `assist` — mark-vm orchestrates the call and its progress Observable. */
229
305
  requestAssist(motivation: Motivation, options: MarkAssistOptions, correlationId?: string): void;
@@ -265,10 +341,10 @@ interface BindNamespace$1 {
265
341
  interface GatherNamespace$1 {
266
342
  annotation(annotationId: AnnotationId, resourceId: ResourceId, options?: {
267
343
  contextWindow?: number;
268
- }): Observable<GatherAnnotationProgress>;
344
+ }): StreamObservable<GatherAnnotationProgress>;
269
345
  resource(resourceId: ResourceId, options?: {
270
346
  contextWindow?: number;
271
- }): Observable<GatherAnnotationProgress>;
347
+ }): StreamObservable<GatherAnnotationProgress>;
272
348
  }
273
349
  /**
274
350
  * Match — search and ranking
@@ -280,10 +356,10 @@ interface GatherNamespace$1 {
280
356
  * Event prefix: match:*
281
357
  */
282
358
  interface MatchNamespace$1 {
283
- search(resourceId: ResourceId, referenceId: string, context: GatheredContext, options?: {
359
+ search(resourceId: ResourceId, referenceId: AnnotationId, context: GatheredContext, options?: {
284
360
  limit?: number;
285
361
  useSemanticScoring?: boolean;
286
- }): Observable<MatchSearchProgress>;
362
+ }): StreamObservable<MatchSearchProgress>;
287
363
  /** Fire-and-forget variant: match-vm orchestrates the call and its result Observable. */
288
364
  requestSearch(input: components['schemas']['MatchSearchRequest']): void;
289
365
  }
@@ -300,7 +376,7 @@ interface YieldNamespace$1 {
300
376
  resource(data: CreateResourceInput): Promise<{
301
377
  resourceId: string;
302
378
  }>;
303
- fromAnnotation(resourceId: ResourceId, annotationId: AnnotationId, options: GenerationOptions): Observable<YieldGenerationEvent>;
379
+ fromAnnotation(resourceId: ResourceId, annotationId: AnnotationId, options: GenerationOptions): StreamObservable<YieldGenerationEvent>;
304
380
  cloneToken(resourceId: ResourceId): Promise<{
305
381
  token: string;
306
382
  expiresAt: string;
@@ -437,13 +513,13 @@ declare class BrowseNamespace implements BrowseNamespace$1 {
437
513
  */
438
514
  private readonly annotationListObs;
439
515
  constructor(transport: ITransport, bus: EventBus, content: IContentTransport);
440
- resource(resourceId: ResourceId): Observable<ResourceDescriptor | undefined>;
441
- resources(filters?: ResourceListFilters): Observable<ResourceDescriptor[] | undefined>;
442
- annotations(resourceId: ResourceId): Observable<Annotation[] | undefined>;
443
- annotation(resourceId: ResourceId, annotationId: AnnotationId): Observable<Annotation | undefined>;
444
- entityTypes(): Observable<string[] | undefined>;
445
- referencedBy(resourceId: ResourceId): Observable<ReferencedByEntry[] | undefined>;
446
- events(resourceId: ResourceId): Observable<StoredEventResponse$1[] | undefined>;
516
+ resource(resourceId: ResourceId): CacheObservable<ResourceDescriptor>;
517
+ resources(filters?: ResourceListFilters): CacheObservable<ResourceDescriptor[]>;
518
+ annotations(resourceId: ResourceId): CacheObservable<Annotation[]>;
519
+ annotation(resourceId: ResourceId, annotationId: AnnotationId): CacheObservable<Annotation>;
520
+ entityTypes(): CacheObservable<string[]>;
521
+ referencedBy(resourceId: ResourceId): CacheObservable<ReferencedByEntry[]>;
522
+ events(resourceId: ResourceId): CacheObservable<StoredEventResponse$1[]>;
447
523
  resourceContent(resourceId: ResourceId): Promise<string>;
448
524
  resourceRepresentation(resourceId: ResourceId, options?: {
449
525
  accept?: string;
@@ -507,14 +583,14 @@ declare class MarkNamespace implements MarkNamespace$1 {
507
583
  private readonly bus;
508
584
  constructor(transport: ITransport, bus: EventBus);
509
585
  annotation(resourceId: ResourceId, input: CreateAnnotationInput): Promise<{
510
- annotationId: string;
586
+ annotationId: AnnotationId;
511
587
  }>;
512
588
  delete(resourceId: ResourceId, annotationId: AnnotationId): Promise<void>;
513
589
  entityType(type: string): Promise<void>;
514
590
  entityTypes(types: string[]): Promise<void>;
515
591
  archive(resourceId: ResourceId): Promise<void>;
516
592
  unarchive(resourceId: ResourceId): Promise<void>;
517
- assist(resourceId: ResourceId, motivation: Motivation, options: MarkAssistOptions): Observable<MarkAssistEvent>;
593
+ assist(resourceId: ResourceId, motivation: Motivation, options: MarkAssistOptions): StreamObservable<MarkAssistEvent>;
518
594
  request(selector: components['schemas']['MarkRequestedEvent']['selector'], motivation: Motivation): void;
519
595
  requestAssist(motivation: Motivation, options: MarkAssistOptions, correlationId?: string): void;
520
596
  submit(input: components['schemas']['MarkSubmitEvent']): void;
@@ -541,10 +617,10 @@ declare class GatherNamespace implements GatherNamespace$1 {
541
617
  constructor(transport: ITransport, bus: EventBus);
542
618
  annotation(annotationId: AnnotationId, resourceId: ResourceId, options?: {
543
619
  contextWindow?: number;
544
- }): Observable<GatherAnnotationProgress>;
620
+ }): StreamObservable<GatherAnnotationProgress>;
545
621
  resource(_resourceId: ResourceId, _options?: {
546
622
  contextWindow?: number;
547
- }): Observable<GatherAnnotationProgress>;
623
+ }): StreamObservable<GatherAnnotationProgress>;
548
624
  }
549
625
 
550
626
  declare class MatchNamespace implements MatchNamespace$1 {
@@ -552,10 +628,10 @@ declare class MatchNamespace implements MatchNamespace$1 {
552
628
  private readonly bus;
553
629
  constructor(transport: ITransport, bus: EventBus);
554
630
  requestSearch(input: components['schemas']['MatchSearchRequest']): void;
555
- search(resourceId: ResourceId, referenceId: string, context: GatheredContext, options?: {
631
+ search(resourceId: ResourceId, referenceId: AnnotationId, context: GatheredContext, options?: {
556
632
  limit?: number;
557
633
  useSemanticScoring?: boolean;
558
- }): Observable<MatchSearchProgress>;
634
+ }): StreamObservable<MatchSearchProgress>;
559
635
  }
560
636
 
561
637
  declare class YieldNamespace implements YieldNamespace$1 {
@@ -566,7 +642,7 @@ declare class YieldNamespace implements YieldNamespace$1 {
566
642
  resource(data: CreateResourceInput): Promise<{
567
643
  resourceId: string;
568
644
  }>;
569
- fromAnnotation(resourceId: ResourceId, annotationId: AnnotationId, options: GenerationOptions): Observable<YieldGenerationEvent>;
645
+ fromAnnotation(resourceId: ResourceId, annotationId: AnnotationId, options: GenerationOptions): StreamObservable<YieldGenerationEvent>;
570
646
  cloneToken(resourceId: ResourceId): Promise<{
571
647
  token: string;
572
648
  expiresAt: string;
@@ -722,10 +798,59 @@ declare class SemiontClient {
722
798
  get state$(): rxjs.Observable<_semiont_core.ConnectionState>;
723
799
  subscribeToResource(resourceId: ResourceId): () => void;
724
800
  dispose(): void;
801
+ /**
802
+ * Convenience factory for the default HTTP setup. Constructs a
803
+ * `BehaviorSubject<AccessToken | null>` internally, plus an
804
+ * `HttpTransport` and `HttpContentTransport`, and returns the wired
805
+ * `SemiontClient`.
806
+ *
807
+ * Use this for one-shot scripts, CLI commands, or any consumer that
808
+ * doesn't need to drive the token from outside (no manual refresh,
809
+ * 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.
813
+ *
814
+ * Strings are accepted for `baseUrl` and `token`; they are branded
815
+ * via `baseUrl()` / `accessToken()` from `@semiont/core` automatically.
816
+ * Pass the already-branded values if you have them.
817
+ *
818
+ * Omit `token` for unauthenticated usage (public endpoints only).
819
+ */
820
+ static fromHttp(opts: {
821
+ baseUrl: BaseUrl | string;
822
+ token?: AccessToken | string | null;
823
+ }): SemiontClient;
824
+ /**
825
+ * 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.
829
+ *
830
+ * This is the right entry point for skills, CLI scripts, and any
831
+ * consumer that starts with email + password rather than a JWT
832
+ * already on hand. For consumers that already hold a token (CLI
833
+ * cached-token path, env-var token, embedded auth flow), use
834
+ * `fromHttp({ baseUrl, token })` instead.
835
+ *
836
+ * For long-running scripts that need refresh, use
837
+ * `SemiontSession.signIn(...)` — same credentials shape, plus the
838
+ * session machinery for proactive refresh and persistence.
839
+ *
840
+ * Throws if authentication fails. The transient client is disposed
841
+ * before the throw, so no resources leak on failure.
842
+ */
843
+ static signIn(opts: {
844
+ baseUrl: BaseUrl | string;
845
+ email: string;
846
+ password: string;
847
+ }): Promise<SemiontClient>;
725
848
  }
726
849
 
727
- declare class BusRequestError extends Error {
728
- constructor(message: string);
850
+ type BusRequestErrorCode = 'bus.timeout' | 'bus.rejected' | 'bus.bad-payload' | 'bus.unauthorized' | 'bus.forbidden' | 'bus.not-found';
851
+ declare class BusRequestError extends SemiontError {
852
+ code: BusRequestErrorCode;
853
+ constructor(message: string, code: BusRequestErrorCode, details?: Record<string, unknown>);
729
854
  }
730
855
  /**
731
856
  * Subset of ITransport that `busRequest` needs: a way to send a command and
@@ -741,7 +866,7 @@ declare function busRequest<TResult>(bus: BusRequestPrimitive, emitChannel: stri
741
866
  /**
742
867
  * RxJS-native read-through cache primitive.
743
868
  *
744
- * Behavioral contract: packages/api-client/docs/CACHE-SEMANTICS.md (B1–B13).
869
+ * Behavioral contract: packages/sdk/docs/CACHE-SEMANTICS.md (B1–B13).
745
870
  *
746
871
  * Framework-agnostic: no React, no dependency on any namespace. Used by
747
872
  * `BrowseNamespace` to back its per-key stores, but equally usable from
@@ -825,12 +950,17 @@ type KbSessionStatus = 'authenticated' | 'expired' | 'signed-out' | 'unreachable
825
950
  * failures that make the session itself unusable (auth failed, actor
826
951
  * couldn't start, token refresh terminally exhausted). Per-request
827
952
  * errors stay with the caller as normal Promise rejections.
953
+ *
954
+ * `SemiontSessionError` extends `SemiontError` (the unified Semiont base)
955
+ * so consumers can catch with `instanceof SemiontError` for any error
956
+ * surfaced through the SDK.
828
957
  */
829
- type SemiontErrorCode = 'session.construct-failed' | 'session.auth-failed' | 'session.refresh-exhausted' | 'browser.sign-in-failed';
830
- declare class SemiontError extends Error {
831
- readonly code: SemiontErrorCode;
958
+
959
+ type SemiontSessionErrorCode = 'session.construct-failed' | 'session.auth-failed' | 'session.refresh-exhausted' | 'browser.sign-in-failed';
960
+ declare class SemiontSessionError extends SemiontError {
961
+ code: SemiontSessionErrorCode;
832
962
  readonly kbId: string | null;
833
- constructor(code: SemiontErrorCode, message: string, kbId?: string | null);
963
+ constructor(code: SemiontSessionErrorCode, message: string, kbId?: string | null);
834
964
  }
835
965
 
836
966
  /**
@@ -944,7 +1074,7 @@ interface SemiontSessionConfig {
944
1074
  */
945
1075
  onAuthFailed?: (message: string | null) => void;
946
1076
  /** Called for session-level failures (auth, refresh exhaustion). */
947
- onError?: (err: SemiontError) => void;
1077
+ onError?: (err: SemiontSessionError) => void;
948
1078
  }
949
1079
  declare class SemiontSession {
950
1080
  readonly kb: KnowledgeBase;
@@ -1001,6 +1131,61 @@ declare class SemiontSession {
1001
1131
  */
1002
1132
  subscribe<K extends keyof EventMap>(channel: K, handler: (payload: EventMap[K]) => void): () => void;
1003
1133
  dispose(): Promise<void>;
1134
+ /**
1135
+ * Convenience factory for the default HTTP setup. Constructs the
1136
+ * shared `BehaviorSubject<AccessToken | null>`, an `HttpTransport`,
1137
+ * an `HttpContentTransport`, and a `SemiontClient`, then wires
1138
+ * the session over them. Removes the load-bearing
1139
+ * "same-token$-instance" invariant from the caller's hands.
1140
+ *
1141
+ * Strings are accepted for `baseUrl` and `token`; they are branded
1142
+ * via `baseUrl()` / `accessToken()` from `@semiont/core` automatically.
1143
+ *
1144
+ * The remaining options (`refresh`, `validate`, `onAuthFailed`,
1145
+ * `onError`) match `SemiontSessionConfig` exactly.
1146
+ */
1147
+ static fromHttp(opts: {
1148
+ kb: KnowledgeBase;
1149
+ storage: SessionStorage;
1150
+ baseUrl: BaseUrl | string;
1151
+ token?: AccessToken | string | null;
1152
+ refresh?: () => Promise<string | null>;
1153
+ validate?: (token: AccessToken) => Promise<UserInfo | null>;
1154
+ onAuthFailed?: (message: string | null) => void;
1155
+ onError?: (err: SemiontSessionError) => void;
1156
+ }): SemiontSession;
1157
+ /**
1158
+ * 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.
1164
+ *
1165
+ * The consumer-supplied `refresh` callback becomes optional — only
1166
+ * needed for non-standard refresh flows (worker-pool shared secret,
1167
+ * OAuth refresh-token grant, interactive re-prompt). The default
1168
+ * uses the refresh token returned by `auth.password`.
1169
+ *
1170
+ * `kb` is required and must be a full `KnowledgeBase`. The `id` field
1171
+ * is the storage key for this session — distinct scripts sharing the
1172
+ * same `SessionStorage` instance must use distinct ids to avoid
1173
+ * trampling each other's tokens. The factory does not synthesize a
1174
+ * default; the consumer makes the choice.
1175
+ *
1176
+ * Throws on auth failure with no resources leaked. On success, the
1177
+ * returned session's `ready` promise has already resolved.
1178
+ */
1179
+ static signIn(opts: {
1180
+ kb: KnowledgeBase;
1181
+ storage: SessionStorage;
1182
+ baseUrl: BaseUrl | string;
1183
+ email: string;
1184
+ password: string;
1185
+ validate?: (token: AccessToken) => Promise<UserInfo | null>;
1186
+ onAuthFailed?: (message: string | null) => void;
1187
+ onError?: (err: SemiontSessionError) => void;
1188
+ }): Promise<SemiontSession>;
1004
1189
  }
1005
1190
 
1006
1191
  /**
@@ -1109,7 +1294,7 @@ declare class SemiontBrowser {
1109
1294
  */
1110
1295
  readonly sessionActivating$: BehaviorSubject<boolean>;
1111
1296
  readonly openResources$: BehaviorSubject<OpenResource[]>;
1112
- readonly error$: Subject<SemiontError>;
1297
+ readonly error$: Subject<SemiontSessionError>;
1113
1298
  readonly identityToken$: BehaviorSubject<string | null>;
1114
1299
  private readonly storage;
1115
1300
  /**
@@ -1685,4 +1870,4 @@ interface ComposePageVM extends ViewModel {
1685
1870
  }
1686
1871
  declare function createComposePageVM(client: SemiontClient, browse: ShellVM, params: ComposeParams, auth?: AccessToken): ComposePageVM;
1687
1872
 
1688
- export { type ActiveJob, AdminNamespace, type AdminSecurityVM, type AdminUsersVM, type AnnotationGroups, type AnnotationHistoryResponse, AuthNamespace, BeckonNamespace, type BeckonVM, BindNamespace, BrowseNamespace, BusRequestError, type BusRequestPrimitive, COMMON_PANELS, type Cache, 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, SemiontError, type SemiontErrorCode, SemiontSession, type SemiontSessionConfig, type SessionStorage, type SessionVM, type ShellVM, type ShellVMOptions, type SmelterActorVM, type SmelterActorVMOptions, type SmelterEvent, type StoredSession, 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 };
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 };