@equinor/fusion-framework-module-bookmark 4.0.2 → 4.0.4

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 (117) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/esm/BookmarkClient.js +18 -3
  3. package/dist/esm/BookmarkClient.js.map +1 -1
  4. package/dist/esm/{BookmarkProvider.error.js → BookmarkFlowError.js} +9 -7
  5. package/dist/esm/BookmarkFlowError.js.map +1 -0
  6. package/dist/esm/{BookmarkConfigurator.js → BookmarkModuleConfigurator.js} +38 -6
  7. package/dist/esm/BookmarkModuleConfigurator.js.map +1 -0
  8. package/dist/esm/BookmarkProvider.js +112 -23
  9. package/dist/esm/BookmarkProvider.js.map +1 -1
  10. package/dist/esm/BookmarkProvider.selectors.js +8 -0
  11. package/dist/esm/BookmarkProvider.selectors.js.map +1 -1
  12. package/dist/esm/BookmarkProviderError.js +20 -0
  13. package/dist/esm/BookmarkProviderError.js.map +1 -0
  14. package/dist/esm/{BookmarkProvider.actions.js → bookmark-actions.js} +1 -1
  15. package/dist/esm/bookmark-actions.js.map +1 -0
  16. package/dist/esm/bookmark-config.schema.js +2 -0
  17. package/dist/esm/bookmark-config.schema.js.map +1 -1
  18. package/dist/esm/bookmark-flows/bookmark-api-flows.js +28 -0
  19. package/dist/esm/bookmark-flows/bookmark-api-flows.js.map +1 -0
  20. package/dist/esm/bookmark-flows/handle-add-bookmark-as-favorite.js +27 -0
  21. package/dist/esm/bookmark-flows/handle-add-bookmark-as-favorite.js.map +1 -0
  22. package/dist/esm/bookmark-flows/handle-create-bookmark.js +27 -0
  23. package/dist/esm/bookmark-flows/handle-create-bookmark.js.map +1 -0
  24. package/dist/esm/bookmark-flows/handle-delete-bookmark.js +26 -0
  25. package/dist/esm/bookmark-flows/handle-delete-bookmark.js.map +1 -0
  26. package/dist/esm/bookmark-flows/handle-fetch-all-bookmark.js +29 -0
  27. package/dist/esm/bookmark-flows/handle-fetch-all-bookmark.js.map +1 -0
  28. package/dist/esm/bookmark-flows/handle-fetch-bookmark-data.js +26 -0
  29. package/dist/esm/bookmark-flows/handle-fetch-bookmark-data.js.map +1 -0
  30. package/dist/esm/bookmark-flows/handle-fetch-bookmark.js +30 -0
  31. package/dist/esm/bookmark-flows/handle-fetch-bookmark.js.map +1 -0
  32. package/dist/esm/bookmark-flows/handle-remove-bookmark-from-favorites.js +28 -0
  33. package/dist/esm/bookmark-flows/handle-remove-bookmark-from-favorites.js.map +1 -0
  34. package/dist/esm/bookmark-flows/handle-remove-bookmark.js +49 -0
  35. package/dist/esm/bookmark-flows/handle-remove-bookmark.js.map +1 -0
  36. package/dist/esm/bookmark-flows/handle-update-bookmark.js +28 -0
  37. package/dist/esm/bookmark-flows/handle-update-bookmark.js.map +1 -0
  38. package/dist/esm/bookmark-flows/index.js +11 -0
  39. package/dist/esm/bookmark-flows/index.js.map +1 -0
  40. package/dist/esm/bookmark-module.js +2 -2
  41. package/dist/esm/bookmark-module.js.map +1 -1
  42. package/dist/esm/bookmark.schemas.js +9 -3
  43. package/dist/esm/bookmark.schemas.js.map +1 -1
  44. package/dist/esm/create-bookmark-reducer.js +122 -0
  45. package/dist/esm/create-bookmark-reducer.js.map +1 -0
  46. package/dist/esm/{BookmarkProvider.store.js → create-bookmark-store.js} +3 -3
  47. package/dist/esm/create-bookmark-store.js.map +1 -0
  48. package/dist/esm/enable-bookmark.js +2 -1
  49. package/dist/esm/enable-bookmark.js.map +1 -1
  50. package/dist/esm/index.js +12 -1
  51. package/dist/esm/index.js.map +1 -1
  52. package/dist/esm/version.js +1 -1
  53. package/dist/tsconfig.tsbuildinfo +1 -1
  54. package/dist/types/BookmarkClient.d.ts +1 -0
  55. package/dist/types/{BookmarkProvider.error.d.ts → BookmarkFlowError.d.ts} +9 -4
  56. package/dist/types/{BookmarkConfigurator.d.ts → BookmarkModuleConfigurator.d.ts} +10 -4
  57. package/dist/types/BookmarkProvider.d.ts +81 -18
  58. package/dist/types/BookmarkProvider.interface.d.ts +1 -1
  59. package/dist/types/BookmarkProvider.selectors.d.ts +3 -3
  60. package/dist/types/BookmarkProviderError.d.ts +16 -0
  61. package/dist/types/{BookmarkProvider.actions.d.ts → bookmark-actions.d.ts} +3 -3
  62. package/dist/types/bookmark-flows/bookmark-api-flows.d.ts +11 -0
  63. package/dist/types/bookmark-flows/handle-add-bookmark-as-favorite.d.ts +10 -0
  64. package/dist/types/bookmark-flows/handle-create-bookmark.d.ts +10 -0
  65. package/dist/types/bookmark-flows/handle-delete-bookmark.d.ts +10 -0
  66. package/dist/types/bookmark-flows/handle-fetch-all-bookmark.d.ts +10 -0
  67. package/dist/types/bookmark-flows/handle-fetch-bookmark-data.d.ts +10 -0
  68. package/dist/types/bookmark-flows/handle-fetch-bookmark.d.ts +10 -0
  69. package/dist/types/bookmark-flows/handle-remove-bookmark-from-favorites.d.ts +10 -0
  70. package/dist/types/bookmark-flows/handle-remove-bookmark.d.ts +14 -0
  71. package/dist/types/bookmark-flows/handle-update-bookmark.d.ts +10 -0
  72. package/dist/types/bookmark-flows/index.d.ts +10 -0
  73. package/dist/types/bookmark-module.d.ts +1 -1
  74. package/dist/types/{BookmarkProvider.reducer.d.ts → create-bookmark-reducer.d.ts} +39 -39
  75. package/dist/types/{BookmarkProvider.store.d.ts → create-bookmark-store.d.ts} +2 -2
  76. package/dist/types/enable-bookmark.d.ts +1 -1
  77. package/dist/types/index.d.ts +12 -1
  78. package/dist/types/version.d.ts +1 -1
  79. package/package.json +11 -11
  80. package/src/BookmarkClient.ts +21 -3
  81. package/src/{BookmarkProvider.error.ts → BookmarkFlowError.ts} +9 -7
  82. package/src/{BookmarkConfigurator.ts → BookmarkModuleConfigurator.ts} +42 -12
  83. package/src/BookmarkProvider.interface.ts +3 -2
  84. package/src/BookmarkProvider.selectors.ts +10 -2
  85. package/src/BookmarkProvider.ts +112 -23
  86. package/src/BookmarkProviderError.ts +19 -0
  87. package/src/{BookmarkProvider.actions.ts → bookmark-actions.ts} +1 -1
  88. package/src/bookmark-config.schema.ts +2 -0
  89. package/src/bookmark-flows/bookmark-api-flows.ts +45 -0
  90. package/src/bookmark-flows/handle-add-bookmark-as-favorite.ts +49 -0
  91. package/src/bookmark-flows/handle-create-bookmark.ts +47 -0
  92. package/src/bookmark-flows/handle-delete-bookmark.ts +47 -0
  93. package/src/bookmark-flows/handle-fetch-all-bookmark.ts +53 -0
  94. package/src/bookmark-flows/handle-fetch-bookmark-data.ts +58 -0
  95. package/src/bookmark-flows/handle-fetch-bookmark.ts +64 -0
  96. package/src/bookmark-flows/handle-remove-bookmark-from-favorites.ts +49 -0
  97. package/src/bookmark-flows/handle-remove-bookmark.ts +76 -0
  98. package/src/bookmark-flows/handle-update-bookmark.ts +48 -0
  99. package/src/bookmark-flows/index.ts +10 -0
  100. package/src/bookmark-module.ts +2 -2
  101. package/src/bookmark.schemas.ts +10 -4
  102. package/src/create-bookmark-reducer.ts +149 -0
  103. package/src/{BookmarkProvider.store.ts → create-bookmark-store.ts} +4 -4
  104. package/src/enable-bookmark.ts +3 -2
  105. package/src/index.ts +12 -1
  106. package/src/version.ts +1 -1
  107. package/dist/esm/BookmarkConfigurator.js.map +0 -1
  108. package/dist/esm/BookmarkProvider.actions.js.map +0 -1
  109. package/dist/esm/BookmarkProvider.error.js.map +0 -1
  110. package/dist/esm/BookmarkProvider.flows.js +0 -217
  111. package/dist/esm/BookmarkProvider.flows.js.map +0 -1
  112. package/dist/esm/BookmarkProvider.reducer.js +0 -113
  113. package/dist/esm/BookmarkProvider.reducer.js.map +0 -1
  114. package/dist/esm/BookmarkProvider.store.js.map +0 -1
  115. package/dist/types/BookmarkProvider.flows.d.ts +0 -79
  116. package/src/BookmarkProvider.flows.ts +0 -421
  117. package/src/BookmarkProvider.reducer.ts +0 -144
