@pulseid/client
v0.5.1
Published
TypeScript SDK for PULSE ID - Your athlete identity
Maintainers
Readme
@pulseid/client
TypeScript SDK for PULSE ID, including auth and typed access to the user timeline entries API.
Install
pnpm add @pulseid/clientServer (Recommended)
import { PulseIdServer } from '@pulseid/client/server';
const server = new PulseIdServer({
issuer: 'https://id.pulserunning.at',
clientId: process.env.PULSEID_CLIENT_ID!,
clientSecret: process.env.PULSEID_CLIENT_SECRET!,
storage: tokenStorage,
});
// Get a user-scoped client with auto-refresh
const pulse = server.forUser(userId);
const profile = await pulse.profile.get();
await pulse.profile.update({ displayName: 'New Name' });Browser
import { PulseIdClient } from '@pulseid/client';
const client = new PulseIdClient({
issuer: 'https://id.pulserunning.at',
clientId: 'your-client-id',
});
// Build auth URL
const authUrl = client.buildAuthorizationUrl({
redirectUri: 'https://yourapp.com/callback',
scope: 'openid profile email offline_access',
state: crypto.randomUUID(),
nonce: crypto.randomUUID(),
codeChallenge,
codeChallengeMethod: 'S256',
});
// After callback
const profile = await client.getProfile(accessToken);Entries Quick Reference
category and type are different filters:
category= broad bucket such asactivity,body,nutrition,calendar, orcustomtype= specific entry kind such asworkout,weight,meal, orevent
const workouts = await pulse.entries.list({
category: 'activity',
type: 'workout',
sortBy: 'createdAt',
sortOrder: 'desc',
limit: 10,
});Use sortBy: 'timestamp' for event-time ordering and sortBy: 'createdAt' for recently-added ordering. from and to currently filter the event timestamp.
Token Storage
import type { TokenStorage, StoredTokens } from '@pulseid/client/server';
const tokenStorage: TokenStorage = {
async getTokens(userId) { /* fetch from db */ },
async setTokens(userId, tokens) { /* save to db */ },
async deleteTokens(userId) { /* delete from db */ },
};Error Handling
import { InvalidTokenError, InsufficientScopeError } from '@pulseid/client';
try {
await pulse.profile.get();
} catch (error) {
if (error instanceof InvalidTokenError) redirect('/login');
if (error instanceof InsufficientScopeError) console.log(error.requiredScope);
throw error;
}Docs
See docs or run pnpm docs:dev.
Contract Sync
Entry contracts are generated from the pulse-id OpenAPI document instead of being hand-maintained.
# In ../pulse-id
pnpm openapi:write
# In this repo
pnpm types:generateIf the server spec lives elsewhere, set PULSE_ID_OPENAPI_PATH before running pnpm types:generate.
License
MIT
