# @strands.gg/accounts

The Strands Accounts SDK. OAuth2/OIDC client, session and token management
(including silent refresh), and ready-made components for Vue, Nuxt, and any
framework via web components.

The package is structured around a small framework-agnostic core that every
binding wraps, so adding React (or anything else) later is a thin layer.

## Install

```bash
npm install @strands.gg/accounts
```

## Vue

Wrap your app once with `<StrandsAccountProvider>` to set up the session store,
then use the components and composables anywhere underneath.

```vue
<script setup lang="ts">
import {
  StrandsAccountProvider,
  OAuthButton,
  OAuthCallback,
  useStrandsAccount,
  useAuthenticatedFetch
} from '@strands.gg/accounts'
import '@strands.gg/accounts/style.css'
</script>

<template>
  <StrandsAccountProvider
    client-id="your-app-id"
    redirect-uri="https://your-app.example.com/oauth/callback"
  >
    <OAuthButton />
    <!-- ...rest of your app... -->
  </StrandsAccountProvider>
</template>
```

### Composables

`useStrandsAccount()` reads the session store provided by the wrapper:

```ts
const { user, isAuthenticated, isLoading, signOut } = useStrandsAccount()
```

`useAuthenticatedFetch()` returns a fetch wrapper that injects the bearer
token and silently refreshes on 401:

```ts
const api = useAuthenticatedFetch()
const profile = await api.get('https://api.example.com/me').then(r => r.json())
```

For non-component contexts (route guards, plugins) use `$authFetch` — the same
helpers, backed by the global default client.

### OAuth callback page

Mount `<OAuthCallback>` at your registered redirect URI:

```vue
<template>
  <OAuthCallback success-redirect="/" error-redirect="/auth/error" />
</template>
```

It reads the URL params, exchanges the authorization code for tokens, fetches
the user profile, then redirects.

## Nuxt

Add the module and configure your client:

```ts
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@strands.gg/accounts/nuxt'],
  strandsAccounts: {
    clientId: 'your-app-id',
    redirectUri: 'https://your-app.example.com/oauth/callback'
  }
})
```

The module:

- registers `<StrandsAccountProvider>`, `<OAuthButton>`, and `<OAuthCallback>`
  as auto-imported components
- auto-imports `useStrandsAccount`, `useAuthenticatedFetch`, and `$authFetch`
- bootstraps the OAuth client on the client side so descendants can call
  composables without manually mounting a provider

## Web components

For non-Vue apps (or for embedding in static pages):

```html
<script type="module" src="/path/to/strands-accounts/dist-webcomponents/index.js"></script>

<sa-account-provider client-id="your-app-id" redirect-uri="https://your-app.example.com/oauth/callback">
  <sa-oauth-button></sa-oauth-button>
</sa-account-provider>
```

The provider element registers a global default OAuth client, and the
`<sa-oauth-button>` / `<sa-oauth-callback>` elements use it.

## Framework-agnostic core

If you're building a binding for a new framework, import directly from
`@strands.gg/accounts/core`:

```ts
import { createOAuthClient, setDefaultClient } from '@strands.gg/accounts/core'

const client = createOAuthClient({
  clientId: 'your-app-id',
  redirectUri: 'https://your-app.example.com/oauth/callback'
})
setDefaultClient(client)

// client.startAuth() / client.handleCallback() / client.refreshTokens()
// client.signOut() / client.authenticatedFetch() / client.subscribe()
```

The client emits state changes via `subscribe(listener)`, which is what every
framework binding wraps.

## License

MIT — Strands Services Limited.
