@equinor/fusion-framework-module-context 6.0.7-next.0 → 7.0.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +30 -5
  2. package/README.md +33 -0
  3. package/dist/esm/ContextConfigBuilder.js +70 -2
  4. package/dist/esm/ContextConfigBuilder.js.map +1 -1
  5. package/dist/esm/ContextProvider.js +207 -2
  6. package/dist/esm/ContextProvider.js.map +1 -1
  7. package/dist/esm/client/ContextClient.js +65 -1
  8. package/dist/esm/client/ContextClient.js.map +1 -1
  9. package/dist/esm/configurator.js +3 -5
  10. package/dist/esm/configurator.js.map +1 -1
  11. package/dist/esm/errors.js +12 -1
  12. package/dist/esm/errors.js.map +1 -1
  13. package/dist/esm/module.js +21 -0
  14. package/dist/esm/module.js.map +1 -1
  15. package/dist/esm/utils/enable-context.js +19 -3
  16. package/dist/esm/utils/enable-context.js.map +1 -1
  17. package/dist/esm/version.js +1 -1
  18. package/dist/esm/version.js.map +1 -1
  19. package/dist/tsconfig.tsbuildinfo +1 -1
  20. package/dist/types/ContextConfigBuilder.d.ts +70 -0
  21. package/dist/types/ContextProvider.d.ts +347 -6
  22. package/dist/types/client/ContextClient.d.ts +65 -1
  23. package/dist/types/errors.d.ts +12 -1
  24. package/dist/types/module.d.ts +31 -0
  25. package/dist/types/types.d.ts +33 -0
  26. package/dist/types/utils/enable-context.d.ts +18 -2
  27. package/dist/types/version.d.ts +1 -1
  28. package/package.json +7 -7
  29. package/src/ContextConfigBuilder.ts +70 -4
  30. package/src/ContextProvider.ts +353 -10
  31. package/src/client/ContextClient.ts +66 -2
  32. package/src/configurator.ts +4 -5
  33. package/src/errors.ts +12 -1
  34. package/src/module.ts +31 -0
  35. package/src/types.ts +33 -0
  36. package/src/utils/enable-context.ts +19 -3
  37. package/src/version.ts +1 -1
