@goodz-core/sdk 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @goodz-core/sdk
2
2
 
3
- Official SDK for **GoodZ.Core** — a type-safe API client for building GoodZ-powered applications. This package provides a zero-dependency HTTP client that speaks the tRPC wire protocol directly, along with OAuth helpers, Z-coin utilities, and full TypeScript type coverage.
3
+ Official SDK for the **GoodZ** ecosystem — a unified, type-safe API client for building GoodZ-powered applications. One package covers all five products: Core, Commerce, Exchange, Alive, and Shops. Stripe-style namespaces route requests to the correct service transparently.
4
4
 
5
5
  ## Installation
6
6
 
@@ -10,7 +10,7 @@ npm install @goodz-core/sdk
10
10
  pnpm add @goodz-core/sdk
11
11
  ```
12
12
 
13
- The SDK has only one runtime dependency (`superjson`) and requires Node.js 18+. It works in any JavaScript runtime that supports the Fetch API (Node.js, Deno, Bun, Cloudflare Workers, browsers).
13
+ Runtime dependency: `superjson` only. Works in Node.js 18+, Deno, Bun, Cloudflare Workers, and browsers (any runtime with Fetch API).
14
14
 
15
15
  ## Quick Start
16
16
 
@@ -21,11 +21,9 @@ const goodz = createGoodZClient({
21
21
  accessToken: "your-jwt-token",
22
22
  });
23
23
 
24
- // All methods are fully typed IDE autocomplete works out of the box
24
+ // Coresettlement
25
25
  const balance = await goodz.zcoin.getMyBalance();
26
- console.log(`Balance: ${balance.balance} hundredths`);
27
-
28
- const result = await goodz.zcoin.commercialTransfer({
26
+ const trade = await goodz.zcoin.commercialTransfer({
29
27
  instanceId: 90447,
30
28
  buyerUserId: 1,
31
29
  sellerUserId: 2,
@@ -34,118 +32,271 @@ const result = await goodz.zcoin.commercialTransfer({
34
32
  referenceId: "order-abc-123",
35
33
  appClientId: "od_myapp",
36
34
  });
37
- console.log(`Trade ID: ${result.tradeId}`);
35
+
36
+ // Commerce — create a shop and launch a campaign
37
+ const shop = await goodz.commerce.createShop({ name: "Frostpeak Store" });
38
+ const campaign = await goodz.commerce.launchCampaign({ shopId: shop.id, name: "Spring Drop" });
39
+ const order = await goodz.commerce.executePurchase({ campaignId: campaign.id, quantity: 1 });
40
+
41
+ // Exchange — list an item for sale
42
+ const listing = await goodz.exchange.createListing({
43
+ instanceId: 42,
44
+ listingType: "fixed_price",
45
+ askPrice: 2000,
46
+ });
47
+ const data = await goodz.exchange.getMarketData({ coreGoodzId: 42 });
48
+
49
+ // Alive — chat with a character
50
+ const reply = await goodz.alive.sendMessage({
51
+ instanceId: 1,
52
+ userId: 1,
53
+ message: "What's your favorite memory?",
54
+ });
38
55
  ```
39
56
 
40
57
  ## Architecture
41
58
 
42
- The SDK is designed around three principles:
59
+ The SDK is built on three principles:
43
60
 
44
- **Zero tRPC dependency.** Unlike a typical tRPC client that requires `@trpc/client` and `@trpc/server` as peer dependencies (and transitively pulls in the entire server type tree), this SDK speaks the tRPC HTTP wire protocol directly using `fetch` + `superjson`. This means consumers never need to install tRPC packages, and the DTS bundle is fully self-contained.
61
+ **One client, all services.** `createGoodZClient()` returns a single object with namespaces for every GoodZ product. Core uses tRPC HTTP wire protocol; sub-sites (Commerce, Exchange, Alive) use MCP JSON-RPC 2.0. The client handles routing transparently developers never need to know which protocol a method uses.
45
62
 
