@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 CHANGED
@@ -95,7 +95,29 @@ if (result.successful) {
95
95
  }
96
96
  ```
97
97
 
98
- ### 4. Create Shareable Snaps (Web App API)
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
- ### 5. Host Your Own Snap Endpoints
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;