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
audiencequery 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 newGET /customers/me/hosted-surfaces/{id}/players/{playerId}/access-codeendpoint 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 addCursorPagination,CursorPaginationSchema, andCursorQuerySchematypes. The SDK's newpaginateCursor()/collectCursor()helpers walk the envelope. Server-side,apps/api/src/common/pagination/cursor.tsprovides 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_keyvsdashboard_jwt). Useful for onboarding CI checks and--healthstyle scripts where the integrator wants to prove "my key is wired and has the scopes I think it does" before shipping. -
0984fa4: Add the
bragresource for the F2.7 Brag Button —client.brag.recordTelemetry()records a share funnel step andclient.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
causesresource backs the Planner "Humanity Hero — Cause Counter" drawer: list/create/update/delete cause definitions and runpreview30Daysto project symbolic units from the last 30 days of eligible events. New exported typesAdminCause,CreateCauseParams,UpdateCauseParams,CausePreviewandCauseTriggerEvent. -
dbe33a0: Add the
eventBadgesresource 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
feedresource 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, andclient.feed.teamEvents.clap(id)toggles the idempotent 👏 clap reaction (a repeat call unclaps). New exported typesFeedResource,TeamEventsResource,TeamEvent,TeamEventKind,TeamEventsPage,ListTeamEventsParams, andClapResult. -
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
foundingCohortresource backs the Planner "Founding Cohort" drawer:previewprojects how many buddies the current eligibility config would mark,backfillruns the one-shot retroactive assignment, andlistAuditreads the assignment history. New exported typesFoundingCohortMode,FoundingCohortPreview,FoundingCohortBackfillResultandFoundingCohortAuditEntry. -
0984fa4: Add Group Quest resources (F2.5). The widget-token
groupQuestsresource lets an embedded buddy list active quests (groupQuests.list()), join one (groupQuests.join(id)) and leave one (groupQuests.leave(id)); join is idempotent and returnsalready_joined. The tenant-adminadminGroupQuestsresource backs the Planner drawer with CRUD, thepublishtransition and a manualforceResolvewatchdog override. New exported typesActiveGroupQuest,JoinGroupQuestResult,LeaveGroupQuestResult,AdminGroupQuest,GroupQuestStatus,GroupQuestRewardConfig,CreateGroupQuestParams,UpdateGroupQuestParamsandForceResolveResult. -
9933e8f: Hexad survey resource + widget-token auth mode.
New
widgetTokenauth mode.HatchedClientnow accepts a third config shape —{ widgetToken }— alongside the existingapiKey(server) andpublishableKey(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:
WidgetTokenConfigconfig 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 viaallowWidgetToken. - The runtime guard recognises widget tokens as browser-safe, so the browser-emit warning only fires for secret keys.
New
hexadSurveyresource 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.consentVersionis required; submitting without acknowledging the active version is rejected server-side.hexadSurvey.me()— read back the user's stored response (ornullwhen none).hexadSurvey.deleteMine()— withdraw consent and purge the raw answers.
- New export:
-
bc02f0d: Add the
kudosresource for F2.3 peer recognition:client.kudos.send()posts a buddy→buddy kudos,client.kudos.received()andclient.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: anavailable: falseresult (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 exposeisGiftOnlyfor items that can only be received as a gift. -
0984fa4: Add a
mentorresource 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, andclient.mentor.logSession({ hours, menteeLabel, summary })/client.mentor.sessionsForMe()cover the self-reported Mentor Hours log. New exported typesMentorDirectoryEntry,MentorSession,MentorSessionsResponse,LogSessionParams, andLogSessionResult. -
6618ae8: Add
nextBestActionresource 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 exposeisNakedto signal the Build-From-Scratch onboarding flow. -
06d98b6: Add
client.buddies.prestige()andclient.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
profileTemplatesresource 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: trueis now refused at runtime unless the SDK can confirm it's being executed inside a test runner. Recognized markers areNODE_ENV=test,VITEST/JEST_WORKER_IDenv vars, or the presence ofglobalThis.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') — andKnownErrorCode, the union of those string values. CompareHatchedError#codeagainstErrorCode.*instead of typing string literals. Unknown codes still arrive onerr.codeas 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) soerr.codecomparisons stay typed across the whole surface. - OperationStatus gained
cancelled, andoperations.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. InsufficientBalanceErrorreadsbalance/requiredfromerr.detailsto match the wire shape (the API moved them underdetails);err.balanceanderr.requiredare populated again. It is now also raised for the402marketplace-gift path (a payment short on coins), not just the400spend path, anderr.statusCodereflects whichever the API returned.- A bare HTTP 400 now parses to a
HatchedErrorthat keeps its 400 status and code (e.g.bad_request). Request-body/DTO validation moved server-side to422 validation_failed(surfaced asValidationError), so a 400 is no longer mis-reported as a 422.
-
69b1331: Add pluggable
SdkLoggerinterface andloggerconfig option. Pass a Pino/Winston/Bunyan instance — or any object with optionaldebug/info/warn/errormethods — to replace the SDK's defaultconsole.warnoutput. Warn-level entries (literal-secret detection, retry hints) emit regardless ofdebug; debug-level request/response traces still gate ondebug: true. Also exports aconsoleLogger()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 fromapps/api/openapi.public.json. The contract is regenerated viapnpm --filter @hatched/sdk-js generate:typesand frozen in CI bycheck:types, so the SDK's typings can never drift from the API specification. Use the generatedpaths['/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 } }), whilepaginateCursor()+collectCursor()walk cursor-paginated endpoints ({ data, pagination: { nextCursor, hasMore, limit } }) — Hatched's canonical pagination shape for new list endpoints. All four return anAsyncIterableIterator<T>that stops automatically when the consumer breaks or the page chain ends, and acceptmaxPages+AbortSignalfor runaway protection. Reduces boilerplate when iterating overbuddies.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, wherereasonsis 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 newRetryMetadatatype is exported alongside the existingRateLimitSnapshot. -
ce6ff37: Fix webhook signature verification and the
whoamiresponse types.- Webhook verification now actually works.
WebhooksResource.verifySignatureand every framework adapter (verifyExpressRequest,verifyFastifyRequest,verifyHonoRequest,verifyNextAppRequest,verifyNextPagesRequest) previously parsed at=…,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 separateX-Hatched-Timestampheader. Adapters read both headers automatically; the rawverifySignatureaccepts the timestamp viaoptions.timestamp. The legacy combined format is still accepted for safety. whoami()types match the wire.WhoamiResultandApiKeySummarywere declared snake_case (customer_id,key_type, …) but the client camelCases every response, so those fields wereundefinedat runtime. They are now camelCase (customerId,keyType,lastUsedAt, …).leaderboard.getno longer offers a throwingscope: 'friends'— the unimplemented option was removed from the public type instead of throwing at runtime.- User-Agent reports the real version. The
SDK_VERSIONconstant is now injected frompackage.jsonat build time, fixing a drift where it reported an older version.
- Webhook verification now actually works.
-
bc02f0d: Add a
teamsresource for widget consumers —client.teams.me()returns the buddy's team, role and members, andclient.teams.leave(teamId)leaves a team. New exported typesTeam,TeamMember,TeamRole, andMyTeamResponse. -
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 toWebhooksResource.verifySignature, returning a uniform{ valid, event, reason }result. Both the package root and@hatched/sdk-js/webhooksdeep import expose the adapters. -
69b1331:
WebhooksResource.verifySignatureand 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. Addsclient.webhooks.rotateSecret(endpointId)to callPOST /webhook-configs/:id/rotate-secretand 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), andclient.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
playersresource and sync webhook + response contracts with the server.- New
players.zero()(idempotent create-or-get of the workspace demo player, user idplayer-0) andplayers.zeroStatus()(read-only existence/hatch check) — previously this endpoint was only reachable by hand-rolled HTTP. WebhookEventunion now matches the server catalog exactly: addsbuddy.ceremony_completed,free_lunch.granted/free_lunch.seen/free_lunch.dismissed,group_quest.joined/group_quest.left,outfit.saved/outfit.worn/outfit.deleted,gate.unlockedandskill.decayed; removesmarketplace.next_drop_announcedandself_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.
- New
Patch Changes
- 0eb7ba0: Add typed widget
badges.list({ includeLocked })andleaderboard.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
isMentorto theBuddytype — true when a buddy holds the mentor role (F4.4 Mentor Role tier). Also fixesbuddies.prestigeStatus()/buddies.prestige()to read the camelCased response correctly, so their fields are no longer undefined at runtime. - 1cf026d: Add
ErrorCode.MissingAudience(missing_audience) andErrorCode.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 theaudiencefield; the SDK now recognises them inKnownErrorCodeso 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
descriptionfield 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
socialNormsresource 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 typesSocialNorm,SocialNormFraming, andSocialNormsTodayResponse.
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).Eggresponses includebuddyId(non-null once the egg is hatched). Two new typed 409 errors are surfaced:NoPublishedConfigError(raised byeggs.createbefore a config version is published — exposespublishUrl) andActiveEggLimitError(raised when the active-egg cap is hit — exposesmaxandactive[]with the existing egg ids/statuses).
0.5.0
Minor Changes
-
d758872: Add
pathsresource — guided multi-step journeys (Duolingo-style). Newclient.pathsexposes 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 optionalcontentUrl+ctaLabelfor deep-linking into a customer's LMS.events.send()response now also exposesstreakUpdatesandpathUpdateson the returnedEventEffects, 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.urlandbugs.urlnow point to the public SDK repo atgithub.com/hatched-live/hatched-sdk-js. (0.4.3 was never published to npm.)
0.4.3
Patch
- Buddy appearance types —
Buddynow exposesbaseImageUrl, typed equipped item objects, and theappearancestatus block used by the persistent AI compositing pipeline. - Equip result typing —
buddies.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 byPOST /buddies/:id/appearance/rerender. Use whenappearance.status === 'failed'(especiallyerror.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 toready.
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
appearancereportsfailedorawaiting_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.appearancerather 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 legacydocs.hatched.comhost is retired; error messages, README links, andpackage.json.homepagehave 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-configsAPI and unwrap dashboard response envelopes. - Docs/examples refresh — README snippets, widget examples, and auth guidance now match the current CDN loader and
Authorization: BearerAPI model.
0.3.0
Major
- Two-tier token model. Tokens now have an explicit
kind:primary(spendable viabuddies.spend, marketplace purchases, gate unlocks) orprogression(earn-only, feeds evolution readiness).token_configDTOs unlocked from the legacy 4-tuple (hatch_token/evolution_token/reroll_token/gift_token) — customers now pick their owntoken_key(e.g.gems,mana,xp). Spending a progression token returnsprogression_not_spendable. - Canonical item categories. The two coexisting taxonomies (
hat/held_item/… vsheadwear/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 newbuddy_evolutionstable that captures every evolve with its image and trigger event.GatesResource— newhatched.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 returnalreadyUnlocked: truewithout touching the economy.- Equip safety rails —
TooManyItemsError(max 4 equipped) andCategoryConflictError(two non-accessory items in the same category) surface at the SDK layer withdetailscarrying the specifics. - Stage-aware item artwork —
items.stage_image_urlsjsonb 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 bybuddy.appearancestatus 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_id→userId,event_id→eventId,occurred_at→occurredAt, etc. The same applies to response fields (egg.egg_id→egg.eggId,op.operation_id→op.operationId). - Operation.wait —
operations.waitForCompletionhas been replaced with the shorteroperations.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 andembedTokens.createare allowed; mutation methods returnPublishableKeyScopeErrorat 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
signalto cancel in-flight requests; combined with the internal timeout viaAbortSignal.any. - Request id tracking —
hatched.getLastRequestId()exposes theX-Request-Idof the most recent response. SDK-generated request ids are sent on every call. - Webhooks resource —
hatched.webhooks.list/create/delete/deliveries/replay+WebhooksResource.verifySignature(rawBody, header, secret)forHatched-Signatureverification. - New error classes —
AuthError(base for 401/403),PublishableKeyScopeError,ConfigVersionMismatchError, and aResourceNotFoundErroralias forNotFoundError. - tsup dual build —
dist/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.timeoutMsalias — equivalent totimeout, aligns with the docs.fetchoverride — supply a customfetchimplementation for edge runtimes and tests.
Fixes
- Correct URL concatenation — paths now preserve the base
/api/v1prefix (previously absolute paths could drop it).
0.1.1
Initial private-preview release.