46
- **Hand-crafted types as API contract.** All input/output types are defined inside the SDK itself (in `src/types.ts`), mirroring the Zod schemas on the Core server. This is the same approach used by the Stripe SDK — the types serve as both documentation and compile-time contract. When Core's API evolves, the SDK types are updated and a new version is published.
63
+ **Hand-crafted types as API contract.** All input/output types are defined inside the SDK itself, mirroring the Zod schemas on Core and the MCP tool schemas on sub-sites. This is the same approach used by the Stripe SDK — types serve as both documentation and compile-time contract. When any service's API evolves, the SDK types are updated and a new version is published.
47
64
 
48
- **Namespace-based API surface.** Methods are organized into logical namespaces (`zcoin`, `inventory`, `collectible`, `user`, `auth`, `ip`) that mirror Core's tRPC router structure. Each namespace method is a thin wrapper around the transport layer, providing typed inputs and outputs.
65
+ **Zero tRPC dependency.** The SDK speaks the tRPC wire protocol directly using `fetch` + `superjson`, and speaks MCP JSON-RPC natively. Consumers never need to install `@trpc/client`, `@trpc/server`, or any MCP client library.
49
66
 
50
- ## API Reference
51
-
52
- ### Client Configuration
67
+ ## Client Configuration
53
68
 
54
69
  ```ts
55
70
  interface GoodZClientConfig {
56
71
  coreUrl?: string; // Default: "https://goodzcore.manus.space"
72
+ commerceUrl?: string; // Default: "https://goodzcommerce.manus.space"
73
+ exchangeUrl?: string; // Default: "https://goodzexchange.manus.space"
74
+ aliveUrl?: string; // Default: "https://goodzalive.manus.space"
57
75
  accessToken?: string; // Static JWT token
58
76
  getAccessToken?: () => string | Promise<string>; // Dynamic token provider
59
77
  headers?: Record<string, string>; // Custom headers for every request
60
78
  }
61
79
  ```
62
80
 
63
- The `getAccessToken` function takes precedence over `accessToken` when both are provided. Use it for auto-refresh scenarios.
81
+ The `getAccessToken` function takes precedence over `accessToken` when both are provided. Use it for auto-refresh scenarios. Sub-site URLs default to production endpoints and rarely need to be changed.
64
82
 
65
- ### Namespaces
83
+ ## API Reference — Core Namespaces
66
84
 
67
- #### `goodz.zcoin` Z-coin Payment & Settlement
85
+ Core namespaces communicate via tRPC HTTP wire protocol with `goodzcore.manus.space`.
68
86
 
69
- The Z-coin namespace handles all monetary operations. These are the primary APIs that Commerce and Exchange apps use to process purchases.
87
+ ### `goodz.zcoin` — Z-coin Payment & Settlement
70
88
 
71
89
  | Method | Type | Description |
72
90
  |--------|------|-------------|
73
- | `getMyBalance()` | Query | Get authenticated user's Z-coin balance |
74
- | `getMyHistory(input?)` | Query | Get Z-coin transaction history with pagination |
75
- | `getDepositPackages(input?)` | Query | List available deposit packages with pricing |
76
- | `createDepositOrder(input)` | Mutation | Create a Stripe checkout session for Z-coin deposit |
91
+ | `getMyBalance()` | Query | Authenticated user's Z-coin balance |
92
+ | `getMyHistory(input?)` | Query | Transaction history with pagination |
93
+ | `getDepositPackages(input?)` | Query | Available deposit packages with pricing |
94
+ | `createDepositOrder(input)` | Mutation | Create Stripe checkout for Z-coin deposit |
77
95
  | `getDepositStatus(input)` | Query | Check deposit checkout session status |
78
- | `commercialTransfer(input)` | Mutation | Atomic Z-coin payment + ownership transfer |
79
- | `mintAndCharge(input)` | Mutation | Mint new instance + charge buyer atomically |
80
- | `chargeUser(input)` | Mutation | Charge user's Z-coin for in-app purchases |
81
- | `createDirectPurchaseOrder(input)` | Mutation | Create fiat-to-Z-coin direct purchase checkout |
96
+ | `commercialTransfer(input)` | Mutation | **Primary API for secondary market.** Atomic: debit buyer credit seller → transfer ownership |
97
+ | `mintAndCharge(input)` | Mutation | **Primary API for primary sales.** Atomic: mint instance charge buyer |
98
+ | `chargeUser(input)` | Mutation | Charge Z-coin for in-app purchases |
99
+ | `createDirectPurchaseOrder(input)` | Mutation | Fiat-to-Z-coin direct purchase checkout |
82
100
 
