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

@iotauz/applet-core

v0.1.0

Published

Core React package for IOTA SDK applets - context injection, hooks, and utilities

Readme

@iotauz/applet-core

Core React package for building IOTA SDK applets. Provides context injection, hooks, and utilities for seamless integration with the IOTA SDK runtime.

Installation

pnpm install @iotauz/applet-core

Quick Start

Basic Setup

import { AppletProvider } from '@iotauz/applet-core'
import App from './App'

function Root() {
  return (
    <AppletProvider windowKey="__BICHAT_CONTEXT__">
      <App />
    </AppletProvider>
  )
}

Using Hooks

import {
  useUser,
  usePermissions,
  useTranslation,
  useSession,
  useRoute,
  useConfig
} from '@iotauz/applet-core'

function App() {
  const { firstName, email } = useUser()
  const { hasPermission } = usePermissions()
  const { t } = useTranslation()
  const { isExpiringSoon, refreshSession } = useSession()
  const { path, params } = useRoute()
  const { graphQLEndpoint } = useConfig()

  // Check permissions
  if (!hasPermission('bichat.access')) {
    return <div>{t('Common.NoAccess')}</div>
  }

  // Auto-refresh expiring session
  if (isExpiringSoon) {
    refreshSession()
  }

  return (
    <div>
      <h1>{t('BiChat.Welcome', { name: firstName })}</h1>
      <p>{t('Common.CurrentPath')}: {path}</p>
    </div>
  )
}

API Reference

Context Providers

AppletProvider

Main context provider that reads context from window global.

<AppletProvider windowKey="__BICHAT_CONTEXT__">
  <App />
</AppletProvider>

Props:

  • windowKey: string - The window global key to read context from (e.g., __BICHAT_CONTEXT__)
  • context?: InitialContext - Optional: provide context directly instead of reading from window
  • children: ReactNode - React children

ConfigProvider

Alternative provider that accepts context via props (useful for testing/SSR).

<ConfigProvider config={initialContext}>
  <App />
</ConfigProvider>

Props:

  • config: InitialContext - The initial context object
  • children: ReactNode - React children

Core Hooks

useUser()

Access current user information.

const { id, email, firstName, lastName, permissions } = useUser()

Returns:

{
  id: number
  email: string
  firstName: string
  lastName: string
  permissions: string[]
}

usePermissions()

Permission checking utilities.

const { hasPermission, hasAnyPermission, permissions } = usePermissions()

if (hasPermission('bichat.access')) {
  // User has bichat access
}

if (hasAnyPermission('finance.view', 'finance.edit')) {
  // User has at least one permission
}

Returns:

{
  hasPermission: (permission: string) => boolean
  hasAnyPermission: (...permissions: string[]) => boolean
  permissions: string[]
}

useTranslation()

i18n translation with interpolation.

const { t, language } = useTranslation()

// Simple translation
const title = t('BiChat.Title')

// Translation with params
const welcome = t('Common.Welcome', { name: 'John' })
// If translation is "Welcome {name}!" -> Returns "Welcome John!"

Returns:

{
  t: (key: string, params?: Record<string, unknown>) => string
  language: string
}

Translation Keys: React uses the same translation keys as Go backend:

  • Go: pageCtx.T("BiChat.Title")
  • React: t("BiChat.Title")

All translations from the locale bundle are automatically available.

useSession()

Session and authentication handling.

const { isExpiringSoon, refreshSession, csrfToken, expiresAt } = useSession()

// Check if session expires soon
if (isExpiringSoon) {
  await refreshSession()
}

// Include CSRF token in requests
fetch('/api/endpoint', {
  headers: { 'X-CSRF-Token': csrfToken }
})

Returns:

{
  isExpiringSoon: boolean        // True if session expires in < 5 minutes
  refreshSession: () => Promise<void>
  csrfToken: string
  expiresAt: number             // Unix timestamp
}

CSRF Token Refresh: Listen for token refresh events:

window.addEventListener('iota:csrf-refresh', (e) => {
  const newToken = e.detail.token
  // Update CSRF token
})

useRoute()

Access current route context.

const { path, params, query } = useRoute()

// Example values:
// path: "/sessions/123"
// params: { id: "123" }
// query: { tab: "history" }

Returns:

{
  path: string
  params: Record<string, string>
  query: Record<string, string>
}

useConfig()

Access applet configuration.

const { graphQLEndpoint, streamEndpoint, restEndpoint } = useConfig()

Returns:

{
  graphQLEndpoint?: string
  streamEndpoint?: string
  restEndpoint?: string
}

useStreaming()

SSE streaming with cancellation support.

const { isStreaming, processStream, cancel, reset } = useStreaming()

// Process async generator stream
await processStream(messageStream, (chunk) => {
  console.log('Received:', chunk)
})

// Cancel ongoing stream
cancel()

// Reset state
reset()

Returns:

{
  isStreaming: boolean
  processStream: <T>(
    generator: AsyncGenerator<T>,
    onChunk: (chunk: T) => void,
    signal?: AbortSignal
  ) => Promise<void>
  cancel: () => void
  reset: () => void
}

TypeScript Types

All types are exported from the main entry point:

import type {
  InitialContext,
  UserContext,
  TenantContext,
  LocaleContext,
  AppConfig,
  RouteContext,
  SessionContext,
  TranslationHook,
  PermissionsHook,
  SessionHook,
  StreamingHook
} from '@iotauz/applet-core'

InitialContext

Complete context object injected by backend:

interface InitialContext {
  user: UserContext
  tenant: TenantContext
  locale: LocaleContext
  config: AppConfig
  route: RouteContext
  session: SessionContext
  custom?: Record<string, unknown>
}

Advanced Usage

Direct Window Global Access

For cases where provider setup is not possible:

import { useAppletContextDirect } from '@iotauz/applet-core'

const context = useAppletContextDirect('__BICHAT_CONTEXT__')

Custom Context Fields

Access custom context fields via the custom property:

const { custom } = useAppletContext()
const customData = custom?.myCustomField

Server-Side Rendering (Next.js)

Use ConfigProvider for SSR:

// pages/index.tsx
export async function getServerSideProps(context) {
  const initialContext = context.req.__APPLET_CONTEXT__

  return {
    props: { initialContext }
  }
}

export default function Page({ initialContext }) {
  return (
    <ConfigProvider config={initialContext}>
      <App />
    </ConfigProvider>
  )
}

Pattern Alignment with Go Backend

Applet-core maintains consistency with Go backend patterns:

Permissions:

// Go backend
sdkcomposables.CanUser(ctx, permissions.BiChatAccess)
// React frontend
hasPermission('bichat.access')

Translations:

// Go backend
pageCtx.T("BiChat.Title")
// React frontend
t("BiChat.Title")

All user permissions and translations are automatically passed from backend - no manual mapping required.

Best Practices

  1. Use specialized hooks instead of useAppletContext() for better type safety
  2. Check permissions early in component lifecycle
  3. Handle session expiration proactively with useSession().isExpiringSoon
  4. Use same translation keys as Go backend for consistency
  5. Include CSRF tokens in all mutating requests
  6. Cancel streams on component unmount to prevent memory leaks

Development

# Install dependencies
pnpm install

# Build package
pnpm run build

# Type check
pnpm run typecheck

# Lint
pnpm run lint

# Development mode (watch)
pnpm run dev

License

MIT