@omen.dog/sdk
v1.2.0
Published
Official server-side TypeScript SDK for the Omen platform
Downloads
344
Maintainers
Readme
@omen.dog/sdk
Official server-side TypeScript SDK for the Omen platform.
Install
npm install @omen.dog/sdkRequires Node.js 18+ (uses native fetch). Zero dependencies.
Quick Start
import { OmenClient } from '@omen.dog/sdk';
const omen = new OmenClient({
token: process.env.OMEN_TOKEN!, // dev_yourorg_abc123...
appId: 'your-app-id', // from the Developer Portal
});Namespaces
Users
const profile = await omen.users.get('pistolphoenix');
const { friends, onlineCount } = await omen.users.friends('pistolphoenix', {
status: 'online',
limit: 10,
});Storage
Per-user key-value storage scoped to your app.
const { data } = await omen.storage.get();
await omen.storage.set({ highScore: 100, level: 5 });
await omen.storage.merge({ highScore: 200 }); // keeps 'level' intactItems
Issue achievements, collectibles, and in-game items to users.
const item = await omen.items.issue({
userId: 'cmm0tzco8...',
name: 'Dragon Slayer',
type: 'achievement',
rarity: 'legendary',
});
// Batch issue (up to 100)
const { items } = await omen.items.issueBatch([
{ userId: 'user1', name: 'Gold Medal', type: 'achievement' },
{ userId: 'user2', name: 'Silver Medal', type: 'achievement' },
]);
// Revoke
await omen.items.revoke(item.id, 'Violated terms');Collections
Structured data storage — like a simple document database.
// Create a collection with schema
await omen.collections.create({
name: 'player_stats',
schema: { score: 'number', level: 'number', name: 'string' },
indexedFields: ['score'],
});
// Insert documents
const doc = await omen.collections.insert('player_stats', {
score: 1500, level: 12, name: 'PistolPhoenix',
});
// Query with filters
const { documents } = await omen.collections.query('player_stats', {
where: { level: { $gte: 10 } },
sort: { score: -1 },
limit: 20,
});
// Atomic transactions (Pro+ tier)
const { results } = await omen.collections.transaction('game_state', [
{ type: 'get', id: 'player_1' },
{ type: 'update', id: 'player_1', data: { health: 50 } },
]);Webhooks
// Register (secret is only returned once!)
const webhook = await omen.webhooks.create({
url: 'https://myapp.com/webhooks/omen',
events: ['item.issued', 'friend.added'],
});
console.log(webhook.secret); // save this!
// Verify incoming webhooks
const valid = await omen.webhooks.verify(rawBody, signature, secret);Sparks (partner awards)
Award money-backed Sparks and catalog items to your users from a prepaid pool (buy/manage it in the Developer Portal → Sparks Pool).
Approved Partner Apps only. Awarding mints real Sparks, so
award,awardBatch, anditems.awardCatalogrequire the app to be an approved Partner App (Developer Portal → Partner Program). Unapproved apps get403 partner_required. Funding a pool does not require approval.
// Award Sparks (pass idempotencyKey to make retries safe)
await omen.sparks.award({
userId, amount: 250, reason: 'Beat level 10',
idempotencyKey: `level10:${userId}`,
});
// Batch (≤100, best-effort per item)
await omen.sparks.awardBatch([
{ userId: 'u1', amount: 100 },
{ userId: 'u2', amount: 100 },
]);
// Award an open-shop item or avatar trait — paid from your pool at list price
await omen.items.awardCatalog({ userId, catalogType: 'store', catalogItemId: 'theme_lava' });
// Pool status
const pool = await omen.sparks.pool();
// Mint a short-lived display token for the UI kit (backend only — needs your
// app's OAuth client secret). Pass it to <omen-sparks-balance>/<omen-inventory>.
const token = omen.sparks.displayToken({ userId, secret: process.env.OMEN_CLIENT_SECRET! });UI kit (embeddable widgets)
<script src="https://sdk.omen.dog/v1/ui-kit.js"></script>
<omen-sparks-balance token="DISPLAY_TOKEN"></omen-sparks-balance>
<omen-inventory token="DISPLAY_TOKEN" limit="24"></omen-inventory>
<script>OmenUI.toast({ amount: 250, message: 'Level cleared!' })</script>Restyle via CSS variables (--omen-bg, --omen-accent, --omen-spark, …),
::part() selectors, or theme="bare" to ship your own CSS entirely.
Shared avatar (Embedded Avatar Kit)
Put the shared Omen avatar inside your app — display it, let users edit it in-place, browse the trait catalog, and gift traits from your Sparks pool.
// Public render URL (pass version from avatar:saved / user.avatar_updated to bust caches)
const url = omen.avatar.renderUrl(userId, { version });
// Mint a short-lived editor token for <omen-avatar-editor> (backend only)
const token = omen.avatar.editorToken({ userId, secret: process.env.OMEN_CLIENT_SECRET! });
// Enumerate the shared catalog — trait ids, names, rarities, ✦ prices (public, no auth).
// Pass { editorToken } and each trait's `locked` reflects that user's ownership.
const { catalog, rarityPricing } = await omen.avatar.catalog();
// Gift a trait app-funded — your pool pays list price, the user pays nothing
await omen.items.awardCatalog({
userId, catalogType: 'avatar_trait', catalogItemId: 'hair/export-01.svg',
});Trait ids are category/file.svg paths and double as public preview SVGs at
https://omen.dog/avatar/{traitId}. Common traits are free for everyone and
can't be awarded.
App-owned assets & image generation
Host content art your app owns (shared across all your users, not a single user's upload) and serve it from a public, immutable, CDN-cacheable URL — exempt from the per-user asset cap. Bring your own bytes, or generate them on Omen billed to your prepaid Sparks pool.
// Host bytes you already have (Buffer / Uint8Array / base64). Max 10 MB.
const asset = await omen.assets.upload(pngBuffer, { name: 'Apple', contentType: 'image/png' });
console.log(asset.url); // /api/v1/assets/…/file — embed anywhere
// List / fetch / evict (eviction is yours to control — never purged on a timer)
const { assets, nextCursor } = await omen.assets.list({ limit: 50 });
await omen.assets.delete(asset.id);
// Generate one image, billed to your pool, hosted app-owned. Requires an
// approved Partner App + a funded pool. Output is child-safety-filtered.
const { asset: img, cost, poolBalance } = await omen.images.generate({
prompt: 'a friendly red apple with a smiling face',
aspectRatio: '4:3', // 1:1 | 4:3 | 3:4 | 16:9 | 9:16
style: 'storybook', // optional preset; omit for raw-prompt mode
idempotencyKey: `apple:${pageId}`,
});
// Keep a recurring character consistent across story pages — pass an identity ref
await omen.images.generate({
prompt: 'the same fox, now jumping over a log',
aspectRatio: '3:4',
referenceImages: [{ data: foxPngBase64, tag: 'identity' }], // up to 4, ≤4 MB each
});A depleted pool fails closed (402, throws OmenError); a rejected prompt or
blocked image throws OmenValidationError (400 content_rejected) and your pool
is not charged.
Creation Runtime Types
For creation developers — get autocomplete for the omen.* global:
/// <reference types="@omen.dog/sdk/creation" />
const save = await omen.load();
omen.score(100);Child Re-Login (ChildLogin)
A safe, thin wrapper over the child device-grant flow for Tier-3 apps that sign
in Omen child accounts (F263). It's a separate export — it uses your OAuth
clientId/clientSecret, not a dev_ token — and is also available from the
server-only subpath @omen.dog/sdk/child-login. scope:'child' is always sent,
RFC 8628 errors map to a calm status union instead of throwing, and scope is
preserved across refresh rotation. Tokens never leave your server.
import { ChildLogin } from '@omen.dog/sdk/child-login';
const child = new ChildLogin({
clientId: process.env.OMEN_CLIENT_ID!,
clientSecret: process.env.OMEN_CLIENT_SECRET!, // omit for public/PKCE clients
webhookSecret: process.env.OMEN_WEBHOOK_SECRET!,
});
const grant = await child.deviceStart({ deviceName: "Astrid's iPad" });
await child.notify({ device_code: grant.device_code, username: 'astrid' }); // cold start
const res = await child.pollUntil(grant.device_code); // honors interval + slow_down
if (res.status === 'approved') {
const session = child.seal(res.tokens!); // store in your httpOnly session; res.rebind = card data
}
// flip the child's screen the instant a parent approves:
if (child.verifyWebhook(rawBody, req.headers['x-omen-signature'])) { /* notify the device */ }Pair it with the in-context <omen-child-login> web component (zero-dep, themeable,
talks only to your own routes). See omen.dog/docs#child-relogin-kit.
The canonical child-side state machine is exported too (deriveInitialState,
reduce, displayGroup, CHILD_LOGIN_STATES) for apps building custom UI on the
same kindness.
Error Handling
import { OmenClient, OmenNotFoundError, OmenRateLimitError } from '@omen.dog/sdk';
try {
await omen.users.get('nonexistent');
} catch (err) {
if (err instanceof OmenNotFoundError) {
console.log('User not found');
}
if (err instanceof OmenRateLimitError) {
console.log(`Rate limited. Retry after ${err.retryAfter}s`);
}
}API Reference
Full documentation at omen.dog/docs.
License
MIT