83
- **Key method: `commercialTransfer`** is the primary API for all secondary market transactions. It atomically debits the buyer's Z-coin balance, credits the seller (minus platform fee), and transfers card instance ownership — all in a single database transaction. The `referenceId` parameter provides idempotency, so duplicate calls (e.g., from retries) return the same result.
101
+ `commercialTransfer` is the most important method in the SDK. It atomically debits the buyer's Z-coin balance, credits the seller (minus platform fee), and transfers card instance ownership — all in a single database transaction. The `referenceId` parameter provides idempotency.
84
102
 
85
- **Key method: `mintAndCharge`** is the primary API for primary sales (gacha, direct-from-creator). It mints a new card instance and charges the buyer in one atomic operation. Requires prior mint authorization via `inventory.grantMintAuth`.
103
+ `mintAndCharge` is the primary API for primary sales (gacha, direct-from-creator). It mints a new card instance and charges the buyer in one atomic operation. Requires prior mint authorization via `inventory.grantMintAuth`.
86
104
 
87
- #### `goodz.inventory` — Card Instance Management
105
+ ### `goodz.inventory` — Card Instance Management
88
106
 
89
107
  | Method | Type | Description |
90
108
  |--------|------|-------------|
91
- | `getUserInventory(input)` | Query | Get a user's owned card instances |
109
+ | `getUserInventory(input)` | Query | User's owned card instances |
92
110
  | `confirmOwnership(input)` | Query | Check if user owns a specific card |
93
- | `mint(input)` | Mutation | Mint new card instances (requires authorization) |
94
- | `transfer(input)` | Mutation | Transfer a specific instance to another user |
95
- | `transferByCard(input)` | Mutation | Transfer instances by cardId (oldest first) |
96
- | `grantMintAuth(input)` | Mutation | Grant mint authorization to another user/app |
97
- | `transferHistory(input)` | Query | Get transfer/ownership history |
111
+ | `mint(input)` | Mutation | Mint new instances (requires authorization) |
112
+ | `transfer(input)` | Mutation | Transfer instance by instanceId |
113
+ | `transferByCard(input)` | Mutation | Transfer by cardId (oldest first) |
114
+ | `grantMintAuth(input)` | Mutation | Grant mint authorization to app/user |
115
+ | `transferHistory(input)` | Query | Ownership/transfer history |
98
116
 
99
- For commercial transactions (purchases, trades), always use `zcoin.commercialTransfer` or `zcoin.mintAndCharge` instead of the raw `transfer`/`mint` methods. The raw methods are intended for administrative operations and gift transfers only.
117
+ For commercial transactions, always use `zcoin.commercialTransfer` or `zcoin.mintAndCharge` instead of raw `transfer`/`mint`. The raw methods are for administrative operations and gift transfers only.
100
118
 
101
- #### `goodz.collectible` — Card & Instance Queries
119
+ ### `goodz.collectible` — Card & Instance Queries
102
120
 
103
121
  | Method | Type | Description |
104
122
  |--------|------|-------------|
105
- | `getInstanceById(input)` | Query | Get instance by numeric ID |
106
- | `getPublicInstance(input)` | Query | Get instance by instance code |
123
+ | `getInstanceById(input)` | Query | Instance by numeric ID |
124
+ | `getPublicInstance(input)` | Query | Instance by instance code |
107
125
  | `getPublicInstancesBatch(input)` | Query | Batch-fetch instances (max 100) |
108
- | `getCardProfile(input)` | Query | Get card metadata, rarity, series info |
109
- | `getShellImageUrl(input)` | Query | Get shell (packaging) image URL |
126
+ | `getCardProfile(input)` | Query | Card metadata, rarity, series info |
127
+ | `getShellImageUrl(input)` | Query | Shell (packaging) image URL |
110
128
 
111
- #### `goodz.user` — User Profiles
129
+ ### `goodz.ip` — IP Management (Franchise/Series/Card)
112
130
 
113
131
  | Method | Type | Description |
114
132
  |--------|------|-------------|
