Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions docs/rfcs/0013-favourites-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# RFC-0013: Favourites API

| | |
| --------------- | --------------------------------------------------------------- |
| **Start Date** | 2026-04-21 |
| **Description** | Let products read and manage the user's bookmarked apps |
| **Authors** | Filippo Vecchiato |

## Summary

Products can query, add and remove bookmarked apps from the host's local product catalogue. The host exposes a subscription for the installed-product list and two mutations for adding/removing entries. Browse (the on-chain discovery product) receives privileged access without an explicit permission prompt.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Browse (the on-chain discovery product) receives privileged access without an explicit permission prompt.

We should mention why? Because it is our default discovery product.


## Motivation

The host maintains a local catalogue of products the user has bookmarked (starred). Today this data lives in the host's IndexedDB and is inaccessible to products. Browse — the primary discovery surface — cannot show which apps are already installed or let the user bookmark new ones without direct database access.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could start by mentioning that hosts store data the products don't have access to, but would benefit from. Bookmarked apps is one such example.

The host maintains

We have three hosts today, Polkadot Desktop, Polkadot Web, and Polkadot Mobile, but only Desktop has bookmarks. Maybe rephrase to "Some hosts maintain".


Exposing this catalogue:

1. **Enables discovery UIs** — Browse can render install/uninstall affordances inline.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very generic

2. **Keeps the host authoritative** — mutations go through the host, which owns the storage schema and can enforce invariants.
3. **Supports other products** — any product with permission can read the installed list (e.g. a dashboard, launcher, or analytics tool).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I'd also tie this to DotNS being permissionless, anyone can publish a product, so discovery is essential. Browse and other products should also be able to help users find and keep track of apps that solve their problems.


## Detailed Design

### Data Model

```rust
struct FavouriteProduct {
product_id: DotNsIdentifier,
installed: bool,
source: ProductSource,
created_at: Timestamp,
updated_at: Timestamp
}

enum ProductSource {
Remote, // discovered via on-chain registry
Local // sideloaded or manually added
}
```

This mirrors the existing `ProductRecord` in the host's `products` table, exposing only the fields relevant to products.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest starting with this sentence, and link to the relevant lines of code in polkadot-desktop as an example.


### API

```rust
enum FavouritesErr {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we return a specific error if the Host doesn't have a favourites table?

NotConnected,
Rejected,
Unknown(GenericErr)
}

fn host_favourites_subscribe(
callback: fn(Vec<FavouriteProduct>)
) -> Result<Subscriber, FavouritesErr>;

fn host_favourites_add(
product_id: DotNsIdentifier
) -> Result<FavouriteProduct, FavouritesErr>;

fn host_favourites_forget(
product_id: DotNsIdentifier
) -> Result<void, FavouritesErr>;
```

- `host_favourites_subscribe` delivers the full list on each callback; hosts MAY debounce.
- `host_favourites_add` upserts a `FavouriteProduct` with `source: Remote`, setting `created_at` on first install and `updated_at` on every call. Returns the resulting record.
- `host_favourites_forget` removes the product from the catalogue entirely.

All methods require authentication (RFC-0009).

### Permission Model

Extends `DevicePermission` from RFC-0002:

```rust
enum DevicePermission {
// ... existing variants ...
Favourites
}
```

| Permission | Grants |
|-----------|--------|
| `Favourites` | Read, add, and forget bookmarked products |

**Browse privilege:** The host MAY grant implicit `Favourites` to Browse (the built-in discovery product) without prompting. This is analogous to how Browse currently writes directly to the products table.

### Host Behaviour

On `host_favourites_add`:
1. Upsert row in the products table with `installed: true`, `source: 'remote'`.
2. Set `created_at` if new, `updated_at` on every call.
3. Notify all active subscribers.

On `host_favourites_forget`:
1. Delete the row from the products table.
2. Notify all active subscribers.

The host SHOULD display a brief confirmation toast on install/forget for products other than Browse.

Favourites are local to the host instance. Cross-host sync is out of scope for this RFC.

## Drawbacks

- **Full-list delivery.** No pagination or filtered subscriptions. Acceptable for typical catalogue sizes (tens to low hundreds).
- **Browse coupling.** Implicit privilege for Browse assumes a well-known product identity. If Browse's DotNS identifier changes, the host must update its allowlist.

## Alternatives

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a straightforward API in my opinion, we can remove


-

## Unresolved Questions

1. **Batch operations.** Should `host_favourites_add` accept multiple product IDs?
Comment on lines +113 to +115

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't think of a use case for this, but worth keeping it in mind.

1 change: 1 addition & 0 deletions docs/rfcs/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ created: 2026-03-13
| 0008 | [Statement Store Host API v0.2](0008-statement-store.md) | accepted | @johnthecat | [#118](https://github.com/paritytech/triangle-js-sdks/pull/118) | [v0.7 → Statement Store Subscribe API](../migration/v0.7.md#statement-store-subscribe-api-rfc-0008) |
| 0009 | [Unauthenticated Product Access](0009-unauthenticated-product-access.md) | accepted | @filvecchiato | [#128](https://github.com/paritytech/triangle-js-sdks/pull/128) | [v0.7 → Request Login](../migration/v0.7.md#new-host_request_login-rfc-0009) |
| 0010 | [Root account access Host API](0010-get-root-account.md) | accepted | @johnthecat | [#126](https://github.com/paritytech/triangle-js-sdks/pull/126) | [v0.7 → Root Account](../migration/v0.7.md#requesting-root-account-from-product) |
| 0013 | [Favourites API](0013-favourites-api.md) | draft | @filvecchiato | - | - |