diff --git a/docs/nitrolite/build/examples.mdx b/docs/nitrolite/build/examples.mdx new file mode 100644 index 0000000..a2e7e44 --- /dev/null +++ b/docs/nitrolite/build/examples.mdx @@ -0,0 +1,168 @@ +--- +title: Examples +description: Deployed Nitrolite example applications, their source repositories, stacks, and SDK usage. +sidebar_position: 4 +--- + +# Examples + +These deployed examples show different ways to build on Nitrolite. Use the live apps to understand the product flow, then inspect the source repositories for integration details. + +:::note +Stack and SDK details reflect the linked repositories when this page was added. The repositories are the source of truth if an example changes after deployment. +::: + +
+
+
+ + Co-Sign Checkout front page + +
+
+

Co-Sign Checkout

+
+
+

+ A shared checkout demo where two participants create a cart, co-sign checkout actions, + move funds into an app-session cart, propose purchases, close the cart, and withdraw + remaining shared-wallet funds. +

+
+
+

Functionality

+
    +
  • Two-party shared cart and approval flow.
  • +
  • Shared Wallet plus Checkout Cart app session.
  • +
  • Purchase proposals, cart close, and wallet withdrawal.
  • +
  • YUSD and YELLOW on Ethereum Sepolia.
  • +
+
+
+

Stack

+
    +
  • Next.js, React, TypeScript, Tailwind CSS.
  • +
  • Supabase rooms, proposals, and events.
  • +
  • Vercel deployment with scheduled proposal expiration.
  • +
  • MetaMask SDK and viem.
  • +
+
+
+

SDKs

+
    +
  • @yellow-org/sdk
  • +
  • @yellow-org/sdk-compat
  • +
+
+
+
+
+ Live demo + Source +
+
+
+
+ +
+
+ + Nitrolite Store front page + +
+
+

Nitrolite Store

+
+
+

+ A content-store reference app with a Go backend and browser frontend. The shopper connects + MetaMask, opens a store app session, adds funds, buys catalog content, reads purchased + content, and withdraws the remaining balance. +

+
+
+

Functionality

+
    +
  • MetaMask shopper identity with backend app signing.
  • +
  • Frontend-constructed app-session updates.
  • +
  • Catalog purchase and content gating.
  • +
  • YUSD and YELLOW pricing on Ethereum Sepolia.
  • +
+
+
+

Stack

+
    +
  • Go service serving API and built web UI.
  • +
  • React, Vite, TypeScript frontend.
  • +
  • SQLite persistence, Docker, Railway.
  • +
  • MetaMask and viem in the browser.
  • +
+
+
+

SDKs

+
    +
  • github.com/layer-3/nitrolite/sdk/go
  • +
  • @yellow-org/sdk
  • +
  • @yellow-org/sdk-compat
  • +
+
+
+
+
+ Live demo + Source +
+
+
+
+ +
+
+ + Nexus P2P Transfer front page + +
+
+

Nexus P2P Transfer

+
+
+

+ A workshop-style content app that demonstrates wallet connection, Nitrolite session setup, + balance polling, and instant peer-to-peer support payments to post authors. +

+
+
+

Functionality

+
    +
  • MetaMask connection and Sepolia network selection.
  • +
  • Nitrolite client session with balance polling.
  • +
  • Small support transfers to author wallets.
  • +
  • YUSD and YELLOW asset selection.
  • +
+
+
+

Stack

+
    +
  • Preact with Hooks, TypeScript, and Vite.
  • +
  • CSS Modules for app styling.
  • +
  • viem for wallet access and amount conversion.
  • +
  • Vercel-hosted static frontend.
  • +
+
+
+

SDKs

+
    +
  • @yellow-org/sdk
  • +
  • @yellow-org/sdk-compat
  • +