115
- | `getPublicProfile(input)` | Query | Get profile by openId |
116
- | `getPublicProfileById(input)` | Query | Get profile by internal userId |
133
+ | `getFranchise(input)` | Query | Franchise by ID or slug |
134
+ | `getSeries(input)` | Query | Series by ID or slug |
135
+ | `listSeriesByFranchise(input)` | Query | All series in a franchise |
136
+ | `getCard(input)` | Query | Card by ID |
137
+ | `listCardsBySeries(input)` | Query | All cards in a series |
117
138
 
118
- #### `goodz.auth` Authentication
139
+ ### `goodz.user` & `goodz.auth`
119
140
 
120
141
  | Method | Type | Description |
121
142
  |--------|------|-------------|
122
- | `me()` | Query | Get authenticated user's profile |
123
- | `getOAuthAppInfo(input)` | Query | Get OAuth app info by client ID |
143
+ | `user.getPublicProfile(input)` | Query | Profile by openId |
144
+ | `user.getPublicProfileById(input)` | Query | Profile by userId |
145
+ | `auth.me()` | Query | Authenticated user's profile |
146
+ | `auth.getOAuthAppInfo(input)` | Query | OAuth app info by clientId |
147
+
148
+ ## API Reference — Commerce Namespace
149
+
150
+ Commerce methods communicate via MCP JSON-RPC with `goodzcommerce.manus.space`. This namespace covers shop management, product assembly, campaigns, purchases, wholesale, and settlement.
151
+
152
+ ### Shop & Product Assembly
153
+
154
+ | Method | Description |
155
+ |--------|-------------|
156
+ | `createShop(input)` | Create a new shop |
157
+ | `getShopDashboard()` | Shop dashboard with stats |
158
+ | `createBatch(input)` | Create a product batch (fixed-price bundle) |
159
+ | `createGachaPool(input)` | Create a gacha/blind-box pool with probability weights |
160
+
161
+ ### Campaign Lifecycle
162
+
163
+ | Method | Description |
164
+ |--------|-------------|
165
+ | `launchCampaign(input)` | Launch a new sales campaign |
166
+ | `activateCampaign(input)` | Activate a paused campaign |
167
+ | `pauseCampaign(input)` | Pause an active campaign |
168
+ | `endCampaign(input)` | End a campaign permanently |
169
+ | `updateCampaign(input)` | Update campaign details |
170
+ | `getCampaignInfo(input)` | Get campaign info |
171
+ | `getCampaignItems(input)` | Get items in a campaign |
172
+
173
+ ### Purchase & Orders
174
+
175
+ | Method | Description |
176
+ |--------|-------------|
177
+ | `executePurchase(input)` | Execute a purchase (direct or gacha draw) |
178
+ | `getMyOrders()` | User's order history |
179
+
180
+ ### Wholesale
181
+
182
+ | Method | Description |
183
+ |--------|-------------|
184
+ | `publishToWholesale(input)` | Publish batch to wholesale market |
185
+ | `browseWholesale()` | Browse wholesale listings |
186
+ | `procureBatch(input)` | Procure a wholesale batch for resale |
187
+
188
+ ### Inventory & Fulfillment
189
+
190
+ | Method | Description |
191
+ |--------|-------------|
192
+ | `manageInventory(input)` | View/manage shop inventory |
193
+ | `registerInstances(input)` | Register minted instances to shop |
194
+ | `mintToInventory(input)` | Mint + register in one step |
195
+ | `redeemPhysical(input)` | Redeem a physical item |
196
+
197
+ ### Settlement & Discovery
198
+
199
+ | Method | Description |
200
+ |--------|-------------|
201
+ | `getSettlementReport()` | Revenue and settlement report |
202
+ | `searchMarketplace(input)` | Search across all shops |
203
+ | `getShopsByBlueprint(input)` | Find shops selling a specific card |
204
+
205
+ ### Webhooks & App Management
206
+
207
+ | Method | Description |
208
+ |--------|-------------|
209
+ | `registerWebhook(input)` | Register event webhook |
210
+ | `listWebhooks()` | List registered webhooks |
211
+ | `testWebhook(input)` | Test a webhook endpoint |
212
+ | `deleteWebhook(input)` | Delete a webhook |
213
+ | `registerApp(input)` | Register an app on Commerce |
214
+ | `updateApp(input)` | Update app details |
215
+ | `listMyApps()` | List your registered apps |
216
+ | `getAuthUrl()` | Get Commerce OAuth URL |
217
+
218
+ ### Commerce Escape Hatch
124
219
 