@@ -36,12 +36,12 @@ import type {
36
36
  } from './types';
37
37
 
38
38
  import type { BookmarkNew, BookmarkUpdate, IBookmarkClient } from './BookmarkClient.interface';
39
- import { type BookmarkActions, bookmarkActions } from './BookmarkProvider.actions';
39
+ import { type BookmarkActions, bookmarkActions } from './bookmark-actions';
40
40
  import {
41
41
  type BookmarkState,
42
42
  createBookmarkStore,
43
43
  type BookmarkStore,
44
- } from './BookmarkProvider.store';
44
+ } from './create-bookmark-store';
45
45
  import {
46
46
  activeBookmarkSelector,
47
47
  bookmarkSelector,
@@ -49,7 +49,7 @@ import {
49
49
  errorsSelector,
50
50
  } from './BookmarkProvider.selectors';
51
51
 
52
- import { type BookmarkFlowError, BookmarkProviderError } from './BookmarkProvider.error';
52
+ import { type BookmarkFlowError, BookmarkProviderError } from './BookmarkFlowError';
53
53
 
54
54
  import type { BookmarkProviderEventMap } from './BookmarkProvider.events';
55
55
  import { version } from './version';
@@ -93,7 +93,7 @@ export class BookmarkProvider implements IBookmarkProvider {
93
93
  return {
94
94
  getCurrentAppIdentification() {
95
95
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
96
- // @ts-ignore
96
+ // @ts-expect-error
97
97
  return window.Fusion.modules.app.current.appKey;
98
98
  },
99
99
  };
@@ -102,6 +102,9 @@ export class BookmarkProvider implements IBookmarkProvider {
102
102
  /**
103
103
  * @deprecated
104
104
  * this will be removed as soon as applications have been migrated to use the bookmark provider
105
+ * @param fn - The payload generator callback to register.
106
+ * @template T - The bookmark data type produced by the generator.
107
+ * @returns A function that unregisters the payload generator when called.
105
108
  */
106
109
  addStateCreator<T extends BookmarkData>(fn: BookmarkPayloadGenerator<T>) {
107
110
  console.warn('addStateCreator is deprecated, use addPayloadGenerator instead');
@@ -111,6 +114,7 @@ export class BookmarkProvider implements IBookmarkProvider {
111
114
  /**
112
115
  * @deprecated
113
116
  * this will be removed as soon as applications have been migrated to use the bookmark provider
117
+ * @param id - The ID of the bookmark to delete.
114
118
  */
115
119
  deleteBookmarkByIdAsync(id: string): Promise<void> {
116
120
  console.warn('deleteBookmarkByIdAsync is deprecated, use deleteBookmarkAsync instead');
@@ -120,6 +124,8 @@ export class BookmarkProvider implements IBookmarkProvider {
120
124
  /**
121
125
  * @deprecated
122
126
  * this will be removed as soon as applications have been migrated to use the bookmark provider
127
+ * @param id - The ID of the bookmark to add as a favorite.
128
+ * @returns The updated bookmark, or undefined if it could not be found.
123
129
  */
124
130
  addBookmarkFavoriteAsync(id: string): Promise<Bookmark | undefined> {
125
131
  console.warn('addBookmarkFavoriteAsync is deprecated, use addBookmarkToFavoritesAsync instead');
@@ -129,6 +135,7 @@ export class BookmarkProvider implements IBookmarkProvider {
129
135
  /**
130
136
  * @deprecated
131
137
  * this will be removed as soon as applications have been migrated to use the bookmark provider
138
+ * @param id - The ID of the bookmark to remove as a favorite.
132
139
  */
133
140
  removeBookmarkFavoriteAsync(id: string): Promise<void> {
134
141
  console.warn(
@@ -140,6 +147,8 @@ export class BookmarkProvider implements IBookmarkProvider {
140
147
  /**
141
148
  * @deprecated
142
149
  * this will be removed as soon as applications have been migrated to use the bookmark provider
150
+ * @param id - The ID of the bookmark to get.
151
+ * @returns The bookmark, or null if it could not be found.
143
152
  */
144
153
  getBookmarkById(id: string): Promise<Bookmark | null> {
145
154
  console.warn('getBookmarkById is deprecated, use getBookmarkAsync instead');
@@ -148,18 +157,21 @@ export class BookmarkProvider implements IBookmarkProvider {
148
157
 
149
158
  /**
150
159
  * Gets the semantic version of the bookmark provider.
160
+ * @returns The semantic version of the bookmark provider.
151
161
  */
152
162
  public get version(): SemanticVersion {
153
163
  return new SemanticVersion(version);
154
164
  }
155
165
 
166
+ /** @returns The configured bookmark filters. */
156
167
  public get filters(): BookmarkModuleConfig['filters'] {
157
- // TODO - freeze the config object?
168
+ // TODO(#5136) - freeze the config object?
158
169
  return this.#config.filters;
159
170
  }
160
171
 
161
172
  /**
162
173
  * Gets the `IBookmarkClient` instance used by this `BookmarkProvider`.
174
+ * @returns The `IBookmarkClient` instance.
163
175
  */
164
176
  public get client(): IBookmarkClient {
165
177
  return this.#config.client;
@@ -167,6 +179,7 @@ export class BookmarkProvider implements IBookmarkProvider {
167
179
 
168
180
  /**
169
181
  * Gets the currently active bookmark (if any).
182
+ * @returns An observable of the currently active bookmark.
170
183
  */
171
184
  public get currentBookmark$(): Observable<Bookmark | null | undefined> {
172
185
  return this.#store.select(activeBookmarkSelector);
@@ -174,6 +187,7 @@ export class BookmarkProvider implements IBookmarkProvider {
174
187
 
175
188
  /**
176
189
  * Gets an observable that emits the current list of bookmarks.
190
+ * @returns An observable of the current list of bookmarks.
177
191
  */
178
192
  public get bookmarks$(): Observable<Array<BookmarkWithoutData>> {
179
193
  this.getAllBookmarksAsync();
@@ -182,6 +196,7 @@ export class BookmarkProvider implements IBookmarkProvider {
182
196
 
183
197
  /**
184
198
  * Gets the current list of bookmarks.
199
+ * @returns The current list of bookmarks.
185
200
  */
186
201
  public get bookmarks(): Array<BookmarkWithoutData> {
187
202
  return bookmarksSelector(this.#store.value);
@@ -189,6 +204,7 @@ export class BookmarkProvider implements IBookmarkProvider {
189
204
 
190
205
  /**
191
206
  * Gets the currently active bookmark.
207
+ * @returns The currently active bookmark, or null/undefined if there is none.
192
208
  */
193
209
  public get currentBookmark(): Bookmark | null | undefined {
194
210
  const bookmark = activeBookmarkSelector(this.#store.value);
@@ -197,6 +213,7 @@ export class BookmarkProvider implements IBookmarkProvider {
197
213
 
198
214
  /**
199
215
  * Represents an observable stream of the bookmark status.
216
+ * @returns An observable of the bookmark status.
200
217
  */
201
218
  public get status$(): Observable<BookmarkState['status']> {
202
219
  return this.#store.select((x) => x.status);
@@ -204,15 +221,16 @@ export class BookmarkProvider implements IBookmarkProvider {
204
221
 
205
222
  /**
206
223
  * Gets an observable that emits the current list of bookmark errors.
224
+ * @returns An observable of the current list of bookmark errors.
207
225
  */
208
226
  public get errors$(): Observable<Array<BookmarkFlowError>> {
209
- // TODO - add deep diff
227
+ // TODO(#5137) - add deep diff
210
228
  return this.#store.select(errorsSelector, deepEqual);
211
229
  }
212
230
 
213
231
  /**
214
232
  * Determines whether there are any bookmark creators configured.
215
- * `true` if there are any bookmark creators configured, `false` otherwise.
233
+ * @returns `true` if there are any bookmark creators configured, `false` otherwise.
216
234
  */
217
235
  public get canCreateBookmarks(): boolean {
218
236
  return this.#payloadGenerators.length > 0;
@@ -220,6 +238,7 @@ export class BookmarkProvider implements IBookmarkProvider {
220
238
 
221
239
  /**
222
240
  * Gets the source system value from the configuration.
241
+ * @returns The source system value.
223
242
  */
224
243
  public get sourceSystem(): BookmarkModuleConfig['sourceSystem'] {
225
244
  return this.#config.sourceSystem;
@@ -227,6 +246,7 @@ export class BookmarkProvider implements IBookmarkProvider {
227
246
 
228
247
  /**
229
248
  * Gets the resolved application from the bookmark module configuration.
249
+ * @returns The resolved application resolver.
230
250
  */
231
251
  public get resolvedApplication(): BookmarkModuleConfig['resolve']['application'] {
232
252
  return this.#config.resolve.application;
@@ -234,17 +254,23 @@ export class BookmarkProvider implements IBookmarkProvider {
234
254
 
235
255
  /**
236
256
  * Gets the resolved context from the bookmark module configuration.
257
+ * @returns The resolved context resolver.
237
258
  */
238
259
  public get resolvedContext(): BookmarkModuleConfig['resolve']['context'] {
239
260
  return this.#config.resolve.context;
240
261
  }
241
262
 
263
+ /**
264
+ * @internal The API client used to communicate with the bookmark backend.
265
+ * @returns The configured `IBookmarkClient` instance.
266
+ */
242
267
  protected get _apiClient(): IBookmarkClient {
243
268
  return this.#config.client;
244
269
  }
245
270
 
246
271
  /**
247
272
  * configured logger instance.
273
+ * @returns The configured logger.
248
274
  */
249
275
  protected get _log(): BookmarkModuleConfig['log'] {
250
276
  return this.#config.log;
@@ -252,6 +278,7 @@ export class BookmarkProvider implements IBookmarkProvider {
252
278
 
253
279
  /**
254
280
  * configured resolvers
281
+ * @returns The configured resolvers.
255
282
  */
256
283
  protected get _resolve(): BookmarkModuleConfig['resolve'] {
257
284
  return this.#config.resolve;
@@ -259,6 +286,7 @@ export class BookmarkProvider implements IBookmarkProvider {
259
286
 
260
287
  /**
261
288
  * configured event provider.
289
+ * @returns The configured event provider.
262
290
  */
263
291
  protected get _event(): BookmarkModuleConfig['eventProvider'] {
264
292
  return this.#config.eventProvider;
@@ -266,6 +294,7 @@ export class BookmarkProvider implements IBookmarkProvider {
266
294
 
267
295
  /**
268
296
  * configured parent bookmark provider
297
+ * @returns The configured parent bookmark provider.
269
298
  */
270
299
  protected get _parent(): BookmarkModuleConfig['parent'] {
271
300
  return this.#config.parent;
@@ -290,6 +319,7 @@ export class BookmarkProvider implements IBookmarkProvider {
290
319
  // subscribe to the store actions and log them
291
320
  this.#subscriptions.add(
292
321
  this.#store.action$.subscribe((action) => {
322
+ // log failure actions as errors, everything else as debug
293
323
  if (isFailureAction(action)) {
294
324
  this._log?.error(`Action: ${action.type}`, action);
295
325
  } else {
@@ -309,7 +339,7 @@ export class BookmarkProvider implements IBookmarkProvider {
309
339
  );
310
340
 
311
341
  // subscribe to child bookmark provider changes
312
- // TODO - add support for disabling this feature
342
+ // TODO(#5138) - add support for disabling this feature
313
343
  if (this._event) {
314
344
  this._event.addEventListener('onCurrentBookmarkChanged', (event) => {
315
345
  const { source, detail } = event;
@@ -324,11 +354,12 @@ export class BookmarkProvider implements IBookmarkProvider {
324
354
  });
325
355
  }
326
356
 
357
+ // if a parent bookmark provider is configured, subscribe to its current bookmark changes
327
358
  if (this._parent) {
328
- // if a parent bookmark provider is configured, subscribe to its current bookmark changes
329
359
  try {
330
360
  this.#subscriptions.add(
331
361
  this._parent.currentBookmark$
362
+ // only forward defined bookmarks that differ from the current one
332
363
  .pipe(
333
364
  filter((x): x is Bookmark => x !== undefined),
334
365
  filter((x) => x !== this.currentBookmark),
@@ -346,6 +377,7 @@ export class BookmarkProvider implements IBookmarkProvider {
346
377
  /**
347
378
  * Registers an event listener for the specified event on the BookmarkProvider.
348
379
  *
380
+ * @template TType - The key of the `BookmarkProviderEventMap` identifying the event.
349
381
  * @param eventName - The name of the event to listen for. Must be a key of the `BookmarkProviderEventMap` type.
350
382
  * @param callback - The callback function to be invoked when the event is triggered.
351
383
  * The callback will receive the event object as its parameter, which will be of the type corresponding to the `eventName`.
@@ -355,6 +387,7 @@ export class BookmarkProvider implements IBookmarkProvider {
355
387
  eventName: TType,
356
388
  callback: (event: BookmarkProviderEventMap[TType]) => void,
357
389
  ): VoidFunction {
390
+ // without an event provider, registering a listener would be a no-op
358
391
  if (!this._event) {
359
392
  this._log?.warn('Failed to register event listener, event provider not configured');
360
393
  return () => {
@@ -362,6 +395,7 @@ export class BookmarkProvider implements IBookmarkProvider {
362
395
  };
363
396
  }
364
397
  return this._event.addEventListener(eventName, (event) => {
398
+ // only forward events originating from this provider instance
365
399
  if (event.source === this) {
366
400
  callback(event);
367
401
  }
@@ -371,6 +405,7 @@ export class BookmarkProvider implements IBookmarkProvider {
371
405
  * Adds a new payload generator function to the BookmarkProvider.
372
406
  * The payload generator function will be used to generate the payload for a bookmark-related action.
373
407
  *
408
+ * @template T - The type of the bookmark data the payload generator produces.
374
409
  * @param fn - The payload generator function to add. It should be of type `PayloadGenerator<T>`, where `T` is the type of the bookmark data.
375
410
  * @returns A function that can be called to remove the added payload generator.
376
411
  */
@@ -390,6 +425,7 @@ export class BookmarkProvider implements IBookmarkProvider {
390
425
  // return a function to remove the added payload generator
391
426
  return () => {
392
427
  this._log?.debug(`removing bookmark payload generator: ${fn.name}`);
428
+ // drop the matching generator reference from the registered list
393
429
  this.#payloadGenerators = this.#payloadGenerators.filter((g) => g !== fn);
394
430
  };
395
431
  }
@@ -478,6 +514,7 @@ export class BookmarkProvider implements IBookmarkProvider {
478
514
  * @param bookmarkId The unique identifier of the bookmark.
479
515
  * @param options An optional object that allows excluding the bookmark payload from the result.
480
516
  * @returns An observable that emits the combined result of fetching the bookmark and bookmark data.
517
+ * @throws The error encountered while fetching the bookmark or its data, after logging it.
481
518
  */
482
519
  public getBookmark<T extends BookmarkData = BookmarkData>(
483
520
  bookmarkId: string,
@@ -505,6 +542,7 @@ export class BookmarkProvider implements IBookmarkProvider {
505
542
  /**
506
543
  * Retrieves a bookmark asynchronously.
507
544
  *
545
+ * @template T - The type of the bookmark payload.
508
546
  * @param id - The ID of the bookmark to retrieve.
509
547
  * @param options - Optional parameters for the retrieval.
510
548
  * @param options.excludePayload - Specifies whether to exclude the payload from the bookmark.
@@ -647,6 +685,7 @@ export class BookmarkProvider implements IBookmarkProvider {
647
685
  * @param bookmark_or_id - The bookmark or ID to set as the current bookmark.
648
686
  * @returns An observable that emits the next bookmark or null.
649
687
  * @template T - The type of the bookmark data.
688
+ * @throws {BookmarkProviderError} If the onCurrentBookmarkChange event is canceled by a listener, or resolving the bookmark fails.
650
689
  */
651
690
  public setCurrentBookmark<T extends BookmarkData = BookmarkData>(
652
691
  bookmark_or_id: Bookmark<T> | string | null,
@@ -659,12 +698,14 @@ export class BookmarkProvider implements IBookmarkProvider {
659
698
  ? this.getBookmark<T>(bookmark_or_id)
660
699
  : of(bookmark_or_id ?? null);
661
700
 
701
+ // notify listeners before committing the next bookmark to the store
662
702
  return next$.pipe(
663
703
  switchMap(async (next) => {
664
704
  const current = this.currentBookmark;
665
705
  const { type, canceled } = await this._dispatchEvent('onCurrentBookmarkChange', {
666
706
  detail: { current, next },
667
707
  });
708
+ // throw an error if the event is canceled
668
709
  if (canceled) {
669
710
  const error = new BookmarkProviderError(
670
711
  `event: ${type} was canceled by listener for change to ${next?.id ?? 'none'}, from ${current?.id ?? 'none'}`,
@@ -691,14 +732,11 @@ export class BookmarkProvider implements IBookmarkProvider {
691
732
  }
692
733
 
693
734
  /**
694
- * Sets the current bookmark.
695
- * This method dispatches an event to notify listeners of a change in the current bookmark,
696
- * and then dispatches a request to set the active bookmark in the application state.
735
+ * Sets the current bookmark asynchronously.
697
736
  *
698
- * The request will be canceled if the subscription is unsubscribed before the request completes.
699
- *
700
- * @param bookmarkId - The ID of the bookmark to set as the current bookmark.
701
- * @returns A subscription to the operation that sets the current bookmark.
737
+ * @template T - The type of the bookmark data.
738
+ * @param bookmark_or_id - The bookmark or ID to set as the current bookmark.
739
+ * @returns A promise that resolves to the next bookmark or null.
702
740
  */
703
741
  public setCurrentBookmarkAsync<T extends BookmarkData = BookmarkData>(
704
742
  bookmark_or_id: Bookmark<T> | string | null,
@@ -712,6 +750,7 @@ export class BookmarkProvider implements IBookmarkProvider {
712
750
  * @template T - The type of bookmark data.
713
751
  * @param {BookmarkCreateArgs<T>} newBookmarkData - The data for creating the bookmark.
714
752
  * @returns {Observable<Bookmark<T>>} - An observable that emits the created bookmark.
753
+ * @throws {BookmarkProviderError} If resolving the bookmark data fails, the onBookmarkCreate event is canceled, the create request fails, or the request times out.
715
754
  */
716
755
  public createBookmark<T extends BookmarkData = BookmarkData>(
717
756
  newBookmarkData: BookmarkCreateArgs<T>,
@@ -726,6 +765,7 @@ export class BookmarkProvider implements IBookmarkProvider {
726
765
  ? of(newBookmarkData.appKey)
727
766
  : defer(() => this._resolve.application()).pipe(
728
767
  map((app) => {
768
+ // the application must resolve to a valid appKey to attribute the bookmark
729
769
  if (!app?.appKey) {
730
770
  throw new BookmarkProviderError('Failed to resolve application key');
731
771
  }
@@ -830,7 +870,8 @@ export class BookmarkProvider implements IBookmarkProvider {
830
870
  /**
831
871
  * Asynchronously creates a new bookmark.
832
872
  *
833
- * @param bookmark - The new bookmark to create.
873
+ * @template T - The type of bookmark data.
874
+ * @param args - The data for creating the bookmark.
834
875
  * @returns A promise that resolves to the created bookmark with its associated data.
835
876
  */
836
877
  public createBookmarkAsync<T extends BookmarkData = BookmarkData>(
@@ -848,12 +889,14 @@ export class BookmarkProvider implements IBookmarkProvider {
848
889
  * @param {BookmarkUpdate<T>} [bookmarkUpdates] - The updates to apply to the bookmark.
849
890
  * @param {BookmarkUpdateOptions} [options] - The options for updating the bookmark.
850
891
  * @returns {Observable<Bookmark<T>>} - An observable that emits the updated bookmark.
892
+ * @throws {BookmarkProviderError} If bookmarkUpdates is omitted while excludePayloadGeneration is set, generating the payload fails, the onBookmarkUpdate event is canceled, the update request fails, or the request times out.
851
893
  */
852
894
  public updateBookmark<T extends BookmarkData = BookmarkData>(
853
895
  bookmarkId: string,
854
896
  bookmarkUpdates?: BookmarkUpdate<T>,
855
897
  options?: BookmarkUpdateOptions,
856
898
  ): Observable<Bookmark<T>> {
899
+ // bookmarkUpdates is required unless the caller opts out of payload generation entirely
857
900
  if (!bookmarkUpdates && options?.excludePayloadGeneration) {
858
901
  throw new BookmarkProviderError(
859
902
  'Cannot update bookmark without updates and excludePayloadGeneration option',
@@ -893,6 +936,7 @@ export class BookmarkProvider implements IBookmarkProvider {
893
936
  cancelable: true,
894
937
  });
895
938
 
939
+ // throw an error if the event is canceled
896
940
  if (canceled) {
897
941
  const error = new BookmarkProviderError(
898
942
  `event: ${type} was canceled by listener for updating bookmark: ${bookmarkId}, ref: ${ref}`,
@@ -938,7 +982,7 @@ export class BookmarkProvider implements IBookmarkProvider {
938
982
  const request$ = action$.pipe(
939
983
  filter(bookmarkActions.updateBookmark.success.match),
940
984
  map(
941
- // TODO: add payload if current bookmark is the same as the updated bookmark
985
+ // TODO(#5139): add payload if current bookmark is the same as the updated bookmark
942
986
  ({ payload }): Bookmark<T> =>
943
987
  ({
944
988
  ...bookmarkSelector(this.#store.value, payload.id),
@@ -966,9 +1010,12 @@ export class BookmarkProvider implements IBookmarkProvider {
966
1010
  /**
967
1011
  * Updates a bookmark asynchronously.
968
1012
  *
969
- * @todo - remove the deprecated method in the next major version
1013
+ * @todo TODO(#5140) - remove the deprecated overload accepting a full bookmark in the next major version
970
1014
  *
971
- * @param bookmark - The bookmark to update.
1015
+ * @template T - The type of the bookmark data.
1016
+ * @param id_or_bookmark - The ID of the bookmark to update, or (deprecated) the full bookmark object.
1017
+ * @param updates_or_options - The updates to apply, or (deprecated) the update options when using the bookmark overload.
1018
+ * @param options - The options for updating the bookmark.
972
1019
  * @returns A promise that resolves to the updated bookmark with its associated data.
973
1020
  */
974
1021
  public updateBookmarkAsync<T extends BookmarkData = BookmarkData>(
@@ -976,12 +1023,16 @@ export class BookmarkProvider implements IBookmarkProvider {
976
1023
  updates_or_options?: BookmarkUpdate<T> | BookmarkUpdateOptions,
977
1024
  options?: BookmarkUpdateOptions,
978
1025
  ): Promise<Bookmark<T>> {
1026
+ // support the deprecated overload that accepted a full bookmark instead of an id
979
1027
  if (typeof id_or_bookmark === 'object') {
980
1028
  // @deprecated
981
1029
  console.warn(
982
1030
  'updateBookmarkAsync(bookmark, updates, options) is deprecated, use updateBookmarkAsync(id, updates, options) instead',
983
1031
  );
984
1032
  const { id, ...updates } = id_or_bookmark as Bookmark<T>;
1033
+ // `updates_or_options` is a union of `BookmarkUpdate<T> | BookmarkUpdateOptions` here,
1034
+ // neither of which declares `updatePayload` — cast through `unknown` to probe for the
1035
+ // legacy options shape at runtime.
985
1036
  return lastValueFrom(
986
1037
  this.updateBookmark<T>(id, updates as BookmarkUpdate<T>, {
987
1038
  excludePayloadGeneration: !(
@@ -1023,6 +1074,7 @@ export class BookmarkProvider implements IBookmarkProvider {
1023
1074
  }),
1024
1075
  ).pipe(
1025
1076
  map(({ canceled, type, detail }) => {
1077
+ // throw an error if the event is canceled
1026
1078
  if (canceled) {
1027
1079
  const error = new BookmarkProviderError(
1028
1080
  `event: ${type} was canceled by listener for removing bookmark: ${bookmarkId}, ref: ${ref}`,
@@ -1096,10 +1148,11 @@ export class BookmarkProvider implements IBookmarkProvider {
1096
1148
  }
1097
1149
 
1098
1150
  /**
1099
- * Adds a bookmark to the favorites.
1151
+ * Adds a bookmark to favorites.
1100
1152
  *
1101
1153
  * @param bookmarkId - The ID of the bookmark to add.
1102
- * @returns A Promise that resolves to the added bookmark, or null if the bookmark was not added.
1154
+ * @returns An observable that emits the added bookmark, or undefined if it could not be resolved.
1155
+ * @throws {BookmarkProviderError} If the onBookmarkFavouriteAdd event is canceled, the add request fails, or the request times out.
1103
1156
  */
1104
1157
  public addBookmarkToFavorites(bookmarkId: string): Observable<BookmarkWithoutData | undefined> {
1105
1158
  /**
@@ -1119,6 +1172,7 @@ export class BookmarkProvider implements IBookmarkProvider {
1119
1172
  }),
1120
1173
  ).pipe(
1121
1174
  map(({ canceled, type }) => {
1175
+ // throw an error if the event is canceled
1122
1176
  if (canceled) {
1123
1177
  const error = new BookmarkProviderError(
1124
1178
  `event: ${type} was canceled by listener for adding favourite bookmark: ${bookmarkId}, ref: ${ref}`,
@@ -1216,6 +1270,7 @@ export class BookmarkProvider implements IBookmarkProvider {
1216
1270
  }),
1217
1271
  ).pipe(
1218
1272
  map(({ canceled, type, detail }) => {
1273
+ // throw an error if the event is canceled
1219
1274
  if (canceled) {
1220
1275
  const error = new BookmarkProviderError(
1221
1276
  `event: ${type} was canceled by listener for removing favourite bookmark: ${bookmarkId}, ref: ${ref}`,
@@ -1293,7 +1348,8 @@ export class BookmarkProvider implements IBookmarkProvider {
1293
1348
  /**
1294
1349
  * Checks if a bookmark is in the favorites.
1295
1350
  * @param bookmarkId - The ID of the bookmark to check.
1296
- * @returns A promise that resolves to a boolean indicating whether the bookmark is in the favorites.
1351
+ * @returns An observable that emits a boolean indicating whether the bookmark is in the favorites.
1352
+ * @throws {BookmarkProviderError} If checking the favorite status fails.
1297
1353
  */
1298
1354
  public isBookmarkInFavorites(bookmarkId: string): Observable<boolean> {
1299
1355
  this._log?.debug(`Checking if bookmark: ${bookmarkId} is in favourites`);
@@ -1324,6 +1380,14 @@ export class BookmarkProvider implements IBookmarkProvider {
1324
1380
  return lastValueFrom(this.isBookmarkInFavorites(bookmarkId));
1325
1381
  }
1326
1382
 
1383
+ /**
1384
+ * Fetches a single bookmark's metadata (without payload) via the store.
1385
+ *
1386
+ * @param bookmarkId - The unique identifier of the bookmark to fetch.
1387
+ * @param options - Optional settings, including a custom `timeout` in milliseconds.
1388
+ * @returns An observable that emits the bookmark's metadata once fetched.
1389
+ * @throws {BookmarkProviderError} If the fetch fails or times out.
1390
+ */
1327
1391
  protected _getBookmarkInfo(
1328
1392
  bookmarkId: string,
1329
1393
  options?: { timeout?: number },
@@ -1357,9 +1421,19 @@ export class BookmarkProvider implements IBookmarkProvider {
1357
1421
 
1358
1422
  this.#store.next(bookmarkActions.fetchBookmark(bookmarkId, { ref: bookmarkId }));
1359
1423
 
1424
+ // race the success and failure streams, whichever resolves first wins
1360
1425
  return success$.pipe(raceWith(failure$));
1361
1426
  }
1362
1427
 
1428
+ /**
1429
+ * Fetches a single bookmark's payload data via the store.
1430
+ *
1431
+ * @template T - The type of the bookmark payload.
1432
+ * @param bookmarkId - The unique identifier of the bookmark whose data to fetch.
1433
+ * @param options - Optional settings, including a custom `timeout` in milliseconds.
1434
+ * @returns An observable that emits the bookmark's payload data once fetched.
1435
+ * @throws {BookmarkProviderError} If the fetch fails or times out.
1436
+ */
1363
1437
  protected _getBookmarkData<T extends BookmarkData = BookmarkData>(
1364
1438
  bookmarkId: string,
1365
1439
  options?: { timeout?: number },
@@ -1394,12 +1468,14 @@ export class BookmarkProvider implements IBookmarkProvider {
1394
1468
  // request the store to fetch the bookmark data
1395
1469
  this.#store.next(bookmarkActions.fetchBookmarkData(bookmarkId, { ref: bookmarkId }));
1396
1470
 
1471
+ // race the success and failure streams, whichever resolves first wins
1397
1472
  return success$.pipe(raceWith(failure$));
1398
1473
  }
1399
1474
 
1400
1475
  /**
1401
1476
  * Dispatches an event of the specified type with the provided arguments.
1402
1477
  *
1478
+ * @template TType - The specific event type key being dispatched.
1403
1479
  * @param type - The type of the event to dispatch.
1404
1480
  * @param args - The arguments to pass to the event.
1405
1481
  * @returns A promise that resolves with the result of the event dispatch.
@@ -1415,9 +1491,11 @@ export class BookmarkProvider implements IBookmarkProvider {
1415
1491
  ...args,
1416
1492
  }) as BookmarkProviderEventMap[NoInfer<TType>];
1417
1493
 
1494
+ // only dispatch through the event bus when one is available
1418
1495
  if (this._event) {
1419
1496
  this._log?.debug(`dispatching event ${type}`, args);
1420
1497
  const { canceled } = await this._event.dispatchEvent(event);
1498
+ // log when a listener canceled the event
1421
1499
  if (canceled) {
1422
1500
  this._log?.debug(`event ${type} was canceled`, args);
1423
1501
  }
@@ -1425,6 +1503,14 @@ export class BookmarkProvider implements IBookmarkProvider {
1425
1503
  return event;
1426
1504
  }
1427
1505
 
1506
+ /**
1507
+ * Creates a scoped action reference and a filtered action stream containing only
1508
+ * actions tagged with that reference (or the provided `ref`, if given).
1509
+ *
1510
+ * @template TAction - The specific action type emitted on the scoped stream.
1511
+ * @param ref - An existing reference to scope actions to; a new GUID is generated when omitted.
1512
+ * @returns An object containing the resolved `ref` and the `action$` stream filtered to it.
1513
+ */
1428
1514
  protected _useScopedActions<TAction extends BookmarkActions>(
1429
1515
  ref?: string,
1430
1516
  ): {
@@ -1454,6 +1540,9 @@ export class BookmarkProvider implements IBookmarkProvider {
1454
1540
  this.#subscriptions.unsubscribe();
1455
1541
  }
1456
1542
 
1543
+ /**
1544
+ * Disposes the BookmarkProvider via the `Symbol.dispose` protocol.
1545
+ */
1457
1546
  [Symbol.dispose]() {
1458
1547
  this.dispose();
1459
1548
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * General-purpose error thrown by {@link BookmarkProvider} methods when a
3
+ * high-level operation (create, update, delete, set current, etc.) fails.
4
+ *
5
+ * Distinct from {@link BookmarkFlowError}, which is scoped to internal
6
+ * store flow pipelines.
7
+ */
8
+ export class BookmarkProviderError extends Error {
9
+ /**
10
+ * Constructs a new `BookmarkProviderError`.
11
+ *
12
+ * @param message - Human-readable error message.
13
+ * @param options - Optional `ErrorOptions` (e.g. `cause`).
14
+ */
15
+ constructor(message: string, options?: ErrorOptions) {
16
+ super(message, options);
17
+ this.name = 'BookmarkProviderError';
18
+ }
19
+ }
@@ -8,7 +8,7 @@ import {
8
8
  import type { Bookmark, BookmarkData, BookmarkWithoutData, Bookmarks } from './types';
9
9
 
10
10
  import type { BookmarkNew, BookmarkUpdate, BookmarksFilter } from './BookmarkClient.interface';
11
- import type { BookmarkFlowError } from './BookmarkProvider.error';
11
+ import type { BookmarkFlowError } from './BookmarkFlowError';
12
12
 
13
13
  /**
14
14
  * Represents the metadata associated with a bookmark action.
@@ -48,6 +48,8 @@ export const bookmarkConfigSchema = z.object({
48
48
  * @returns A validated {@link BookmarkModuleConfig}.
49
49
  * @throws {ZodError} When validation fails.
50
50
  */
51
+ // tightly coupled parse helper for the schema above
52
+ // fusion-lint-disable-next-line single-export-per-file
51
53
  export const parseBookmarkConfig = (config: unknown): BookmarkModuleConfig => {
52
54
  return bookmarkConfigSchema.parse(config) as BookmarkModuleConfig;
53
55
  };
@@ -0,0 +1,45 @@
1
+ import { of, type Observable } from 'rxjs';
2
+ import { mergeMap } from 'rxjs/operators';
3
+
4
+ import type { Flow } from '@equinor/fusion-observable';
5
+
6
+ import type { BookmarkActions } from '../bookmark-actions';
7
+ import type { BookmarkState } from '../create-bookmark-store';
8
+ import type { IBookmarkClient } from '../BookmarkClient.interface';
9
+
10
+ import { handleFetchBookmark } from './handle-fetch-bookmark';
11
+ import { handleFetchBookmarkData } from './handle-fetch-bookmark-data';
12
+ import { handleFetchAllBookmark } from './handle-fetch-all-bookmark';
13
+ import { handleCreateBookmark } from './handle-create-bookmark';
14
+ import { handleUpdateBookmark } from './handle-update-bookmark';
15
+ import { handleDeleteBookmark } from './handle-delete-bookmark';
16
+ import { handleRemoveBookmark } from './handle-remove-bookmark';
17
+ import { handleRemoveBookmarkFromFavorites } from './handle-remove-bookmark-from-favorites';
18
+ import { handleAddBookmarkAsFavorite } from './handle-add-bookmark-as-favorite';
19
+
20
+ /**
21
+ * Defines a set of flows that handle various bookmark-related actions, such as fetching, creating, updating, and deleting bookmarks.
22
+ *
23
+ * @param api - An instance of `IBookmarkClient` that provides the necessary API methods for interacting with the bookmark service.
24
+ * @returns A combined flow that handles all the bookmark-related actions.
25
+ */
26
+ export const bookmarkApiFlows = (api: IBookmarkClient): Flow<BookmarkActions, BookmarkState> => {
27
+ /**
28
+ * Combines multiple Bookmark-related observable flows into a single observable stream.
29
+ * The resulting observable stream emits the combined effects of these flows,
30
+ * which can be used to update the application state.
31
+ */
32
+ return (actions$: Observable<BookmarkActions>, state$: Observable<BookmarkState>) =>
33
+ // Invoke every bookmark flow with the shared api client and merge their emissions.
34
+ of(
35
+ handleFetchBookmark,
36
+ handleFetchBookmarkData,
37
+ handleFetchAllBookmark,
38
+ handleCreateBookmark,
39
+ handleUpdateBookmark,
40
+ handleDeleteBookmark,
41
+ handleRemoveBookmark,
42
+ handleRemoveBookmarkFromFavorites,
43
+ handleAddBookmarkAsFavorite,
44
+ ).pipe(mergeMap((flow) => flow(api)(actions$, state$)));
45
+ };