npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@equinor/fusion-framework-module-bookmark

v4.0.0

Published

`@equinor/fusion-framework-module-bookmark` provides bookmark management for Fusion Framework applications. It lets users **create, update, delete, and favourite bookmarks**, track a **current (active) bookmark**, and react to bookmark lifecycle events.

Readme

Bookmark Module

@equinor/fusion-framework-module-bookmark provides bookmark management for Fusion Framework applications. It lets users create, update, delete, and favourite bookmarks, track a current (active) bookmark, and react to bookmark lifecycle events.

Under the hood the module uses an RxJS-based state store with side-effect flows, an API client backed by @equinor/fusion-framework-module-services, and an event system powered by @equinor/fusion-framework-module-event.

Key Concepts

| Concept | Description | | --- | --- | | BookmarkProvider | Runtime service exposed after the module initialises. All CRUD, favourites, and current-bookmark operations go through this class. | | BookmarkModuleConfigurator | Builder used during the configure phase to set the source system, filters, resolvers, and custom client. | | Payload Generator | Callback registered via addPayloadGenerator that participates in building the bookmark payload during create and update. The callback receives an Immer draft — mutate in place. | | Source System | Identifies which system owns the bookmarks (used for filtering and creation). | | Filters | Optional flags (application, context) that restrict bookmark queries to the current app and/or context. |

Installation

pnpm add @equinor/fusion-framework-module-bookmark

Quick Start

The simplest setup — no custom configuration, inherits everything from the parent (e.g. the portal framework):

import { enableBookmark } from '@equinor/fusion-framework-module-bookmark';

const configure = (configurator) => {
  enableBookmark(configurator);
};

Configuration

Use the callback form of enableBookmark to customise behaviour:

import { enableBookmark } from '@equinor/fusion-framework-module-bookmark';

const configure = (configurator) => {
  enableBookmark(configurator, (builder) => {
    // Tag bookmarks with their originating system
    builder.setSourceSystem({
      identifier: 'my-app-id',
      name: 'My Application',
    });

    // Only return bookmarks for the current application
    builder.setFilter('application', true);

    // Only return bookmarks for the current context
    builder.setFilter('context', true);
  });
};

Advanced Configuration

enableBookmark(configurator, (builder) => {
  // Provide a custom API client (must implement IBookmarkClient)
  builder.setClient(myCustomClient);

  // Inherit bookmarks from a different parent provider
  builder.setParent(parentProvider);

  // Override how the current context is resolved
  builder.setContextResolver(async (init) => {
    return async () => ({ id: 'custom-context-id' });
  });

  // Override how the current application is resolved
  builder.setApplicationResolver(async (init) => {
    return async () => ({ appKey: 'my-app' });
  });
});

[!NOTE] When no explicit configuration is provided, the configurator resolves values from the parent framework (portal) and falls back to defaults for:

  • Source system
  • Filters
  • Context resolver
  • Application resolver

BookmarkProvider

BookmarkProvider is the runtime service you interact with after the module is initialised. It exposes both Observable and async/Promise APIs for every operation.

Creating a Bookmark

bookmarkProvider.createBookmark({
  name: 'My Bookmark',
  payload: { filters: { status: 'active' } },
}).subscribe({
  next: (bookmark) => console.log('Created:', bookmark.id),
  error: (err) => console.error('Create failed:', err),
});

// Or with async/await:
const bookmark = await bookmarkProvider.createBookmarkAsync({
  name: 'My Bookmark',
  payload: { filters: { status: 'active' } },
});

Updating a Bookmark

bookmarkProvider.updateBookmark('bookmark-id', {
  name: 'Updated Name',
  payload: { filters: { status: 'closed' } },
}).subscribe({
  next: (updated) => console.log('Updated:', updated.id),
  error: (err) => console.error('Update failed:', err),
});

Deleting a Bookmark

bookmarkProvider.deleteBookmark('bookmark-id').subscribe({
  next: () => console.log('Deleted'),
  error: (err) => console.error('Delete failed:', err),
});

