HatchedDocs
Reference

Changelog

Release notes for @hatched/sdk-js — mirrored from the package's CHANGELOG.md.

Release notes for @hatched/sdk-js. Produced by changesets on every merge to main.

@hatched/sdk-js

1.2.0

Minor Changes

  • 48e9fdd: eggs.create now accepts a first-class audience option that binds the egg (and the buddy it hatches into) to a named audience. Audience-scoped content — streaks, badges, marketplace items — is keyed by audience, so a buddy born in the wrong audience makes those widgets 404 or render empty. The option is shorthand for metadata.audience and is folded in before the request, so the intuitive create({ userId, audience }) call sends the shape the API expects instead of being rejected by strict body validation. Single-audience workspaces can omit it; multi-audience workspaces should set it during the first-run bootstrap.

1.1.3

Patch Changes

  • fd3aff9: Refresh the generated OpenAPI types to cover two new dashboard endpoints: hosted-surface logo upload (POST /customers/me/hosted-surfaces/{id}/logo) and the admin event-trigger (POST /events/admin-trigger). This is a type-only refresh — no SDK resource methods or runtime behavior changed.

1.1.2

Patch Changes

  • e67d739: Analytics endpoints (engagement, activity-summary, economy-summary, economy-health, popular-items, popular-badges, retention, roi-metrics) now accept an optional audience query parameter, so metrics can be scoped to a single audience instead of the whole workspace. Omitting it returns the workspace-wide numbers as before.
  • e67d739: Generated API types now reflect the documented error contract for embed/session token creation and config-version publishing: a 404 is returned when the supplied buddy does not exist for the tenant, publishing an empty draft returns a 400, and the "already published" publish conflict is described more precisely (409 for a non-draft version). The new GET /billing/checkout/session/{id} checkout-reconcile endpoint is also now described, so a delayed or dropped Stripe webhook can be confirmed synchronously on dashboard return. A new GET /customers/me/hosted-surfaces/{id}/players/{playerId}/access-code endpoint lets a tenant admin re-view an existing hosted-surface player's access code and QR token without rotating them. These are additive response/endpoint-type refinements — existing request and success types are unchanged.

1.1.1

Patch Changes

  • a54b74c: Regenerated API types now cover the dashboard password endpoints (POST /auth/password/change, POST /auth/password/reset/request, POST /auth/password/reset) and the updated Player Zero response shape, with typed response bodies for each.

1.1.0