@@ -23,11 +23,35 @@ import type {
23
23
  import Query from '@equinor/fusion-query';
24
24
 
25
25
  /**
26
- * WARNING: this is an initial out cast.
27
- * api clients will most probably not be exposed in future!
28
- */
29
- /**
30
- * Represents a context provider that manages the current context and provides methods for querying and manipulating context items.
26
+ * Interface representing a provider for managing and interacting with context items within an application.
27
+ *
28
+ * The `IContextProvider` interface defines a contract for querying, validating, resolving, and managing the current context state.
29
+ * It supports both synchronous and asynchronous operations, as well as observable streams for reactive programming.
30
+ * This interface is intended to be implemented by modules that encapsulate context-related logic, such as user, tenant, or environment context.
31
+ *
32
+ * ## Core Responsibilities
33
+ * - **Querying Contexts:** Search and retrieve context items based on search criteria, both as observables and promises.
34
+ * - **Current Context Management:** Get, set, and clear the current context, with support for validation and resolution.
35
+ * - **Context Resolution:** Resolve context items to their full representation, synchronously or asynchronously.
36
+ * - **Related Contexts:** Retrieve related context items based on specific parameters.
37
+ * - **Path Utilities:** Extract context IDs from paths and generate paths from context items, supporting deep linking and routing.
38
+ * - **Reactive State:** Expose the current context as an observable stream for reactive UI updates.
39
+ *
40
+ * ## Usage Example
41
+ * ```ts
42
+ * const provider: IContextProvider = ...;
43
+ * provider.currentContext$.subscribe(ctx => {
44
+ * // React to context changes
45
+ * });
46
+ * const items = await provider.queryContextAsync('search-term');
47
+ * ```
48
+ *
49
+ * ## Notes
50
+ * - Some members are marked as **DANGER** and are intended for advanced or internal use only.
51
+ * - Implementations should ensure thread safety and consistency of the current context state.
52
+ * - Optional methods for path extraction and generation enable integration with routing systems.
53
+ *
54
+ * @template T - The shape of the context item data.
31
55
  */
32
56
  export interface IContextProvider {
33
57
  /** DANGER */
@@ -35,14 +59,48 @@ export interface IContextProvider {
35
59
  /** DANGER */
36
60
  readonly queryClient: Query<ContextItem[], QueryContextParameters>;
37
61
 
38
- // stream of current context
62
+ /**
63
+ * Observable stream emitting the current context item.
64
+ *
65
+ * - Emits `undefined` if the context has not been initialized.
66
+ * - Emits `null` when the current context is cleared.
67
+ * - Emits a `ContextItem` when a valid context is set.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * portal.context.currentContext$.subscribe(context => {
72
+ * if (context) {
73
+ * console.log('Current context:', context);
74
+ * } else if (context === null) {
75
+ * console.log('Current context cleared');
76
+ * }
77
+ * });
78
+ * ```
79
+ */
39
80
  readonly currentContext$: Observable<ContextItem | null | undefined>;
40
81
 
41
- // current context of the current state
42
- currentContext: ContextItem | null | undefined;
82
+ /**
83
+ * Snapshot of the current context item.
84
+ *
85
+ * @remarks
86
+ * This property provides the current context item as a snapshot.
87
+ * It may be `null` or `undefined` if no context is set or if the context is not initialized.
88
+ * It is intended for synchronous access to the current context state.
89
+ *
90
+ * __Use {@link currentContext$} instead of this property to get the current context as an observable stream.__
91
+ */
92
+ readonly currentContext: ContextItem | null | undefined;
43
93
 
44
94
  /**
45
95
  * Queries the context items based on the provided search string.
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * portal.context.queryContext('search-term').subscribe(contextItems => {
100
+ * console.log('Queried context items:', contextItems);
101
+ * });
102
+ * ```
103
+ *
46
104
  * @param search The search string.
47
105
  * @returns An observable that emits an array of context items.
48
106
  */
@@ -50,6 +108,14 @@ export interface IContextProvider {
50
108
 
51
109
  /**
52
110
  * Queries the context items asynchronously based on the provided search string.
111
+ *
112
+ * @example
113
+ * ```ts
114
+ * portal.context.queryContextAsync('search-term').then(contextItems => {
115
+ * console.log('Queried context items:', contextItems);
116
+ * });
117
+ * ```
118
+ *
53
119
  * @param search The search string.
54
120
  * @returns A promise that resolves to an array of context items.
55
121
  */
@@ -57,6 +123,21 @@ export interface IContextProvider {
57
123
 
58
124
  /**
59
125
  * Validates the given context item.
126
+ * This method is used to check if the context item meets the criteria defined in the provider's configuration.
127
+ *
128
+ * @example
129
+ * ```ts
130
+ * const currentContext = portal.context.currentContext;
131
+ * if(app.context.validateContext(currentContext)) {
132
+ * // the application can safely use the context item
133
+ * } else {
134
+ * // the context item is not valid, handle accordingly
135
+ * }
136
+ * ```
137
+ *
138
+ * @remarks
139
+ * This method will use the configured validation function to check if the context item is valid.
140
+ *
60
141
  * @param item The context item to validate.
61
142
  * @returns A boolean indicating whether the context item is valid or not.
62
143
  */
@@ -64,6 +145,29 @@ export interface IContextProvider {
64
145
 
65
146
  /**
66
147
  * Resolves the context item as a stream.
148
+ *
149
+ * This method will try to resolve the context item based on the current context.
150
+ * This is useful when transferring context items between different parts of the application.
151
+ *
152
+ * @remarks
153
+ * A normal implementation of this method will first validate the context item and if it is not valid,
154
+ * it will use the {@link relatedContexts} method to find related context items.
155
+ *
156
+ * @example
157
+ * ```ts
158
+ * app.context.resolveContext(portal.context.currentContext).subscribe({
159
+ * next: (resolvedContext) => {
160
+ * // the application can safely use the resolved context item
161
+ * },
162
+ * error: (err) => {
163
+ * // handle error during context resolution
164
+ * },
165
+ * complete: () => {
166
+ * // context resolution completed
167
+ * }
168
+ * });
169
+ * ```
170
+ *
67
171
  * @param current The current context item.
68
172
  * @returns An observable that emits the resolved context item.
69
173
  */
@@ -71,6 +175,9 @@ export interface IContextProvider {
71
175
 
72
176
  /**
73
177
  * Resolves the context item asynchronously.
178
+ *
179
+ * @see {@link resolveContext} for more details.
180
+ *
74
181
  * @param current The current context item.
75
182
  * @returns A promise that resolves to the resolved context item.
76
183
  */
@@ -78,6 +185,7 @@ export interface IContextProvider {
78
185
 
79
186
  /**
80
187
  * Retrieves the related context items based on the provided parameters.
188
+ *
81
189
  * @param args The parameters for retrieving related context items.
82
190
  * @returns An observable that emits an array of related context items.
83
191
  */
@@ -87,6 +195,9 @@ export interface IContextProvider {
87
195
 
88
196
  /**
89
197
  * Retrieves the related context items asynchronously based on the provided parameters.
198
+ *
199
+ * @see {@link relatedContexts}
200
+ *
90
201
  * @param args The parameters for retrieving related context items.
91
202
  * @returns A promise that resolves to an array of related context items.
92
203
  */
@@ -96,11 +207,13 @@ export interface IContextProvider {
96
207
 
97
208
  /**
98
209
  * Clears the current context.
210
+ * This method will set the current context to `null`.
99
211
  */
100
212
  clearCurrentContext: VoidFunction;
101
213
 
102
214
  /**
103
215
  * Sets the current context item by its ID.
216
+ *
104
217
  * @param id The ID of the context item.
105
218
  * @returns An observable that emits the current context item.
106
219
  */
@@ -108,6 +221,9 @@ export interface IContextProvider {
108
221
 
109
222
  /**
110
223
  * Sets the current context item by its ID asynchronously.
224
+ *
225
+ * @see {@link setCurrentContextById}
226
+ *
111
227
  * @param id The ID of the context item.
112
228
  * @returns A promise that resolves to the current context item.
113
229
  */
@@ -115,6 +231,9 @@ export interface IContextProvider {
115
231
 
116
232
  /**
117
233
  * Sets the current context item.
234
+ *
235
+ * Optionally validates and resolves the context item based on the provided settings.
236
+ *
118
237
  * @param context The context item to set as the current context.
119
238
  * @param opt Optional settings for the operation.
120
239
  * @param opt.validate Specifies whether to validate the context item. Default is `true`.
@@ -128,6 +247,9 @@ export interface IContextProvider {
128
247
 
129
248
  /**
130
249
  * Sets the current context item asynchronously.
250
+ *
251
+ * @see {@link setCurrentContext}
252
+ *
131
253
  * @param context The context item to set as the current context.
132
254
  * @param opt Optional settings for the operation.
133
255
  * @param opt.validate Specifies whether to validate the context item. Default is `true`.
@@ -142,14 +264,30 @@ export interface IContextProvider {
142
264
  /**
143
265
  * Method for extracting context id from a path.
144
266
  *
267
+ * @remarks
268
+ * This method extracts the context ID from a given path using the extraction method
269
+ * provided to the provider via the configuration. If no extraction method is configured,
270
+ * it returns undefined.
271
+ *
145
272
  * @param path path to resolve context from
146
273
  * @returns the resolved context item id
274
+ *
275
+ * @example
276
+ * ```ts
277
+ * // configured with extracting id from path like '/context/:id'
278
+ * provider.extractContextIdFromPath('/context/1234'); // returns '1234'
279
+ * ```
147
280
  */
148
281
  extractContextIdFromPath?: (path: string) => string | undefined;
149
282
 
150
283
  /**
151
284
  * Method for generating path from a context item.
152
285
  *
286
+ * @remarks
287
+ * This method generates a path for the context item using the generation method
288
+ * provided to the provider via the configuration. If no generation method is configured,
289
+ * it returns undefined.
290
+ *
153
291
  * @param context context item to generate path from
154
292
  * @param path current path
155
293
  * @returns path for the context item
@@ -157,6 +295,36 @@ export interface IContextProvider {
157
295
  generatePathFromContext?: (context: ContextItem, path: string) => string | undefined;
158
296
  }
159
297
 
298
+ /**
299
+ * Provides context management functionality, including querying, setting, validating, and resolving context items.
300
+ *
301
+ * The `ContextProvider` class acts as a central service for handling context state, supporting asynchronous operations,
302
+ * event-driven updates, and integration with parent/child context providers. It manages a queue for context changes,
303
+ * supports validation and resolution logic, and can interact with related context items.
304
+ *
305
+ * Key Features:
306
+ * - Maintains the current context and exposes it as both an observable and a property.
307
+ * - Allows querying for context items based on search criteria and filters.
308
+ * - Supports setting the current context by ID or by context item, with optional validation and resolution.
309
+ * - Handles context changes asynchronously, queuing tasks and supporting cancellation.
310
+ * - Integrates with an event module to dispatch and listen for context-related events.
311
+ * - Supports connecting to a parent context provider to synchronize context state.
312
+ * - Provides methods for resolving related contexts and validating context items.
313
+ * - Manages subscriptions and ensures proper resource cleanup via `dispose`.
314
+ *
315
+ * @template T The type of context item managed by the provider.
316
+ *
317
+ * @remarks
318
+ * - Some methods and properties are marked as deprecated and may be removed in future versions.
319
+ * - Event integration is optional and depends on the presence of an event module.
320
+ * - The provider is designed to be extensible and can be configured via the `ContextModuleConfig`.
321
+ *
322
+ * @example
323
+ * ```typescript
324
+ * const provider = new ContextProvider({ config: myConfig, event: myEventModule });
325
+ * provider.setCurrentContextById('context-id').subscribe(...);
326
+ * ```
327
+ */
160
328
  export class ContextProvider implements IContextProvider {
161
329
  #contextClient: ContextClient;
162
330
  #contextQuery: Query<Array<ContextItem>, QueryContextParameters>;
@@ -219,8 +387,12 @@ export class ContextProvider implements IContextProvider {
219
387
  this.#event = event;
220
388
 
221
389
  // set the resolve and validate context functions
222
- config.resolveContext && (this.resolveContext = config.resolveContext?.bind(this));
223
- config.validateContext && (this.validateContext = config.validateContext?.bind(this));
390
+ if (config.resolveContext) {
391
+ this.resolveContext = config.resolveContext?.bind(this);
392
+ }
393
+ if (config.validateContext) {
394
+ this.validateContext = config.validateContext?.bind(this);
395
+ }
224
396
 
225
397
  if (config.extractContextIdFromPath) {
226
398
  // @ts-ignore
@@ -294,6 +466,22 @@ export class ContextProvider implements IContextProvider {
294
466
  );
295
467
  }
296
468
 
469
+ /**
470
+ * Connects this context provider to a parent context provider, subscribing to changes in the parent's context.
471
+ *
472
+ * When the parent context changes, this method will:
473
+ * - Optionally skip the first emitted value from the parent (if `opt.skipFirst` is true).
474
+ * - Only update the current context if the context ID has changed.
475
+ * - Dispatch an `onParentContextChanged` event before updating, allowing for cancellation.
476
+ * - Set the current context with validation and resolution, handling errors gracefully.
477
+ *
478
+ * The subscription is automatically managed and will be cleaned up with the provider.
479
+ *
480
+ * @param provider - The parent context provider to connect to.
481
+ * @param opt - Optional settings.
482
+ * @param opt.skipFirst - If true, skips the first emitted value from the parent context.
483
+ * @returns A `Subscription` object representing the connection to the parent context.
484
+ */
297
485
  public connectParentContext(
298
486
  provider: IContextProvider,
299
487
  opt?: { skipFirst: boolean },
@@ -354,6 +542,18 @@ export class ContextProvider implements IContextProvider {
354
542
  return subscription;
355
543
  }
356
544
 
545
+ /**
546
+ * Sets the current context by resolving a context item using the provided ID.
547
+ *
548
+ * This method attempts to resolve a context item by its unique identifier,
549
+ * filters out any invalid or undefined items, and then sets the current context
550
+ * using the resolved item. The operation is performed as an Observable stream,
551
+ * allowing subscribers to react to the context change or handle errors.
552
+ *
553
+ * @param id - The unique identifier of the context item to resolve and set as current.
554
+ * @returns An Observable that emits the resolved and set {@link ContextItem}.
555
+ * Emits an error if the context cannot be resolved or set.
556
+ */
357
557
  public setCurrentContextById(id: string): Observable<ContextItem<Record<string, unknown>>> {
358
558
  return new Observable((subscriber) => {
359
559
  try {
@@ -374,6 +574,18 @@ export class ContextProvider implements IContextProvider {
374
574
  });
375
575
  }
376
576
 
577
+ /**
578
+ * Asynchronously sets the current context by its unique identifier and returns a promise
579
+ * that resolves to the corresponding `ContextItem`.
580
+ *
581
+ * This method wraps the observable returned by `setCurrentContextById` into a promise,
582
+ * allowing for async/await usage.
583
+ *
584
+ * @see {@link setCurrentContextById} for more details.
585
+ *
586
+ * @param id - The unique identifier of the context to set as current.
587
+ * @returns A promise that resolves to the `ContextItem` associated with the given ID.
588
+ */
377
589
  public setCurrentContextByIdAsync(id: string): Promise<ContextItem<Record<string, unknown>>> {
378
590
  // return last value from observable
379
591
  return lastValueFrom(this.setCurrentContextById(id));
@@ -425,6 +637,47 @@ export class ContextProvider implements IContextProvider {
425
637
  );
426
638
  }
427
639
 
640
+ /**
641
+ * Sets the current context, optionally validating and resolving it.
642
+ *
643
+ * This method emits the provided context as an observable. If the context is the same as the current one,
644
+ * it emits and completes immediately. If validation is requested and fails, it either emits an error or,
645
+ * if resolution is enabled, attempts to resolve the context before setting it. The method dispatches various
646
+ * events to notify listeners about validation failures, resolution steps, and context changes, allowing
647
+ * cancellation at several stages.
648
+ *
649
+ * ### Step-by-step process:
650
+ * 1. **Check if the context is the same as the current one:**
651
+ * - If so, emit the context and complete the observable immediately.
652
+ * 2. **Validate the context (if requested):**
653
+ * - If validation fails and resolution is not enabled:
654
+ * - Dispatch the `onSetContextValidationFailed` event.
655
+ * - Emit an error and complete.
656
+ * - If validation fails but resolution is enabled:
657
+ * - Dispatch the `onSetContextResolve` event (cancelable).
658
+ * - If canceled, throw an error and abort.
659
+ * - Attempt to resolve the context using `resolveContext`.
660
+ * - Dispatch the `onSetContextResolved` event (cancelable) after resolution.
661
+ * - If canceled, throw an error and abort.
662
+ * - Recursively call `_setCurrentContext` with the resolved context (without validation/resolution).
663
+ * 3. **If validation passes or not requested:**
664
+ * - Dispatch the `onCurrentContextChange` event (cancelable).
665
+ * - If canceled, throw an error and abort.
666
+ * - Emit the context and complete the observable.
667
+ *
668
+ * @protected
669
+ * @typeParam T - The type of the context item, which extends `ContextItem<Record<string, unknown>>` or can be `null`.
670
+ * @param context - The new context to set.
671
+ * @param opt - Optional settings:
672
+ * - `validate`: Whether to validate the context before setting.
673
+ * - `resolve`: Whether to attempt to resolve the context if validation fails.
674
+ * @returns An `Observable<T>` that emits the context when set, or errors if validation or resolution fails.
675
+ * @fires onSetContextValidationFailed - When context validation fails and resolution is not enabled.
676
+ * @fires onSetContextResolve - Before attempting to resolve the context.
677
+ * @fires onSetContextResolved - After the context has been resolved.
678
+ * @fires onCurrentContextChange - Before changing the current context.
679
+ * @throws Error if validation fails and resolution is not enabled, or if any event handler cancels the operation.
680
+ */
428
681
  protected _setCurrentContext<T extends ContextItem<Record<string, unknown>> | null>(
429
682
  context: T,
430
683
  opt?: { validate?: boolean; resolve?: boolean },
@@ -523,6 +776,18 @@ export class ContextProvider implements IContextProvider {
523
776
  });
524
777
  }
525
778
 
779
+ /**
780
+ * Asynchronously sets the current context and returns a promise that resolves with the provided context.
781
+ *
782
+ * @see {@link setCurrentContext} for more details.
783
+ *
784
+ * @typeParam T - The type of the context item, which extends `ContextItem<Record<string, unknown>>` or can be `null`.
785
+ * @param context - The context item to set as the current context, or `null` to clear it.
786
+ * @param opt - Optional settings for context handling.
787
+ * @param opt.validate - If `true`, validates the context before setting it.
788
+ * @param opt.resolve - If `true`, resolves any dependencies or references in the context before setting it.
789
+ * @returns A promise that resolves with the context item that was set.
790
+ */
526
791
  public async setCurrentContextAsync<T extends ContextItem<Record<string, unknown>> | null>(
527
792
  context: T,
528
793
  opt?: { validate?: boolean; resolve?: boolean },
@@ -530,6 +795,17 @@ export class ContextProvider implements IContextProvider {
530
795
  return lastValueFrom(this.setCurrentContext(context, opt));
531
796
  }
532
797
 
798
+ /**
799
+ * Queries the context for items matching the provided search string.
800
+ *
801
+ * This method constructs query parameters using the given search term and the current context type,
802
+ * then executes the query using the internal query client. If a context filter is defined, it is applied
803
+ * to the results before emitting them. Errors thrown by the query client of type `QueryClientError` will
804
+ * have their underlying cause re-thrown.
805
+ *
806
+ * @param search - The search string to filter context items.
807
+ * @returns An Observable that emits an array of `ContextItem` objects matching the search criteria.
808
+ */
533
809
  public queryContext(search: string): Observable<Array<ContextItem>> {
534
810
  const query$ = this.queryClient
535
811
  .query(
@@ -554,15 +830,43 @@ export class ContextProvider implements IContextProvider {
554
830
  return this.#contextFilter ? query$.pipe(map(this.#contextFilter)) : query$;
555
831
  }
556
832
 
833
+ /**
834
+ * Asynchronously queries the context for items matching the provided search string.
835
+ *
836
+ * @see {@link queryContext} for more details.
837
+ *
838
+ * @param search - The search string used to filter context items.
839
+ * @returns A promise that resolves to an array of `ContextItem` objects matching the search criteria.
840
+ */
557
841
  public queryContextAsync(search: string): Promise<Array<ContextItem>> {
558
842
  return lastValueFrom(this.queryContext(search));
559
843
  }
560
844
 
845
+ /**
846
+ * Validates whether the provided context item matches one of the allowed context types.
847
+ *
848
+ * @param item - The context item to validate, containing a type with an `id` property.
849
+ * @returns `true` if the context type is not set or if the item's type ID matches one of the allowed types (case-insensitive); otherwise, `false`.
850
+ */
561
851
  public validateContext(item: ContextItem<Record<string, unknown>>): boolean {
562
852
  if (!this.#contextType) return true;
563
853
  return this.#contextType.map((x) => x.toLowerCase()).includes(item.type.id.toLowerCase());
564
854
  }
565
855
 
856
+ /**
857
+ * Resolves a context item by fetching related context items of the same type as configured in the provider.
858
+ *
859
+ * This method:
860
+ * - Requests related context items matching the provider's context type.
861
+ * - Filters out invalid context items using `validateContext`.
862
+ * - Selects the first valid context item, throwing an error if none are found.
863
+ * - Logs a warning if multiple valid context items are found.
864
+ * - Returns the resolved context item as an observable.
865
+ *
866
+ * @param item - The context item for which to resolve related context.
867
+ * @returns An observable emitting the resolved context item.
868
+ * @throws Error if no valid related context item is found.
869
+ */
566
870
  public resolveContext(
567
871
  item: ContextItem<Record<string, unknown>>,
568
872
  ): Observable<ContextItem<Record<string, unknown>>> {
@@ -590,12 +894,31 @@ export class ContextProvider implements IContextProvider {
590
894
  );
591
895
  }
592
896
 
897
+ /**
898
+ * Asynchronously resolves the provided context item.
899
+ *
900
+ * @see {@link resolveContext} for more details.
901
+ *
902
+ * @param item - The context item to resolve.
903
+ * @returns A promise that resolves to the resolved context item.
904
+ */
593
905
  public resolveContextAsync(
594
906
  item: ContextItem<Record<string, unknown>>,
595
907
  ): Promise<ContextItem<Record<string, unknown>>> {
596
908
  return lastValueFrom(this.resolveContext(item));
597
909
  }
598
910
 
911
+ /**
912
+ * Retrieves related context items based on the provided parameters.
913
+ *
914
+ * This method queries the related context client to fetch an array of context items
915
+ * that are related to the specified parameters. If the related context client is not
916
+ * available, it returns an observable that emits an error.
917
+ *
918
+ * @param args - The parameters used to query for related context items.
919
+ * @returns An Observable that emits an array of related context items.
920
+ * @throws Error if no related context client is defined or if the query fails.
921
+ */
599
922
  public relatedContexts(
600
923
  args: RelatedContextParameters,
601
924
  ): Observable<Array<ContextItem<Record<string, unknown>>>> {
@@ -618,16 +941,36 @@ export class ContextProvider implements IContextProvider {
618
941
  );
619
942
  }
620
943
 
944
+ /**
945
+ * Asynchronously retrieves an array of related context items based on the provided parameters.
946
+ *
947
+ * @see {@link relatedContexts} for more details.
948
+ *
949
+ * @param args - The parameters used to determine which related contexts to retrieve.
950
+ * @returns A promise that resolves to an array of `ContextItem` objects containing generic records.
951
+ */
621
952
  public relatedContextsAsync(
622
953
  args: RelatedContextParameters,
623
954
  ): Promise<Array<ContextItem<Record<string, unknown>>>> {
624
955
  return lastValueFrom(this.relatedContexts(args));
625
956
  }
626
957
 
958
+ /**
959
+ * Clears the current context by setting it to null.
960
+ *
961
+ * This method is typically used to reset or remove the active context,
962
+ * ensuring that subsequent operations do not reference any previous context state.
963
+ */
627
964
  public clearCurrentContext(): void {
628
965
  this.setCurrentContext(null);
629
966
  }
630
967
 
968
+ /**
969
+ * Disposes of resources held by the context provider.
970
+ *
971
+ * Unsubscribes from all active subscriptions and disposes of the context client,
972
+ * ensuring that any allocated resources are properly released.
973
+ */
631
974
  dispose() {
632
975
  this.#subscriptions.unsubscribe();
633
976
  this.#contextClient.dispose();
@@ -10,22 +10,62 @@ import type { ContextItem } from '../types';
10
10
  export type GetContextParameters = { id: string };
11
11
 
12
12
  /**
13
- * @todo - add documentation
13
+ * `ContextClient` is an observable client for managing and retrieving context items.
14
+ *
15
+ * This class extends `Observable<ContextItem | null | undefined>`, allowing consumers to subscribe to context changes.
16
+ * It encapsulates a `Query` instance for fetching context items by ID and maintains the current context state using a `BehaviorSubject`.
17
+ *
18
+ * ### Features
19
+ * - Exposes the current context synchronously and as an observable stream.
20
+ * - Provides methods to set the current context by ID or item, resolving and updating as needed.
21
+ * - Supports asynchronous context resolution with optional await behavior.
22
+ * - Handles errors during context resolution, unwrapping nested causes.
23
+ * - Implements a `dispose` method to clean up internal subscriptions.
24
+ *
25
+ * @template ContextItem The type of the context item managed by the client.
26
+ * @extends Observable<ContextItem | null | undefined>
27
+ *
14
28
  * @todo - should this have `undefined` as a valid value?
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * const client = new ContextClient(options);
33
+ * client.setCurrentContext('context-id');
34
+ * client.currentContext$.subscribe(ctx => { ... });
35
+ * ```
15
36
  */
16
37
  export class ContextClient extends Observable<ContextItem | null | undefined> {
17
38
  #client: Query<ContextItem, { id: string }>;
18
39
  /** might change to reactive state, for comparing state with reducer */
19
40
  #currentContext$: BehaviorSubject<ContextItem | null | undefined>;
20
41
 
42
+ /**
43
+ * Gets the current context item.
44
+ *
45
+ * @returns The current {@link ContextItem}, or `null` if no context is set, or `undefined` if the context has not been initialized.
46
+ */
21
47
  get currentContext(): ContextItem | null | undefined {
22
48
  return this.#currentContext$.value;
23
49
  }
24
50
 
51
+ /**
52
+ * An observable stream that emits the current context item.
53
+ *
54
+ * @remarks
55
+ * This observable emits the current `ContextItem` whenever it changes.
56
+ * It can emit `null` or `undefined` if there is no current context.
57
+ *
58
+ * @returns Observable that emits the current `ContextItem`, `null`, or `undefined`.
59
+ */
25
60
  get currentContext$(): Observable<ContextItem | null | undefined> {
26
61
  return this.#currentContext$.asObservable();
27
62
  }
28
63
 
64
+ /**
65
+ * Gets the query client for retrieving a specific `ContextItem` by its ID.
66
+ *
67
+ * @returns A `Query` instance configured to fetch a `ContextItem` using an object containing an `id` property.
68
+ */
29
69
  get client(): Query<ContextItem, { id: string }> {
30
70
  return this.#client;
31
71
  }
@@ -36,7 +76,15 @@ export class ContextClient extends Observable<ContextItem | null | undefined> {
36
76
  this.#currentContext$ = new BehaviorSubject<ContextItem | null | undefined>(undefined);
37
77
  }
38
78
 
39
- public setCurrentContext(idOrItem?: string | ContextItem | null) {
79
+ /**
80
+ * Sets the current context based on the provided identifier or context item.
81
+ *
82
+ * If a string identifier is provided, attempts to resolve the corresponding context asynchronously.
83
+ * If a `ContextItem` or `null` is provided, updates the current context only if it differs from the existing one.
84
+ *
85
+ * @param idOrItem - The context identifier (string), a `ContextItem`, or `null`. If omitted, the current context may be cleared.
86
+ */
87
+ public setCurrentContext(idOrItem?: string | ContextItem | null): void {
40
88
  if (typeof idOrItem === 'string') {
41
89
  // TODO - compare context
42
90
  this.resolveContext(idOrItem)
@@ -49,6 +97,13 @@ export class ContextClient extends Observable<ContextItem | null | undefined> {
49
97
  }
50
98
  }
51
99
 
100
+ /**
101
+ * Resolves a context item by its unique identifier.
102
+ *
103
+ * @param id - The unique identifier of the context item to resolve.
104
+ * @returns An Observable that emits the resolved {@link ContextItem}.
105
+ * @throws Rethrows the underlying error cause if present, otherwise throws the original error.
106
+ */
52
107
  public resolveContext(id: string): Observable<ContextItem> {
53
108
  return this.#client.query({ id }).pipe(
54
109
  map((x) => x.value),
@@ -62,6 +117,15 @@ export class ContextClient extends Observable<ContextItem | null | undefined> {
62
117
  );
63
118
  }
64
119
 
120
+ /**
121
+ * Resolves a context item asynchronously by its ID.
122
+ *
123
+ * @param id - The unique identifier of the context item to resolve.
124
+ * @param opt - Optional settings for resolution.
125
+ * @param opt.awaitResolve - If true, waits for the observable to complete and returns the last emitted value;
126
+ * otherwise, returns the first emitted value.
127
+ * @returns A promise that resolves to the requested {@link ContextItem}.
128
+ */
65
129
  public resolveContextAsync(id: string, opt?: { awaitResolve: boolean }): Promise<ContextItem> {
66
130
  const fn = opt?.awaitResolve ? lastValueFrom : firstValueFrom;
67
131
  return fn(this.resolveContext(id));