+
+
+
+
+ Live demo + Source +
+
+
+
+
diff --git a/docs/nitrolite/build/sdk/typescript-compat/errors.mdx b/docs/nitrolite/build/sdk/typescript-compat/errors.mdx new file mode 100644 index 0000000..277409e --- /dev/null +++ b/docs/nitrolite/build/sdk/typescript-compat/errors.mdx @@ -0,0 +1,174 @@ +--- +title: "Errors and recovery (compat)" +description: Typed compat errors and recovery recipes for migrated apps +sidebar_position: 6 +--- + +# Errors and Recovery + +At app boundaries, classify raw wallet or SDK failures and show only UI-safe copy: + +```typescript +import { NitroliteClient, getUserFacingMessage } from '@yellow-org/sdk-compat'; + +try { + await client.deposit(tokenAddress, 11_000_000n); +} catch (err) { + const typed = NitroliteClient.classifyError(err); + showToast(getUserFacingMessage(typed)); + throw typed; +} +``` + +## Error Catalogue + +| Error class | Code | Trigger | Recovery | +|---|---|---|---| +| `CompatError` | varies | Base compat failure | Log `error.code`; show `getUserFacingMessage(error)` | +| `AllowanceError` | `ALLOWANCE_INSUFFICIENT` | ChannelHub needs ERC-20 allowance | Approve, then retry | +| `UserRejectedError` | `USER_REJECTED` | Wallet rejected a signature or transaction | Show retry UI; do not auto-loop prompts | +| `InsufficientFundsError` | `INSUFFICIENT_FUNDS` | Not enough gas or token balance | Show funding guidance | +| `NotInitializedError` | `NOT_INITIALIZED` | Wallet/client is disconnected | Reconnect and recreate the client | +| `OngoingStateTransitionError` | `ONGOING_STATE_TRANSITION` | Previous transition still finalizing | Poll status, then retry | + +## Allowance + +Compat token helpers use token addresses and raw token units: + +```typescript +import { AllowanceError, NitroliteClient, getUserFacingMessage } from '@yellow-org/sdk-compat'; + +try { + await client.deposit(tokenAddress, 11_000_000n); +} catch (err) { + const typed = NitroliteClient.classifyError(err); + showToast(getUserFacingMessage(typed)); + + if (typed instanceof AllowanceError) { + await client.approveTokens(tokenAddress, 11_000_000n); + await client.deposit(tokenAddress, 11_000_000n); + } +} +``` + +When you fall through to native v1, use `client.innerClient.approveToken(chainId, asset, amount)` with `Decimal`: + +```typescript +import Decimal from 'decimal.js'; + +try { + await client.innerClient.checkpoint('usdc'); +} catch (err) { + showToast(getUserFacingMessage(err)); + await client.innerClient.approveToken(11155111n, 'usdc', new Decimal(11)); + await client.innerClient.checkpoint('usdc'); +} +``` + +## Prompt and Reconnect + +For `UserRejectedError`, show `getUserFacingMessage(error)` and expose an explicit retry button. Do not auto-loop wallet prompts. For `NotInitializedError`, reconnect the wallet and recreate `NitroliteClient` before retrying. + +## Ongoing Transition + +Use `EventPoller` to wait for channel status to settle before enabling another write: + +```typescript +import { + EventPoller, + OngoingStateTransitionError, + NitroliteClient, + getUserFacingMessage, +} from '@yellow-org/sdk-compat'; + +try { + await client.deposit(tokenAddress, 11_000_000n); +} catch (err) { + const typed = NitroliteClient.classifyError(err); + showToast(getUserFacingMessage(typed)); + + if (typed instanceof OngoingStateTransitionError) { + const poller = new EventPoller(client, { + onChannelUpdate: (channels) => { + if (!channels.some((channel) => channel.status === 'resizing')) { + poller.stop(); + enableRetry(); + } + }, + onError: (pollError) => showToast(getUserFacingMessage(pollError)), + }, 3000); + poller.start(); + } +} +``` + +## Insufficient Funds + +```typescript +import { InsufficientFundsError, NitroliteClient, getUserFacingMessage } from '@yellow-org/sdk-compat'; + +try { + await client.deposit(tokenAddress, 11_000_000n); +} catch (err) { + const typed = NitroliteClient.classifyError(err); + showToast(getUserFacingMessage(typed)); + + if (typed instanceof InsufficientFundsError) { + const tokenBalance = await client.getTokenBalance(tokenAddress); + renderFundingHelp({ tokenBalance, chainId: 11155111 }); + } +} +``` + +## Missing RPC URL + +On-chain helpers throw `No RPC URL configured for chain ...` when `blockchainRPCs` is missing. Fix the client config with `blockchainRPCs: { 80002: process.env.POLYGON_AMOY_RPC_URL! }`. + +```typescript +try { + await client.getOpenChannels(); +} catch (err) { + showToast(getUserFacingMessage(err)); + if (err instanceof Error && err.message.includes('No RPC URL configured')) promptForRpcUrl(); +} +``` + +## Unsupported Asset or Wrong Amount Unit + +```typescript +try { + await client.transfer(destination, [{ asset: 'usdc', amount: '5000000' }]); +} catch (err) { + showToast(getUserFacingMessage(err)); + + if (err instanceof Error && err.message.includes('Unknown asset')) { + renderSupportedAssets(await client.getAssetsList()); + } +} +``` + +If a transfer uses `5.0`, fix it before retrying. Compat transfer uses raw asset-unit strings. Keep the [amount-units table](./overview#amount-units) next to migrated payment code reviews. + +## Failed Checkpoint + +Retry with capped backoff only after approval and state preconditions are satisfied. Keep the visible message behind `getUserFacingMessage(err)`: + +```typescript +let lastError: unknown; + +for (const waitMs of [1000, 3000, 5000]) { + try { + await client.innerClient.checkpoint('usdc'); + lastError = undefined; + break; + } catch (err) { + lastError = err; + showToast(getUserFacingMessage(err)); + await new Promise((resolve) => setTimeout(resolve, waitMs)); + } +} + +if (lastError) { + throw lastError; +} +``` diff --git a/docs/nitrolite/build/sdk/typescript-compat/event-poller.mdx b/docs/nitrolite/build/sdk/typescript-compat/event-poller.mdx new file mode 100644 index 0000000..54d2bd4 --- /dev/null +++ b/docs/nitrolite/build/sdk/typescript-compat/event-poller.mdx @@ -0,0 +1,98 @@ +--- +title: "EventPoller: bridging the dropped server-push model" +description: Polling bridge for migrated v0.5.3 event handlers +sidebar_position: 5 +--- + +# EventPoller + +`EventPoller` is the compat bridge for apps that used 0.5.3-style pushed channel, balance, or asset updates. The v1 runtime does not preserve that server-push event model, so compat polls the query methods and calls your existing UI update hooks. + +Use it when the rest of your app still expects callbacks. If you are already rewriting the state layer, call `client.getChannels()`, `client.getBalances()`, and `client.getAssetsList()` directly. + +## Public Surface + +```typescript +import { EventPoller } from '@yellow-org/sdk-compat'; + +const poller = new EventPoller(client, callbacks, intervalMs); + +poller.start(); +poller.stop(); +poller.setInterval(10000); +``` + +The constructor takes the compat `NitroliteClient`, optional `EventPollerCallbacks`, and an optional interval in milliseconds. The default interval is `5000`. + +```typescript +interface EventPollerCallbacks { + onChannelUpdate?: (channels: LedgerChannel[]) => void; + onBalanceUpdate?: (balances: LedgerBalance[]) => void; + onAssetsUpdate?: (assets: ClearNodeAsset[]) => void; + onError?: (error: Error) => void; +} +``` + +`onAssetsUpdate` keeps the legacy asset shape for backwards compatibility. New native v1 code should read the asset surface directly from `@yellow-org/sdk`. + +## Full Example + +```typescript +import { + EventPoller, + NitroliteClient, + getUserFacingMessage, +} from '@yellow-org/sdk-compat'; + +const client = await NitroliteClient.create({ + wsURL: '', + walletClient, + chainId: 11155111, + blockchainRPCs, +}); + +const poller = new EventPoller(client, { + onChannelUpdate: (channels) => { + channelStore.replace(channels); + }, + onBalanceUpdate: (balances) => { + balanceStore.replace(balances); + }, + onAssetsUpdate: (assets) => { + assetStore.replace(assets); + }, + onError: (err) => { + showToast(getUserFacingMessage(err)); + }, +}, 5000); + +poller.start(); + +window.addEventListener('beforeunload', () => { + poller.stop(); +}); +``` + +## Intervals + +Use `2000` to `5000` ms during active deposits, withdrawals, or app-session transitions. Use `5000` to `10000` ms for normal dashboards, and `15000` to `30000` ms for background views. Switch intervals as the user moves between active and passive flows: + +```typescript +poller.setInterval(isTransitionPending ? 3000 : 10000); +``` + +## Failure Behavior + +Each poll cycle calls: + +- `client.getChannels()` +- `client.getBalances()` +- `client.getAssetsList()` + +Those requests run independently. If one fails, `EventPoller` calls `onError` for that failure and still delivers fulfilled results from the other requests. + +`EventPoller` does not renew auth tokens, persist state, or replace your app cache. It gives migrated apps a single start/stop lifecycle and normalizes channel, balance, and asset polling failures into one `onError` path while they move away from pushed WebSocket events. + +## Moving to Native v1 + +When you remove compat, remove `EventPoller` too. Native v1 apps should own their own refresh policy and call SDK query methods such as `client.getChannels(wallet)`, `client.getBalances(wallet)`, and `client.getAssets()` from the screen that needs the data. diff --git a/docs/nitrolite/build/sdk/typescript-compat/migration-offchain.mdx b/docs/nitrolite/build/sdk/typescript-compat/migration-offchain.mdx index a5efde4..08aec5f 100644 --- a/docs/nitrolite/build/sdk/typescript-compat/migration-offchain.mdx +++ b/docs/nitrolite/build/sdk/typescript-compat/migration-offchain.mdx @@ -6,103 +6,173 @@ sidebar_position: 4 # Off-Chain Migration Guide -Covers authentication, app sessions, transfers, ledger queries, and event polling when migrating from v0.5.3. +This page covers authentication, app sessions, transfers, ledger queries, and event polling when moving 0.5.3 app code to `@yellow-org/sdk-compat`. ## Authentication -v1.0.0 handles authentication internally when using `NitroliteClient`. For legacy WebSocket-auth code paths, the compat layer keeps `createAuthRequestMessage`, `createAuthVerifyMessage`, `createAuthVerifyMessageWithJWT`, and `createEIP712AuthMessageSigner` available. +Native `NitroliteClient` usage handles connection authentication inside the client. Legacy auth helper imports are split into three buckets. -## App Sessions +### Available and Functional -### List +These helpers are exported and implemented for migration code that still owns a WebSocket auth flow: -**Before:** `createGetAppSessionsMessage` + `sendRequest` + `parseGetAppSessionsResponse` +```typescript +import { + createAuthRequestMessage, + createAuthVerifyMessage, + createAuthVerifyMessageWithJWT, + createEIP712AuthMessageSigner, +} from '@yellow-org/sdk-compat'; +``` -**After:** +The v1 auth request fields are `application`, `expires_at`, `session_key`, `scope`, and `allowances`. The codemod flags older `app_name`, `expire`, `participant`, and `challenge` usage for review. + +### Exported but Fail Fast + +Workflow helpers that cannot map honestly to a single live v1 RPC remain exported so old imports compile, but throw with migration guidance: ```typescript -const sessions = await client.getAppSessionsList(); +createTransferMessage; +createCreateChannelMessage; +createCloseChannelMessage; +createResizeChannelMessage; ``` -### Create +Use `NitroliteClient` methods instead. + +### Parse v1 Payloads Into 0.5.x Shapes -**Before:** +The `parse*Response` helpers normalize known v1 response payloads into the older app-facing response shape: ```typescript -const msg = await createAppSessionMessage(signer.sign, { definition, allocations }); -const raw = await sendRequest(msg); -parseCreateAppSessionResponse(raw); +parseGetChannelsResponse; +parseGetLedgerBalancesResponse; +parseGetLedgerEntriesResponse; +parseGetAppSessionsResponse; +parseCreateAppSessionResponse; +parseCloseAppSessionResponse; +parseSubmitAppStateResponse; +parseGetAppDefinitionResponse; +parseAnyRPCResponse; ``` +These are migration aids, not a reason to keep an app-owned RPC transport indefinitely. + +## App Sessions + +### List + +**Before:** `createGetAppSessionsMessage` + `sendRequest` + `parseGetAppSessionsResponse`. + **After:** ```typescript -await client.createAppSession(definition, allocations); +const sessions = await client.getAppSessionsList(); ``` -### Close - -**Before:** `createCloseAppSessionMessage` + send + parse +### Create -**After:** +App-session allocation strings remain human-readable decimal strings: ```typescript -await client.closeAppSession(appSessionId, allocations); +const appAmount = '5.0'; // human-readable app-session decimal string + +await client.createAppSession(definition, [ + { participant: userAddress, asset: 'usdc', amount: appAmount }, +], quorumSigs); ``` ### Submit State -**Before:** `createSubmitAppStateMessage` + send +```typescript +import { RPCAppStateIntent } from '@yellow-org/sdk-compat'; + +await client.submitAppState({ + app_session_id: appSessionId, + intent: RPCAppStateIntent.Operate, + version, + allocations, + quorum_sigs: quorumSigs, +}); +``` -**After:** +### Close ```typescript -await client.submitAppState(params); +await client.closeAppSession(appSessionId, allocations, quorumSigs); ``` ## Transfers -**Before:** +Transfer allocations are raw asset-unit strings, not human-readable decimal strings. + +**Before:** helper workflow. ```typescript const msg = await createTransferMessage(signer.sign, { destination, allocations }); await sendRequest(msg); ``` -**After:** +**After:** compat method. ```typescript -await client.transfer(destination, allocations); +await client.transfer(destination, [ + { asset: 'usdc', amount: '5000000' }, +]); ``` +That example means 5 USDC when the asset has 6 decimals. See the [amount-units table](./overview#amount-units). + ## Ledger Queries -**Before:** `createGetLedgerBalancesMessage` / `createGetLedgerEntriesMessage` + send + parse +**Before:** create, send, parse. -**After:** +```typescript +const msg = await createGetLedgerBalancesMessage(signer.sign, accountId); +const raw = await sendRequest(msg); +const balances = parseGetLedgerBalancesResponse(raw).params.ledgerBalances; +``` + +**After:** direct client calls. ```typescript const balances = await client.getBalances(); const entries = await client.getLedgerEntries(); +const channels = await client.getChannels(); ``` ## Event Polling -v0.5.3 used WebSocket push events (`ChannelUpdate`, `BalanceUpdate`). v1.0.0 uses polling. The `EventPoller` bridges this gap: +0.5.3 apps often listened for pushed channel and balance updates. Compat replaces that with `EventPoller`, which polls the same query methods your app can call directly. ```typescript import { EventPoller } from '@yellow-org/sdk-compat'; const poller = new EventPoller(client, { - onChannelUpdate: (channels) => updateUI(channels), + onChannelUpdate: (channels) => updateChannels(channels), onBalanceUpdate: (balances) => updateBalances(balances), - onAssetsUpdate: (assets) => updateAssets(assets), - onError: (err) => console.error(err), + onAssetsUpdate: (assets) => updateAssets(assets), + onError: (err) => reportError(err), }, 5000); poller.start(); ``` -## RPC Compatibility Helpers +See the [EventPoller cookbook](./event-poller) for lifecycle, interval, and cleanup guidance. + +## Error Handling + +Wrap migrated calls with typed error handling instead of string-matching raw wallet or RPC errors: + +```typescript +import { getUserFacingMessage, NitroliteClient } from '@yellow-org/sdk-compat'; + +try { + await client.transfer(destination, [{ asset: 'usdc', amount: '5000000' }]); +} catch (err) { + const typed = NitroliteClient.classifyError(err); + showToast(getUserFacingMessage(typed)); +} +``` -The `create*Message` and `parse*Response` functions still exist so existing imports compile. Most are transitional placeholders. Prefer `NitroliteClient` methods directly for new code. +See [Errors and recovery](./errors) for recovery recipes. diff --git a/docs/nitrolite/build/sdk/typescript-compat/migration-onchain.mdx b/docs/nitrolite/build/sdk/typescript-compat/migration-onchain.mdx index 73a0ee4..f87d801 100644 --- a/docs/nitrolite/build/sdk/typescript-compat/migration-onchain.mdx +++ b/docs/nitrolite/build/sdk/typescript-compat/migration-onchain.mdx @@ -6,11 +6,13 @@ sidebar_position: 3 # On-Chain Migration Guide -Covers deposits, withdrawals, channel operations, amount handling, and contract addresses when migrating from v0.5.3. +This page covers deposits, withdrawals, channel operations, amount handling, and contract-address migration for apps moving from `@erc7824/nitrolite@0.5.3` to `@yellow-org/sdk-compat`. ## Deposits -**Before (v0.5.3):** Manual approve → deposit → createChannel +In v1, home-channel creation is implicit on first deposit. Apps should stop sending a separate `createChannel` workflow. + +**Before:** manual approve, deposit, and channel creation. ```typescript await approveToken(custody, tokenAddress, amount); @@ -18,63 +20,104 @@ await sendRequest(createDepositMessage(signer.sign, { token: tokenAddress, amoun await sendRequest(createCreateChannelMessage(signer.sign, { token: tokenAddress, amount })); ``` -**After (compat):** Single call — approval and channel creation are implicit +**After:** one compat call with raw token units. ```typescript +const amount = 11_000_000n; // 11 USDC when the token has 6 decimals await client.deposit(tokenAddress, amount); ``` +`deposit()` resolves the token to a v1 asset, sets the home blockchain, calls the native deposit path, and checkpoints. If token allowance is missing, the compat client retries after approval through the v1 SDK. + ## Withdrawals -**Before (v0.5.3):** Manual close → checkpoint → withdraw +**Before:** close or resize workflow plus a manual withdrawal request. ```typescript -const closeMsg = await createCloseChannelMessage(signer.sign, { channel_id }); -const raw = await sendRequest(closeMsg); +const closeMsg = await createCloseChannelMessage(signer.sign, channelId, destination); +await sendRequest(closeMsg); await sendRequest(createWithdrawMessage(signer.sign, { token, amount })); ``` -**After (compat):** Single call +**After:** one compat call with raw token units. ```typescript +const amount = 5_000_000n; // 5 USDC await client.withdrawal(tokenAddress, amount); ``` ## Channel Operations -| Operation | v0.5.3 | Compat | -|-----------|--------|--------| -| Create | Explicit `createChannel()` | Implicit on first `deposit()` | -| Close | `createCloseChannelMessage` + send + parse | `client.closeChannel()` | -| Resize | `createResizeChannelMessage` + send + parse | `client.resizeChannel({ allocate_amount, token })` | +| Operation | v0.5.3 habit | Compat behavior | +|---|---|---| +| Create | `createChannel()` | Unsupported as a standalone flow; first `deposit()` creates the home channel when needed | +| Close | `createCloseChannelMessage` + send + parse | `client.closeChannel()` or `client.closeChannel({ tokenAddress })` | +| Resize | `createResizeChannelMessage` + send + parse | `client.resizeChannel({ allocate_amount, token })`, implemented through deposit | +| Checkpoint | `checkpointChannel(...)` | Fail-fast stub; use `client.innerClient.checkpoint(asset)` | +| Challenge | `challengeChannel({ state })` | Delegates to the v1 challenge path | ## Amount Handling -**Before (v0.5.3):** Raw `BigInt` everywhere; app must handle decimals +Compat does not accept one universal amount shape. Use the canonical [amount-units table](./overview#amount-units) before changing production amounts. ```typescript -const amount = 11_000_000n; // 11 USDC (6 decimals) +// Raw token-unit bigint for deposit and withdrawal. +await client.deposit(usdcTokenAddress, 11_000_000n); +await client.withdrawal(usdcTokenAddress, 5_000_000n); + +// Helpers for display conversion. +const formatted = client.formatAmount(usdcTokenAddress, 11_000_000n); // "11" +const parsed = client.parseAmount(usdcTokenAddress, '11.0'); // 11_000_000n ``` -**After (compat):** Accepts both; conversion handled internally +Transfers are different. A transfer allocation uses a raw asset-unit string: ```typescript -// Raw BigInt still works -await client.deposit(tokenAddress, 11_000_000n); - -// Or use helpers -const formatted = client.formatAmount(tokenAddress, 11_000_000n); // "11.0" -const parsed = client.parseAmount(tokenAddress, "11.0"); // 11_000_000n +await client.transfer(recipientAddress, [ + { asset: 'usdc', amount: '5000000' }, +]); ``` -For transfers and allocations, compat accepts human-readable strings: `{ asset: 'usdc', amount: '5.0' }`. +App-session allocations are different again: they use human-readable decimal strings. Keep these three cases separate during review. ## Contract Addresses -**Before (v0.5.3):** Manual config +**Before:** apps often carried manual contract maps. ```typescript const addresses = { custody: '0x...', adjudicator: '0x...' }; ``` -**After (compat):** Fetched from clearnode `get_config` — no manual setup. The `addresses` field in config is deprecated and ignored. +**After:** contract and asset metadata comes from Nitronode config and asset discovery. The `addresses` config field is deprecated and ignored. + +```typescript +const config = await client.getConfig(); +const assets = await client.getAssetsList(); +``` + +If an on-chain helper needs an RPC URL for a chain, pass `blockchainRPCs` when creating `NitroliteClient` or use `blockchainRPCsFromEnv()`. + +```typescript +const client = await NitroliteClient.create({ + wsURL: '', + walletClient, + chainId: 11155111, + blockchainRPCs: { + 11155111: process.env.SEPOLIA_RPC_URL!, + }, +}); +``` + +## Approval Helpers + +Compat exposes allowance helpers for migration code that still thinks in raw token units: + +```typescript +const allowance = await client.getTokenAllowance(tokenAddress); + +if (allowance < 11_000_000n) { + await client.approveTokens(tokenAddress, 11_000_000n); +} +``` + +For native v1-only flows, use `client.innerClient.approveToken(chainId, asset, amount)` with `Decimal`. diff --git a/docs/nitrolite/build/sdk/typescript-compat/migration-overview.mdx b/docs/nitrolite/build/sdk/typescript-compat/migration-overview.mdx index 8a71402..e3d55fc 100644 --- a/docs/nitrolite/build/sdk/typescript-compat/migration-overview.mdx +++ b/docs/nitrolite/build/sdk/typescript-compat/migration-overview.mdx @@ -4,70 +4,144 @@ description: Migrating from v0.5.3 to the compat layer sidebar_position: 2 --- -# Migrating from v0.5.3 to Compat Layer +# Migrating from v0.5.3 to Compat -This guide explains how to migrate your Nitrolite dApp from the v0.5.3 SDK to the compat layer, which bridges the old API to the v1.0.0 runtime with minimal code changes. +Use this guide when an existing app depends on `@erc7824/nitrolite@0.5.3` and needs a staged path onto the v1 runtime. Compat preserves the supported app-facing surface, but it does not promise full 0.5.3 package parity. -## Why Use the Compat Layer +## Start With the Codemod -A direct migration from v0.5.3 to v1.0.0 touches **20+ files** per app with deep, scattered rewrites. The compat layer reduces this to **~5 file changes** per app. +Run the codemod before hand-editing. It rewrites imports, migrates client constructors, renames auth fields, updates dependencies, and leaves `TODO [codemod]` comments where a human needs to collapse a workflow. -:::tip Automate with Codemod -Before migrating manually, try the [yellow-sdk-codemod](https://github.com/layer-3/yellow-sdk-codemod). It rewrites `@erc7824/nitrolite` imports, renames auth fields, migrates client constructors, updates `package.json`, and flags RPC patterns with `// TODO [codemod]` comments for the remaining manual steps. -::: +```bash +git clone https://github.com/layer-3/yellow-sdk-codemod.git +cd yellow-sdk-codemod +npm install +npm run build + +node dist/cli.js scan --path /path/to/your-app/src +node dist/cli.js run --path /path/to/your-app --update-deps +``` -## Installation +Then search for the manual markers: ```bash -npm install @yellow-org/sdk-compat -# Peer dependencies -npm install @yellow-org/sdk viem +rg "TODO \\[codemod\\]" /path/to/your-app ``` -## Import Swap +See the [overview](./overview) for the command sequence and `node dist/cli.js list` for available transforms. + +## MCP-Assisted Migration + +:::info Coming soon +The Yellow SDK MCP server is proposed for npm publication as `@yellow-org/sdk-mcp`. Until that package is published, treat this as a preview of the assisted workflow, not a command that should work today. +::: + +After publication, connect the MCP server to your MCP-compatible client and use it as a second review pass after the codemod: + +1. Run `server_info` to confirm the MCP content version matches the SDK version you are migrating to. +2. Use the `migrate-from-v053` prompt to walk through changed files and unresolved `TODO [codemod]` markers. +3. Use `validate_import` when you are unsure whether a symbol belongs to `@yellow-org/sdk-compat` or native `@yellow-org/sdk`. +4. Use `get_rpc_method` to map old `create*Message` + `sendRequest` + `parse*Response` flows onto the v1 wire method. +5. Use `lookup_method`, `lookup_type`, or `search_api` to verify direct v1 SDK replacements before reaching for `client.innerClient`. + +MCP assistance does not replace the manual checklist below. Tool-specific setup belongs with the package publish so the documented commands are runnable on the day they appear here. -| Before (v0.5.3) | After (compat) | -|-----------------|----------------| -| `import { createGetChannelsMessage, parseGetChannelsResponse } from '@layer-3/nitrolite'` | `import { NitroliteClient } from '@yellow-org/sdk-compat'` | -| Types: `AppSession`, `LedgerChannel`, `RPCAppDefinition` | Same types — re-exported from `@yellow-org/sdk-compat` | +## Install Compat -For **types**, just change the package name. For **functions**, switch to client methods instead of `create*Message` / `parse*Response`. +```bash +npm install @yellow-org/sdk-compat +npm install @yellow-org/sdk viem +``` -## The Key Pattern Change +## Client Construction -**Before (v0.5.3):** create-sign-send-parse +**Before:** app-owned WebSocket plus helper calls. ```typescript -const msg = await createGetChannelsMessage(signer.sign, addr); +const msg = await createGetChannelsMessage(signer.sign, address); const raw = await sendRequest(msg); const parsed = parseGetChannelsResponse(raw); -const channels = parsed.params.channels; ``` -**After (compat):** direct client method +**After:** one compat client backed by the v1 SDK. ```typescript -const client = await NitroliteClient.create(config); +import { NitroliteClient, blockchainRPCsFromEnv } from '@yellow-org/sdk-compat'; + +const client = await NitroliteClient.create({ + wsURL: '', + walletClient, + chainId: 11155111, + blockchainRPCs: blockchainRPCsFromEnv(), +}); + const channels = await client.getChannels(); ``` -## What Stays the Same +:::info Sandbox URL - coming soon +Use the same Nitronode URL placeholder pattern as the native v1 quickstart. Replace `` only when the canonical sandbox host is pinned. +::: + +## Migration Matrix + +| Legacy use | Compat status | Direct v1 replacement | +|---|---|---| +| Auth helpers | Available: `createAuthRequestMessage`, `createAuthVerifyMessage`, `createAuthVerifyMessageWithJWT`, `createEIP712AuthMessageSigner` | SDK client auth flow | +| Channel create or resize helpers | Unsupported or fail-fast where no honest v1 mapping exists | `Client.deposit`, `Client.checkpoint`, lifecycle methods | +| Transfer | Available with raw-amount caveat | `Client.transfer(recipient, asset, Decimal)` | +| App sessions | Available with v1 remapping | Native app-session methods on `Client` | + +## Amount Rules + +Do not flatten all amounts into one convention. Compat intentionally keeps separate units for separate method families. + +- `deposit`, `withdrawal`, and token allowance helpers use raw token-unit `bigint`. +- `transfer` uses raw asset-unit strings, for example `{ asset: 'usdc', amount: '5000000' }` for 5 USDC with 6 decimals. +- App-session allocations use human-readable decimal strings, for example `'5.0'`. +- Direct native v1 calls use `Decimal`. -- **Type shapes:** `AppSession`, `LedgerChannel`, `RPCAppDefinition`, `RPCBalance`, `RPCAsset`, etc. -- **Response formats:** Balances, ledger entries, app sessions — same structure as v0.5.3. -- **Auth helpers:** `createAuthRequestMessage`, `createAuthVerifyMessage`, `createAuthVerifyMessageWithJWT` remain available. +See the canonical [amount-units table](./overview#amount-units). ## What Changes -| Concern | v0.5.3 | Compat | -|---------|--------|--------| -| WebSocket | App creates and manages `WebSocket` | Managed internally by the client | -| Signing | App passes `signer.sign` into every message | Internal — client uses `WalletClient` | -| Amounts | Raw `BigInt` everywhere | Compat accepts both; conversion handled internally | -| Contract addresses | Manual config | Fetched from clearnode `get_config` | -| Channel creation | Explicit `createChannel()` | Implicit on first `deposit()` | +| Concern | v0.5.3 habit | Compat behavior | +|---|---|---| +| WebSocket ownership | App creates and manages `WebSocket` | `NitroliteClient` manages the connection | +| Signing | App passes `signer.sign` into each helper | Client methods sign internally with `walletClient` | +| Contract addresses | App hard-codes custody and adjudicator addresses | Compat reads current node config and asset metadata | +| Channel creation | App calls `createChannel()` | First `deposit()` creates the home channel when needed | +| Server-push events | App handles pushed channel and balance events | Use [EventPoller](./event-poller) | +| Errors | App matches raw strings | Use typed errors and [Errors and recovery](./errors) | + +## Manual Review Checklist + +After the codemod runs, review each changed area before shipping: + +| Area | What to check | +|---|---| +| Imports | `@erc7824/nitrolite`, `@layer-3/nitrolite`, and vendored tarballs are gone from app source | +| Client setup | `new NitroliteClient(...)` and `createNitroliteClient(...)` are replaced with `NitroliteClient.create({ wsURL, walletClient, chainId, blockchainRPCs })` | +| Auth | `app_name`, `expire`, `participant`, and `challenge` are migrated to `application`, `expires_at`, `session_key`, `scope`, and `allowances` | +| RPC chains | `create*Message` + `sendRequest` + `parse*Response` call chains are replaced with client methods or consciously kept as transitional helpers | +| Channel operations | `createChannel`, `depositToChannel`, and old `approveToken` wrappers are replaced with `deposit`, `withdrawal`, `approveTokens`, or a direct `innerClient` call | +| Events | WebSocket push handlers are replaced with [EventPoller](./event-poller) or app-owned polling | +| Contract config | `custody`, `adjudicator`, `CUSTODIES`, and `ADJUDICATORS` constants are removed; config comes from Nitronode | +| Amounts | Transfer amounts are raw asset-unit strings; app-session allocations are human-readable decimal strings | +| Errors | Raw string matching is replaced with `NitroliteClient.classifyError()` and `getUserFacingMessage()` | +| SSR | Do not import `Client` from `@yellow-org/sdk-compat`; import SDK classes directly from `@yellow-org/sdk` | + +## Unsupported Surfaces + +The following names can still appear in migrated code, but they are not full live replacements: + +- `checkpointChannel(...)` fails fast; use `client.innerClient.checkpoint(asset)`. +- Workflow-only `create*Message` helpers such as `createTransferMessage`, `createCreateChannelMessage`, `createCloseChannelMessage`, and `createResizeChannelMessage` fail fast with migration guidance. +- `parse*Response` helpers normalize known v1 payloads into 0.5.x-shaped responses, but they are not a replacement for an app-owned RPC transport. +- `get_session_keys` directory-style APIs and `get_rpc_history` are not preserved. ## Next Steps -- [On-Chain Changes](./migration-onchain) — Deposits, withdrawals, channel operations, amount handling -- [Off-Chain Changes](./migration-offchain) — App sessions, transfers, ledger queries, event polling +- [On-Chain Changes](./migration-onchain) - deposits, withdrawals, channel operations, and raw token units +- [Off-Chain Changes](./migration-offchain) - auth helpers, app sessions, transfers, and ledger queries +- [EventPoller](./event-poller) - replace server-push handlers with polling callbacks +- [Errors and recovery](./errors) - classify wallet, allowance, funds, and transition errors diff --git a/docs/nitrolite/build/sdk/typescript-compat/overview.mdx b/docs/nitrolite/build/sdk/typescript-compat/overview.mdx index db1e283..c53ff72 100644 --- a/docs/nitrolite/build/sdk/typescript-compat/overview.mdx +++ b/docs/nitrolite/build/sdk/typescript-compat/overview.mdx @@ -1,39 +1,49 @@ --- title: Overview -description: Compatibility layer bridging Nitrolite SDK v0.5.3 API to v1.0.0 +description: Compatibility layer bridging selected Nitrolite SDK v0.5.3 APIs to the v1 runtime sidebar_position: 1 --- # TypeScript Compat SDK -Compatibility layer that bridges the Nitrolite SDK **v0.5.3 API** to the **v1.0.0 runtime**, letting existing dApps upgrade to the new protocol with minimal code changes. +`@yellow-org/sdk-compat` is a migration layer for apps already built on the published `@erc7824/nitrolite@0.5.3` API. It keeps selected app-facing calls available while routing them through the native v1 `@yellow-org/sdk` runtime. + +:::note Package naming +The published npm package audited for this migration path is `@erc7824/nitrolite@0.5.3`. Some older internal docs refer to the same 0.5.3 codebase as `@layer-3/nitrolite`. +:::
Already integrated with @erc7824/nitrolite? -If your app is already built on `@erc7824/nitrolite` (v0.4 through v0.5.3), you can speed up the migration using the [yellow-sdk-codemod](https://github.com/layer-3/yellow-sdk-codemod) tool. It handles the repetitive parts of the upgrade automatically: rewriting imports, migrating client constructors, renaming auth fields, and updating your `package.json`. Where the change requires context (collapsing RPC call chains, removing manual WebSocket setup), the codemod leaves a `// TODO [codemod]` comment with the exact replacement so you know what to do. +Speed up the migration with the `yellow-sdk-codemod` repository: ```bash # Clone the codemod and install its dependencies git clone https://github.com/layer-3/yellow-sdk-codemod.git -cd yellow-sdk-codemod && npm install +cd yellow-sdk-codemod +npm install +npm run build -# Scan your project to see what needs changing (no files are modified) -npx tsx src/cli.ts scan --path /path/to/your-app/src +# Scan your codebase for migrate-able patterns (no files modified) +node dist/cli.js scan --path /path/to/your-app/src -# Apply all transforms and update dependencies -npx tsx src/cli.ts run --path /path/to/your-app --update-deps +# Apply transforms (and update package.json deps) +node dist/cli.js run --path /path/to/your-app --update-deps ``` -After running, search for `TODO [codemod]` in your codebase and work through the remaining items. See the [codemod README](https://github.com/layer-3/yellow-sdk-codemod#readme) for the full list of transforms and CLI options. +After running, search for `TODO [codemod]` in your codebase and resolve them manually. The codemod surfaces every place a chained `create*Message` + `sendRequest` + `parse*Response` pattern needs context. See `node dist/cli.js list` for the full transform list. + +:::info MCP-assisted migration - coming soon +The Yellow SDK MCP server is planned for npm as `@yellow-org/sdk-mcp`, but it is not published yet. After it lands, use it as a second review pass for unresolved codemod markers, uncertain imports, old RPC helper chains, and direct v1 SDK replacements. See the [migration overview](./migration-overview#mcp-assisted-migration) for the planned workflow. +:::
-## Why Use the Compat Layer +## Why Use Compat -The v1.0.0 protocol introduces breaking changes across 14 dimensions — wire format, authentication, WebSocket lifecycle, unit system, asset resolution, and more. A direct migration touches 20+ files per app with deep, scattered rewrites. +Use compat when a live app needs to move off the 0.5.3 package without rewriting every transport, auth, event, and amount-handling call at once. New apps should start with the native [`@yellow-org/sdk`](../typescript/getting-started) instead. -The compat layer centralises this complexity into **~1,000 lines** that absorb the protocol differences, reducing per-app integration effort by an estimated **56–70%**. +Compat is a bridge, not full package parity. The underlying v1 client is available as `client.innerClient` for flows that the migration surface cannot model honestly. ## Installation @@ -43,134 +53,86 @@ npm install @yellow-org/sdk-compat npm install @yellow-org/sdk viem ``` +:::info Sandbox URL - coming soon +Use your Nitronode WebSocket URL in the `wsURL` field below. The public sandbox URL is intentionally shown as `` until the canonical host is pinned. +::: + ## Quick Start ```typescript import { NitroliteClient, blockchainRPCsFromEnv } from '@yellow-org/sdk-compat'; -// Create client (replaces new Client(ws, signer)) const client = await NitroliteClient.create({ - wsURL: 'wss://clearnode.example.com/ws', + wsURL: '', walletClient, // viem WalletClient with account chainId: 11155111, // Sepolia blockchainRPCs: blockchainRPCsFromEnv(), }); -// Deposit (creates channel if needed) await client.deposit(tokenAddress, 11_000_000n); -// Query const channels = await client.getChannels(); const balances = await client.getBalances(); const sessions = await client.getAppSessionsList(); -// Transfer -await client.transfer(recipientAddress, [{ asset: 'usdc', amount: '5.0' }]); +// 5 USDC (6 decimals) as raw asset-unit string: +await client.transfer(recipientAddress, [{ asset: 'usdc', amount: '5000000' }]); -// Cleanup -await client.closeChannel(); await client.close(); ``` +`TransferAllocation.amount` is a raw asset-unit string using the asset's canonical decimals; the compat layer divides by decimals before delegating to the v1 SDK. + +## Amount Units + +| Method area | Amount format | Example | +|---|---|---| +| `deposit`, `withdrawal`, token allowance helpers | raw token-unit `bigint` | `11_000_000n` | +| `transfer` allocations | raw asset-unit string | `'5000000'` | +| App-session allocations | human-readable decimal string | `'5.0'` | +| Direct `@yellow-org/sdk` channel and app amounts | `Decimal` | `new Decimal(5)` | + ## Method Cheat Sheet -### Channel Operations - -| Method | Description | -|--------|-------------| -| `deposit(token, amount)` | Deposit to channel (creates if needed) | -| `depositAndCreateChannel(token, amount)` | Alias for `deposit()` | -| `withdrawal(token, amount)` | Withdraw from channel | -| `closeChannel(params?)` | Close open channels (optionally for a specific token) | -| `resizeChannel({ allocate_amount, token })` | Resize an existing channel | -| `challengeChannel({ state })` | Challenge a channel on-chain | -| `createChannel()` | No-op in v1 (channel creation is implicit on `deposit()`) | - -### Queries - -| Method | Description | -|--------|-------------| -| `getChannels()` | List all ledger channels | -| `getChannelData(channelId)` | Full channel + state for a specific channel | -| `getBalances(wallet?)` | Get ledger balances | -| `getLedgerEntries(wallet?)` | Get transaction history | -| `getAppSessionsList(wallet?, status?)` | List app sessions | -| `getLastAppSessionsListError()` | Last error from `getAppSessionsList()` (if any) | -| `getAssetsList()` | List supported assets | -| `getAccountInfo()` | Aggregate balance + channel count | -| `getConfig()` | Node configuration | - -### Transfers - -| Method | Description | -|--------|-------------| -| `transfer(destination, allocations)` | Off-chain transfer to another participant | - -### App Sessions - -| Method | Description | -|--------|-------------| -| `createAppSession(definition, allocations, quorumSigs?)` | Create an app session | -| `closeAppSession(appSessionId, allocations, quorumSigs?)` | Close an app session | -| `submitAppState(params)` | Submit state update (operate/deposit/withdraw/close) | -| `getAppDefinition(appSessionId)` | Get session definition | - -### App Session Signing Helpers - -| Helper | Description | -|--------|-------------| -| `packCreateAppSessionHash(params)` | Deterministic hash for `createAppSession` quorum signing | -| `packSubmitAppStateHash(params)` | Deterministic hash for `submitAppState` quorum signing | -| `toWalletQuorumSignature(signature)` | Prefix wallet signature for app-session quorum format | -| `toSessionKeyQuorumSignature(signature)` | Prefix session key signature (`0xa2`) for quorum format | - -### Session Keys - -| Method | Description | -|--------|-------------| -| `signChannelSessionKeyState(state)` | Sign a channel session-key state | -| `submitChannelSessionKeyState(state)` | Register channel session-key | -| `getLastChannelKeyStates(userAddress, sessionKey?)` | Get active channel session-key states | -| `signSessionKeyState(state)` | Sign an app-session key state | -| `submitSessionKeyState(state)` | Register app-session key | -| `getLastKeyStates(userAddress, sessionKey?)` | Get active app-session key states | - -### Asset Resolution - -| Method | Description | -|--------|-------------| -| `resolveToken(tokenAddress)` | Look up asset info by token address | -| `resolveAsset(symbol)` | Look up asset info by symbol | -| `resolveAssetDisplay(tokenAddress, chainId?)` | Get display-friendly symbol + decimals | -| `getTokenDecimals(tokenAddress)` | Get decimals for a token | -| `formatAmount(tokenAddress, rawAmount)` | Raw bigint → human-readable string | -| `parseAmount(tokenAddress, humanAmount)` | Human-readable string → raw bigint | -| `findOpenChannel(tokenAddress, chainId?)` | Find an open channel for a given token | - -### Lifecycle - -| Method | Description | -|--------|-------------| -| `ping()` | Health check | -| `close()` | Close the WebSocket connection | -| `refreshAssets()` | Re-fetch the asset map from the clearnode | - -## Properties - -| Property | Type | Description | -|----------|------|-------------| -| `innerClient` | `Client` (readonly) | The underlying v1.0.0 SDK Client | -| `userAddress` | `Address` (readonly) | The connected wallet address | +| Area | Covered surface | +|---|---| +| Channel operations | `deposit`, `depositAndCreateChannel`, `withdrawal`, `closeChannel`, `resizeChannel`, `challengeChannel`, `acknowledge` | +| Query methods | `getChannels`, `getChannelData`, `getBalances`, `getLedgerEntries`, `getAppSessionsList`, `getAssetsList`, `getAccountInfo`, `getConfig`, `getBlockchains`, `getActionAllowances` | +| Transfers | `transfer(destination, allocations)` with raw asset-unit strings | +| App sessions | `createAppSession`, `closeAppSession`, `submitAppState`, `getAppDefinition`, `registerApp`, `getApps` | +| App-session signing | `packCreateAppSessionHash`, `packSubmitAppStateHash`, `toWalletQuorumSignature`, `toSessionKeyQuorumSignature` | +| Auth helpers | `createAuthRequestMessage`, `createAuthVerifyMessage`, `createAuthVerifyMessageWithJWT`, `createEIP712AuthMessageSigner` | +| Event polling | `EventPoller` polls `getChannels()`, `getBalances()`, and `getAssetsList()` and emits legacy-shaped callbacks | + +`checkpointChannel(...)` is exported as a fail-fast migration shim; use `client.innerClient.checkpoint(asset)` instead. + +See [EventPoller](./event-poller) for the cookbook. + +Lifecycle helpers include `ping()`, `close()`, `waitForClose()`, and `refreshAssets()`. + +## What Compat Does Not Preserve + +:::warning Compat is curated, not a drop-in +`@yellow-org/sdk-compat` preserves selected `@erc7824/nitrolite@0.5.3` app-facing APIs. It does not preserve: + +- the legacy server-push event model; use [EventPoller](./event-poller) +- `checkpointChannel(...)`; it is a fail-fast stub, use `client.innerClient.checkpoint(asset)` +- `get_session_keys` directory-style APIs +- `get_rpc_history` +- full root-export parity with `@erc7824/nitrolite@0.5.3` + +If your code touches these surfaces, run the codemod first, then use the migration guides below to finish the manual changes. +::: ## Configuration ```typescript interface NitroliteClientConfig { - wsURL: string; // Clearnode WebSocket URL + wsURL: string; // Nitronode WebSocket URL walletClient: WalletClient; // viem WalletClient with account - chainId: number; // Chain ID (e.g. 11155111) - blockchainRPCs?: Record; // Chain ID → RPC URL map - channelSessionKeySigner?: { // Optional session key for quick approvals + chainId: number; // Chain ID, for example 11155111 + blockchainRPCs?: Record; // Chain ID -> RPC URL map + channelSessionKeySigner?: { sessionKeyPrivateKey: Hex; walletAddress: Address; metadataHash: Hex; @@ -179,17 +141,15 @@ interface NitroliteClientConfig { } ``` -### Environment Variables - `blockchainRPCsFromEnv()` reads from `NEXT_PUBLIC_BLOCKCHAIN_RPCS`: ```text NEXT_PUBLIC_BLOCKCHAIN_RPCS=11155111:https://rpc.sepolia.io,1:https://mainnet.infura.io/v3/KEY ``` -## Accessing the v1.0.0 SDK +## Accessing the v1 SDK -The underlying v1.0.0 `Client` is exposed for advanced use cases not covered by the compat surface: +`Client` is not re-exported from `@yellow-org/sdk-compat` for SSR safety. Import SDK classes directly from `@yellow-org/sdk`, or use the wrapped instance exposed on the compat client: ```typescript const v1Client = client.innerClient; @@ -200,57 +160,10 @@ await v1Client.approveToken(chainId, 'usdc', amount); ## Error Handling -| Error Class | Code | Description | -|-------------|------|-------------| -| `AllowanceError` | `ALLOWANCE_INSUFFICIENT` | Token approval needed | -| `UserRejectedError` | `USER_REJECTED` | User cancelled in wallet | -| `InsufficientFundsError` | `INSUFFICIENT_FUNDS` | Not enough balance | -| `NotInitializedError` | `NOT_INITIALIZED` | Client not connected | - -```typescript -import { getUserFacingMessage, AllowanceError } from '@yellow-org/sdk-compat'; - -try { - await client.deposit(token, amount); -} catch (err) { - // Convert raw errors to typed compat errors - const typed = NitroliteClient.classifyError(err); - if (typed instanceof AllowanceError) { - // prompt user to approve token spending - } - showToast(getUserFacingMessage(err)); -} -``` - -## Event Polling - -v0.5.3 used WebSocket push events. v1.0.0 uses polling. The `EventPoller` bridges this gap: - -```typescript -import { EventPoller } from '@yellow-org/sdk-compat'; - -const poller = new EventPoller(client, { - onChannelUpdate: (channels) => updateUI(channels), - onBalanceUpdate: (balances) => updateBalances(balances), - onAssetsUpdate: (assets) => updateAssets(assets), - onError: (err) => console.error(err), -}, 5000); - -poller.start(); -``` - -## Next.js Integration - -Add to `transpilePackages` in `next.config.ts`: - -```typescript -const nextConfig = { - transpilePackages: ['@yellow-org/sdk', '@yellow-org/sdk-compat'], -}; -``` +The compat package exports typed errors plus `getUserFacingMessage(error)` for UI-safe messages. See [Errors and recovery](./errors) for the cookbook. ## Migration Guides -- [Migration Overview](./migration-overview) — Pattern changes, import swaps -- [On-Chain Changes](./migration-onchain) — Deposits, withdrawals, channels -- [Off-Chain Changes](./migration-offchain) — Auth, app sessions, transfers +- [Migration Overview](./migration-overview) - choose the compat path and run the codemod +- [On-Chain Changes](./migration-onchain) - deposits, withdrawals, channel operations, and amount units +- [Off-Chain Changes](./migration-offchain) - auth, app sessions, transfers, ledger queries, and polling diff --git a/src/css/custom.css b/src/css/custom.css index c8634c9..08105b8 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -218,6 +218,104 @@ a.table-of-contents__link.table-of-contents__link--active code { color: #333333 !important; } +/* Nitrolite Build examples page */ +.nitrolite-example-list { + display: flex; + flex-direction: column; + gap: 24px; +} + +.nitrolite-example-card { + border-radius: 8px; + overflow: hidden; +} + +.nitrolite-example-card__layout { + display: grid; + grid-template-columns: minmax(340px, 48%) minmax(0, 1fr); + align-items: center; +} + +.nitrolite-example-card__media { + display: flex; + align-items: center; + justify-content: center; + align-self: center; + aspect-ratio: 16 / 10; + overflow: hidden; + background: var(--ifm-color-emphasis-100); + border-right: 1px solid var(--ifm-color-emphasis-200); +} + +.nitrolite-example-card__image { + display: block; + width: 100%; + height: 100%; + object-fit: contain; + object-position: center; +} + +.nitrolite-example-card__content { + align-self: stretch; + min-width: 0; +} + +.nitrolite-example-card__content .card__header h2 { + margin: 0; + font-size: 1.55rem; + line-height: 1.2; +} + +.nitrolite-example-card__summary { + margin-bottom: 1rem; +} + +.nitrolite-example-card__details { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 20px; +} + +.nitrolite-example-card__details > div:last-child { + grid-column: 1 / -1; +} + +.nitrolite-example-card__details code { + overflow-wrap: anywhere; +} + +.nitrolite-example-card__details h3 { + margin-bottom: 0.5rem; + font-size: 1rem; +} + +.nitrolite-example-card__details ul { + margin: 0; + padding-left: 1.1rem; +} + +.nitrolite-example-card__details li { + margin-bottom: 0.35rem; +} + +@media (max-width: 996px) { + .nitrolite-example-card__layout { + grid-template-columns: 1fr; + } + + .nitrolite-example-card__media { + aspect-ratio: 16 / 10; + border-right: 0; + border-bottom: 1px solid var(--ifm-color-emphasis-200); + } +} + +@media (max-width: 640px) { + .nitrolite-example-card__details { + grid-template-columns: 1fr; + } +} + [data-theme='dark'] .table-of-contents__link:hover, [data-theme='dark'] .table-of-contents__link:hover code { color: #cccccc !important; diff --git a/static/img/nitrolite/examples/cosign-demo.png b/static/img/nitrolite/examples/cosign-demo.png new file mode 100644 index 0000000..87ba806 Binary files /dev/null and b/static/img/nitrolite/examples/cosign-demo.png differ diff --git a/static/img/nitrolite/examples/nexus-p2p-transfer.png b/static/img/nitrolite/examples/nexus-p2p-transfer.png new file mode 100644 index 0000000..cf1f921 Binary files /dev/null and b/static/img/nitrolite/examples/nexus-p2p-transfer.png differ diff --git a/static/img/nitrolite/examples/nitrolite-store.png b/static/img/nitrolite/examples/nitrolite-store.png new file mode 100644 index 0000000..af26978 Binary files /dev/null and b/static/img/nitrolite/examples/nitrolite-store.png differ