Minor Changes

  • 69b1331: Define cursor pagination as the canonical list shape ({ data, pagination: { nextCursor, hasMore, limit } }) and add CursorPagination, CursorPaginationSchema, and CursorQuerySchema types. The SDK's new paginateCursor()/collectCursor() helpers walk the envelope. Server-side, apps/api/src/common/pagination/cursor.ts provides a TypeORM helper that applies keyset filters and emits the canonical envelope — adopt it on new list endpoints. Existing offset-paginated endpoints are unchanged; consumers can mix both pagination styles.

  • 69b1331: Add client.auth.whoami() for validating an API key without performing a side-effectful call. Returns the customer id + name, plan, capability list entitled by that plan, the authenticating credential's id/label/type/scopes, and the auth method (api_key vs dashboard_jwt). Useful for onboarding CI checks and --health style scripts where the integrator wants to prove "my key is wired and has the scopes I think it does" before shipping.

  • 0984fa4: Add the brag resource for the F2.7 Brag Button — client.brag.recordTelemetry() records a share funnel step and client.brag.sendSlackPost() dispatches a Win-State brag to a tenant Slack/Teams webhook. Both map to explicit per-event user actions in the widget consent modal; there is no auto-share path.

  • 4d7c563: Add the Symbolic Cause Counter admin resource (F2.12). The tenant-admin causes resource backs the Planner "Humanity Hero — Cause Counter" drawer: list/create/update/delete cause definitions and run preview30Days to project symbolic units from the last 30 days of eligible events. New exported types AdminCause, CreateCauseParams, UpdateCauseParams, CausePreview and CauseTriggerEvent.

  • dbe33a0: Add the eventBadges resource for managing Event-Triggered Badge campaigns. A campaign binds a badge to a time window so any buddy active inside the window earns it once — the surprise, story-bound "you were here that day" badge. Supports list (with grant counts), create, update and delete from the tenant admin surface.

  • 0984fa4: Add a feed resource for the SeeSaw Bump team feed (F2.11). client.feed.teamEvents.list({ cursor, limit }) returns the buddy's cursor-paginated team feed of auto-generated events, and client.feed.teamEvents.clap(id) toggles the idempotent 👏 clap reaction (a repeat call unclaps). New exported types FeedResource, TeamEventsResource, TeamEvent, TeamEventKind, TeamEventsPage, ListTeamEventsParams, and ClapResult.

  • 38a4d0e: Add the FlashSalesResource for managing marketplace flash sales (F3.9 Marketplace FOMO). Tenants can list, schedule and cancel flash sales via client.flashSales — a scheduled sale applies a temporary discount to a set of marketplace items for a bounded window, run by a once-a-minute API cron.

  • 4d7c563: Add the Founding Cohort admin resource (F2.13). The tenant-admin foundingCohort resource backs the Planner "Founding Cohort" drawer: preview projects how many buddies the current eligibility config would mark, backfill runs the one-shot retroactive assignment, and listAudit reads the assignment history. New exported types FoundingCohortMode, FoundingCohortPreview, FoundingCohortBackfillResult and FoundingCohortAuditEntry.

  • 0984fa4: Add Group Quest resources (F2.5). The widget-token groupQuests resource lets an embedded buddy list active quests (groupQuests.list()), join one (groupQuests.join(id)) and leave one (groupQuests.leave(id)); join is idempotent and returns already_joined. The tenant-admin adminGroupQuests resource backs the Planner drawer with CRUD, the publish transition and a manual forceResolve watchdog override. New exported types ActiveGroupQuest, JoinGroupQuestResult, LeaveGroupQuestResult, AdminGroupQuest, GroupQuestStatus, GroupQuestRewardConfig, CreateGroupQuestParams, UpdateGroupQuestParams and ForceResolveResult.

  • 9933e8f: Hexad survey resource + widget-token auth mode.

    New widgetToken auth mode. HatchedClient now accepts a third config shape — { widgetToken } — alongside the existing apiKey (server) and publishableKey (browser) modes. Widget embed/session tokens are buddy-scoped and browser-safe; the client auto-allows them on /widget/* runtime paths and refuses everything else.

    • New export: WidgetTokenConfig config type.
    • New export: WidgetTokenScopeError — thrown without a network round-trip when a widget-token client calls a non-widget endpoint or a mutation that hasn't opted in via allowWidgetToken.
    • The runtime guard recognises widget tokens as browser-safe, so the browser-emit warning only fires for secret keys.

    New hexadSurvey resource for the Marczewski Hexad self-assessment widget. All four methods are widget-token scoped — admin recompute and aggregate endpoints stay dashboard-only.

    • hexadSurvey.questions() — fetch the 24-question axis catalog plus the current consent version.
    • hexadSurvey.submit({ answers, consentVersion }) — UPSERT the widget user's Likert responses; returns the normalised six-axis distribution, primary type, and retention expiry. consentVersion is required; submitting without acknowledging the active version is rejected server-side.
    • hexadSurvey.me() — read back the user's stored response (or null when none).
    • hexadSurvey.deleteMine() — withdraw consent and purge the raw answers.
  • bc02f0d: Add the kudos resource for F2.3 peer recognition: client.kudos.send() posts a buddy→buddy kudos, client.kudos.received() and client.kudos.given() read the recent kudos feed and lifetime assist count.

  • bc02f0d: Add team scope to the leaderboard resource. leaderboard.get({ scope: 'team' }) now restricts the board to the requesting buddy's active team roster (HTCH-48), alongside the existing global scope. scope: 'friends' throws a client-side not-implemented error until Phase 3 ships. The response gains an optional effectiveTeamId field, and the scope-policy pill label is exposed as teamLabel.

  • 8e95453: Add the LeaguesResource for the F4.1 LEAGUES endgame feature. client.leagues.me() reads the widget buddy's live league standing — current tier, the next-tier promotion target, cohort standings, season countdown and the demotion-zone flag. The snapshot self-gates: an available: false result (plan not entitled, no active season, or buddy not enrolled) is a normal outcome callers render nothing for, never an error.

  • dbe33a0: Add the LotteryResource for managing recurring lotteries (F3.11 Rolling Reward). Tenants can list and CRUD lottery definitions via client.lottery, read past-draw history, fetch the live "next draw" preview and run a non-persisted draw simulation. A lottery silently enters any buddy that meets its eligibility rule into a weekly or monthly draw, resolved by a once-a-minute API cron.

  • bbc4600: Expose widget marketplace and outfit composition helpers, aura tier fields, and the new marketplace/aura webhook event types.

  • 0984fa4: Add client.marketplace.gift() for F2.4 Social Treasure gifting: a buddy can gift a marketplace item to a teammate, the sender pays and the item lands in the recipient's inventory. Marketplace items now expose isGiftOnly for items that can only be received as a gift.

  • 0984fa4: Add a mentor resource for widget consumers (F2.6 Mentorship, visibility-only). client.mentor.setAvailability({ available }) toggles the buddy's mentor availability, client.mentor.teamMentors(teamId) lists a team's available mentors with server-rendered contact deep links, and client.mentor.logSession({ hours, menteeLabel, summary }) / client.mentor.sessionsForMe() cover the self-reported Mentor Hours log. New exported types MentorDirectoryEntry, MentorSession, MentorSessionsResponse, LogSessionParams, and LogSessionResult.

  • 6618ae8: Add nextBestAction resource that returns the single highest-priority next-best-action for the widget session's buddy. The server orchestrates eight strategies (streak warning, almost-badge, dress-first-outfit, etc.), applies tenant overrides, and caches per buddy for 30 seconds — clients receive { action, fallbackUsed }. Buddy responses now also expose isNaked to signal the Build-From-Scratch onboarding flow.

  • 06d98b6: Add client.buddies.prestige() and client.buddies.prestigeStatus() for the F4.3 Prestige Loop. A buddy that has reached the maximum evolution stage can prestige — reset to stage 0 in exchange for an incremented prestige level and a permanent prestige aura. prestigeStatus() reports whether the buddy can prestige and, when it cannot, the blocking reason (not at max stage, cooldown active, champion required, or the loop disabled for the workspace); prestige() performs the reset and returns the new prestige level, aura tint and reverted image.

  • dbe33a0: Add the profileTemplates resource for the F3.14 Profile Page Editor v2. Tenant admins can now list the template gallery (built-in system templates plus their own), create, update and delete custom profile-page templates, and bulk-apply a template to all buddies or a single audience.

  • 69b1331: allowBrowser: true is now refused at runtime unless the SDK can confirm it's being executed inside a test runner. Recognized markers are NODE_ENV=test, VITEST/JEST_WORKER_ID env vars, or the presence of globalThis.expect + globalThis.it. Outside a test runner, attempting to bypass the secret-key-in-browser guard throws immediately. This closes the "I copy-pasted my unit test config into production" footgun without changing any test-time behavior.

  • 69b1331: Export ErrorCode — a typed enum-shaped object whose keys map every known Hatched API error code (e.g. ErrorCode.EventQuotaExceeded === 'event_quota_exceeded') — and KnownErrorCode, the union of those string values. Compare HatchedError#code against ErrorCode.* instead of typing string literals. Unknown codes still arrive on err.code as plain strings; the enum covers what the current SDK release knows about.

  • a95c14e: Align typed error, webhook, and operation surfaces with the live API.

    • WebhookEvent now covers every server-emitted event (86, up from 26). Handlers can exhaustively switch on the full set — kudos, group quests, leagues and the league-season lifecycle, council, mystery box, lottery, showroom, cause-counter, mentor, and lapsed-user re-engagement events are all typed instead of falling through as plain strings.
    • ErrorCode gained the remaining server codes (bad_request, capability_disabled, onboarding_cap_reached, not_found, bad_gateway, service_unavailable, onboarding_extract_failed, internal_server_error) so err.code comparisons stay typed across the whole surface.
    • OperationStatus gained cancelled, and operations.wait() treats it as terminal. A cancelled async operation previously polled until the timeout threw; it now returns as soon as the status is reached.
    • InsufficientBalanceError reads balance / required from err.details to match the wire shape (the API moved them under details); err.balance and err.required are populated again. It is now also raised for the 402 marketplace-gift path (a payment short on coins), not just the 400 spend path, and err.statusCode reflects whichever the API returned.
    • A bare HTTP 400 now parses to a HatchedError that keeps its 400 status and code (e.g. bad_request). Request-body/DTO validation moved server-side to 422 validation_failed (surfaced as ValidationError), so a 400 is no longer mis-reported as a 422.
  • 69b1331: Add pluggable SdkLogger interface and logger config option. Pass a Pino/Winston/Bunyan instance — or any object with optional debug/info/warn/error methods — to replace the SDK's default console.warn output. Warn-level entries (literal-secret detection, retry hints) emit regardless of debug; debug-level request/response traces still gate on debug: true. Also exports a consoleLogger() factory for the default behavior.

  • 69b1331: Ship auto-generated OpenAPI types alongside the hand-written resources. import type { paths, components, operations } from '@hatched/sdk-js' exposes every public endpoint's exact request/response shape as derived from apps/api/openapi.public.json. The contract is regenerated via pnpm --filter @hatched/sdk-js generate:types and frozen in CI by check:types, so the SDK's typings can never drift from the API specification. Use the generated paths['/buddies/{id}']['get']['responses']['200']['content']['application/json'] style references when you need a shape that doesn't have a hand-written equivalent yet.

  • 69b1331: Add async-iterator pagination helpers. paginate() + collect() walk offset-paginated endpoints ({ data, meta: { total, page, limit } }), while paginateCursor() + collectCursor() walk cursor-paginated endpoints ({ data, pagination: { nextCursor, hasMore, limit } }) — Hatched's canonical pagination shape for new list endpoints. All four return an AsyncIterableIterator<T> that stops automatically when the consumer breaks or the page chain ends, and accept maxPages + AbortSignal for runaway protection. Reduces boilerplate when iterating over buddies.list(), operations.list(), and any new cursor-based endpoint.

  • 69b1331: Expose retry metadata via hatched.getLastRetryMetadata(). Returns { attempts, reasons, totalDelayMs, totalElapsedMs } for the most recent request, where reasons is a per-retry list of '429' | '5xx' | '408' | 'network'. Lets consumers feed observability dashboards with how often the SDK had to retry to land a call, and inflate timeouts on hot paths where retries are routine. The new RetryMetadata type is exported alongside the existing RateLimitSnapshot.

  • ce6ff37: Fix webhook signature verification and the whoami response types.

    • Webhook verification now actually works. WebhooksResource.verifySignature and every framework adapter (verifyExpressRequest, verifyFastifyRequest, verifyHonoRequest, verifyNextAppRequest, verifyNextPagesRequest) previously parsed a t=…,v1=… header that the API never sends — so no real delivery could be verified. They now match the wire contract: X-Hatched-Signature: sha256=<hex> plus a separate X-Hatched-Timestamp header. Adapters read both headers automatically; the raw verifySignature accepts the timestamp via options.timestamp. The legacy combined format is still accepted for safety.
    • whoami() types match the wire. WhoamiResult and ApiKeySummary were declared snake_case (customer_id, key_type, …) but the client camelCases every response, so those fields were undefined at runtime. They are now camelCase (customerId, keyType, lastUsedAt, …).
    • leaderboard.get no longer offers a throwing scope: 'friends' — the unimplemented option was removed from the public type instead of throwing at runtime.
    • User-Agent reports the real version. The SDK_VERSION constant is now injected from package.json at build time, fixing a drift where it reported an older version.
  • bc02f0d: Add a teams resource for widget consumers — client.teams.me() returns the buddy's team, role and members, and client.teams.leave(teamId) leaves a team. New exported types Team, TeamMember, TeamRole, and MyTeamResponse.

  • 69b1331: Add framework adapters for verifying inbound webhook deliveries: verifyExpressRequest, verifyFastifyRequest, verifyHonoRequest, verifyNextAppRequest, verifyNextPagesRequest. Each adapter pulls the raw body + signature header from its framework's request shape and delegates to WebhooksResource.verifySignature, returning a uniform { valid, event, reason } result. Both the package root and @hatched/sdk-js/webhooks deep import expose the adapters.

  • 69b1331: WebhooksResource.verifySignature and every framework adapter (verifyExpressRequest, verifyFastifyRequest, verifyHonoRequest, verifyNextAppRequest, verifyNextPagesRequest) now accept either a single secret or an array of secrets. Pass [currentSecret, previousSecret] during a rotation window to accept payloads signed under either secret without a separate code path. Adds client.webhooks.rotateSecret(endpointId) to call POST /webhook-configs/:id/rotate-secret and return the new plaintext secret.

  • ce6ff37: Add five widget-token resources so embedded buddy widgets can drive their in-app surfaces with full types: client.notifications (feed list, unread count, mark read / dismiss / dismiss-all / snooze), client.mysteryBox (state + claim), client.council (list my narrative proposals + submit a proposal), client.freeLunch (pending welcome notification + acknowledge), and client.beginnersLuck (hatch-ceremony result). Each wraps the corresponding /widget/* endpoint with hand-defined response types matching the API JSON. A new coverage test ratchets the SDK against the public spec's /widget/* surface so future widget endpoints can't silently ship without either an SDK resource or an explicit acknowledgement.

  • cf3f560: Add the players resource and sync webhook + response contracts with the server.

    • New players.zero() (idempotent create-or-get of the workspace demo player, user id player-0) and players.zeroStatus() (read-only existence/hatch check) — previously this endpoint was only reachable by hand-rolled HTTP.
    • WebhookEvent union now matches the server catalog exactly: adds buddy.ceremony_completed, free_lunch.granted/free_lunch.seen/free_lunch.dismissed, group_quest.joined/group_quest.left, outfit.saved/outfit.worn/outfit.deleted, gate.unlocked and skill.decayed; removes marketplace.next_drop_announced and self_awareness.profile_revealed, which were documented but never emitted.
    • Delete acknowledgements are now typed against the standard { ok: true } success envelope instead of per-endpoint { deleted: true } shapes.

Patch Changes

  • 0eb7ba0: Add typed widget badges.list({ includeLocked }) and leaderboard.get(...) SDK resources for the badge collection grid and leaderboard view-mode APIs.
  • 06d98b6: Add client.leagues.bossFightProgress() for the F4.2 Boss Fight seasonal challenge. It returns the widget buddy's progress toward the season-long target — the name and description, the target metric and value, the buddy's own progress and completion rank, the deadline, and the challenge leaderboard. An unavailable view is a normal outcome (no active boss fight) and callers render nothing.
  • 8e95453: Add client.leagues.seasonHighlights(seasonId) for the F4.1a Season Closing Ceremony. It returns a buddy's four personalized season highlights (best week, kudos sent, items collected, cohort role), each z-scored against the cohort so callers can auto-pick the most brag-worthy moment, plus the season outcome, final rank and public-share code.
  • 06d98b6: Add isMentor to the Buddy type — true when a buddy holds the mentor role (F4.4 Mentor Role tier). Also fixes buddies.prestigeStatus() / buddies.prestige() to read the camelCased response correctly, so their fields are no longer undefined at runtime.
  • 1cf026d: Add ErrorCode.MissingAudience (missing_audience) and ErrorCode.UnknownAudience (unknown_audience) to the known error-code enum. The API already returns these 400s when a request to a multi-audience customer omits or mis-names the audience field; the SDK now recognises them in KnownErrorCode so callers can switch on them exhaustively.
  • 569de43: SDK README header gains a one-line tagline ("The motivation API your backend already speaks.") above the existing intro paragraph, and the intro picks up a single-sentence bridge to the Yu-kai Chou Octalysis framework — the data model the SDK was shaped around. The npm description field is revised to lead with the runtime + language + product + framework hook + security default in one line ("TypeScript-first Node SDK for Hatched — the B2B gamification platform with Octalysis-native scoring. Server-only; secret keys never in the browser."). No runtime change; package metadata + README markup only.
  • 0984fa4: Add a socialNorms resource for widget consumers (F2.9). client.socialNorms.today() returns the buddy's positive-framing team norms for today — completion, momentum, and elitism framings, server-rendered and believability-gated. New exported types SocialNorm, SocialNormFraming, and SocialNormsTodayResponse.

1.0.0

Major Changes

  • 6dff237: PathDisplayMode renamed: replace 'path' with 'straight' (clean centered column) and add 'zigzag' (Duolingo-style alternating sides). Existing 'path' consumers must migrate to 'straight'. The legacy half-zigzag rendering (node offset, text static) is removed.

Minor Changes

  • d73cafe: First-run bootstrap ergonomics: eggs.create({ userId, ensure: true }) now reuses the user's existing waiting/ready egg instead of creating a new one (avoids the per-user active-egg cap on retries). Egg responses include buddyId (non-null once the egg is hatched). Two new typed 409 errors are surfaced: NoPublishedConfigError (raised by eggs.create before a config version is published — exposes publishUrl) and ActiveEggLimitError (raised when the active-egg cap is hit — exposes max and active[] with the existing egg ids/statuses).

0.5.0

Minor Changes

  • d758872: Add paths resource — guided multi-step journeys (Duolingo-style). New client.paths exposes admin CRUD over path definitions, steps, and sub-steps; setActive() flips the audience's single active path atomically; getForBuddy() returns the buddy-scoped runtime payload with locked / available / completed sub-step states; completeSubStep() manually marks a sub-step done and returns cascade flags so callers can celebrate without an extra round-trip. Sub-steps support an optional contentUrl + ctaLabel for deep-linking into a customer's LMS.

    events.send() response now also exposes streakUpdates and pathUpdates on the returned EventEffects, so a single track call can drive streak counters and path widgets in addition to coins/badges without an extra fetch.

  • 42907d4: Added new feature: path and performance improvements

0.4.4

Patch Changes

  • ea76743: Republish 0.4.3 with corrected package metadata: repository.url and bugs.url now point to the public SDK repo at github.com/hatched-live/hatched-sdk-js. (0.4.3 was never published to npm.)

0.4.3

Patch

  • Buddy appearance typesBuddy now exposes baseImageUrl, typed equipped item objects, and the appearance status block used by the persistent AI compositing pipeline.
  • Equip result typingbuddies.equip() now returns a typed { accepted, operationId, status, appearanceStatus, cached } result so clients can distinguish instant cache hits from queued appearance generation.
  • Rerender appearance — new buddies.rerenderAppearance(buddyId) method backed by POST /buddies/:id/appearance/rerender. Use when appearance.status === 'failed' (especially error.code === 'needs_rerender' after the appearance pipeline migration) to regenerate the bare stage image. Equipped items are cleared from the rendered set; re-equip after status returns to ready.

Behavior change (non-breaking type-wise, breaking semantically)

  • Evolution no longer blocks on item composite failure. Previously, if the bare stage image succeeded but compositing equipped items failed, the buddy stayed on the prior stage and the evolve operation was marked failed. Now the buddy advances to the new stage with its bare base image and appearance reports failed or awaiting_credits. The evolve operation completes successfully and the appearance recovery flow re-attempts the composite.
  • Awaiting-credits self-recovery. When equip/evolve hits a credit limit, an internal scheduler retries with exponential backoff (60s → 5m → 15m → 30m). Clients should poll buddy.appearance rather than the original operation status to track final resolution.

0.4.1

Patch

  • Docs domain — all references now point to docs.hatched.live (single canonical domain). The legacy docs.hatched.com host is retired; error messages, README links, and package.json.homepage have been updated. No API or behavior changes.

0.4.0

Minor

  • Publishable-key hardening — browser keys can mint scoped read-only embed tokens, but no longer mint interactive widget sessions. Interactive session tokens stay server-only.
  • Webhooks resource alignment — SDK methods now target the production /webhook-configs API and unwrap dashboard response envelopes.
  • Docs/examples refresh — README snippets, widget examples, and auth guidance now match the current CDN loader and Authorization: Bearer API model.

0.3.0

Major

  • Two-tier token model. Tokens now have an explicit kind: primary (spendable via buddies.spend, marketplace purchases, gate unlocks) or progression (earn-only, feeds evolution readiness). token_config DTOs unlocked from the legacy 4-tuple (hatch_token/evolution_token/reroll_token/gift_token) — customers now pick their own token_key (e.g. gems, mana, xp). Spending a progression token returns progression_not_spendable.
  • Canonical item categories. The two coexisting taxonomies (hat/held_item/… vs headwear/eyewear/…) collapse into 8 canonical slots: background, body, feet, hand, neck, face, head, accessory. Migration 023 normalises existing rows and locks the column via CHECK.

Minor

  • buddies.tokens(buddyId) — typed primary + progression balance snapshot with lifetime earn/spend sums.
  • buddies.evolutions(buddyId) — paginated stage-transition timeline (prod + demo). Backed by a new buddy_evolutions table that captures every evolve with its image and trigger event.
  • GatesResource — new hatched.gates.unlock(buddyId, gateKey) / unlocks(buddyId) primitive. Customers author gates in the dashboard (gate_key, token_key, cost, metadata); end-users spend tokens to unlock features. Unlock is idempotent — repeat calls return alreadyUnlocked: true without touching the economy.
  • Equip safety railsTooManyItemsError (max 4 equipped) and CategoryConflictError (two non-accessory items in the same category) surface at the SDK layer with details carrying the specifics.
  • Stage-aware item artworkitems.stage_image_urls jsonb lets designers ship stage-2-specific hats; the composite pipeline picks the right variant per stage.
  • Evolve×equip pipeline (pre-0.4.3) — the initial implementation attempted to block operations.wait(evolveOp) until equipped items were composited. In 0.4.3 this was replaced by buddy.appearance status recovery so stage advancement can complete even when item compositing is delayed.
  • Theme-aware defaults — empty marketplace or token bundle at onboarding seeds from a theme-appropriate catalog (fantasy → gems/mana + fantasy items, fitness → reps/streaks, etc.). Source tracked in customers.settings.applied_sources.

0.2.1

Patch

  • Docs: README now has a dedicated "Two ways to authenticate" section with a secret-vs-publishable key comparison, a browser-safe publishable-key example, and a per-resource secret/publishable capability matrix. No code changes.

0.2.0

Major

  • camelCase public surface — all params and response fields exposed by the SDK are now camelCase. Snake_case wire format is converted transparently. Migration: rename user_iduserId, event_ideventId, occurred_atoccurredAt, etc. The same applies to response fields (egg.egg_idegg.eggId, op.operation_idop.operationId).
  • Operation.waitoperations.waitForCompletion has been replaced with the shorter operations.wait. The old name is still exported as a deprecated alias.

Minor

  • Server-only runtime guard — the SDK now throws when constructed in a browser-like environment with a secret key. Override with allowBrowser: true (test-only).
  • Publishable key support — browser-safe HatchedClient({ publishableKey }) constructor variant. Only read endpoints and embedTokens.create are allowed; mutation methods return PublishableKeyScopeError at runtime.
  • Automatic retries — exponential backoff + jitter on network errors, 408, 429 (retry-after honoured), and 5xx. Configurable via maxRetries (default 3).
  • AbortSignal on every method — pass signal to cancel in-flight requests; combined with the internal timeout via AbortSignal.any.
  • Request id trackinghatched.getLastRequestId() exposes the X-Request-Id of the most recent response. SDK-generated request ids are sent on every call.
  • Webhooks resourcehatched.webhooks.list/create/delete/deliveries/replay + WebhooksResource.verifySignature(rawBody, header, secret) for Hatched-Signature verification.
  • New error classesAuthError (base for 401/403), PublishableKeyScopeError, ConfigVersionMismatchError, and a ResourceNotFoundError alias for NotFoundError.
  • tsup dual builddist/index.mjs, dist/index.cjs, plus .d.ts/.d.cts. Subpath exports for tree-shaking: @hatched/sdk-js/errors, @hatched/sdk-js/webhooks.
  • sideEffects: false — enables aggressive tree-shaking by bundlers.
  • timeoutMs alias — equivalent to timeout, aligns with the docs.
  • fetch override — supply a custom fetch implementation for edge runtimes and tests.

Fixes

  • Correct URL concatenation — paths now preserve the base /api/v1 prefix (previously absolute paths could drop it).

0.1.1

Initial private-preview release.