2.0.0: changelog and skill docs for slugs and environments
CI / check (push) Successful in 16s
CI / publish (push) Has been skipped

Claude-Session: https://claude.ai/code/session_01SMCvdwDmuxoaqGgvGBLk1V
This commit is contained in:
edmand46
2026-09-06 22:39:03 +03:00
parent a7401b534a
commit 7271874cac
9 changed files with 76 additions and 28 deletions
+10 -8
View File
@@ -13,7 +13,7 @@ client.stores.onChange(cb);
await client.stores.load() / .reload();
// Direct purchase (bypassing handles):
await client.stores.purchase(storeSlug, offerId, options?);
await client.stores.purchase(storeSlug, offerSlug, options?);
```
## Handles
@@ -28,7 +28,8 @@ class ShopHandle {
}
class OfferHandle {
readonly id: string;
readonly id: string; // authoring id, differs between staging and prod
readonly slug: string; // stable across environments — what purchases use
readonly name?: string;
readonly price?: OfferPrice; // { amount?: number; currency?: string }
readonly contents: OfferContent[]; // { amount?: number; itemId?: string }[]
@@ -48,15 +49,15 @@ interface PurchaseOfferResponse {
## Purchase semantics
- `stores.purchase(storeSlug, offerId, options?)` and `offer.buy(options?)` are
the same executor; handles just bind the slug/id.
- `stores.purchase(storeSlug, offerSlug, options?)` and `offer.buy(options?)` are
the same executor; handles just bind the store slug and the offer slug.
- When `options.idempotencyKey` is omitted the SDK generates
`crypto.randomUUID()` per call — safe retries require passing your own key.
- On success the executor invalidates `player`, `inventory`, and `stores`, so
subscribers observe fresh wallet/inventory/store data immediately.
- Check `response.success` / `response.error` — a failed purchase is a resolved
response, not necessarily a thrown error.
- Purchase metrics (`purchase.offer:<offerId>`, `purchase.item:<itemId>`) are
- Purchase metrics (`purchase.offer:<offerSlug>`, `purchase.item:<itemId>`) are
reported to quests automatically server-side — do not report them manually
(see `reference/quests.md`).
@@ -71,10 +72,11 @@ interface Store {
}
interface Offer {
contents?: OfferContent[]; createdAt?: string; id?: string;
maxPurchases?: number; name?: string; price?: OfferPrice; updatedAt?: string;
maxPurchases?: number; name?: string; price?: OfferPrice; slug?: string;
updatedAt?: string;
}
```
`ShopHandle`/`OfferHandle` throw a plain `Error` if constructed from a store
without `slug` / an offer without `id` — in practice the domain only builds
handles from server data that has both.
without `slug` / an offer without `id` or `slug` — in practice the domain only
builds handles from server data that has all of them.