Payload Generators

Register a callback that runs during create and update to build or transform the bookmark payload. The callback receives an Immer draft — mutate it in place:

const unregister = bookmarkProvider.addPayloadGenerator((payload, initial) => {
  // `payload` is an Immer draft — mutate directly
  payload.savedAt = new Date().toISOString();
  payload.counter = (initial?.counter ?? 0) + 1;
});

// Call unregister() when the component unmounts to remove the generator

canCreateBookmarks returns true only when at least one payload generator is registered.

Current Bookmark

Set, observe, or clear the active bookmark:

// Set current bookmark by ID (fetches full data automatically)
bookmarkProvider.setCurrentBookmark('bookmark-id').subscribe();

// Clear the current bookmark
bookmarkProvider.setCurrentBookmark(null).subscribe();

// Observe changes
bookmarkProvider.currentBookmark$.subscribe((bookmark) => {
  console.log('Active bookmark:', bookmark);
});

Favourites

// Add to favourites
bookmarkProvider.addBookmarkToFavorites('bookmark-id').subscribe();

// Remove from favourites
bookmarkProvider.removeBookmarkAsFavorite('bookmark-id').subscribe();

// Check favourite status
bookmarkProvider.isBookmarkInFavorites('bookmark-id').subscribe((isFav) => {
  console.log('Is favourite:', isFav);
});

Event Listeners

Subscribe to lifecycle events emitted by the provider:

const unsubscribe = bookmarkProvider.on('onCurrentBookmarkChanged', (event) => {
  console.log('Current bookmark changed:', event.detail);
});

// Call unsubscribe() to remove the listener

Available events:

| Event | When it fires | | --- | --- | | onCurrentBookmarkChange | Before the current bookmark changes (cancelable) | | onCurrentBookmarkChanged | After the current bookmark has changed | | onBookmarkCreate | Before a bookmark is created (cancelable) | | onBookmarkCreated | After a bookmark has been created | | onBookmarkUpdate | Before a bookmark is updated (cancelable) | | onBookmarkUpdated | After a bookmark has been updated | | onBookmarkDelete | Before a bookmark is deleted (cancelable) | | onBookmarkDeleted | After a bookmark has been deleted | | onBookmarkFavouriteAdd | Before a bookmark is added to favourites (cancelable) | | onBookmarkFavouriteAdded | After a bookmark has been added to favourites | | onBookmarkFavouriteRemove | Before a bookmark is removed from favourites (cancelable) | | onBookmarkFavouriteRemoved | After a bookmark has been removed from favourites | | onBookmarkPayloadCreatorAdded | When a new payload generator is registered |

Custom Bookmark Client

To use a different backend, implement the IBookmarkClient interface and pass it to the configurator:

import type { IBookmarkClient } from '@equinor/fusion-framework-module-bookmark';

const myClient: IBookmarkClient = {
  getAllBookmarks: (filter) => { /* ... */ },
  getBookmarkById: (id) => { /* ... */ },
  getBookmarkData: (id) => { /* ... */ },
  setBookmarkData: (id, data) => { /* ... */ },
  createBookmark: (bookmark) => { /* ... */ },
  updateBookmark: (id, updates) => { /* ... */ },
  deleteBookmark: (id) => { /* ... */ },
  addBookmarkToFavorites: (id) => { /* ... */ },
  removeBookmarkFromFavorites: (id) => { /* ... */ },
  isBookmarkFavorite: (id) => { /* ... */ },
};

enableBookmark(configurator, (builder) => {
  builder.setClient(myClient);
});

Error Handling

The module exposes two error classes:

  • BookmarkProviderError — thrown by BookmarkProvider methods when a high-level operation fails (e.g. timeout, cancelled event, resolution failure).
  • BookmarkFlowError — thrown inside internal store flows when an API call fails. Carries a reference to the originating request action.

Errors are also collected in the store and accessible via bookmarkProvider.errors$.