Home

Mangrove Reviews JS Library

Read and write Open Reviews from JavaScript. The library covers the reviewer API, signing with a key the app holds, logging people in through the signer so the app holds no keys, binding a key to a reviewer identity, and following a subject or reviewer from the Fediverse.

npm

Installation

npm install mangrove-reviews

The library needs fetch, URL and WebCrypto, which browsers and Node 20 and later provide. A script tag can load dist/index.umd.js instead; it defines mangrove-reviews, with the signer calls under signer.

Read reviews

import { getReviews, getSubject } from 'mangrove-reviews'

const reviews = await getReviews({ sub: 'https://example.com' })
const aggregate = await getSubject('https://example.com')

Write reviews with a local key

The app generates a keypair and keeps it, for example as JWK in IndexedDB. Reviews of https://example.com and of geo:0,0?q=<any name>&u=30 are removed from the dataset, so use those subjects for tests.

import {
  generateKeypair,
  keypairToJwk,
  signAndSubmitReview
} from 'mangrove-reviews'

const keypair = await generateKeypair()
const jwk = await keypairToJwk(keypair) // store this to keep the same reviewer

await signAndSubmitReview(keypair, {
  sub: 'https://example.com',
  rating: 75,
  opinion: 'Great website to be used as an example.',
  metadata: { nickname: 'docs reader' }
})

Write reviews through the signer

The signer holds one key per person who logs in with OpenStreetMap, Bluesky, Google, GitHub or a passkey, so the app manages no keys and the person keeps one identity across devices and apps. The app needs a client id; the login guide says how to get one and walks through the callback.

import {
  loginUrl,
  parseCallback,
  signAndSubmitReview
} from 'mangrove-reviews/signer'

window.location.href = loginUrl(clientId, callbackUrl, 'osm', undefined, state)

// On the callback page:
const { sessionToken, did } = parseCallback(window.location.href)
await signAndSubmitReview(sessionToken, {
  sub: 'https://example.com',
  rating: 80
})

A logged-in person can add a passkey to their account, list their passkeys and remove one:

import {
  passkeyAddUrl,
  listPasskeys,
  removePasskey
} from 'mangrove-reviews/signer'

window.location.href = await passkeyAddUrl(sessionToken, callbackUrl, state)
// The signer's page returns to callbackUrl with #passkey=added&state=... in the fragment.
const passkeys = await listPasskeys(sessionToken)
await removePasskey(sessionToken, passkeys[0].id)

Follow from the Fediverse

import { getFediverseHandle, followUrl } from 'mangrove-reviews'

const { acct, actor } = await getFediverseHandle({ sub: 'https://example.com' })
// Show `acct` with a copy button, or open the follow dialog on the person's server:
window.open(followUrl('mastodon.social', actor))

Errors

A refused request rejects with an ApiError carrying the HTTP status and the server's reason in body, such as the field of a review that is wrong or 401 for an expired session.

License

Apache-2.0

index.js

signer.js

Log reviewers in with an account they already have and sign reviews through the signer, which holds one key per person.

Source: