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

@onaio/akuko-embed-sdk

v0.1.1

Published

Framework-agnostic embed SDK for Akuko dashboards

Readme

@onaio/akuko-embed-sdk

Framework-agnostic SDK for embedding Akuko dashboards and storytelling content into any web page. It mounts a sandboxed <iframe> and talks to it over a versioned postMessage bridge — themes, filters, visibility, member re-sync, and lifecycle events all flow through one small, typed API.

  • Zero runtime dependencies. Ships as ESM + UMD with TypeScript types.
  • Framework-agnostic. Use it from vanilla JS, or via the React wrapper @onaio/akuko-embed-react.
  • Auth-aware. Public dashboards embed with no login; private/federated dashboards use redirect-based Keycloak brokering (Path D), so they keep working even when third-party cookies are blocked.

Install

pnpm add @onaio/akuko-embed-sdk
# or: npm install @onaio/akuko-embed-sdk
# or: yarn add @onaio/akuko-embed-sdk

Quick start (vanilla)

<div id="mount"></div>
<script type="module">
  import { AkukoDashboard } from "@onaio/akuko-embed-sdk";

  const dashboard = new AkukoDashboard({
    container: "#mount",
    dashboardId: "your-dashboard-id",
    baseUrl: "https://akuko.io",
  });

  dashboard.on("akuko:ready", () => console.log("dashboard ready"));
  // …later: dashboard.destroy();
</script>

container accepts a CSS selector string or an HTMLElement. The constructor throws if the container can't be found.

Entry modes

Pass exactly one of these mutually-exclusive entry props (the constructor throws must pass exactly one of … otherwise):

| Prop | Loads | Use when | |------|-------|----------| | dashboardId | a single published dashboard (post) | you have a specific dashboard/post id | | spaceUuid | a whole Akuko space | you want the full space surface | | onadataOrgId | resolves an OnaData org → its linked space, brokered | embedding from an OnaData-authenticated host | | onadataProjectId | resolves an OnaData project → its linked folder, brokered | per-project analytics in an OnaData host | | onadataFormId | resolves a single OnaData form → its generated dashboard, brokered | embedding one form's auto-generated dashboard | | linkProjectsOrgId | the standalone "link projects" picker surface | rendering the admin link-projects modal |

The onadata* and linkProjects* modes run Akuko's brokered OIDC login inside the iframe (same-origin), call /v1/embed/resolve, then redirect themselves to the resolved space/onboarding and emit akuko:resolved back over the bridge. The host never makes a cross-origin API call.

When the host knows the owning org (and, for a form, its project) but the current user hasn't completed a personal OnaData grant, pass resolveOnadataOrgId (and resolveOnadataProjectId for a form) alongside the entry prop. These are companions, not entry props — they let akuko resolve role-appropriate content for every authenticated org user, not just the admin who provisioned analytics.

Options

All options are passed to the AkukoDashboard constructor (AkukoSDKOptions):

| Option | Type | Default | Notes | |--------|------|---------|-------| | container | string \| HTMLElement | — | Required. Mount point. | | dashboardId | string | — | Entry mode (see above). | | spaceUuid | string | — | Entry mode. | | onadataOrgId | string | — | Entry mode. | | onadataProjectId | string | — | Entry mode. | | onadataFormId | string | — | Entry mode — a single OnaData form's generated dashboard. | | linkProjectsOrgId | string | — | Entry mode (org slug). | | resolveOnadataOrgId | string | — | Grant-independent companion (not an entry prop): owning org slug, so akuko can derive the embed's state without the caller's personal OnaData grant. Pairs with onadataProjectId / onadataFormId. Does not count toward "exactly one entry prop". | | resolveOnadataProjectId | string | — | Companion: the form's project id. Pairs with onadataFormId. | | baseUrl | string | https://akuko.io | Origin serving the embed /embed/* routes. | | apiBaseUrl | string | — | Accepted for back/forward-compat but no longer used — resolve/resync run inside the iframe. Safe to keep passing. | | idpHint | string | — | Keycloak kc_idp_hint alias for silent federation (see SSO). | | initialPostId | string | — | Post/dashboard to open on mount, overriding the configured default. For host deep-linking/sharing (forwarded as ?post=). | | theme | AkukoTheme | — | Initial theme (see below). | | visibility | AkukoVisibility | — | Initial chrome visibility. | | filters | Record<string, unknown> | — | Initial filter values. | | hostIsAdmin | boolean | — | Hint that the current user can administer the embedded org/project; gates the in-iframe onboarding consent for an unlinked org. UX-only — the backend re-verifies ownership at provisioning. | | hostUser | { email: string } | — | The host's current signed-in OnaData user; lets the embed detect a host user-switch and tear down a stale session. Untrusted — only forces a re-auth on mismatch. | | allowedOrigin | string | origin of baseUrl | Origin the bridge accepts messages from. | | sandbox | string | allow-scripts allow-same-origin allow-popups allow-forms allow-downloads | iframe sandbox attribute. The iframe is also granted fullscreen; clipboard-write via the allow attribute (so the embed can enter OS fullscreen and the in-embed Share can copy the post URL). | | layout | "content" \| "fill" | content | content auto-resizes to the embed height; fill makes the embed fill a host-sized container (host owns height). | | minHeight | number \| string | — | content layout only: a minimum height floor (px number or CSS length) so a short/empty dashboard still fills down to the host footer. Ignored in fill. | | iframeLoadTimeoutMs | number | 30000 | Watchdog before akuko:error{code:'IFRAME_LOAD_FAILED'}. 0 disables; <5000 not recommended. | | logoutTimeoutMs | number | 2000 | How long logout() waits for akuko:logoutComplete before resolving anyway. |

AkukoTheme

primary, background, foreground, card, border, radius, fontFamily, darkMode (boolean), and chart1chart5. All optional.

AkukoVisibility

Booleans to show/hide chrome: header, breadcrumbs, footer, undoRedo, chartActions, filterBar.

Methods

const d = new AkukoDashboard({ /* … */ });

| Method | Description | |--------|-------------| | setTheme(theme) | Apply an AkukoTheme. Cached and re-applied on every akuko:ready. | | setVisibility(v) | Show/hide chrome. Cached and replayed on ready. | | setViewport(viewport) | Report the iframe's currently-visible vertical band ({ top, height }) so in-iframe floating UI can center itself under content layout. The React wrapper does this automatically. Cached and replayed. | | setFilters(filters) | Push filter values into the dashboard. Cached and replayed. | | clearFilters(keys?) | Clear specific filter keys, or all filters when called with no args. | | refresh() | Ask the dashboard to reload its data. | | getState() | Request current state; response arrives via akuko:stateResponse. | | resyncMembers(opts) | Re-sync OnaData members into the linked space/folder. opts.scope is "org" or "project". Progress via akuko:provisioningStatus. | | linkProjects() | Navigate the iframe to the org's project-picker. Throws unless constructed with onadataOrgId. | | logout() | Tear down the in-iframe Akuko session (RP-initiated end-session). Resolves on akuko:logoutComplete or after logoutTimeoutMs. Never rejects, never hangs. | | destroy() | Remove the iframe and tear down the bridge. |

State pushed via setTheme / setVisibility / setFilters / setViewport (and the hostUser identity) is replayed automatically on each akuko:ready, so it survives the iframe's full-document replacements during brokered OIDC + SPA navigation.

Events

Subscribe with on(type, handler) and unsubscribe with off(type, handler):

const onResize = (p) => console.log("height", p.height);
d.on("akuko:resize", onResize);
d.off("akuko:resize", onResize);

The AkukoEventType union:

| Event | Fires when | |-------|------------| | akuko:ready | a surface inside the iframe has mounted and is ready. | | akuko:resolved | brokered resolve completed; payload is ResolveResponse (linked / unlinked / provisioning / reauth_required). | | akuko:resize | content height changed ({ height }); ignored in fill layout. | | akuko:filterChange | the user changed a filter inside the dashboard. | | akuko:cellClick | a chart/table cell was clicked. | | akuko:dashboardChange | the active dashboard changed. | | akuko:provisioningStatus | JIT member-sync progress. | | akuko:stateResponse | response to getState(). | | akuko:linkProjects / akuko:linkProjectsDone | link-projects surface opened / finished. | | akuko:navigate | the embed asks the host to navigate to a project's analytics page (payload { scope, onadataProjectId, ownerUsername? }). | | akuko:share | the embed asks the host to copy a shareable post URL (payload { postId, scope, url? }); the embed also copies it itself, so handling is optional. | | akuko:logout / akuko:logoutComplete | logout requested / acknowledged. | | akuko:error | an error occurred (e.g. { code: 'IFRAME_LOAD_FAILED' }). | | akuko:close | the embed asked the host to close it (e.g. a modal surface). |

The bridge only accepts messages from allowedOrigin (default: the origin of baseUrl) and scopes them to this iframe, so multiple embeds on one page don't cross-talk.

SSO (federated login)

For private or federated dashboards, Akuko authenticates users via Keycloak identity brokering (Path D) — a redirect-based OIDC flow, so it works cross-domain and survives third-party-cookie blocking. Your host passes the brokered IdP alias as idpHint; first-time users go straight from your app → Akuko iframe → your IdP → back → dashboard, with no broker-selection UI.

See ./docs/sso-path-d-brokering.md for the full setup, and ./examples/keycloak-path-d-setup.sh for a sanitized kcadm.sh reference.

Host recipes

Concrete WordPress and Directus integration recipes live in ./docs/host-recipes.md.

Testing with canary builds

Branch builds are published under the canary dist-tag so you can test an unreleased change in a consumer before it ships:

pnpm add @onaio/akuko-embed-sdk@canary

Browser support

Modern evergreen browsers. Note that browsers with third-party-cookie blocking (Safari ITP, Firefox ETP) restrict cross-site cookies — but Akuko's federated login (Path D) is redirect-based, not cookie-shared, so embedded private dashboards keep working under those restrictions.

License

Apache-2.0