@semiont/sdk 0.5.5 → 0.5.6

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
@@ -45,9 +45,12 @@ declare class StreamObservable<T> extends Observable<T> implements PromiseLike<T
45
45
  * cache entry. Used by Browse live-query methods (`browse.resource`,
46
46
  * `browse.annotations`, etc.).
47
47
  *
48
- * Awaiting resolves to the **first non-undefined** value (waits past the
49
- * loading state). Subscribing yields the full sequence including the
50
- * initial `undefined`, so reactive consumers can render a loading state.
48
+ * Awaiting (the one-shot path) fetches a **fresh** value via the optional
49
+ * `fetchFresh` action and rejects on failure a re-read reflects writes
50
+ * (#847). Subscribing yields the SWR sequence: the initial `undefined`, the
51
+ * loaded value, and re-emits on invalidation. (Without a `fetchFresh` action
52
+ * — e.g. a non-cache wrapper — the await falls back to the first
53
+ * non-undefined emission.)
51
54
  *
52
55
  * The class is parameterized as `CacheObservable<T>` even though the
53
56
  * stream's element type is `T | undefined` — `T` is what the consumer
@@ -56,10 +59,22 @@ declare class StreamObservable<T> extends Observable<T> implements PromiseLike<T
56
59
  * `.pipe` in the natural way.
57
60
  */
58
61
  declare class CacheObservable<T> extends Observable<T | undefined> implements PromiseLike<T> {
62
+ /**
63
+ * Optional one-shot fresh-fetch action. When present, `then()` (the await
64
+ * path) resolves to a freshly fetched value and rejects on fetch failure —
65
+ * so a re-read reflects writes (#847). `.subscribe(...)` never uses it: it
66
+ * keeps the stale-while-revalidate cached view over `source`.
67
+ */
68
+ private fetchFresh?;
59
69
  then<R1 = T, R2 = never>(onfulfilled?: ((v: T) => R1 | PromiseLike<R1>) | null, onrejected?: ((e: unknown) => R2 | PromiseLike<R2>) | null): PromiseLike<R1 | R2>;
60
70
  /**
61
71
  * Wrap an existing Observable's subscribe behavior in a `CacheObservable`.
62
72
  *
73
+ * `fetchFresh`, when supplied, backs the await path: `await` resolves to a
74
+ * freshly fetched value (rejecting on failure), so a one-shot read reflects
75
+ * writes without a scoped subscription (#847). `.subscribe(...)` consumers
76
+ * keep the SWR view over `source`.
77
+ *
63
78
  * Memoizes on source identity: passing the same `source` returns the same
64
79
  * wrapper instance. The Browse cache primitive already returns a stable
65
80
  * Observable per key (its B4 contract), so this preserves that contract
@@ -69,7 +84,7 @@ declare class CacheObservable<T> extends Observable<T | undefined> implements Pr
69
84
  *
70
85
  * Backed by a `WeakMap`, so wrappers are GC'd when their source is.
71
86
  */
72
- static from<T>(source: Observable<T | undefined>): CacheObservable<T>;
87
+ static from<T>(source: Observable<T | undefined>, fetchFresh?: () => Promise<T>): CacheObservable<T>;
73
88
  }
74
89
  /**
75
90
  * Discriminated phases of an upload's lifecycle.
@@ -294,6 +309,7 @@ interface BrowseNamespace$1 {
294
309
  limit?: number;
295
310
  archived?: boolean;
296
311
  search?: string;
312
+ entityType?: string;
297
313
  }): CacheObservable<ResourceDescriptor[]>;
298
314
  annotations(resourceId: ResourceId): CacheObservable<Annotation[]>;
299
315
  annotation(resourceId: ResourceId, annotationId: AnnotationId): CacheObservable<Annotation>;
@@ -545,6 +561,7 @@ type ResourceListFilters = {
545
561
  limit?: number;
546
562
  archived?: boolean;
547
563
  search?: string;
564
+ entityType?: string;
548
565
  };
549
566
  declare class BrowseNamespace implements BrowseNamespace$1 {
550
567
  private readonly transport;
@@ -578,7 +595,33 @@ declare class BrowseNamespace implements BrowseNamespace$1 {
578
595
  * `distinctUntilChanged` at a higher level — would misbehave.
579
596
  */
580
597
  private readonly annotationListObs;
598
+ /**
599
+ * Per-source memo for the scope-acquiring wrapper (#847 Phase 4), keyed by
600
+ * the underlying (stable, per-key) cache observable so the wrapped
601
+ * observable is itself stable per key — preserving B4/B11 referential
602
+ * identity through to `CacheObservable.from`'s own memo.
603
+ */
604
+ private readonly scopedSources;
581
605
  constructor(transport: ITransport, bus: EventBus, content: IContentTransport);
606
+ /**
607
+ * Wrap a resource-scoped live query's source so that *subscribing* acquires
608
+ * the resource's scope (via the transport's ref-counted
609
+ * `subscribeToResource`) and the last unsubscribe releases it (#847 Phase 4).
610
+ * Freshness follows observation: a `.subscribe()` keeps `rId`'s scoped
611
+ * events flowing — so `mark:*` / entity-tag invalidations reach this cache —
612
+ * with no separate `subscribeToResource` call from the consumer.
613
+ *
614
+ * The one-shot `await` path does NOT go through here (it resolves via the
615
+ * cache's `fetch` — see `CacheObservable.from`'s `fetchFresh`), so a
616
+ * one-shot read acquires no scope.
617
+ *
618
+ * Memoized per source so the wrapped observable is stable per key (B4/B11).
619
+ * Each subscription calls `subscribeToResource(rId)`; the transport
620
+ * ref-counts concurrent subscriptions for the same resource onto a single
621
+ * SSE scope. Single-scope model unchanged — multi-scope is deferred (see
622
+ * `.plans/MULTI-RESOURCE-SCOPE.md`).
623
+ */
624
+ private withScope;
582
625
  resource(resourceId: ResourceId): CacheObservable<ResourceDescriptor>;
583
626
  resources(filters?: ResourceListFilters): CacheObservable<ResourceDescriptor[]>;
584
627
  annotations(resourceId: ResourceId): CacheObservable<Annotation[]>;
@@ -768,9 +811,9 @@ declare class JobNamespace implements JobNamespace$1 {
768
811
  get queued$(): Observable<EventMap['job:queued']>;
769
812
  /** Live stream of `job:report-progress` events. */
770
813
  get progress$(): Observable<EventMap['job:report-progress']>;
771
- /** Live stream of `job:complete` events. */
814
+ /** Live stream of `job:complete` events (global; filter by `jobId`). */
772
815
  get complete$(): Observable<EventMap['job:complete']>;
773
- /** Live stream of `job:fail` events. */
816
+ /** Live stream of `job:fail` events (global; filter by `jobId`). */
774
817
  get fail$(): Observable<EventMap['job:fail']>;
775
818
  status(jobId: JobId): Promise<JobStatusResponse>;
776
819
  pollUntilComplete(jobId: JobId, options?: {
@@ -879,7 +922,6 @@ declare class SemiontClient {
879
922
  constructor(transport: ITransport, content: IContentTransport, backend?: IBackendOperations);
880
923
  /** Transport-level connection state. HTTP reflects SSE health; local is always 'connected'. */
881
924
  get state$(): rxjs.Observable<_semiont_core.ConnectionState>;
882
- subscribeToResource(resourceId: ResourceId): () => void;
883
925
  dispose(): void;
884
926
  /**
885
927
  * Convenience factory for the default HTTP setup. Constructs a
package/dist/index.js CHANGED
@@ -17,12 +17,27 @@ var StreamObservable = class _StreamObservable extends Observable {
17
17
  }
18
18
  };
19
19
  var CacheObservable = class _CacheObservable extends Observable {
20
+ /**
21
+ * Optional one-shot fresh-fetch action. When present, `then()` (the await
22
+ * path) resolves to a freshly fetched value and rejects on fetch failure —
23
+ * so a re-read reflects writes (#847). `.subscribe(...)` never uses it: it
24
+ * keeps the stale-while-revalidate cached view over `source`.
25
+ */
26
+ fetchFresh;
20
27
  then(onfulfilled, onrejected) {
28
+ if (this.fetchFresh) {
29
+ return this.fetchFresh().then(onfulfilled, onrejected);
30
+ }
21
31
  return firstValueFrom(this.pipe(filter((v) => v !== void 0))).then(onfulfilled, onrejected);
22
32
  }
23
33
  /**
24
34
  * Wrap an existing Observable's subscribe behavior in a `CacheObservable`.
25
35
  *
36
+ * `fetchFresh`, when supplied, backs the await path: `await` resolves to a
37
+ * freshly fetched value (rejecting on failure), so a one-shot read reflects
38
+ * writes without a scoped subscription (#847). `.subscribe(...)` consumers
39
+ * keep the SWR view over `source`.
40
+ *
26
41
  * Memoizes on source identity: passing the same `source` returns the same
27
42
  * wrapper instance. The Browse cache primitive already returns a stable
28
43
  * Observable per key (its B4 contract), so this preserves that contract
@@ -32,10 +47,11 @@ var CacheObservable = class _CacheObservable extends Observable {
32
47
  *
33
48
  * Backed by a `WeakMap`, so wrappers are GC'd when their source is.
34
49
  */
35
- static from(source) {
50
+ static from(source, fetchFresh) {
36
51
  let wrapper = wrapperCache.get(source);
37
52
  if (!wrapper) {
38
53
  wrapper = new _CacheObservable((subscriber) => source.subscribe(subscriber));
54
+ wrapper.fetchFresh = fetchFresh;
39
55
  wrapperCache.set(source, wrapper);
40
56
  }
41
57
  return wrapper;
@@ -110,25 +126,31 @@ async function busRequest(bus, emitChannel, payload, resultChannel, failureChann
110
126
  }
111
127
  function createCache(fetchFn) {
112
128
  const store$ = new BehaviorSubject(/* @__PURE__ */ new Map());
113
- const inflight = /* @__PURE__ */ new Set();
129
+ const inflight = /* @__PURE__ */ new Map();
114
130
  const obsCache = /* @__PURE__ */ new Map();
115
- const doFetch = async (key) => {
116
- if (inflight.has(key)) return;
117
- inflight.add(key);
118
- try {
119
- const value = await fetchFn(key);
120
- const next = new Map(store$.value);
121
- next.set(key, value);
122
- store$.next(next);
123
- } catch {
124
- } finally {
125
- inflight.delete(key);
126
- }
131
+ const runFetch = (key) => {
132
+ const existing = inflight.get(key);
133
+ if (existing) return existing;
134
+ let p;
135
+ p = (async () => {
136
+ try {
137
+ const value = await fetchFn(key);
138
+ const next = new Map(store$.value);
139
+ next.set(key, value);
140
+ store$.next(next);
141
+ return value;
142
+ } finally {
143
+ if (inflight.get(key) === p) inflight.delete(key);
144
+ }
145
+ })();
146
+ inflight.set(key, p);
147
+ return p;
127
148
  };
128
149
  return {
129
150
  observe(key) {
130
151
  if (!store$.value.has(key) && !inflight.has(key)) {
131
- void doFetch(key);
152
+ void runFetch(key).catch(() => {
153
+ });
132
154
  }
133
155
  let obs = obsCache.get(key);
134
156
  if (!obs) {
@@ -140,6 +162,9 @@ function createCache(fetchFn) {
140
162
  }
141
163
  return obs;
142
164
  },
165
+ fetch(key) {
166
+ return runFetch(key);
167
+ },
143
168
  get(key) {
144
169
  return store$.value.get(key);
145
170
  },
@@ -148,7 +173,8 @@ function createCache(fetchFn) {
148
173
  },
149
174
  invalidate(key) {
150
175
  inflight.delete(key);
151
- void doFetch(key);
176
+ void runFetch(key).catch(() => {
177
+ });
152
178
  },
153
179
  remove(key) {
154
180
  const next = new Map(store$.value);
@@ -164,7 +190,8 @@ function createCache(fetchFn) {
164
190
  invalidateAll() {
165
191
  for (const key of store$.value.keys()) {
166
192
  inflight.delete(key);
167
- void doFetch(key);
193
+ void runFetch(key).catch(() => {
194
+ });
168
195
  }
169
196
  },
170
197
  dispose() {
@@ -199,7 +226,13 @@ var BrowseNamespace = class {
199
226
  const result = await busRequest(
200
227
  this.transport,
201
228
  "browse:resources-requested",
202
- { search, archived: filters.archived, limit: filters.limit ?? 100, offset: 0 },
229
+ {
230
+ search,
231
+ archived: filters.archived,
232
+ entityType: filters.entityType,
233
+ limit: filters.limit ?? 100,
234
+ offset: 0
235
+ },
203
236
  "browse:resources-result",
204
237
  "browse:resources-failed"
205
238
  );
@@ -270,6 +303,9 @@ var BrowseNamespace = class {
270
303
  });
271
304
  this.subscribeToEvents();
272
305
  }
306
+ transport;
307
+ bus;
308
+ content;
273
309
  // ── Caches, backed by the RxJS-native `Cache<K, V>` primitive ───────────
274
310
  //
275
311
  // Each cache encapsulates the BehaviorSubject store, in-flight guard,
@@ -306,18 +342,58 @@ var BrowseNamespace = class {
306
342
  * `distinctUntilChanged` at a higher level — would misbehave.
307
343
  */
308
344
  annotationListObs = /* @__PURE__ */ new Map();
345
+ /**
346
+ * Per-source memo for the scope-acquiring wrapper (#847 Phase 4), keyed by
347
+ * the underlying (stable, per-key) cache observable so the wrapped
348
+ * observable is itself stable per key — preserving B4/B11 referential
349
+ * identity through to `CacheObservable.from`'s own memo.
350
+ */
351
+ scopedSources = /* @__PURE__ */ new WeakMap();
352
+ /**
353
+ * Wrap a resource-scoped live query's source so that *subscribing* acquires
354
+ * the resource's scope (via the transport's ref-counted
355
+ * `subscribeToResource`) and the last unsubscribe releases it (#847 Phase 4).
356
+ * Freshness follows observation: a `.subscribe()` keeps `rId`'s scoped
357
+ * events flowing — so `mark:*` / entity-tag invalidations reach this cache —
358
+ * with no separate `subscribeToResource` call from the consumer.
359
+ *
360
+ * The one-shot `await` path does NOT go through here (it resolves via the
361
+ * cache's `fetch` — see `CacheObservable.from`'s `fetchFresh`), so a
362
+ * one-shot read acquires no scope.
363
+ *
364
+ * Memoized per source so the wrapped observable is stable per key (B4/B11).
365
+ * Each subscription calls `subscribeToResource(rId)`; the transport
366
+ * ref-counts concurrent subscriptions for the same resource onto a single
367
+ * SSE scope. Single-scope model unchanged — multi-scope is deferred (see
368
+ * `.plans/MULTI-RESOURCE-SCOPE.md`).
369
+ */
370
+ withScope(rId, source) {
371
+ let scoped = this.scopedSources.get(source);
372
+ if (!scoped) {
373
+ scoped = new Observable((subscriber) => {
374
+ const release = this.transport.subscribeToResource(rId);
375
+ const inner = source.subscribe(subscriber);
376
+ return () => {
377
+ inner.unsubscribe();
378
+ release();
379
+ };
380
+ });
381
+ this.scopedSources.set(source, scoped);
382
+ }
383
+ return scoped;
384
+ }
309
385
  // ── Live queries ────────────────────────────────────────────────────────
310
386
  //
311
387
  // These return `CacheObservable<T>`: subscribers see `T | undefined`
312
388
  // (with `undefined` during initial load), and `await` resolves to the
313
389
  // first non-undefined value.
314
390
  resource(resourceId2) {
315
- return CacheObservable.from(this.resourceCache.observe(resourceId2));
391
+ return CacheObservable.from(this.withScope(resourceId2, this.resourceCache.observe(resourceId2)), () => this.resourceCache.fetch(resourceId2));
316
392
  }
317
393
  resources(filters) {
318
394
  const key = JSON.stringify(filters ?? {});
319
395
  this.resourceListFilters.set(key, filters ?? {});
320
- return CacheObservable.from(this.resourceListCache.observe(key));
396
+ return CacheObservable.from(this.resourceListCache.observe(key), () => this.resourceListCache.fetch(key));
321
397
  }
322
398
  annotations(resourceId2) {
323
399
  let obs = this.annotationListObs.get(resourceId2);
@@ -325,23 +401,23 @@ var BrowseNamespace = class {
325
401
  obs = this.annotationListCache.observe(resourceId2).pipe(map$1((r) => r?.annotations));
326
402
  this.annotationListObs.set(resourceId2, obs);
327
403
  }
328
- return CacheObservable.from(obs);
404
+ return CacheObservable.from(this.withScope(resourceId2, obs), () => this.annotationListCache.fetch(resourceId2).then((r) => r.annotations));
329
405
  }
330
406
  annotation(resourceId2, annotationId2) {
331
407
  this.annotationResources.set(annotationId2, resourceId2);
332
- return CacheObservable.from(this.annotationDetailCache.observe(annotationId2));
408
+ return CacheObservable.from(this.withScope(resourceId2, this.annotationDetailCache.observe(annotationId2)), () => this.annotationDetailCache.fetch(annotationId2));
333
409
  }
334
410
  entityTypes() {
335
- return CacheObservable.from(this.entityTypesCache.observe(ENTITY_TYPES_KEY));
411
+ return CacheObservable.from(this.entityTypesCache.observe(ENTITY_TYPES_KEY), () => this.entityTypesCache.fetch(ENTITY_TYPES_KEY));
336
412
  }
337
413
  tagSchemas() {
338
- return CacheObservable.from(this.tagSchemasCache.observe(TAG_SCHEMAS_KEY));
414
+ return CacheObservable.from(this.tagSchemasCache.observe(TAG_SCHEMAS_KEY), () => this.tagSchemasCache.fetch(TAG_SCHEMAS_KEY));
339
415
  }
340
416
  referencedBy(resourceId2) {
341
- return CacheObservable.from(this.referencedByCache.observe(resourceId2));
417
+ return CacheObservable.from(this.withScope(resourceId2, this.referencedByCache.observe(resourceId2)), () => this.referencedByCache.fetch(resourceId2));
342
418
  }
343
419
  events(resourceId2) {
344
- return CacheObservable.from(this.resourceEventsCache.observe(resourceId2));
420
+ return CacheObservable.from(this.withScope(resourceId2, this.resourceEventsCache.observe(resourceId2)), () => this.resourceEventsCache.fetch(resourceId2));
345
421
  }
346
422
  // ── One-shot reads ──────────────────────────────────────────────────────
347
423
  async resourceContent(resourceId2) {
@@ -544,6 +620,8 @@ var MarkNamespace = class {
544
620
  this.transport = transport;
545
621
  this.bus = bus;
546
622
  }
623
+ transport;
624
+ bus;
547
625
  async annotation(input) {
548
626
  const resourceId2 = resourceId(input.target.source);
549
627
  const result = await busRequest(
@@ -569,7 +647,6 @@ var MarkNamespace = class {
569
647
  let done = false;
570
648
  let pollTimer = null;
571
649
  let pollInterval = null;
572
- let unsubscribeResource = this.transport.subscribeToResource(resourceId2);
573
650
  const cleanup = () => {
574
651
  done = true;
575
652
  if (pollTimer) {
@@ -580,10 +657,6 @@ var MarkNamespace = class {
580
657
  clearInterval(pollInterval);
581
658
  pollInterval = null;
582
659
  }
583
- if (unsubscribeResource) {
584
- unsubscribeResource();
585
- unsubscribeResource = null;
586
- }
587
660
  };
588
661
  const resetPollTimer = (jobId) => {
589
662
  if (pollTimer) clearTimeout(pollTimer);
@@ -742,6 +815,8 @@ var BindNamespace = class {
742
815
  this.transport = transport;
743
816
  this.bus = bus;
744
817
  }
818
+ transport;
819
+ bus;
745
820
  async body(resourceId2, annotationId2, operations) {
746
821
  await this.transport.emit("bind:update-body", {
747
822
  correlationId: crypto.randomUUID(),
@@ -759,6 +834,8 @@ var GatherNamespace = class {
759
834
  this.transport = transport;
760
835
  this.bus = bus;
761
836
  }
837
+ transport;
838
+ bus;
762
839
  annotation(resourceId2, annotationId2, options) {
763
840
  return new StreamObservable((subscriber) => {
764
841
  const correlationId = crypto.randomUUID();
@@ -810,6 +887,8 @@ var MatchNamespace = class {
810
887
  this.transport = transport;
811
888
  this.bus = bus;
812
889
  }
890
+ transport;
891
+ bus;
813
892
  requestSearch(input) {
814
893
  this.bus.get("match:search-requested").next(input);
815
894
  }
@@ -853,6 +932,9 @@ var YieldNamespace = class {
853
932
  this.bus = bus;
854
933
  this.content = content;
855
934
  }
935
+ transport;
936
+ bus;
937
+ content;
856
938
  resource(data) {
857
939
  const totalBytes = typeof Buffer !== "undefined" && data.file instanceof Buffer ? data.file.length : data.file.size;
858
940
  return new UploadObservable((subscriber) => {
@@ -905,7 +987,6 @@ var YieldNamespace = class {
905
987
  let done = false;
906
988
  let pollTimer = null;
907
989
  let pollInterval = null;
908
- let unsubscribeResource = this.transport.subscribeToResource(resourceId2);
909
990
  const cleanup = () => {
910
991
  done = true;
911
992
  if (pollTimer) {
@@ -916,10 +997,6 @@ var YieldNamespace = class {
916
997
  clearInterval(pollInterval);
917
998
  pollInterval = null;
918
999
  }
919
- if (unsubscribeResource) {
920
- unsubscribeResource();
921
- unsubscribeResource = null;
922
- }
923
1000
  };
924
1001
  const resetPollTimer = (jid) => {
925
1002
  if (pollTimer) clearTimeout(pollTimer);
@@ -1062,6 +1139,8 @@ var BeckonNamespace = class {
1062
1139
  this.transport = transport;
1063
1140
  this.bus = bus;
1064
1141
  }
1142
+ transport;
1143
+ bus;
1065
1144
  attention(resourceId2, annotationId2) {
1066
1145
  void this.transport.emit("beckon:focus", { annotationId: annotationId2, resourceId: resourceId2 });
1067
1146
  }
@@ -1078,6 +1157,7 @@ var FrameNamespace = class {
1078
1157
  constructor(transport) {
1079
1158
  this.transport = transport;
1080
1159
  }
1160
+ transport;
1081
1161
  async addEntityType(type) {
1082
1162
  await this.transport.emit("frame:add-entity-type", { tag: type });
1083
1163
  }
@@ -1097,6 +1177,8 @@ var JobNamespace = class {
1097
1177
  this.transport = transport;
1098
1178
  this.bus = bus;
1099
1179
  }
1180
+ transport;
1181
+ bus;
1100
1182
  /**
1101
1183
  * Live stream of `job:queued` events. Surfaces a typed view onto the
1102
1184
  * underlying bus channel for consumers (CLIs, MCP handlers, widgets)
@@ -1109,11 +1191,11 @@ var JobNamespace = class {
1109
1191
  get progress$() {
1110
1192
  return this.bus.get("job:report-progress");
1111
1193
  }
1112
- /** Live stream of `job:complete` events. */
1194
+ /** Live stream of `job:complete` events (global; filter by `jobId`). */
1113
1195
  get complete$() {
1114
1196
  return this.bus.get("job:complete");
1115
1197
  }
1116
- /** Live stream of `job:fail` events. */
1198
+ /** Live stream of `job:fail` events (global; filter by `jobId`). */
1117
1199
  get fail$() {
1118
1200
  return this.bus.get("job:fail");
1119
1201
  }
@@ -1153,6 +1235,7 @@ var AuthNamespace = class {
1153
1235
  constructor(backend) {
1154
1236
  this.backend = backend;
1155
1237
  }
1238
+ backend;
1156
1239
  async password(emailStr, passwordStr) {
1157
1240
  return this.backend.authenticatePassword(email(emailStr), passwordStr);
1158
1241
  }
@@ -1184,6 +1267,7 @@ var AdminNamespace = class {
1184
1267
  constructor(backend) {
1185
1268
  this.backend = backend;
1186
1269
  }
1270
+ backend;
1187
1271
  async users() {
1188
1272
  const result = await this.backend.listUsers();
1189
1273
  return result.users;
@@ -1306,9 +1390,6 @@ var SemiontClient = class _SemiontClient {
1306
1390
  get state$() {
1307
1391
  return this.transport.state$;
1308
1392
  }
1309
- subscribeToResource(resourceId2) {
1310
- return this.transport.subscribeToResource(resourceId2);
1311
- }
1312
1393
  dispose() {
1313
1394
  this.transport.dispose();
1314
1395
  this.content.dispose();