125
- #### `goodz.ip` — IP Management (Franchise/Series/Card)
220
+ ```ts
221
+ // For MCP tools not yet in the typed API
222
+ const result = await goodz.commerce.rawTool("some_new_tool", { key: "value" });
223
+ ```
126
224
 
127
- | Method | Type | Description |
128
- |--------|------|-------------|
129
- | `getFranchise(input)` | Query | Get franchise by ID or slug |
130
- | `getSeries(input)` | Query | Get series by ID or slug |
131
- | `listSeriesByFranchise(input)` | Query | List all series in a franchise |
132
- | `getCard(input)` | Query | Get card by ID |
133
- | `listCardsBySeries(input)` | Query | List all cards in a series |
225
+ ## API Reference Exchange Namespace
134
226
 
135
- ### Raw Escape Hatches
227
+ Exchange methods communicate via MCP JSON-RPC with `goodzexchange.manus.space`. This namespace covers the secondary market: listings, auctions, want-to-buy requests, P2P trades, and market data.
136
228
 
137
- For routes not yet covered by the typed namespaces, use the raw methods:
229
+ ### Marketplace & Listings
230
+
231
+ | Method | Description |
232
+ |--------|-------------|
233
+ | `browseMarketplace(input?)` | Browse active listings with filters |
234
+ | `getListingDetail(input)` | Get listing details |
235
+ | `createListing(input)` | Create listing (fixed_price or auction). Core locks the instance |
236
+ | `cancelListing(input)` | Cancel listing. Core unlocks the instance |
237
+
238
+ ### Purchase & Bidding
239
+
240
+ | Method | Description |
241
+ |--------|-------------|
242
+ | `buyListing(input)` | Buy a fixed-price listing. Z-coin debit + ownership transfer |
243
+ | `placeBid(input)` | Bid on auction. If meets buy-now price → instant purchase |
244
+ | `getBids(input)` | All bids for an auction (highest first) |
245
+
246
+ ### Want-to-Buy (WTB)
247
+
248
+ | Method | Description |
249
+ |--------|-------------|
250
+ | `createWtb(input)` | Post a want-to-buy request |
251
+ | `fulfillWtb(input)` | Fulfill a WTB by offering your item |
252
+ | `cancelWtb(input)` | Cancel your WTB request |
253
+
254
+ ### P2P Trade
255
+
256
+ | Method | Description |
257
+ |--------|-------------|
258
+ | `proposeTrade(input)` | Propose an item swap (optional Z-coin compensation) |
259
+ | `respondToTrade(input)` | Accept/reject trade. If accepted → all items transfer atomically |
260
+
261
+ ### Watchlist & Market Data
262
+
263
+ | Method | Description |
264
+ |--------|-------------|
265
+ | `getWatchlist()` | Your watchlist |
266
+ | `addToWatchlist(input)` | Add to watchlist |
267
+ | `removeFromWatchlist(input)` | Remove from watchlist |
268
+ | `getMarketData(input)` | Price history, floor price, volume, trends |
269
+
270
+ ### Exchange Escape Hatch
138
271
 
139
272
  ```ts
140
- const data = await goodz.rawQuery("some.newRoute", { id: 123 });
141
- const result = await goodz.rawMutation("some.newMutation", { name: "test" });
273
+ const result = await goodz.exchange.rawTool("some_new_tool", { key: "value" });
142
274
  ```
143
275
 
144
- ## Authentication
276
+ ## API Reference — Alive Namespace
145
277
 
146
- ### Server-to-Server with Static Token
278
+ Alive methods communicate via MCP JSON-RPC with `goodzalive.manus.space`. This namespace powers AI companion interactions: memory, intimacy, context building, and conversation.
147
279
 
