@equinor/fusion-framework-module-bookmark 2.2.1 → 3.0.0
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/CHANGELOG.md +23 -0
- package/dist/esm/BookmarkConfigurator.js +6 -3
- package/dist/esm/BookmarkConfigurator.js.map +1 -1
- package/dist/esm/BookmarkProvider.js +287 -219
- package/dist/esm/BookmarkProvider.js.map +1 -1
- package/dist/esm/bookmark-config.schema.js +5 -4
- package/dist/esm/bookmark-config.schema.js.map +1 -1
- package/dist/esm/bookmark.schemas.js +4 -1
- package/dist/esm/bookmark.schemas.js.map +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/BookmarkProvider.actions.d.ts +7 -175
- package/dist/types/BookmarkProvider.d.ts +47 -46
- package/dist/types/BookmarkProvider.reducer.d.ts +7 -90
- package/dist/types/bookmark-config.schema.d.ts +13 -104
- package/dist/types/bookmark.schemas.d.ts +20 -376
- package/dist/types/types.d.ts +96 -18
- package/dist/types/version.d.ts +1 -1
- package/package.json +5 -5
- package/src/BookmarkConfigurator.ts +10 -5
- package/src/BookmarkProvider.ts +373 -307
- package/src/bookmark-config.schema.ts +7 -6
- package/src/bookmark.schemas.ts +6 -2
- package/src/types.ts +92 -28
- package/src/version.ts +1 -1
package/src/BookmarkProvider.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Observable, Subscription, forkJoin, from, lastValueFrom, of } from 'rxjs';
|
|
1
|
+
import { Observable, Subscription, forkJoin, from, lastValueFrom, of, defer } from 'rxjs';
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
filter,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
catchError,
|
|
13
13
|
} from 'rxjs/operators';
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { castDraft, createDraft, finishDraft } from 'immer';
|
|
16
16
|
|
|
17
17
|
import { v4 as generateGUID } from 'uuid';
|
|
18
18
|
|
|
@@ -61,7 +61,8 @@ import type {
|
|
|
61
61
|
IBookmarkProvider,
|
|
62
62
|
} from './BookmarkProvider.interface';
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
// Default timeout for bookmark operations (2 minutes)
|
|
65
|
+
const defaultTimeout = 2 * 60 * 1000;
|
|
65
66
|
|
|
66
67
|
/**
|
|
67
68
|
* The `BookmarkProvider` class is responsible for managing bookmarks in the application.
|
|
@@ -356,9 +357,11 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
356
357
|
): VoidFunction {
|
|
357
358
|
if (!this._event) {
|
|
358
359
|
this._log?.warn('Failed to register event listener, event provider not configured');
|
|
359
|
-
return () => {
|
|
360
|
+
return () => {
|
|
361
|
+
// No-op function when event provider is not configured
|
|
362
|
+
};
|
|
360
363
|
}
|
|
361
|
-
return this._event
|
|
364
|
+
return this._event.addEventListener(eventName, (event) => {
|
|
362
365
|
if (event.source === this) {
|
|
363
366
|
callback(event);
|
|
364
367
|
}
|
|
@@ -398,21 +401,21 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
398
401
|
* @returns An observable that emits the generated payload.
|
|
399
402
|
* @template T - The type of the generated payload.
|
|
400
403
|
*/
|
|
401
|
-
public generatePayload<T extends BookmarkData>(
|
|
404
|
+
public generatePayload<T extends BookmarkData = BookmarkData>(
|
|
402
405
|
initial?: Partial<T> | null,
|
|
403
406
|
): Observable<T | null | undefined> {
|
|
404
|
-
this._log?.debug(
|
|
407
|
+
this._log?.debug('generating payload', initial);
|
|
405
408
|
|
|
406
409
|
/**
|
|
407
410
|
* Observable that emits the generated payload.
|
|
408
411
|
*/
|
|
409
412
|
const result$ = from(this.#payloadGenerators).pipe(
|
|
410
413
|
mergeScan(
|
|
411
|
-
(acc, generator) =>
|
|
414
|
+
(acc, generator) => from(Promise.resolve(this._producePayload(acc, generator))),
|
|
412
415
|
initial ?? ({} as Partial<T>),
|
|
413
416
|
1,
|
|
414
417
|
),
|
|
415
|
-
tap((payload) => this._log?.debug(
|
|
418
|
+
tap((payload) => this._log?.debug('generated payload', { initial, payload })),
|
|
416
419
|
) as Observable<T | null | undefined>;
|
|
417
420
|
|
|
418
421
|
return result$;
|
|
@@ -432,35 +435,41 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
432
435
|
* If the generator returns a value, a warning will be logged.
|
|
433
436
|
* If the generator returns null, an info message will be logged indicating that the bookmark data should be cleared.
|
|
434
437
|
*/
|
|
435
|
-
protected _producePayload<T extends BookmarkData>(
|
|
438
|
+
protected async _producePayload<T extends BookmarkData = BookmarkData>(
|
|
436
439
|
value: Partial<T>,
|
|
437
440
|
generator: BookmarkPayloadGenerator<T>,
|
|
438
441
|
initial?: Partial<T> | null,
|
|
439
|
-
) {
|
|
440
|
-
//
|
|
441
|
-
|
|
442
|
-
try {
|
|
443
|
-
const result = generator(draft as Partial<T>, initial);
|
|
444
|
-
// cast the result to a draft object
|
|
445
|
-
if (result) {
|
|
446
|
-
this._log?.warn(
|
|
447
|
-
`bookmark data generator ${generator.name} returned a value, but it should not do this, since the data is an immer draft object`,
|
|
448
|
-
);
|
|
449
|
-
// Dirty fix since some developers are returning the reference object, which will freeze the object
|
|
450
|
-
return castDraft(JSON.parse(JSON.stringify(result)));
|
|
451
|
-
}
|
|
442
|
+
): Promise<T | null | undefined> {
|
|
443
|
+
// Create a draft for async operations using createDraft/finishDraft pattern
|
|
444
|
+
const draft = createDraft(value);
|
|
452
445
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
446
|
+
try {
|
|
447
|
+
const generatorResult = await Promise.resolve(generator(draft as Partial<T>, initial));
|
|
448
|
+
|
|
449
|
+
// Handle the generator result
|
|
450
|
+
if (generatorResult) {
|
|
451
|
+
this._log?.warn(
|
|
452
|
+
`bookmark data generator ${generator.name} returned a value, but it should not do this, since the data is an immer draft object`,
|
|
453
|
+
);
|
|
454
|
+
// Dirty fix since some developers are returning the reference object, which will freeze the object
|
|
455
|
+
return castDraft(generatorResult) as T | null | undefined;
|
|
462
456
|
}
|
|
463
|
-
|
|
457
|
+
|
|
458
|
+
// clear the bookmark data if the generator returns null
|
|
459
|
+
if (generatorResult === null) {
|
|
460
|
+
this._log?.info(
|
|
461
|
+
`bookmark data generator ${generator.name} wish to clear the bookmark data`,
|
|
462
|
+
);
|
|
463
|
+
return undefined;
|
|
464
|
+
}
|
|
465
|
+
} catch (error) {
|
|
466
|
+
this._log?.error(`Failed to produce payload using generator ${generator.name}`, error);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Finish the draft to get the immutable result
|
|
470
|
+
const result = finishDraft(draft);
|
|
471
|
+
|
|
472
|
+
return result as T | null | undefined;
|
|
464
473
|
}
|
|
465
474
|
|
|
466
475
|
/**
|
|
@@ -470,10 +479,10 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
470
479
|
* @param options An optional object that allows excluding the bookmark payload from the result.
|
|
471
480
|
* @returns An observable that emits the combined result of fetching the bookmark and bookmark data.
|
|
472
481
|
*/
|
|
473
|
-
public getBookmark<T extends BookmarkData>(
|
|
482
|
+
public getBookmark<T extends BookmarkData = BookmarkData>(
|
|
474
483
|
bookmarkId: string,
|
|
475
484
|
options?: { excludePayload?: boolean },
|
|
476
|
-
) {
|
|
485
|
+
): Observable<Bookmark<T>> {
|
|
477
486
|
this._log?.debug(`fetching bookmark: ${bookmarkId}`, options);
|
|
478
487
|
|
|
479
488
|
// fetch the bookmark and bookmark data
|
|
@@ -501,7 +510,7 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
501
510
|
* @param options.excludePayload - Specifies whether to exclude the payload from the bookmark.
|
|
502
511
|
* @returns A promise that resolves to the retrieved bookmark, or null if the bookmark is not found.
|
|
503
512
|
*/
|
|
504
|
-
public getBookmarkAsync<T extends BookmarkData>(
|
|
513
|
+
public getBookmarkAsync<T extends BookmarkData = BookmarkData>(
|
|
505
514
|
id: string,
|
|
506
515
|
options?: { excludePayload?: boolean },
|
|
507
516
|
): Promise<Bookmark<T> | null> {
|
|
@@ -509,24 +518,59 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
509
518
|
}
|
|
510
519
|
|
|
511
520
|
/**
|
|
512
|
-
*
|
|
521
|
+
* Retrieves all bookmarks from the store as an Observable stream.
|
|
513
522
|
*
|
|
514
|
-
*
|
|
523
|
+
* This method implements a complex flow that:
|
|
524
|
+
* 1. Resolves filter parameters (sourceSystem, appKey, contextId) based on configuration
|
|
525
|
+
* 2. Dispatches a fetch action to the store with resolved filters
|
|
526
|
+
* 3. Monitors store actions for success/failure responses
|
|
527
|
+
* 4. Returns the bookmarks data or throws appropriate errors
|
|
528
|
+
*
|
|
529
|
+
* @remarks
|
|
530
|
+
* The method uses a reactive pattern where filter resolution and store actions are
|
|
531
|
+
* handled asynchronously. If filtering is enabled, it will resolve the current
|
|
532
|
+
* application and context to filter bookmarks accordingly.
|
|
533
|
+
*
|
|
534
|
+
* @example
|
|
535
|
+
* ```ts
|
|
536
|
+
* // Basic usage
|
|
537
|
+
* bookmarkProvider.getAllBookmarks().subscribe({
|
|
538
|
+
* next: (bookmarks) => console.log('Retrieved bookmarks:', bookmarks),
|
|
539
|
+
* error: (err) => console.error('Failed to fetch bookmarks:', err)
|
|
540
|
+
* });
|
|
541
|
+
*
|
|
542
|
+
* // With filtering enabled in config
|
|
543
|
+
* const config = {
|
|
544
|
+
* filters: { context: true, application: true }
|
|
545
|
+
* };
|
|
546
|
+
* // Will automatically filter by current context and application
|
|
547
|
+
* ```
|
|
548
|
+
*
|
|
549
|
+
* @returns An Observable that emits the array of bookmarks when successfully retrieved
|
|
550
|
+
* @throws {BookmarkProviderError} When filter resolution fails or store operations fail
|
|
551
|
+
* @throws {BookmarkProviderError} When a timeout occurs during the fetch operation
|
|
515
552
|
*/
|
|
516
553
|
public getAllBookmarks(): Observable<Bookmarks> {
|
|
517
554
|
return new Observable<Bookmarks>((observer) => {
|
|
518
|
-
this._log?.debug(
|
|
555
|
+
this._log?.debug('fetching all bookmarks');
|
|
519
556
|
|
|
520
|
-
//
|
|
557
|
+
// Step 1: Generate filter parameters based on configuration
|
|
558
|
+
// This creates a stream that resolves all necessary filter values
|
|
521
559
|
const filter$ = forkJoin({
|
|
560
|
+
// Always include the source system for the current provider
|
|
522
561
|
sourceSystem: of(this.sourceSystem),
|
|
562
|
+
|
|
563
|
+
// Resolve application key if filtering by application is enabled
|
|
523
564
|
appKey: this.#config.filters?.application
|
|
524
|
-
?
|
|
565
|
+
? defer(() => this._resolve.application()).pipe(map((x) => x?.appKey))
|
|
525
566
|
: of(undefined),
|
|
567
|
+
|
|
568
|
+
// Resolve context ID if filtering by context is enabled
|
|
526
569
|
contextId: this.#config.filters?.context
|
|
527
|
-
?
|
|
570
|
+
? defer(() => this._resolve.context()).pipe(map((x) => x?.id))
|
|
528
571
|
: of(undefined),
|
|
529
572
|
}).pipe(
|
|
573
|
+
// Handle any errors during filter parameter resolution
|
|
530
574
|
catchError((err) => {
|
|
531
575
|
const error = new BookmarkProviderError(
|
|
532
576
|
'Could not fetch bookmarks, failed to resolve filter parameters',
|
|
@@ -537,20 +581,25 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
537
581
|
}),
|
|
538
582
|
);
|
|
539
583
|
|
|
540
|
-
//
|
|
584
|
+
// Step 2: Dispatch fetch action to store when filter parameters are ready
|
|
585
|
+
// This triggers the actual API call through the store's action system
|
|
586
|
+
// The store will handle the async operation and emit success/failure actions
|
|
587
|
+
// Using observer.add() ensures proper cleanup when the Observable is unsubscribed
|
|
541
588
|
observer.add(
|
|
542
589
|
filter$.subscribe((filter) => {
|
|
543
590
|
this.#store.next(bookmarkActions.fetchBookmarks(filter));
|
|
544
591
|
}),
|
|
545
592
|
);
|
|
546
593
|
|
|
547
|
-
//
|
|
594
|
+
// Step 3: Monitor for failure responses from the store
|
|
595
|
+
// This stream will emit and throw an error if the fetch operation fails
|
|
548
596
|
const failure$ = this.#store.action$.pipe(
|
|
549
597
|
filter(bookmarkActions.fetchBookmarks.failure.match),
|
|
550
598
|
map((action) => {
|
|
551
599
|
this._log?.error('Failed to fetch bookmarks', action.payload);
|
|
552
600
|
throw new BookmarkProviderError('Failed to fetch bookmarks', action.payload);
|
|
553
601
|
}),
|
|
602
|
+
// Add timeout protection to prevent hanging requests
|
|
554
603
|
timeout({
|
|
555
604
|
each: defaultTimeout,
|
|
556
605
|
with: () => {
|
|
@@ -559,17 +608,22 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
559
608
|
}),
|
|
560
609
|
);
|
|
561
610
|
|
|
562
|
-
//
|
|
611
|
+
// Step 4: Monitor for success responses from the store
|
|
612
|
+
// This stream will emit the bookmarks data when successfully retrieved
|
|
563
613
|
const request$ = this.#store.action$.pipe(
|
|
564
614
|
filter(bookmarkActions.fetchBookmarks.success.match),
|
|
565
615
|
map((a) => a.payload),
|
|
566
616
|
tap((bookmarks) => {
|
|
567
|
-
this._log?.debug(
|
|
617
|
+
this._log?.debug('fetched all bookmarks', bookmarks);
|
|
568
618
|
}),
|
|
619
|
+
// Race against failure stream - whichever completes first wins
|
|
620
|
+
// This ensures we either get the bookmarks data or an error, not both
|
|
569
621
|
raceWith(failure$),
|
|
622
|
+
// Only take the first emission (success or failure) to complete the stream
|
|
570
623
|
first(),
|
|
571
624
|
);
|
|
572
625
|
|
|
626
|
+
// Step 5: Subscribe to the request stream and forward results to observer
|
|
573
627
|
request$.subscribe(observer);
|
|
574
628
|
});
|
|
575
629
|
}
|
|
@@ -594,7 +648,7 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
594
648
|
* @returns An observable that emits the next bookmark or null.
|
|
595
649
|
* @template T - The type of the bookmark data.
|
|
596
650
|
*/
|
|
597
|
-
public setCurrentBookmark<T extends BookmarkData>(
|
|
651
|
+
public setCurrentBookmark<T extends BookmarkData = BookmarkData>(
|
|
598
652
|
bookmark_or_id: Bookmark<T> | string | null,
|
|
599
653
|
): Observable<Bookmark<T> | null> {
|
|
600
654
|
this._log?.debug('setting current bookmark', bookmark_or_id);
|
|
@@ -646,7 +700,7 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
646
700
|
* @param bookmarkId - The ID of the bookmark to set as the current bookmark.
|
|
647
701
|
* @returns A subscription to the operation that sets the current bookmark.
|
|
648
702
|
*/
|
|
649
|
-
public setCurrentBookmarkAsync<T extends BookmarkData>(
|
|
703
|
+
public setCurrentBookmarkAsync<T extends BookmarkData = BookmarkData>(
|
|
650
704
|
bookmark_or_id: Bookmark<T> | string | null,
|
|
651
705
|
): Promise<Bookmark<T> | null> {
|
|
652
706
|
return lastValueFrom(this.setCurrentBookmark<T>(bookmark_or_id));
|
|
@@ -654,116 +708,121 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
654
708
|
|
|
655
709
|
/**
|
|
656
710
|
* Creates a new bookmark with the provided bookmark data.
|
|
711
|
+
* The creation executes immediately when this method is called.
|
|
657
712
|
* @template T - The type of bookmark data.
|
|
658
713
|
* @param {BookmarkCreateArgs<T>} newBookmarkData - The data for creating the bookmark.
|
|
659
714
|
* @returns {Observable<Bookmark<T>>} - An observable that emits the created bookmark.
|
|
660
715
|
*/
|
|
661
|
-
public createBookmark<T extends BookmarkData>(
|
|
716
|
+
public createBookmark<T extends BookmarkData = BookmarkData>(
|
|
662
717
|
newBookmarkData: BookmarkCreateArgs<T>,
|
|
663
718
|
): Observable<Bookmark<T>> {
|
|
664
|
-
|
|
665
|
-
|
|
719
|
+
const { ref, action$ } = this._useScopedActions();
|
|
720
|
+
|
|
721
|
+
this._log?.debug(`creating new bookmark, ref: ${ref}`, newBookmarkData);
|
|
722
|
+
|
|
723
|
+
// resolve the bookmark
|
|
724
|
+
const bookmark$ = forkJoin({
|
|
725
|
+
appKey: newBookmarkData.appKey
|
|
726
|
+
? of(newBookmarkData.appKey)
|
|
727
|
+
: defer(() => this._resolve.application()).pipe(
|
|
728
|
+
map((app) => {
|
|
729
|
+
if (!app?.appKey) {
|
|
730
|
+
throw new BookmarkProviderError('Failed to resolve application key');
|
|
731
|
+
}
|
|
732
|
+
return app.appKey;
|
|
733
|
+
}),
|
|
734
|
+
),
|
|
735
|
+
contextId: defer(() => this._resolve.context()).pipe(map((context) => context?.id)),
|
|
736
|
+
payload: this.generatePayload<T>(newBookmarkData.payload),
|
|
737
|
+
sourceSystem: of(this.sourceSystem),
|
|
738
|
+
}).pipe(
|
|
739
|
+
catchError((err) => {
|
|
740
|
+
const error = new BookmarkProviderError(
|
|
741
|
+
'Could not create new bookmark, failed to resolve bookmark data',
|
|
742
|
+
err,
|
|
743
|
+
);
|
|
744
|
+
this._log?.error(error.message, error);
|
|
745
|
+
throw error;
|
|
746
|
+
}),
|
|
747
|
+
// merge the resolved data with the new bookmark data
|
|
748
|
+
map(
|
|
749
|
+
(resolvedData) =>
|
|
750
|
+
({
|
|
751
|
+
...newBookmarkData,
|
|
752
|
+
...resolvedData,
|
|
753
|
+
}) as BookmarkNew<T>,
|
|
754
|
+
),
|
|
755
|
+
);
|
|
666
756
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
:
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
return app.appKey;
|
|
679
|
-
}),
|
|
680
|
-
),
|
|
681
|
-
contextId: this._resolve.context().then((context) => context?.id),
|
|
682
|
-
payload: this.generatePayload<T>(newBookmarkData.payload),
|
|
683
|
-
sourceSystem: of(this.sourceSystem),
|
|
684
|
-
}).pipe(
|
|
685
|
-
catchError((err) => {
|
|
757
|
+
// notify listeners that a bookmark is about to be created
|
|
758
|
+
const dispatch$ = bookmark$.pipe(
|
|
759
|
+
switchMap(async (bookmark) => {
|
|
760
|
+
// notify listeners that a bookmark is about to be created
|
|
761
|
+
const { canceled, type } = await this._dispatchEvent('onBookmarkCreate', {
|
|
762
|
+
detail: bookmark,
|
|
763
|
+
cancelable: true,
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
// throw an error if the event is canceled
|
|
767
|
+
if (canceled) {
|
|
686
768
|
const error = new BookmarkProviderError(
|
|
687
|
-
|
|
688
|
-
err,
|
|
769
|
+
`event: ${type} was canceled by listener for creating bookmark: ${ref}`,
|
|
689
770
|
);
|
|
690
|
-
this._log?.
|
|
771
|
+
this._log?.info(error.message);
|
|
691
772
|
throw error;
|
|
692
|
-
}
|
|
693
|
-
// merge the resolved data with the new bookmark data
|
|
694
|
-
map(
|
|
695
|
-
(resolvedData) =>
|
|
696
|
-
({
|
|
697
|
-
...newBookmarkData,
|
|
698
|
-
...resolvedData,
|
|
699
|
-
}) as BookmarkNew<T>,
|
|
700
|
-
),
|
|
701
|
-
);
|
|
702
|
-
|
|
703
|
-
// notify listeners that a bookmark is about to be created
|
|
704
|
-
const dispatch$ = bookmark$.pipe(
|
|
705
|
-
switchMap(async (bookmark) => {
|
|
706
|
-
// notify listeners that a bookmark is about to be created
|
|
707
|
-
const { canceled, type } = await this._dispatchEvent('onBookmarkCreate', {
|
|
708
|
-
detail: bookmark,
|
|
709
|
-
cancelable: true,
|
|
710
|
-
});
|
|
773
|
+
}
|
|
711
774
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
`event: ${type} was canceled by listener for creating bookmark: ${ref}`,
|
|
716
|
-
);
|
|
717
|
-
this._log?.info(error.message);
|
|
718
|
-
throw error;
|
|
719
|
-
}
|
|
775
|
+
return bookmark;
|
|
776
|
+
}),
|
|
777
|
+
);
|
|
720
778
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
)
|
|
779
|
+
// Start the creation process immediately
|
|
780
|
+
const createSubscription = dispatch$.subscribe({
|
|
781
|
+
error: (error) => {
|
|
782
|
+
this._log?.error(`Failed to prepare bookmark creation: ${ref}`, error);
|
|
783
|
+
},
|
|
784
|
+
next: (newBookmark) => {
|
|
785
|
+
// request the store to create the bookmark
|
|
786
|
+
this.#store.next(bookmarkActions.createBookmark(newBookmark, { ref }));
|
|
787
|
+
},
|
|
788
|
+
});
|
|
724
789
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
)
|
|
790
|
+
// monitor the failure case when creating a bookmark
|
|
791
|
+
const failure$ = action$.pipe(
|
|
792
|
+
filter(bookmarkActions.createBookmark.failure.match),
|
|
793
|
+
map(({ payload: cause }) => {
|
|
794
|
+
const error = new BookmarkProviderError(`Failed to create bookmark: ${ref}`, {
|
|
795
|
+
cause,
|
|
796
|
+
});
|
|
797
|
+
this._log?.warn(error.message);
|
|
798
|
+
throw error;
|
|
799
|
+
}),
|
|
800
|
+
timeout({
|
|
801
|
+
each: defaultTimeout,
|
|
802
|
+
with: () => {
|
|
803
|
+
throw new BookmarkProviderError(`Timeout while creating bookmark: ${ref}`);
|
|
804
|
+
},
|
|
805
|
+
}),
|
|
806
|
+
);
|
|
735
807
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
each: defaultTimeout,
|
|
748
|
-
with: () => {
|
|
749
|
-
throw new BookmarkProviderError(`Timeout while creating bookmark: ${ref}`);
|
|
750
|
-
},
|
|
751
|
-
}),
|
|
752
|
-
);
|
|
808
|
+
// monitor the success case when creating a bookmark
|
|
809
|
+
const request$ = action$.pipe(
|
|
810
|
+
filter(bookmarkActions.createBookmark.success.match),
|
|
811
|
+
map(({ payload }) => payload as Bookmark<T>),
|
|
812
|
+
tap((bookmark) => {
|
|
813
|
+
this._log?.info(`Bookmark created: ${bookmark.id}, ref: ${ref}`);
|
|
814
|
+
this._dispatchEvent('onBookmarkCreated', { detail: bookmark });
|
|
815
|
+
}),
|
|
816
|
+
raceWith(failure$),
|
|
817
|
+
first(),
|
|
818
|
+
);
|
|
753
819
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
tap((bookmark) => {
|
|
759
|
-
this._log?.info(`Bookmark created: ${bookmark.id}, ref: ${ref}`);
|
|
760
|
-
this._dispatchEvent('onBookmarkCreated', { detail: bookmark });
|
|
761
|
-
}),
|
|
762
|
-
raceWith(failure$),
|
|
763
|
-
first(),
|
|
764
|
-
);
|
|
820
|
+
// Return the observable that will emit the result
|
|
821
|
+
return new Observable<Bookmark<T>>((subscriber) => {
|
|
822
|
+
// Clean up the create subscription when the result observable is unsubscribed
|
|
823
|
+
subscriber.add(() => createSubscription.unsubscribe());
|
|
765
824
|
|
|
766
|
-
//
|
|
825
|
+
// Emit the created bookmark
|
|
767
826
|
request$.subscribe(subscriber);
|
|
768
827
|
});
|
|
769
828
|
}
|
|
@@ -774,7 +833,7 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
774
833
|
* @param bookmark - The new bookmark to create.
|
|
775
834
|
* @returns A promise that resolves to the created bookmark with its associated data.
|
|
776
835
|
*/
|
|
777
|
-
public createBookmarkAsync<T extends BookmarkData>(
|
|
836
|
+
public createBookmarkAsync<T extends BookmarkData = BookmarkData>(
|
|
778
837
|
args: BookmarkCreateArgs<T>,
|
|
779
838
|
): Promise<Bookmark<T>> {
|
|
780
839
|
return lastValueFrom(this.createBookmark<T>(args));
|
|
@@ -782,14 +841,15 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
782
841
|
|
|
783
842
|
/**
|
|
784
843
|
* Updates a bookmark with the specified bookmarkId and bookmarkUpdates.
|
|
844
|
+
* The update executes immediately when this method is called.
|
|
785
845
|
*
|
|
786
846
|
* @template T - The type of the bookmark data.
|
|
787
847
|
* @param {string} bookmarkId - The identifier of the bookmark to update.
|
|
788
848
|
* @param {BookmarkUpdate<T>} [bookmarkUpdates] - The updates to apply to the bookmark.
|
|
789
849
|
* @param {BookmarkUpdateOptions} [options] - The options for updating the bookmark.
|
|
790
|
-
* @returns {
|
|
850
|
+
* @returns {Observable<Bookmark<T>>} - An observable that emits the updated bookmark.
|
|
791
851
|
*/
|
|
792
|
-
public updateBookmark<T extends BookmarkData>(
|
|
852
|
+
public updateBookmark<T extends BookmarkData = BookmarkData>(
|
|
793
853
|
bookmarkId: string,
|
|
794
854
|
bookmarkUpdates?: BookmarkUpdate<T>,
|
|
795
855
|
options?: BookmarkUpdateOptions,
|
|
@@ -800,101 +860,105 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
800
860
|
);
|
|
801
861
|
}
|
|
802
862
|
|
|
803
|
-
|
|
804
|
-
const { ref, action$ } = this._useScopedActions();
|
|
863
|
+
const { ref, action$ } = this._useScopedActions();
|
|
805
864
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
/**
|
|
809
|
-
* Generate updates with payload
|
|
810
|
-
* @remarks
|
|
811
|
-
* If `excludePayloadGeneration` is `true`, it emits the `bookmarkUpdates` directly.
|
|
812
|
-
* If `excludePayloadGeneration` is `false`, it generates the payload using the `generatePayload` method and emits the updated `bookmarkUpdates` with the generated payload.
|
|
813
|
-
*/
|
|
814
|
-
const updates$ = options?.excludePayloadGeneration
|
|
815
|
-
? of(bookmarkUpdates as BookmarkUpdate<T>)
|
|
816
|
-
: this.generatePayload<T>(bookmarkUpdates?.payload).pipe(
|
|
817
|
-
map(
|
|
818
|
-
(payload) =>
|
|
819
|
-
({
|
|
820
|
-
...bookmarkUpdates,
|
|
821
|
-
payload,
|
|
822
|
-
}) as BookmarkUpdate<T>,
|
|
823
|
-
),
|
|
824
|
-
);
|
|
865
|
+
this._log?.debug(`Updating bookmark: ${bookmarkId}, ref: ${ref}`);
|
|
825
866
|
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
return updates;
|
|
846
|
-
}),
|
|
847
|
-
);
|
|
867
|
+
/**
|
|
868
|
+
* Generate updates with payload
|
|
869
|
+
* @remarks
|
|
870
|
+
* If `excludePayloadGeneration` is `true`, it emits the `bookmarkUpdates` directly.
|
|
871
|
+
* If `excludePayloadGeneration` is `false`, it generates the payload using the `generatePayload` method and emits the updated `bookmarkUpdates` with the generated payload.
|
|
872
|
+
*/
|
|
873
|
+
const updates$ = options?.excludePayloadGeneration
|
|
874
|
+
? of(bookmarkUpdates as BookmarkUpdate<T>)
|
|
875
|
+
: this.generatePayload<T>(bookmarkUpdates?.payload).pipe(
|
|
876
|
+
map(
|
|
877
|
+
(payload) =>
|
|
878
|
+
({
|
|
879
|
+
...bookmarkUpdates,
|
|
880
|
+
payload,
|
|
881
|
+
}) as BookmarkUpdate<T>,
|
|
882
|
+
),
|
|
883
|
+
);
|
|
848
884
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
885
|
+
// notify listeners that a bookmark is about to be updated
|
|
886
|
+
const dispatch$ = updates$.pipe(
|
|
887
|
+
switchMap(async (updates) => {
|
|
888
|
+
const { canceled, type } = await this._dispatchEvent('onBookmarkUpdate', {
|
|
889
|
+
detail: {
|
|
890
|
+
current: bookmarkSelector(this.#store.value, bookmarkId),
|
|
891
|
+
updates,
|
|
856
892
|
},
|
|
857
|
-
|
|
858
|
-
|
|
893
|
+
cancelable: true,
|
|
894
|
+
});
|
|
859
895
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
cause,
|
|
866
|
-
});
|
|
867
|
-
this._log?.info(error.message);
|
|
896
|
+
if (canceled) {
|
|
897
|
+
const error = new BookmarkProviderError(
|
|
898
|
+
`event: ${type} was canceled by listener for updating bookmark: ${bookmarkId}, ref: ${ref}`,
|
|
899
|
+
);
|
|
900
|
+
this._log?.warn(error.message, updates);
|
|
868
901
|
throw error;
|
|
869
|
-
}
|
|
870
|
-
timeout({
|
|
871
|
-
each: defaultTimeout,
|
|
872
|
-
with: () => {
|
|
873
|
-
throw new BookmarkProviderError(`Timeout while updating bookmark: ${bookmarkId}`);
|
|
874
|
-
},
|
|
875
|
-
}),
|
|
876
|
-
);
|
|
902
|
+
}
|
|
877
903
|
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
)
|
|
904
|
+
return updates;
|
|
905
|
+
}),
|
|
906
|
+
);
|
|
907
|
+
|
|
908
|
+
// Start the update process immediately
|
|
909
|
+
const updateSubscription = dispatch$.subscribe({
|
|
910
|
+
error: (error) => {
|
|
911
|
+
this._log?.error(`Failed to prepare bookmark update: ${bookmarkId}`, error);
|
|
912
|
+
},
|
|
913
|
+
next: (updates) => {
|
|
914
|
+
// trigger the store to update the bookmark
|
|
915
|
+
this.#store.next(bookmarkActions.updateBookmark({ bookmarkId, updates }, { ref }));
|
|
916
|
+
},
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
// monitor the failure case when updating a bookmark
|
|
920
|
+
const failure$ = action$.pipe(
|
|
921
|
+
filter(bookmarkActions.updateBookmark.failure.match),
|
|
922
|
+
map(({ payload: cause }) => {
|
|
923
|
+
const error = new BookmarkProviderError(`Failed to update bookmark: ${bookmarkId}`, {
|
|
924
|
+
cause,
|
|
925
|
+
});
|
|
926
|
+
this._log?.info(error.message);
|
|
927
|
+
throw error;
|
|
928
|
+
}),
|
|
929
|
+
timeout({
|
|
930
|
+
each: defaultTimeout,
|
|
931
|
+
with: () => {
|
|
932
|
+
throw new BookmarkProviderError(`Timeout while updating bookmark: ${bookmarkId}`);
|
|
933
|
+
},
|
|
934
|
+
}),
|
|
935
|
+
);
|
|
936
|
+
|
|
937
|
+
// monitor the success case when updating a bookmark
|
|
938
|
+
const request$ = action$.pipe(
|
|
939
|
+
filter(bookmarkActions.updateBookmark.success.match),
|
|
940
|
+
map(
|
|
941
|
+
// TODO: add payload if current bookmark is the same as the updated bookmark
|
|
942
|
+
({ payload }): Bookmark<T> =>
|
|
943
|
+
({
|
|
944
|
+
...bookmarkSelector(this.#store.value, payload.id),
|
|
945
|
+
payload: payload.payload,
|
|
946
|
+
}) as Bookmark<T>,
|
|
947
|
+
),
|
|
948
|
+
tap((bookmark) => {
|
|
949
|
+
this._log?.info(`Bookmark updated: ${bookmark.id}, ref: ${ref}`);
|
|
950
|
+
this._dispatchEvent('onBookmarkUpdated', { detail: bookmark });
|
|
951
|
+
}),
|
|
952
|
+
raceWith(failure$),
|
|
953
|
+
first(),
|
|
954
|
+
);
|
|
955
|
+
|
|
956
|
+
// Return the observable that will emit the result
|
|
957
|
+
return new Observable<Bookmark<T>>((subscriber) => {
|
|
958
|
+
// Clean up the update subscription when the result observable is unsubscribed
|
|
959
|
+
subscriber.add(() => updateSubscription.unsubscribe());
|
|
896
960
|
|
|
897
|
-
//
|
|
961
|
+
// Emit the updated bookmark
|
|
898
962
|
request$.subscribe(subscriber);
|
|
899
963
|
});
|
|
900
964
|
}
|
|
@@ -907,7 +971,7 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
907
971
|
* @param bookmark - The bookmark to update.
|
|
908
972
|
* @returns A promise that resolves to the updated bookmark with its associated data.
|
|
909
973
|
*/
|
|
910
|
-
public updateBookmarkAsync<T extends BookmarkData>(
|
|
974
|
+
public updateBookmarkAsync<T extends BookmarkData = BookmarkData>(
|
|
911
975
|
id_or_bookmark: string | Bookmark<T>,
|
|
912
976
|
updates_or_options?: BookmarkUpdate<T> | BookmarkUpdateOptions,
|
|
913
977
|
options?: BookmarkUpdateOptions,
|
|
@@ -925,10 +989,7 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
925
989
|
updatePayload: boolean;
|
|
926
990
|
}
|
|
927
991
|
).updatePayload,
|
|
928
|
-
})
|
|
929
|
-
// this is totally wrong, but we need to keep the API for now
|
|
930
|
-
map((bookmark) => bookmark.payload as Bookmark<T>),
|
|
931
|
-
),
|
|
992
|
+
}),
|
|
932
993
|
);
|
|
933
994
|
}
|
|
934
995
|
return lastValueFrom(
|
|
@@ -938,83 +999,88 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
938
999
|
|
|
939
1000
|
/**
|
|
940
1001
|
* Deletes a bookmark with the specified bookmarkId.
|
|
1002
|
+
* The deletion executes immediately when this method is called.
|
|
941
1003
|
*
|
|
942
1004
|
* @param bookmarkId - The unique identifier of the bookmark to be deleted.
|
|
943
|
-
* @returns
|
|
1005
|
+
* @returns An Observable that emits when the bookmark is successfully deleted.
|
|
944
1006
|
* @throws {BookmarkProviderError} If there is an error deleting the bookmark.
|
|
945
1007
|
*/
|
|
946
1008
|
public deleteBookmark(bookmarkId: string): Observable<void> {
|
|
947
|
-
|
|
948
|
-
const { ref, action$ } = this._useScopedActions();
|
|
1009
|
+
const { ref, action$ } = this._useScopedActions();
|
|
949
1010
|
|
|
950
|
-
|
|
1011
|
+
this._log?.debug(`Removing bookmark: ${bookmarkId}, ref: ${ref}`);
|
|
951
1012
|
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
// observable that dispatches the 'onBookmarkDelete' event and maps the result
|
|
958
|
-
const dispatch$ = from(
|
|
959
|
-
this._dispatchEvent('onBookmarkDelete', {
|
|
960
|
-
detail: bookmark,
|
|
961
|
-
cancelable: true,
|
|
962
|
-
}),
|
|
963
|
-
).pipe(
|
|
964
|
-
map(({ canceled, type, detail }) => {
|
|
965
|
-
if (canceled) {
|
|
966
|
-
const error = new BookmarkProviderError(
|
|
967
|
-
`event: ${type} was canceled by listener for removing bookmark: ${bookmarkId}, ref: ${ref}`,
|
|
968
|
-
);
|
|
969
|
-
this._log?.warn(error.message);
|
|
970
|
-
throw error;
|
|
971
|
-
}
|
|
972
|
-
return detail;
|
|
973
|
-
}),
|
|
974
|
-
);
|
|
975
|
-
|
|
976
|
-
// execute the delete bookmark action when the event is not canceled
|
|
977
|
-
subscriber.add(
|
|
978
|
-
dispatch$.subscribe({
|
|
979
|
-
error: (error) => subscriber.error(error),
|
|
980
|
-
next: (bookmark) => {
|
|
981
|
-
// request the store to delete the bookmark
|
|
982
|
-
this.#store.next(bookmarkActions.deleteBookmark(bookmark.id, { ref }));
|
|
983
|
-
},
|
|
984
|
-
}),
|
|
985
|
-
);
|
|
1013
|
+
// bookmark to delete
|
|
1014
|
+
const bookmark = bookmarkSelector(this.#store.value, bookmarkId) ?? {
|
|
1015
|
+
id: bookmarkId,
|
|
1016
|
+
};
|
|
986
1017
|
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1018
|
+
// observable that dispatches the 'onBookmarkDelete' event and maps the result
|
|
1019
|
+
const dispatch$ = from(
|
|
1020
|
+
this._dispatchEvent('onBookmarkDelete', {
|
|
1021
|
+
detail: bookmark,
|
|
1022
|
+
cancelable: true,
|
|
1023
|
+
}),
|
|
1024
|
+
).pipe(
|
|
1025
|
+
map(({ canceled, type, detail }) => {
|
|
1026
|
+
if (canceled) {
|
|
1027
|
+
const error = new BookmarkProviderError(
|
|
1028
|
+
`event: ${type} was canceled by listener for removing bookmark: ${bookmarkId}, ref: ${ref}`,
|
|
1029
|
+
);
|
|
994
1030
|
this._log?.warn(error.message);
|
|
995
1031
|
throw error;
|
|
996
|
-
}
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
throw new BookmarkProviderError(`Timeout while updating bookmark: ${bookmarkId}`);
|
|
1001
|
-
},
|
|
1002
|
-
}),
|
|
1003
|
-
);
|
|
1032
|
+
}
|
|
1033
|
+
return detail;
|
|
1034
|
+
}),
|
|
1035
|
+
);
|
|
1004
1036
|
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
})
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
);
|
|
1037
|
+
// Start the deletion process immediately
|
|
1038
|
+
const deleteSubscription = dispatch$.subscribe({
|
|
1039
|
+
error: (error) => {
|
|
1040
|
+
this._log?.error(`Failed to prepare bookmark deletion: ${bookmarkId}`, error);
|
|
1041
|
+
},
|
|
1042
|
+
next: (bookmark) => {
|
|
1043
|
+
// request the store to delete the bookmark
|
|
1044
|
+
this.#store.next(bookmarkActions.deleteBookmark(bookmark.id, { ref }));
|
|
1045
|
+
},
|
|
1046
|
+
});
|
|
1016
1047
|
|
|
1017
|
-
|
|
1048
|
+
// monitor the failure case when deleting a bookmark
|
|
1049
|
+
const failure$ = action$.pipe(
|
|
1050
|
+
filter(bookmarkActions.deleteBookmark.failure.match),
|
|
1051
|
+
map(({ payload: cause }) => {
|
|
1052
|
+
const error = new BookmarkProviderError(`Failed to delete bookmark: ${bookmarkId}`, {
|
|
1053
|
+
cause,
|
|
1054
|
+
});
|
|
1055
|
+
this._log?.warn(error.message);
|
|
1056
|
+
throw error;
|
|
1057
|
+
}),
|
|
1058
|
+
timeout({
|
|
1059
|
+
each: defaultTimeout,
|
|
1060
|
+
with: () => {
|
|
1061
|
+
throw new BookmarkProviderError(`Timeout while deleting bookmark: ${bookmarkId}`);
|
|
1062
|
+
},
|
|
1063
|
+
}),
|
|
1064
|
+
);
|
|
1065
|
+
|
|
1066
|
+
// monitor the success case when deleting a bookmark
|
|
1067
|
+
const request$ = action$.pipe(
|
|
1068
|
+
filter(bookmarkActions.deleteBookmark.success.match),
|
|
1069
|
+
map(() => undefined),
|
|
1070
|
+
tap(() => {
|
|
1071
|
+
this._log?.info(`Removed bookmark: ${bookmark.id}, ref: ${ref}`);
|
|
1072
|
+
this._dispatchEvent('onBookmarkDeleted', { detail: bookmark });
|
|
1073
|
+
}),
|
|
1074
|
+
raceWith(failure$),
|
|
1075
|
+
first(),
|
|
1076
|
+
);
|
|
1077
|
+
|
|
1078
|
+
// Return the observable that will emit the result
|
|
1079
|
+
return new Observable<void>((subscriber) => {
|
|
1080
|
+
// Clean up the delete subscription when the result observable is unsubscribed
|
|
1081
|
+
subscriber.add(() => deleteSubscription.unsubscribe());
|
|
1082
|
+
|
|
1083
|
+
// Emit the deletion result
|
|
1018
1084
|
request$.subscribe(subscriber);
|
|
1019
1085
|
});
|
|
1020
1086
|
}
|
|
@@ -1202,7 +1268,7 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
1202
1268
|
this._log?.info(`Removed bookmark: ${bookmarkId} from favourites, ref: ${ref}`);
|
|
1203
1269
|
this._dispatchEvent('onBookmarkFavouriteRemoved', { detail: bookmark });
|
|
1204
1270
|
}),
|
|
1205
|
-
map(() =>
|
|
1271
|
+
map(() => undefined),
|
|
1206
1272
|
raceWith(failure$),
|
|
1207
1273
|
first(),
|
|
1208
1274
|
);
|
|
@@ -1294,7 +1360,7 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
1294
1360
|
return success$.pipe(raceWith(failure$));
|
|
1295
1361
|
}
|
|
1296
1362
|
|
|
1297
|
-
protected _getBookmarkData<T extends BookmarkData>(
|
|
1363
|
+
protected _getBookmarkData<T extends BookmarkData = BookmarkData>(
|
|
1298
1364
|
bookmarkId: string,
|
|
1299
1365
|
options?: { timeout?: number },
|
|
1300
1366
|
): Observable<T | null> {
|
|
@@ -1368,16 +1434,16 @@ export class BookmarkProvider implements IBookmarkProvider {
|
|
|
1368
1434
|
/**
|
|
1369
1435
|
* Generates a unique identifier for the operation
|
|
1370
1436
|
*/
|
|
1371
|
-
ref
|
|
1437
|
+
const operationRef = ref ?? generateGUID();
|
|
1372
1438
|
|
|
1373
1439
|
/**
|
|
1374
1440
|
* Observable stream of actions filtered by a specific reference.
|
|
1375
1441
|
*/
|
|
1376
1442
|
const action$ = this.#store.action$.pipe(
|
|
1377
|
-
filter((action): action is TAction => 'meta' in action && action.meta?.ref ===
|
|
1443
|
+
filter((action): action is TAction => 'meta' in action && action.meta?.ref === operationRef),
|
|
1378
1444
|
);
|
|
1379
1445
|
|
|
1380
|
-
return { ref, action$ };
|
|
1446
|
+
return { ref: operationRef, action$ };
|
|
1381
1447
|
}
|
|
1382
1448
|
|
|
1383
1449
|
/**
|