@stellar-snaps/sdk 0.3.1 → 0.3.3
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 +124 -2
- package/dist/index.d.mts +113 -1
- package/dist/index.d.ts +113 -1
- package/dist/index.js +129 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +125 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,7 +95,29 @@ if (result.successful) {
|
|
|
95
95
|
}
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
### 4.
|
|
98
|
+
### 4. Payment flow (payment route like the web app)
|
|
99
|
+
|
|
100
|
+
Implement a **payment route** (e.g. `/s/[id]`) with the same behavior as stellar-snaps.vercel.app: fetch the snap, then run the full pay flow (Freighter connect → build tx → sign → submit) in one call.
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { getSnap, executeSnapPayment, getTransactionUrl } from '@stellar-snaps/sdk';
|
|
104
|
+
|
|
105
|
+
// On your /s/[id] page: load snap, then on "Pay" click:
|
|
106
|
+
const snap = await getSnap(id, { baseUrl: 'https://your-app.com' });
|
|
107
|
+
const amount = snap.amount ?? userEnteredAmount;
|
|
108
|
+
|
|
109
|
+
const result = await executeSnapPayment({ snap, amount });
|
|
110
|
+
|
|
111
|
+
if (result.successful) {
|
|
112
|
+
const explorerUrl = getTransactionUrl(result.hash, snap.network as 'public' | 'testnet');
|
|
113
|
+
console.log('Paid! View:', explorerUrl);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- **`getAccountSequence(publicKey, network)`** – Fetches account sequence from Horizon (for building a transaction).
|
|
118
|
+
- **`executeSnapPayment({ snap, amount })`** – Full flow: connect Freighter, build payment tx, sign with Freighter, submit. Same behavior as the web app’s “Pay with Stellar” button. **Browser only** (requires Freighter).
|
|
119
|
+
|
|
120
|
+
### 5. Create Shareable Snaps (Web App API)
|
|
99
121
|
|
|
100
122
|
Create, fetch, list, and delete database-backed snaps—same behavior as the web dashboard. Uses `https://stellar-snaps.vercel.app` by default.
|
|
101
123
|
|
|
@@ -134,7 +156,21 @@ const { url } = await createSnap({
|
|
|
134
156
|
});
|
|
135
157
|
```
|
|
136
158
|
|
|
137
|
-
|
|
159
|
+
**Show the same modal overlay as the web app** (browser only): open the snap URL in a modal so users can pay without leaving your page:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { createSnap, openSnapModal, closeSnapModal } from '@stellar-snaps/sdk';
|
|
163
|
+
|
|
164
|
+
const { url } = await createSnap({ creator: 'G...', title: 'Tip', destination: 'G...' });
|
|
165
|
+
openSnapModal(url, {
|
|
166
|
+
width: 420,
|
|
167
|
+
height: 560,
|
|
168
|
+
onClose: () => console.log('Modal closed'),
|
|
169
|
+
});
|
|
170
|
+
// User sees the same payment UI as stellar-snaps.vercel.app/s/xxx in an overlay
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### 6. Host Your Own Snap Endpoints
|
|
138
174
|
|
|
139
175
|
Create a discovery file to enable the browser extension to find your snaps:
|
|
140
176
|
|
|
@@ -152,6 +188,40 @@ const discovery = createDiscoveryFile({
|
|
|
152
188
|
// Save as: public/.well-known/stellar-snap.json
|
|
153
189
|
```
|
|
154
190
|
|
|
191
|
+
### 7. Build your own project (full flow)
|
|
192
|
+
|
|
193
|
+
Everything in the stellar-snaps web app can be built in **your own project** using only this SDK. Use the same APIs and flows so creators can create snaps, share URLs, and payers can pay from your domain.
|
|
194
|
+
|
|
195
|
+
**1. Backend (your server or serverless)**
|
|
196
|
+
|
|
197
|
+
| Endpoint | Purpose | SDK usage |
|
|
198
|
+
|----------|---------|-----------|
|
|
199
|
+
| `POST /api/snaps` | Create snap, return `{ id, ... }` | Store snap in your DB; return `id`. Use `validateSnapInput`, `createSnapObject`, `generateSnapId` from SDK. |
|
|
200
|
+
| `GET /api/snap/[id]` | Get full snap | Return snap from DB. |
|
|
201
|
+
| `GET /api/metadata/[id]` | Snap metadata for extension | Same as above; return flat object: `id`, `title`, `destination`, `amount`, `assetCode`, `assetIssuer`, `memo`, `memoType`, `network`. |
|
|
202
|
+
| `POST /api/build-tx` | Build XDR for extension | `buildPaymentXdrFromPayload(req.body)` → return `{ xdr }`. Extension calls this when user clicks "Pay with Stellar" on your snap links. |
|
|
203
|
+
| `DELETE /api/snaps?id=...&creator=...` | Delete snap | Optional; enforce creator ownership. |
|
|
204
|
+
|
|
205
|
+
**2. Payment page (e.g. `/s/[id]`)**
|
|
206
|
+
|
|
207
|
+
- Load snap: `getSnap(id, { baseUrl: 'https://your-app.com' })`.
|
|
208
|
+
- On "Pay" click: `executeSnapPayment({ snap, amount })` (browser only; requires Freighter).
|
|
209
|
+
- Show success: `getTransactionUrl(result.hash, snap.network)`.
|
|
210
|
+
|
|
211
|
+
**3. Discovery file**
|
|
212
|
+
|
|
213
|
+
- Host `/.well-known/stellar-snap.json` with rules mapping your snap path to your metadata API, e.g. `pathPattern: "/s/*"`, `apiPath: "/api/metadata/$1"`. Use `createDiscoveryFile` from the SDK.
|
|
214
|
+
|
|
215
|
+
**4. Extension and registry**
|
|
216
|
+
|
|
217
|
+
- Add your domain to the Stellar Snaps registry (or the registry your extension uses) so the extension shows snap cards for links to your domain.
|
|
218
|
+
|
|
219
|
+
**5. Create snap from your app**
|
|
220
|
+
|
|
221
|
+
- Call `createSnap({ creator, title, destination, ..., baseUrl: 'https://your-app.com' })` from the SDK; use the returned `url` (e.g. `https://your-app.com/s/abc123`) as the shareable link.
|
|
222
|
+
|
|
223
|
+
End-to-end: **create snap** (SDK + your API) → **share URL** → **payer opens `/s/[id]`** (your payment page using `executeSnapPayment`) or **payer sees link on Twitter** → extension fetches metadata and build-tx from your API → **pay with Stellar**. All of this works in your own project using only the library.
|
|
224
|
+
|
|
155
225
|
## API Reference
|
|
156
226
|
|
|
157
227
|
### Shareable Snap API (Web App)
|
|
@@ -225,6 +295,22 @@ interface Snap {
|
|
|
225
295
|
}
|
|
226
296
|
```
|
|
227
297
|
|
|
298
|
+
#### `openSnapModal(snapUrl, options?)`
|
|
299
|
+
|
|
300
|
+
Opens a snap URL in a full-screen modal overlay (iframe). Same payment UI as opening the link on the Stellar Snaps web app. **Browser only**; no-op in Node.
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
interface OpenSnapModalOptions {
|
|
304
|
+
width?: number; // Default: 420
|
|
305
|
+
height?: number; // Default: 560
|
|
306
|
+
onClose?: () => void;
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### `closeSnapModal()`
|
|
311
|
+
|
|
312
|
+
Closes the snap modal if one is open. Safe to call anytime.
|
|
313
|
+
|
|
228
314
|
### SEP-0007 URI Functions
|
|
229
315
|
|
|
230
316
|
#### `createPaymentSnap(options)`
|
|
@@ -316,6 +402,42 @@ const xlm = createAsset('XLM');
|
|
|
316
402
|
const usdc = createAsset('USDC', 'GA5ZS...');
|
|
317
403
|
```
|
|
318
404
|
|
|
405
|
+
#### `buildPaymentXdrFromPayload(payload)`
|
|
406
|
+
|
|
407
|
+
Builds payment XDR from the same payload the browser extension sends to `POST /api/build-tx`. Use in your server handler so the extension can build transactions when users click "Pay with Stellar" on your snap links.
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
// In your POST /api/build-tx handler:
|
|
411
|
+
const xdr = buildPaymentXdrFromPayload(req.body);
|
|
412
|
+
res.json({ xdr });
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Payload: `{ source, sequence, destination, amount, assetCode?, assetIssuer?, memo?, memoType?, network? }`. Returns the transaction XDR string.
|
|
416
|
+
|
|
417
|
+
### Payment Flow (Web App–Style Pay-with-Snap)
|
|
418
|
+
|
|
419
|
+
#### `getAccountSequence(publicKey, network)`
|
|
420
|
+
|
|
421
|
+
Fetches the account's current sequence from Horizon (for building a transaction). Use in browser or Node; requires network access.
|
|
422
|
+
|
|
423
|
+
```typescript
|
|
424
|
+
const sequence = await getAccountSequence(publicKey, 'testnet');
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
#### `executeSnapPayment(options)`
|
|
428
|
+
|
|
429
|
+
Runs the full payment flow for a snap: connect Freighter, build payment transaction, sign with Freighter, submit to the network. Same behavior as the web app's "Pay with Stellar" button on `/s/[id]`. **Browser only** (requires Freighter).
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
const result = await executeSnapPayment({
|
|
433
|
+
snap: await getSnap(id, { baseUrl: 'https://your-app.com' }),
|
|
434
|
+
amount: '10',
|
|
435
|
+
});
|
|
436
|
+
// => { hash: '...', successful: true, ledger?: number }
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Use this to implement a payment route (e.g. `/s/[id]`) with the same functionality as stellar-snaps.vercel.app.
|
|
440
|
+
|
|
319
441
|
### Freighter Wallet Integration
|
|
320
442
|
|
|
321
443
|
#### `connectFreighter()`
|
package/dist/index.d.mts
CHANGED
|
@@ -102,6 +102,40 @@ declare function deleteSnap(id: string, creator: string, options?: {
|
|
|
102
102
|
baseUrl?: string;
|
|
103
103
|
}): Promise<void>;
|
|
104
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Snap Modal Overlay
|
|
107
|
+
*
|
|
108
|
+
* Opens a snap URL (e.g. from createSnap) in a modal overlay so users can pay
|
|
109
|
+
* without leaving the page. Same payment UI as the web app, loaded in an iframe.
|
|
110
|
+
* Browser-only; no-op in Node.
|
|
111
|
+
*/
|
|
112
|
+
interface OpenSnapModalOptions {
|
|
113
|
+
/** Width of the iframe content area (default: 420) */
|
|
114
|
+
width?: number;
|
|
115
|
+
/** Height of the iframe (default: 560) */
|
|
116
|
+
height?: number;
|
|
117
|
+
/** Called when the user closes the modal */
|
|
118
|
+
onClose?: () => void;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Opens a snap URL in a modal overlay (iframe). Same experience as opening
|
|
122
|
+
* the link on the Stellar Snaps web app—payment form, Freighter, etc.
|
|
123
|
+
* Use the URL returned from createSnap(), e.g. result.url.
|
|
124
|
+
*
|
|
125
|
+
* Browser-only; does nothing in Node.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* const { url } = await createSnap({ ... });
|
|
130
|
+
* openSnapModal(url, { onClose: () => console.log('Closed') });
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
declare function openSnapModal(snapUrl: string, options?: OpenSnapModalOptions): void;
|
|
134
|
+
/**
|
|
135
|
+
* Closes the snap modal if one is open. Safe to call anytime.
|
|
136
|
+
*/
|
|
137
|
+
declare function closeSnapModal(): void;
|
|
138
|
+
|
|
105
139
|
/**
|
|
106
140
|
* Snap ID Generation
|
|
107
141
|
*
|
|
@@ -500,6 +534,38 @@ declare function createAsset(code: string, issuer?: string): StellarSdk.Asset;
|
|
|
500
534
|
* ```
|
|
501
535
|
*/
|
|
502
536
|
declare function buildPaymentTransaction(options: BuildPaymentOptions): string;
|
|
537
|
+
/**
|
|
538
|
+
* Payload shape sent by the browser extension to POST /api/build-tx.
|
|
539
|
+
* Use this to implement the build-tx endpoint so the extension can build
|
|
540
|
+
* transactions when users pay from your domain.
|
|
541
|
+
*/
|
|
542
|
+
interface BuildTxPayload {
|
|
543
|
+
source: string;
|
|
544
|
+
sequence: string;
|
|
545
|
+
destination: string;
|
|
546
|
+
amount: string;
|
|
547
|
+
assetCode?: string;
|
|
548
|
+
assetIssuer?: string;
|
|
549
|
+
memo?: string;
|
|
550
|
+
memoType?: string;
|
|
551
|
+
network?: Network;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Builds payment transaction XDR from the same payload the browser extension
|
|
555
|
+
* sends to POST /api/build-tx. Use in your server handler so the extension
|
|
556
|
+
* can build transactions when users click "Pay with Stellar" on your snap links.
|
|
557
|
+
*
|
|
558
|
+
* @param payload - Request body: source, sequence, destination, amount, assetCode?, assetIssuer?, memo?, memoType?, network?
|
|
559
|
+
* @returns Transaction XDR string
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* ```typescript
|
|
563
|
+
* // In your POST /api/build-tx handler:
|
|
564
|
+
* const xdr = buildPaymentXdrFromPayload(req.body);
|
|
565
|
+
* res.json({ xdr });
|
|
566
|
+
* ```
|
|
567
|
+
*/
|
|
568
|
+
declare function buildPaymentXdrFromPayload(payload: BuildTxPayload): string;
|
|
503
569
|
|
|
504
570
|
/**
|
|
505
571
|
* Result of connecting to Freighter wallet.
|
|
@@ -606,6 +672,52 @@ declare function signWithFreighter(xdr: string, network: Network): Promise<strin
|
|
|
606
672
|
*/
|
|
607
673
|
declare function submitTransaction(signedXdr: string, network: Network): Promise<TransactionSubmitResult>;
|
|
608
674
|
|
|
675
|
+
/**
|
|
676
|
+
* Payment Flow
|
|
677
|
+
*
|
|
678
|
+
* Full "pay with snap" flow matching the web app: connect Freighter,
|
|
679
|
+
* build payment transaction, sign, submit. Use this to implement a
|
|
680
|
+
* payment route (e.g. /s/[id]) with the same behavior as stellar-snaps.vercel.app.
|
|
681
|
+
*/
|
|
682
|
+
|
|
683
|
+
interface ExecuteSnapPaymentOptions {
|
|
684
|
+
/** Snap from getSnap(id, { baseUrl }) */
|
|
685
|
+
snap: Snap$1;
|
|
686
|
+
/** Amount to send (use snap.amount for fixed-amount snaps) */
|
|
687
|
+
amount: string;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Fetches the current account sequence from Horizon (for building a transaction).
|
|
691
|
+
* Use in browser or Node; requires network access.
|
|
692
|
+
*
|
|
693
|
+
* @param publicKey - Stellar account public key
|
|
694
|
+
* @param network - 'public' or 'testnet'
|
|
695
|
+
* @returns The account's sequence number as string
|
|
696
|
+
*/
|
|
697
|
+
declare function getAccountSequence(publicKey: string, network: Network): Promise<string>;
|
|
698
|
+
/**
|
|
699
|
+
* Executes the full payment flow for a snap: connect Freighter, build payment tx,
|
|
700
|
+
* sign with Freighter, submit to the network. Same behavior as the web app's
|
|
701
|
+
* "Pay with Stellar" button on /s/[id].
|
|
702
|
+
*
|
|
703
|
+
* Call this from your payment page when the user clicks Pay. Requires browser
|
|
704
|
+
* with Freighter installed.
|
|
705
|
+
*
|
|
706
|
+
* @param options - { snap, amount }
|
|
707
|
+
* @returns Transaction result (hash, successful, ledger)
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```typescript
|
|
711
|
+
* const snap = await getSnap(id, { baseUrl: 'https://your-app.com' });
|
|
712
|
+
* const amount = snap.amount ?? userEnteredAmount;
|
|
713
|
+
* const result = await executeSnapPayment({ snap, amount });
|
|
714
|
+
* if (result.successful) {
|
|
715
|
+
* console.log('Paid! TX:', result.hash);
|
|
716
|
+
* }
|
|
717
|
+
* ```
|
|
718
|
+
*/
|
|
719
|
+
declare function executeSnapPayment(options: ExecuteSnapPaymentOptions): Promise<TransactionSubmitResult>;
|
|
720
|
+
|
|
609
721
|
/**
|
|
610
722
|
* A rule for matching URL paths to API endpoints.
|
|
611
723
|
*/
|
|
@@ -1179,4 +1291,4 @@ declare class SnapApiError extends StellarSnapError {
|
|
|
1179
1291
|
constructor(message: string, statusCode?: number | undefined);
|
|
1180
1292
|
}
|
|
1181
1293
|
|
|
1182
|
-
export { type ApiResponse, type BuildPaymentOptions, CACHE_HEADERS, CORS_HEADERS, type CreateDiscoveryFileOptions, type CreateSnapInput, type CreateSnapOptions, type CreateSnapResult, type DiscoveryFile, type DiscoveryRule, type DomainEntry, type DomainStatus, EXPLORER_URLS, type ExplorerType, type FreighterConnectionResult, HORIZON_URLS, InvalidAddressError, InvalidAmountError, InvalidAssetError, InvalidUriError, type MemoType, type MetaTags, NETWORK_PASSPHRASES, type Network, POSTGRES_SCHEMA, type ParsedSnap, type PaymentSnapOptions, type PaymentSnapResult, type RateLimitBucket, type Registry, type ResolvedUrl, SHORTENER_DOMAINS, SQLITE_SCHEMA, type Snap$1 as Snap, SnapApiError, type SnapMetadata, SnapNotFoundError, type Snap as SnapRecord, SnapUnauthorizedError, StellarSnapError, type TransactionSnapOptions, type TransactionSnapResult, type TransactionSubmitResult, type UpdateSnapInput, addDomain, buildPaymentTransaction, buildUrl, connectFreighter, createAsset, createDiscoveryFile, createPaymentSnap, createRateLimiter, createRegistry, createSnap, createSnapObject, createTransactionSnap, deleteSnap, errorResponse, extractDomain, extractPath, extractSnapId, generateJsonLd, generateMetaTags, generateSnapId, getAccountUrl, getAssetUrl, getBlockedDomains, getDomainStatus, getFreighterNetwork, getOperationUrl, getSnap, getTransactionUrl, getVerifiedDomains, isDomainBlocked, isDomainVerified, isFreighterConnected, isShortenerUrl, isValidAmount, isValidAssetCode, isValidSnapId, isValidStellarAddress, listSnaps, matchUrlToRule, metaTagsToHtml, parseAddress, parseQueryParams, parseSnapUri, removeDomain, resolveUrl, resolveUrls, signWithFreighter, submitTransaction, successResponse, validateDiscoveryFile, validateRegistry, validateRequired, validateSnapInput };
|
|
1294
|
+
export { type ApiResponse, type BuildPaymentOptions, type BuildTxPayload, CACHE_HEADERS, CORS_HEADERS, type CreateDiscoveryFileOptions, type CreateSnapInput, type CreateSnapOptions, type CreateSnapResult, type DiscoveryFile, type DiscoveryRule, type DomainEntry, type DomainStatus, EXPLORER_URLS, type ExecuteSnapPaymentOptions, type ExplorerType, type FreighterConnectionResult, HORIZON_URLS, InvalidAddressError, InvalidAmountError, InvalidAssetError, InvalidUriError, type MemoType, type MetaTags, NETWORK_PASSPHRASES, type Network, type OpenSnapModalOptions, POSTGRES_SCHEMA, type ParsedSnap, type PaymentSnapOptions, type PaymentSnapResult, type RateLimitBucket, type Registry, type ResolvedUrl, SHORTENER_DOMAINS, SQLITE_SCHEMA, type Snap$1 as Snap, SnapApiError, type SnapMetadata, SnapNotFoundError, type Snap as SnapRecord, SnapUnauthorizedError, StellarSnapError, type TransactionSnapOptions, type TransactionSnapResult, type TransactionSubmitResult, type UpdateSnapInput, addDomain, buildPaymentTransaction, buildPaymentXdrFromPayload, buildUrl, closeSnapModal, connectFreighter, createAsset, createDiscoveryFile, createPaymentSnap, createRateLimiter, createRegistry, createSnap, createSnapObject, createTransactionSnap, deleteSnap, errorResponse, executeSnapPayment, extractDomain, extractPath, extractSnapId, generateJsonLd, generateMetaTags, generateSnapId, getAccountSequence, getAccountUrl, getAssetUrl, getBlockedDomains, getDomainStatus, getFreighterNetwork, getOperationUrl, getSnap, getTransactionUrl, getVerifiedDomains, isDomainBlocked, isDomainVerified, isFreighterConnected, isShortenerUrl, isValidAmount, isValidAssetCode, isValidSnapId, isValidStellarAddress, listSnaps, matchUrlToRule, metaTagsToHtml, openSnapModal, parseAddress, parseQueryParams, parseSnapUri, removeDomain, resolveUrl, resolveUrls, signWithFreighter, submitTransaction, successResponse, validateDiscoveryFile, validateRegistry, validateRequired, validateSnapInput };
|
package/dist/index.d.ts
CHANGED
|
@@ -102,6 +102,40 @@ declare function deleteSnap(id: string, creator: string, options?: {
|
|
|
102
102
|
baseUrl?: string;
|
|
103
103
|
}): Promise<void>;
|
|
104
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Snap Modal Overlay
|
|
107
|
+
*
|
|
108
|
+
* Opens a snap URL (e.g. from createSnap) in a modal overlay so users can pay
|
|
109
|
+
* without leaving the page. Same payment UI as the web app, loaded in an iframe.
|
|
110
|
+
* Browser-only; no-op in Node.
|
|
111
|
+
*/
|
|
112
|
+
interface OpenSnapModalOptions {
|
|
113
|
+
/** Width of the iframe content area (default: 420) */
|
|
114
|
+
width?: number;
|
|
115
|
+
/** Height of the iframe (default: 560) */
|
|
116
|
+
height?: number;
|
|
117
|
+
/** Called when the user closes the modal */
|
|
118
|
+
onClose?: () => void;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Opens a snap URL in a modal overlay (iframe). Same experience as opening
|
|
122
|
+
* the link on the Stellar Snaps web app—payment form, Freighter, etc.
|
|
123
|
+
* Use the URL returned from createSnap(), e.g. result.url.
|
|
124
|
+
*
|
|
125
|
+
* Browser-only; does nothing in Node.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* const { url } = await createSnap({ ... });
|
|
130
|
+
* openSnapModal(url, { onClose: () => console.log('Closed') });
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
declare function openSnapModal(snapUrl: string, options?: OpenSnapModalOptions): void;
|
|
134
|
+
/**
|
|
135
|
+
* Closes the snap modal if one is open. Safe to call anytime.
|
|
136
|
+
*/
|
|
137
|
+
declare function closeSnapModal(): void;
|
|
138
|
+
|
|
105
139
|
/**
|
|
106
140
|
* Snap ID Generation
|
|
107
141
|
*
|
|
@@ -500,6 +534,38 @@ declare function createAsset(code: string, issuer?: string): StellarSdk.Asset;
|
|
|
500
534
|
* ```
|
|
501
535
|
*/
|
|
502
536
|
declare function buildPaymentTransaction(options: BuildPaymentOptions): string;
|
|
537
|
+
/**
|
|
538
|
+
* Payload shape sent by the browser extension to POST /api/build-tx.
|
|
539
|
+
* Use this to implement the build-tx endpoint so the extension can build
|
|
540
|
+
* transactions when users pay from your domain.
|
|
541
|
+
*/
|
|
542
|
+
interface BuildTxPayload {
|
|
543
|
+
source: string;
|
|
544
|
+
sequence: string;
|
|
545
|
+
destination: string;
|
|
546
|
+
amount: string;
|
|
547
|
+
assetCode?: string;
|
|
548
|
+
assetIssuer?: string;
|
|
549
|
+
memo?: string;
|
|
550
|
+
memoType?: string;
|
|
551
|
+
network?: Network;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Builds payment transaction XDR from the same payload the browser extension
|
|
555
|
+
* sends to POST /api/build-tx. Use in your server handler so the extension
|
|
556
|
+
* can build transactions when users click "Pay with Stellar" on your snap links.
|
|
557
|
+
*
|
|
558
|
+
* @param payload - Request body: source, sequence, destination, amount, assetCode?, assetIssuer?, memo?, memoType?, network?
|
|
559
|
+
* @returns Transaction XDR string
|
|
560
|
+
*
|
|
561
|
+
* @example
|
|
562
|
+
* ```typescript
|
|
563
|
+
* // In your POST /api/build-tx handler:
|
|
564
|
+
* const xdr = buildPaymentXdrFromPayload(req.body);
|
|
565
|
+
* res.json({ xdr });
|
|
566
|
+
* ```
|
|
567
|
+
*/
|
|
568
|
+
declare function buildPaymentXdrFromPayload(payload: BuildTxPayload): string;
|
|
503
569
|
|
|
504
570
|
/**
|
|
505
571
|
* Result of connecting to Freighter wallet.
|
|
@@ -606,6 +672,52 @@ declare function signWithFreighter(xdr: string, network: Network): Promise<strin
|
|
|
606
672
|
*/
|
|
607
673
|
declare function submitTransaction(signedXdr: string, network: Network): Promise<TransactionSubmitResult>;
|
|
608
674
|
|
|
675
|
+
/**
|
|
676
|
+
* Payment Flow
|
|
677
|
+
*
|
|
678
|
+
* Full "pay with snap" flow matching the web app: connect Freighter,
|
|
679
|
+
* build payment transaction, sign, submit. Use this to implement a
|
|
680
|
+
* payment route (e.g. /s/[id]) with the same behavior as stellar-snaps.vercel.app.
|
|
681
|
+
*/
|
|
682
|
+
|
|
683
|
+
interface ExecuteSnapPaymentOptions {
|
|
684
|
+
/** Snap from getSnap(id, { baseUrl }) */
|
|
685
|
+
snap: Snap$1;
|
|
686
|
+
/** Amount to send (use snap.amount for fixed-amount snaps) */
|
|
687
|
+
amount: string;
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Fetches the current account sequence from Horizon (for building a transaction).
|
|
691
|
+
* Use in browser or Node; requires network access.
|
|
692
|
+
*
|
|
693
|
+
* @param publicKey - Stellar account public key
|
|
694
|
+
* @param network - 'public' or 'testnet'
|
|
695
|
+
* @returns The account's sequence number as string
|
|
696
|
+
*/
|
|
697
|
+
declare function getAccountSequence(publicKey: string, network: Network): Promise<string>;
|
|
698
|
+
/**
|
|
699
|
+
* Executes the full payment flow for a snap: connect Freighter, build payment tx,
|
|
700
|
+
* sign with Freighter, submit to the network. Same behavior as the web app's
|
|
701
|
+
* "Pay with Stellar" button on /s/[id].
|
|
702
|
+
*
|
|
703
|
+
* Call this from your payment page when the user clicks Pay. Requires browser
|
|
704
|
+
* with Freighter installed.
|
|
705
|
+
*
|
|
706
|
+
* @param options - { snap, amount }
|
|
707
|
+
* @returns Transaction result (hash, successful, ledger)
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```typescript
|
|
711
|
+
* const snap = await getSnap(id, { baseUrl: 'https://your-app.com' });
|
|
712
|
+
* const amount = snap.amount ?? userEnteredAmount;
|
|
713
|
+
* const result = await executeSnapPayment({ snap, amount });
|
|
714
|
+
* if (result.successful) {
|
|
715
|
+
* console.log('Paid! TX:', result.hash);
|
|
716
|
+
* }
|
|
717
|
+
* ```
|
|
718
|
+
*/
|
|
719
|
+
declare function executeSnapPayment(options: ExecuteSnapPaymentOptions): Promise<TransactionSubmitResult>;
|
|
720
|
+
|
|
609
721
|
/**
|
|
610
722
|
* A rule for matching URL paths to API endpoints.
|
|
611
723
|
*/
|
|
@@ -1179,4 +1291,4 @@ declare class SnapApiError extends StellarSnapError {
|
|
|
1179
1291
|
constructor(message: string, statusCode?: number | undefined);
|
|
1180
1292
|
}
|
|
1181
1293
|
|
|
1182
|
-
export { type ApiResponse, type BuildPaymentOptions, CACHE_HEADERS, CORS_HEADERS, type CreateDiscoveryFileOptions, type CreateSnapInput, type CreateSnapOptions, type CreateSnapResult, type DiscoveryFile, type DiscoveryRule, type DomainEntry, type DomainStatus, EXPLORER_URLS, type ExplorerType, type FreighterConnectionResult, HORIZON_URLS, InvalidAddressError, InvalidAmountError, InvalidAssetError, InvalidUriError, type MemoType, type MetaTags, NETWORK_PASSPHRASES, type Network, POSTGRES_SCHEMA, type ParsedSnap, type PaymentSnapOptions, type PaymentSnapResult, type RateLimitBucket, type Registry, type ResolvedUrl, SHORTENER_DOMAINS, SQLITE_SCHEMA, type Snap$1 as Snap, SnapApiError, type SnapMetadata, SnapNotFoundError, type Snap as SnapRecord, SnapUnauthorizedError, StellarSnapError, type TransactionSnapOptions, type TransactionSnapResult, type TransactionSubmitResult, type UpdateSnapInput, addDomain, buildPaymentTransaction, buildUrl, connectFreighter, createAsset, createDiscoveryFile, createPaymentSnap, createRateLimiter, createRegistry, createSnap, createSnapObject, createTransactionSnap, deleteSnap, errorResponse, extractDomain, extractPath, extractSnapId, generateJsonLd, generateMetaTags, generateSnapId, getAccountUrl, getAssetUrl, getBlockedDomains, getDomainStatus, getFreighterNetwork, getOperationUrl, getSnap, getTransactionUrl, getVerifiedDomains, isDomainBlocked, isDomainVerified, isFreighterConnected, isShortenerUrl, isValidAmount, isValidAssetCode, isValidSnapId, isValidStellarAddress, listSnaps, matchUrlToRule, metaTagsToHtml, parseAddress, parseQueryParams, parseSnapUri, removeDomain, resolveUrl, resolveUrls, signWithFreighter, submitTransaction, successResponse, validateDiscoveryFile, validateRegistry, validateRequired, validateSnapInput };
|
|
1294
|
+
export { type ApiResponse, type BuildPaymentOptions, type BuildTxPayload, CACHE_HEADERS, CORS_HEADERS, type CreateDiscoveryFileOptions, type CreateSnapInput, type CreateSnapOptions, type CreateSnapResult, type DiscoveryFile, type DiscoveryRule, type DomainEntry, type DomainStatus, EXPLORER_URLS, type ExecuteSnapPaymentOptions, type ExplorerType, type FreighterConnectionResult, HORIZON_URLS, InvalidAddressError, InvalidAmountError, InvalidAssetError, InvalidUriError, type MemoType, type MetaTags, NETWORK_PASSPHRASES, type Network, type OpenSnapModalOptions, POSTGRES_SCHEMA, type ParsedSnap, type PaymentSnapOptions, type PaymentSnapResult, type RateLimitBucket, type Registry, type ResolvedUrl, SHORTENER_DOMAINS, SQLITE_SCHEMA, type Snap$1 as Snap, SnapApiError, type SnapMetadata, SnapNotFoundError, type Snap as SnapRecord, SnapUnauthorizedError, StellarSnapError, type TransactionSnapOptions, type TransactionSnapResult, type TransactionSubmitResult, type UpdateSnapInput, addDomain, buildPaymentTransaction, buildPaymentXdrFromPayload, buildUrl, closeSnapModal, connectFreighter, createAsset, createDiscoveryFile, createPaymentSnap, createRateLimiter, createRegistry, createSnap, createSnapObject, createTransactionSnap, deleteSnap, errorResponse, executeSnapPayment, extractDomain, extractPath, extractSnapId, generateJsonLd, generateMetaTags, generateSnapId, getAccountSequence, getAccountUrl, getAssetUrl, getBlockedDomains, getDomainStatus, getFreighterNetwork, getOperationUrl, getSnap, getTransactionUrl, getVerifiedDomains, isDomainBlocked, isDomainVerified, isFreighterConnected, isShortenerUrl, isValidAmount, isValidAssetCode, isValidSnapId, isValidStellarAddress, listSnaps, matchUrlToRule, metaTagsToHtml, openSnapModal, parseAddress, parseQueryParams, parseSnapUri, removeDomain, resolveUrl, resolveUrls, signWithFreighter, submitTransaction, successResponse, validateDiscoveryFile, validateRegistry, validateRequired, validateSnapInput };
|
package/dist/index.js
CHANGED
|
@@ -176,6 +176,74 @@ async function deleteSnap(id, creator, options = {}) {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
+
// src/snap-modal.ts
|
|
180
|
+
var MODAL_ID = "stellar-snap-modal";
|
|
181
|
+
var IFRAME_ID = "stellar-snap-modal-iframe";
|
|
182
|
+
function isBrowser() {
|
|
183
|
+
return typeof document !== "undefined" && typeof window !== "undefined";
|
|
184
|
+
}
|
|
185
|
+
function openSnapModal(snapUrl, options = {}) {
|
|
186
|
+
if (!isBrowser()) return;
|
|
187
|
+
closeSnapModal();
|
|
188
|
+
const { width = 420, height = 560, onClose } = options;
|
|
189
|
+
const overlay = document.createElement("div");
|
|
190
|
+
overlay.id = MODAL_ID;
|
|
191
|
+
overlay.setAttribute("role", "dialog");
|
|
192
|
+
overlay.setAttribute("aria-modal", "true");
|
|
193
|
+
overlay.setAttribute("aria-label", "Stellar Snap payment");
|
|
194
|
+
const styles = {
|
|
195
|
+
position: "fixed",
|
|
196
|
+
inset: "0",
|
|
197
|
+
zIndex: "2147483647",
|
|
198
|
+
display: "flex",
|
|
199
|
+
alignItems: "center",
|
|
200
|
+
justifyContent: "center",
|
|
201
|
+
backgroundColor: "rgba(0, 0, 0, 0.6)",
|
|
202
|
+
padding: "20px",
|
|
203
|
+
boxSizing: "border-box"
|
|
204
|
+
};
|
|
205
|
+
Object.assign(overlay.style, styles);
|
|
206
|
+
const container = document.createElement("div");
|
|
207
|
+
container.style.position = "relative";
|
|
208
|
+
container.style.width = `${width}px`;
|
|
209
|
+
container.style.maxWidth = "100%";
|
|
210
|
+
container.style.height = `${height}px`;
|
|
211
|
+
container.style.maxHeight = "90vh";
|
|
212
|
+
container.style.backgroundColor = "rgb(23, 23, 23)";
|
|
213
|
+
container.style.borderRadius = "16px";
|
|
214
|
+
container.style.boxShadow = "0 25px 50px -12px rgba(0, 0, 0, 0.5)";
|
|
215
|
+
container.style.overflow = "hidden";
|
|
216
|
+
const closeBtn = document.createElement("button");
|
|
217
|
+
closeBtn.type = "button";
|
|
218
|
+
closeBtn.setAttribute("aria-label", "Close");
|
|
219
|
+
closeBtn.textContent = "\xD7";
|
|
220
|
+
closeBtn.style.cssText = "position:absolute;top:12px;right:12px;z-index:10;width:32px;height:32px;border:none;border-radius:8px;background:rgba(255,255,255,0.1);color:#e5e5e5;font-size:24px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;";
|
|
221
|
+
closeBtn.onclick = () => {
|
|
222
|
+
closeSnapModal();
|
|
223
|
+
onClose?.();
|
|
224
|
+
};
|
|
225
|
+
const iframe = document.createElement("iframe");
|
|
226
|
+
iframe.id = IFRAME_ID;
|
|
227
|
+
iframe.src = snapUrl;
|
|
228
|
+
iframe.title = "Stellar Snap payment";
|
|
229
|
+
iframe.style.cssText = "width:100%;height:100%;border:none;border-radius:16px;";
|
|
230
|
+
container.appendChild(closeBtn);
|
|
231
|
+
container.appendChild(iframe);
|
|
232
|
+
overlay.appendChild(container);
|
|
233
|
+
overlay.addEventListener("click", (e) => {
|
|
234
|
+
if (e.target === overlay) {
|
|
235
|
+
closeSnapModal();
|
|
236
|
+
onClose?.();
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
document.body.appendChild(overlay);
|
|
240
|
+
}
|
|
241
|
+
function closeSnapModal() {
|
|
242
|
+
if (!isBrowser()) return;
|
|
243
|
+
const el = document.getElementById(MODAL_ID);
|
|
244
|
+
if (el) el.remove();
|
|
245
|
+
}
|
|
246
|
+
|
|
179
247
|
// src/snap-id.ts
|
|
180
248
|
var ALPHABET = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
|
181
249
|
function generateSnapId(length = 8) {
|
|
@@ -545,6 +613,21 @@ function buildPaymentTransaction(options) {
|
|
|
545
613
|
const transaction = builder.build();
|
|
546
614
|
return transaction.toXDR();
|
|
547
615
|
}
|
|
616
|
+
function buildPaymentXdrFromPayload(payload) {
|
|
617
|
+
const network = payload.network === "public" ? "public" : "testnet";
|
|
618
|
+
return buildPaymentTransaction({
|
|
619
|
+
source: payload.source,
|
|
620
|
+
sequence: payload.sequence,
|
|
621
|
+
destination: payload.destination,
|
|
622
|
+
amount: payload.amount,
|
|
623
|
+
asset: payload.assetCode && payload.assetCode !== "XLM" && payload.assetIssuer ? { code: payload.assetCode, issuer: payload.assetIssuer } : void 0,
|
|
624
|
+
memo: payload.memo != null ? {
|
|
625
|
+
type: payload.memoType ?? "MEMO_TEXT",
|
|
626
|
+
value: payload.memo
|
|
627
|
+
} : void 0,
|
|
628
|
+
network
|
|
629
|
+
});
|
|
630
|
+
}
|
|
548
631
|
async function isFreighterConnected() {
|
|
549
632
|
try {
|
|
550
633
|
const connected = await freighterApi.isConnected();
|
|
@@ -661,6 +744,47 @@ async function submitTransaction(signedXdr, network) {
|
|
|
661
744
|
}
|
|
662
745
|
}
|
|
663
746
|
|
|
747
|
+
// src/payment-flow.ts
|
|
748
|
+
async function getAccountSequence(publicKey, network) {
|
|
749
|
+
const horizonUrl = HORIZON_URLS[network];
|
|
750
|
+
const response = await fetch(`${horizonUrl}/accounts/${publicKey}`);
|
|
751
|
+
if (!response.ok) {
|
|
752
|
+
if (response.status === 404) {
|
|
753
|
+
throw new Error("Account not found. Fund the account first.");
|
|
754
|
+
}
|
|
755
|
+
throw new Error(`Failed to load account: ${response.status}`);
|
|
756
|
+
}
|
|
757
|
+
const data = await response.json();
|
|
758
|
+
return String(data.sequence);
|
|
759
|
+
}
|
|
760
|
+
async function executeSnapPayment(options) {
|
|
761
|
+
const { snap, amount } = options;
|
|
762
|
+
if (!amount || Number(amount) <= 0) {
|
|
763
|
+
throw new Error("Please enter a valid amount");
|
|
764
|
+
}
|
|
765
|
+
const network = snap.network === "public" ? "public" : "testnet";
|
|
766
|
+
const { publicKey } = await connectFreighter();
|
|
767
|
+
const currentNetwork = await getFreighterNetwork();
|
|
768
|
+
if (currentNetwork !== network) {
|
|
769
|
+
throw new Error(`Please switch Freighter to ${network}. Currently on ${currentNetwork}.`);
|
|
770
|
+
}
|
|
771
|
+
const sequence = await getAccountSequence(publicKey, network);
|
|
772
|
+
const xdr = buildPaymentTransaction({
|
|
773
|
+
source: publicKey,
|
|
774
|
+
sequence,
|
|
775
|
+
destination: snap.destination,
|
|
776
|
+
amount,
|
|
777
|
+
asset: snap.assetCode && snap.assetCode !== "XLM" && snap.assetIssuer ? { code: snap.assetCode, issuer: snap.assetIssuer } : void 0,
|
|
778
|
+
memo: snap.memo ? {
|
|
779
|
+
type: snap.memoType ?? "MEMO_TEXT",
|
|
780
|
+
value: snap.memo
|
|
781
|
+
} : void 0,
|
|
782
|
+
network
|
|
783
|
+
});
|
|
784
|
+
const signedXdr = await signWithFreighter(xdr, network);
|
|
785
|
+
return submitTransaction(signedXdr, network);
|
|
786
|
+
}
|
|
787
|
+
|
|
664
788
|
// src/discovery.ts
|
|
665
789
|
function createDiscoveryFile(options) {
|
|
666
790
|
const { name, description, icon, rules } = options;
|
|
@@ -1204,7 +1328,9 @@ exports.SnapUnauthorizedError = SnapUnauthorizedError;
|
|
|
1204
1328
|
exports.StellarSnapError = StellarSnapError;
|
|
1205
1329
|
exports.addDomain = addDomain;
|
|
1206
1330
|
exports.buildPaymentTransaction = buildPaymentTransaction;
|
|
1331
|
+
exports.buildPaymentXdrFromPayload = buildPaymentXdrFromPayload;
|
|
1207
1332
|
exports.buildUrl = buildUrl;
|
|
1333
|
+
exports.closeSnapModal = closeSnapModal;
|
|
1208
1334
|
exports.connectFreighter = connectFreighter;
|
|
1209
1335
|
exports.createAsset = createAsset;
|
|
1210
1336
|
exports.createDiscoveryFile = createDiscoveryFile;
|
|
@@ -1216,12 +1342,14 @@ exports.createSnapObject = createSnapObject;
|
|
|
1216
1342
|
exports.createTransactionSnap = createTransactionSnap;
|
|
1217
1343
|
exports.deleteSnap = deleteSnap;
|
|
1218
1344
|
exports.errorResponse = errorResponse;
|
|
1345
|
+
exports.executeSnapPayment = executeSnapPayment;
|
|
1219
1346
|
exports.extractDomain = extractDomain;
|
|
1220
1347
|
exports.extractPath = extractPath;
|
|
1221
1348
|
exports.extractSnapId = extractSnapId;
|
|
1222
1349
|
exports.generateJsonLd = generateJsonLd;
|
|
1223
1350
|
exports.generateMetaTags = generateMetaTags;
|
|
1224
1351
|
exports.generateSnapId = generateSnapId;
|
|
1352
|
+
exports.getAccountSequence = getAccountSequence;
|
|
1225
1353
|
exports.getAccountUrl = getAccountUrl;
|
|
1226
1354
|
exports.getAssetUrl = getAssetUrl;
|
|
1227
1355
|
exports.getBlockedDomains = getBlockedDomains;
|
|
@@ -1242,6 +1370,7 @@ exports.isValidStellarAddress = isValidStellarAddress;
|
|
|
1242
1370
|
exports.listSnaps = listSnaps;
|
|
1243
1371
|
exports.matchUrlToRule = matchUrlToRule;
|
|
1244
1372
|
exports.metaTagsToHtml = metaTagsToHtml;
|
|
1373
|
+
exports.openSnapModal = openSnapModal;
|
|
1245
1374
|
exports.parseAddress = parseAddress;
|
|
1246
1375
|
exports.parseQueryParams = parseQueryParams;
|
|
1247
1376
|
exports.parseSnapUri = parseSnapUri;
|