148
- The simplest approach for backend services:
280
+ | Method | Description |
281
+ |--------|-------------|
282
+ | `storeMemory(input)` | Store a memory for a character-user pair |
283
+ | `recallMemories(input)` | Semantic search for relevant memories |
284
+ | `forgetMemory(input)` | Delete a specific memory |
285
+ | `getIntimacy(input)` | Get intimacy/affection state between character and user |
286
+ | `updateIntimacy(input)` | Update intimacy level after interaction |
287
+ | `buildContext(input)` | Build full AI context (profile + memories + history + system prompt) |
288
+ | `classifyIntent(input)` | Classify user message into intent category |
289
+ | `sendMessage(input)` | Send message → get character response (includes memory/intimacy processing) |
290
+
291
+ ### Alive Escape Hatch
292
+
293
+ ```ts
294
+ const result = await goodz.alive.rawTool("some_new_tool", { key: "value" });
295
+ ```
296
+
297
+ ## Authentication
298
+
299
+ ### Static Token (simplest)
149
300
 
150
301
  ```ts
151
302
  const goodz = createGoodZClient({
@@ -169,7 +320,6 @@ const tokenManager = new TokenManager({
169
320
  expiresAt: savedExpiresAt,
170
321
  },
171
322
  onTokenRefresh: async (tokens) => {
172
- // Persist refreshed tokens to your database
173
323
  await db.update(appTokens).set({
174
324
  accessToken: tokens.accessToken,
175
325
  refreshToken: tokens.refreshToken,
@@ -198,7 +348,7 @@ const authUrl = buildAuthorizationUrl({
198
348
  state: crypto.randomUUID(),
199
349
  });
200
350
 
201
- // Step 2: Exchange code for tokens in your callback handler
351
+ // Step 2: Exchange code for tokens
202
352
  const tokens = await exchangeCode({
203
353
  clientId: "od_myapp",
204
354
  clientSecret: process.env.CLIENT_SECRET,
@@ -214,7 +364,7 @@ const userGoodz = createGoodZClient({
214
364
 
215
365
  ## Z-coin Precision
216
366
 
217
- GoodZ.Core stores Z-coin amounts in **hundredths** (1/100th of a Z-coin). For example, 10.50 Z-coin is stored as `1050`. The SDK provides utility functions to convert between display values and hundredths:
367
+ GoodZ stores Z-coin amounts in **hundredths** (1/100th of a Z-coin). For example, 10.50 Z-coin is stored as `1050`.
218
368
 
219
369
  ```ts
220
370
  import { toHundredths, toDisplay, formatZcoin } from "@goodz-core/sdk/zcoin";
@@ -224,7 +374,7 @@ toDisplay(1050); // → 10.5
224
374
  formatZcoin(1050); // → "10.50"
225
375
  ```
226
376
 
227
- Always use `toHundredths()` when constructing API inputs to avoid the off-by-100x error:
377
+ Always use `toHundredths()` when constructing API inputs:
228
378
 
229
379
  ```ts
230
380
  // ✅ Correct
@@ -242,7 +392,7 @@ await goodz.zcoin.commercialTransfer({
242
392
 
243
393
  ## Error Handling
244
394
 
245
- All API errors are thrown as `GoodZApiError` instances with structured fields:
395
+ All API errors are thrown as `GoodZApiError` instances:
246
396
 
247
397
  ```ts
248
398
  import { GoodZApiError } from "@goodz-core/sdk";
@@ -251,33 +401,67 @@ try {
251
401
  await goodz.zcoin.commercialTransfer({ /* ... */ });
252
402
  } catch (err) {
253
403
  if (err instanceof GoodZApiError) {
254
- console.error(err.code); // "BAD_REQUEST", "FORBIDDEN", "CONFLICT", etc.
255
- console.error(err.httpStatus); // 400, 403, 409, etc.
404
+ console.error(err.code); // "BAD_REQUEST", "FORBIDDEN", etc.
405
+ console.error(err.httpStatus); // 400, 403, etc.
256
406
  console.error(err.path); // "zcoin.commercialTransfer"
257
- console.error(err.message); // Human-readable error message
258
-
259
- // Zod validation errors (if input was malformed)
407
+ console.error(err.message); // Human-readable message
260
408
  if (err.zodErrors) {
261
409
  for (const fieldErr of err.zodErrors) {
262
410
  console.error(`${fieldErr.path.join(".")}: ${fieldErr.message}`);
263
411
  }
264
412
  }
265
-
266
- // Full detailed string for logging
267
- console.error(err.toDetailedString());
268
413
  }
269
414
  }
270
415
  ```
271
416
 
272
- Common error codes and recommended handling:
417
+ | Code | HTTP | Meaning | Action |
418
+ |------|------|---------|--------|
419
+ | `BAD_REQUEST` | 400 | Invalid input or insufficient balance | Check input values |
420
+ | `UNAUTHORIZED` | 401 | Missing or invalid token | Refresh token or re-login |
421
+ | `FORBIDDEN` | 403 | No permission | Show permission denied |
422
+ | `NOT_FOUND` | 404 | Resource doesn't exist | Show 404 or fallback |
423
+ | `CONFLICT` | 409 | Version conflict | Retry the operation |
424
+
425
+ ## UI Components (React)
426
+
427
+ The SDK includes a React component for displaying GoodZ collectibles with full material effects and tilt interaction — the same experience used on GoodZ.Core itself.
428
+
429
+ ### GoodZCardFocus
430
+
431
+ ```tsx
432
+ import { GoodZCardFocus } from "@goodz-core/sdk/ui";
433
+
434
+ <GoodZCardFocus
435
+ imageUrl="https://goodzcore.manus.space/api/shell/42.png"
436
+ cardName="Luna"
437
+ rarity="SSR"
438
+ formFactor="trading_card"
439
+ >
440
+ <img src={thumbnailUrl} alt="Luna" className="w-full rounded-lg" />
441
+ </GoodZCardFocus>
442
+ ```
443
+
444
+ Supports all 10 form factors with unique material effects:
445
+
446
+ | Form Factor | Material Effect |
447
+ |---|---|
448
+ | `trading_card` | Holographic gradient + sparkle (intensity by rarity) |
449
+ | `postcard` / `postcard_portrait` | Paper texture + subtle shadow |
450
+ | `polaroid` | White border (thick bottom) + paper texture |
451
+ | `laser_ticket` | Intense rainbow holographic + shimmer animation |
452
+ | `badge_*` | Circular clip + metal frame + dome highlight |
453
+ | `acrylic_stand_*` | Transparent glass + edge refraction + caustic |
273
454
 
274
- | Code | HTTP | Meaning | Recommended Action |
275
- |------|------|---------|--------------------|
276
- | `BAD_REQUEST` | 400 | Invalid input or insufficient balance | Check input values, show user-friendly message |
277
- | `UNAUTHORIZED` | 401 | Missing or invalid token | Redirect to login or refresh token |
278
- | `FORBIDDEN` | 403 | No permission (e.g., not the owner) | Show permission denied message |
279
- | `NOT_FOUND` | 404 | Resource doesn't exist | Show 404 page or fallback |
280
- | `CONFLICT` | 409 | Version conflict (optimistic locking) | Retry the operation |
455
+ Interaction: desktop mouse tilt, mobile gyroscope (auto-detected), touch drag fallback, iOS permission prompt. React 18+ peer dependency. No CSS framework required.
456
+
457
+ ### Form Factor Utilities
458
+
459
+ ```ts
460
+ import { FORM_FACTORS, getAspectRatioCSS, getFormFactorSpec } from "@goodz-core/sdk/ui";
461
+
462
+ getAspectRatioCSS("trading_card"); // "5 / 7"
463
+ getFormFactorSpec("polaroid"); // { key, label, aspectRatio: [3, 4], isCircle: false }
464
+ ```
281
465
 
282
466
  ## Subpath Imports
283
467
 
@@ -287,6 +471,10 @@ For tree-shaking, import from specific subpaths:
287
471
  import { createGoodZClient } from "@goodz-core/sdk/core";
288
472
  import { TokenManager } from "@goodz-core/sdk/auth";
289
473
  import { toHundredths } from "@goodz-core/sdk/zcoin";
474
+ import { GoodZCardFocus } from "@goodz-core/sdk/ui";
475
+ import { createCommerceNamespace } from "@goodz-core/sdk/commerce";
476
+ import { createExchangeNamespace } from "@goodz-core/sdk/exchange";
477
+ import { createAliveNamespace } from "@goodz-core/sdk/alive";
290
478
  ```
291
479
 
292
480
  The root import (`@goodz-core/sdk`) re-exports everything for convenience.