@secondlayer/sdk 6.19.0 → 6.21.0

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
@@ -328,8 +328,15 @@ const { data } = await sl.subgraphs.list();
328
328
  // Get
329
329
  const subgraph = await sl.subgraphs.get("my-subgraph");
330
330
 
331
- // Query table
332
- const rows = await sl.subgraphs.queryTable("my-subgraph", "transfers", {
331
+ // Open read (/v1) — keyless for public subgraphs; pass apiKey for your private ones
332
+ const { rows, next_cursor, tip } = await sl.subgraphs.rows("my-subgraph", "transfers", {
333
+ order: "desc",
334
+ limit: 50,
335
+ // cursor: next_cursor — pass back to resume
336
+ });
337
+
338
+ // Authed control-plane query (/api)
339
+ const page = await sl.subgraphs.queryTable("my-subgraph", "transfers", {
333
340
  sort: "block_height",
334
341
  order: "desc",
335
342
  limit: 50,
@@ -344,8 +351,12 @@ const spec = await sl.subgraphs.openapi("my-subgraph");
344
351
  const source = await sl.subgraphs.getSource("my-subgraph");
345
352
  const gaps = await sl.subgraphs.gaps("my-subgraph");
346
353
 
347
- // Deploy
348
- const result = await sl.subgraphs.deploy({ name, sources, schema, handlerCode });
354
+ // Deploy — managed deploys default visibility "public", BYO default "private"
355
+ const result = await sl.subgraphs.deploy({ name, sources, schema, handlerCode, visibility: "public" });
356
+
357
+ // Flip visibility — publish claims the global public name (409 PUBLIC_NAME_TAKEN if claimed)
358
+ await sl.subgraphs.publish("my-subgraph");
359
+ await sl.subgraphs.unpublish("my-subgraph");
349
360
  ```
350
361
 
351
362
  Stream rows live with the typed client — each table exposes `subscribe`
@@ -483,6 +494,52 @@ verifySecondlayerSignature(
483
494
  Prefer the per-subscription HMAC (Standard Webhooks) secret instead? Use
484
495
  `verifyWebhookSignature(rawBody, headers, secret)` — raw body first.
485
496
 
497
+ ## x402 pay-per-call (accountless)
498
+
499
+ Call the public `/v1/*` reads with **no API key, no account, no Stripe** — pay a
500
+ few hundredths of a cent per request from a Stacks wallet. Payment is **gasless**
501
+ (you sign; we sponsor the STX fee) and uses standard **x402 v2** on `stacks:1`.
502
+ Supported assets: **sBTC** (default), **USDCx**, **STX**.
503
+
504
+ > Keyed (`sk-sl_`) requests bypass x402 and bill through your plan — x402 is for
505
+ > accountless callers.
506
+
507
+ Drop-in `fetch` that pays on `402` automatically:
508
+
509
+ ```typescript
510
+ import { withX402, readX402Receipt } from "@secondlayer/sdk";
511
+ import { privateKeyToAccount } from "@secondlayer/stacks/accounts";
512
+
513
+ const x402fetch = withX402(fetch, {
514
+ account: privateKeyToAccount(process.env.AGENT_STACKS_KEY!), // funded with sBTC/USDCx
515
+ preferAssets: ["sBTC", "USDCx", "STX"], // optional (this is the default)
516
+ maxAmountPerCall: { sBTC: 2000n }, // optional spend guard (atomic units)
517
+ });
518
+
519
+ const res = await x402fetch(
520
+ "https://api.secondlayer.tools/v1/index/events?event_type=ft_transfer",
521
+ );
522
+ const data = await res.json();
523
+ readX402Receipt(res); // { success, txid, payer, network } | null
524
+ ```
525
+
526
+ Or a small client returning `{ data, payment }`:
527
+
528
+ ```typescript
529
+ import { createX402Client } from "@secondlayer/sdk";
530
+
531
+ const sl = createX402Client({ account, baseUrl: "https://api.secondlayer.tools" });
532
+ const { data, payment } = await sl.get("/v1/index/events", {
533
+ query: { event_type: "ft_transfer" },
534
+ });
535
+ ```
536
+
537
+ The SDK selects an offer by `preferAssets` (skipping any over `maxAmountPerCall`,
538
+ else throws `X402SpendGuardError`), auto-resolves your account nonce, signs
539
+ origin-only, and retries. A paid call settles on-chain before returning
540
+ (confirmed-tier today, ~seconds; near-instant optimistic serve for Index/Streams
541
+ is rolling out). Discover capabilities at `GET /x402/supported`.
542
+
486
543
  ## Error Handling
487
544
 
488
545
  ```typescript
package/dist/index.d.ts CHANGED
@@ -52,6 +52,16 @@ interface SubgraphOperationStatus {
52
52
  createdAt: string;
53
53
  updatedAt: string;
54
54
  }
55
+ /** /v1 cursor envelope for subgraph table reads. */
56
+ interface SubgraphRowsEnvelope<T = unknown> {
57
+ rows: T[];
58
+ next_cursor: string | null;
59
+ tip: {
60
+ block_height: number
61
+ subgraph_height: number
62
+ blocks_behind: number
63
+ };
64
+ }
55
65
  interface BundleSubgraphResponse {
56
66
  ok: true;
57
67
  name: string;
@@ -94,6 +104,29 @@ declare class Subgraphs extends BaseClient {
94
104
  }): Promise<{
95
105
  message: string
96
106
  }>;
107
+ /**
108
+ * Publish: claim the name in the global public namespace and open anon
109
+ * reads on /v1/subgraphs/:name. 409 PUBLIC_NAME_TAKEN if another account
110
+ * holds the public name.
111
+ */
112
+ publish(name: string): Promise<{
113
+ name: string
114
+ visibility: "public"
115
+ url: string
116
+ }>;
117
+ /** Make reads private again (owning account's bearer key required). */
118
+ unpublish(name: string): Promise<{
119
+ name: string
120
+ visibility: "private"
121
+ }>;
122
+ /**
123
+ * Open /v1 read: cursor-paginated rows. Anon works for public subgraphs;
124
+ * pass an apiKey on the client for private ones. Resume with the returned
125
+ * `next_cursor`.
126
+ */
127
+ rows<T = unknown>(name: string, table: string, params?: Omit<SubgraphQueryParams, "offset" | "sort"> & {
128
+ cursor?: string
129
+ }): Promise<SubgraphRowsEnvelope<T>>;
97
130
  /** Recent reindex/backfill operations for a subgraph, newest first. */
98
131
  operations(name: string): Promise<{
99
132
  operations: SubgraphOperationStatus[]
@@ -240,155 +273,6 @@ declare class Contracts extends BaseClient {
240
273
  includeAbi?: boolean
241
274
  }): Promise<ContractSummary | null>;
242
275
  }
243
- /**
244
- * Typed client for the Foundation Datasets REST API (`/v1/datasets/*`).
245
- *
246
- * Most datasets are cursor-paginated event lists with a uniform `list`/`walk`
247
- * surface; a few (bns names/namespaces/resolve, network-health) are
248
- * offset/single-object/summary and get bespoke methods. Query params are typed
249
- * per dataset; rows are `DatasetRow` (JSON) in v1 — per-dataset row interfaces
250
- * are a fast-follow.
251
- */
252
- /** A dataset row — flat JSON object. Per-dataset interfaces are a follow-up. */
253
- type DatasetRow = Record<string, unknown>;
254
- /** Filters shared by every cursor-paginated dataset. */
255
- interface CursorListParams {
256
- cursor?: string;
257
- limit?: number;
258
- fromBlock?: number;
259
- toBlock?: number;
260
- }
261
- interface CursorEnvelope {
262
- rows: DatasetRow[];
263
- next_cursor: string | null;
264
- tip?: {
265
- block_height: number
266
- };
267
- }
268
- type RangeFilters = CursorListParams;
269
- type StxTransfersParams = RangeFilters & {
270
- sender?: string
271
- recipient?: string
272
- };
273
- type SbtcEventsParams = RangeFilters & {
274
- topic?: string
275
- address?: string
276
- };
277
- type SbtcTokenEventsParams = RangeFilters & {
278
- eventType?: string
279
- sender?: string
280
- recipient?: string
281
- };
282
- type Pox4CallsParams = RangeFilters & {
283
- functionName?: string
284
- stacker?: string
285
- delegateTo?: string
286
- signerKey?: string
287
- rewardCycle?: number
288
- /** Any-role: matches caller OR stacker OR delegate_to. */
289
- address?: string
290
- };
291
- type BurnchainRewardsParams = RangeFilters & {
292
- /** Filter to one Bitcoin reward address. */
293
- recipient?: string
294
- };
295
- type BurnchainRewardSlotsParams = RangeFilters & {
296
- /** Filter to one reward-set Bitcoin address. */
297
- holder?: string
298
- };
299
- type BnsEventsParams = RangeFilters & {
300
- topic?: string
301
- namespace?: string
302
- name?: string
303
- owner?: string
304
- };
305
- type BnsNamespaceEventsParams = RangeFilters & {
306
- status?: string
307
- namespace?: string
308
- };
309
- type BnsMarketplaceEventsParams = RangeFilters & {
310
- action?: string
311
- bnsId?: string
312
- };
313
- type CursorDataset<P> = {
314
- list: (params?: P) => Promise<CursorEnvelope>
315
- walk: (params?: P & {
316
- batchSize?: number
317
- signal?: AbortSignal
318
- }) => AsyncIterable<DatasetRow>
319
- };
320
- /** Cursor-paginated dataset slugs → REST path + envelope row key. */
321
- declare const CURSOR_SLUGS: Record<string, {
322
- path: string
323
- rowKey: string
324
- }>;
325
- declare class Datasets extends BaseClient {
326
- private catalogPromise?;
327
- constructor(options?: Partial<SecondLayerOptions>);
328
- /** Dataset catalog + freshness (the discovery endpoint). */
329
- listDatasets(): Promise<unknown>;
330
- /**
331
- * Generic read by slug for ANY catalog dataset — cursor or bespoke. Resolves
332
- * the slug against the live `/v1/datasets` catalog (so datasets added
333
- * server-side work with no SDK change), issues the GET, and normalizes the
334
- * response into a uniform `{ rows, next_cursor, tip }` envelope. Single-object
335
- * datasets (bns/resolve, network-health/summary) come back as 0-or-1 rows.
336
- * Accepts both family (`sbtc-events`) and path (`sbtc/events`) slug forms.
337
- * Prefer this over {@link query} unless you specifically need cursor-only
338
- * semantics.
339
- */
340
- get(slug: string, params?: Record<string, unknown>): Promise<CursorEnvelope>;
341
- /**
342
- * Generic cursor query by slug — used by the CLI. Params are passed through as
343
- * REST query keys (snake_case), so callers can use the documented filter names
344
- * directly. Throws for non-cursor (bespoke) datasets — use {@link get} for
345
- * those (and for slugs added to the catalog after this SDK was built).
346
- */
347
- query(slug: string, params?: Record<string, unknown>): Promise<CursorEnvelope>;
348
- readonly stxTransfers: CursorDataset<StxTransfersParams>;
349
- readonly sbtcEvents: CursorDataset<SbtcEventsParams>;
350
- readonly sbtcTokenEvents: CursorDataset<SbtcTokenEventsParams>;
351
- readonly pox4Calls: CursorDataset<Pox4CallsParams>;
352
- readonly burnchainRewards: CursorDataset<BurnchainRewardsParams>;
353
- readonly burnchainRewardSlots: CursorDataset<BurnchainRewardSlotsParams>;
354
- readonly bnsEvents: CursorDataset<BnsEventsParams>;
355
- readonly bnsNamespaceEvents: CursorDataset<BnsNamespaceEventsParams>;
356
- readonly bnsMarketplaceEvents: CursorDataset<BnsMarketplaceEventsParams>;
357
- /** BNS names — offset-paginated. */
358
- bnsNames(params?: {
359
- namespace?: string
360
- owner?: string
361
- limit?: number
362
- offset?: number
363
- }): Promise<{
364
- names: DatasetRow[]
365
- }>;
366
- /** All BNS namespaces (no pagination). */
367
- bnsNamespaces(): Promise<{
368
- namespaces: DatasetRow[]
369
- }>;
370
- /** Resolve a fully-qualified BNS name → single record. */
371
- bnsResolve(fqn: string): Promise<{
372
- name: DatasetRow | null
373
- }>;
374
- /** Network health summary. */
375
- networkHealth(): Promise<{
376
- summary: DatasetRow
377
- }>;
378
- private requestPath;
379
- /** Resolve a slug → relative path + row key. Known cursor slugs take a
380
- * network-free fast path; anything else is matched against the live catalog
381
- * by family name or path tail. */
382
- private resolveDataset;
383
- /** Fetch + cache the catalog families. Caches the in-flight promise so
384
- * concurrent first-calls share one request; no TTL — agent sessions are
385
- * short-lived, and a new client picks up newly added datasets. */
386
- private loadCatalog;
387
- /** Map camelCase filter fields to snake_case query keys (dropping pagination
388
- * controls) and build the canonical query suffix. */
389
- private paramsToQuery;
390
- private cursorDataset;
391
- }
392
276
  import { RewardSet } from "@secondlayer/shared/node/consensus";
393
277
  import { MerkleProofStep } from "@secondlayer/shared/node/nakamoto";
394
278
  /**
@@ -968,6 +852,30 @@ type MempoolWalkParams = Omit<MempoolListParams, "limit"> & {
968
852
  batchSize?: number
969
853
  signal?: AbortSignal
970
854
  };
855
+ /**
856
+ * `index.ftTransfers` — callable shorthand for `.list()`, with `.list`/`.walk`
857
+ * still available: `await sl.index.ftTransfers({ contractId })`.
858
+ *
859
+ * The API accepts `contract_id`/`sender`/`recipient` equality filters only —
860
+ * no amount filtering and no asset-slug resolution on /v1/index/ft-transfers.
861
+ */
862
+ interface FtTransfersResource {
863
+ (params?: FtTransfersListParams): Promise<FtTransfersEnvelope>;
864
+ list(params?: FtTransfersListParams): Promise<FtTransfersEnvelope>;
865
+ walk(params?: FtTransfersWalkParams): AsyncIterable<FtTransfer>;
866
+ }
867
+ /** `index.nftTransfers` — callable shorthand for `.list()` (see {@link FtTransfersResource}). */
868
+ interface NftTransfersResource {
869
+ (params?: NftTransfersListParams): Promise<NftTransfersEnvelope>;
870
+ list(params?: NftTransfersListParams): Promise<NftTransfersEnvelope>;
871
+ walk(params?: NftTransfersWalkParams): AsyncIterable<NftTransfer>;
872
+ }
873
+ /** `index.events` — callable shorthand for `.list()`; `eventType` is required. */
874
+ interface IndexEventsResource {
875
+ (params: EventsListParams): Promise<EventsEnvelope>;
876
+ list(params: EventsListParams): Promise<EventsEnvelope>;
877
+ walk(params: EventsWalkParams): AsyncIterable<IndexEvent>;
878
+ }
971
879
  /** Per-event-type filter vocabulary in the {@link IndexDiscovery} doc. */
972
880
  type IndexEventTypeFilters = {
973
881
  columns?: string[]
@@ -992,19 +900,13 @@ declare class Index extends BaseClient {
992
900
  * learn what's queryable (and which types accept `trait`) instead of hardcoding.
993
901
  */
994
902
  discover(): Promise<IndexDiscovery>;
995
- readonly ftTransfers: {
996
- list: (params?: FtTransfersListParams) => Promise<FtTransfersEnvelope>
997
- walk: (params?: FtTransfersWalkParams) => AsyncIterable<FtTransfer>
998
- };
999
- readonly nftTransfers: {
1000
- list: (params?: NftTransfersListParams) => Promise<NftTransfersEnvelope>
1001
- walk: (params?: NftTransfersWalkParams) => AsyncIterable<NftTransfer>
1002
- };
1003
- /** Generic decoded events by `event_type` (the full /v1/index/events surface). */
1004
- readonly events: {
1005
- list: (params: EventsListParams) => Promise<EventsEnvelope>
1006
- walk: (params: EventsWalkParams) => AsyncIterable<IndexEvent>
1007
- };
903
+ /** Callable: `index.ftTransfers(params)` ≡ `index.ftTransfers.list(params)`. */
904
+ readonly ftTransfers: FtTransfersResource;
905
+ /** Callable: `index.nftTransfers(params)` ≡ `index.nftTransfers.list(params)`. */
906
+ readonly nftTransfers: NftTransfersResource;
907
+ /** Generic decoded events by `event_type` (the full /v1/index/events surface).
908
+ * Callable: `index.events(params)` ≡ `index.events.list(params)`. */
909
+ readonly events: IndexEventsResource;
1008
910
  readonly contractCalls: {
1009
911
  list: (params?: ContractCallsListParams) => Promise<ContractCallsEnvelope>
1010
912
  walk: (params?: ContractCallsWalkParams) => AsyncIterable<IndexContractCall>
@@ -1389,6 +1291,36 @@ type StreamsEventsConsumeParams = {
1389
1291
  maxEmptyPolls?: number
1390
1292
  signal?: AbortSignal
1391
1293
  };
1294
+ /**
1295
+ * One yielded page from {@link StreamsClient.consume} — the
1296
+ * `GET /v1/streams/events` envelope verbatim, with `next_cursor` renamed to
1297
+ * `cursor` (the checkpoint to persist and resume from).
1298
+ */
1299
+ type StreamsBatch = {
1300
+ /** Canonical events of this page, in cursor order. */
1301
+ events: StreamsEvent[]
1302
+ /** Checkpoint after this page — pass back as `consume({ cursor })` to resume. */
1303
+ cursor: string | null
1304
+ tip: StreamsTip
1305
+ /** Chain reorgs reported alongside this page; empty when none. */
1306
+ reorgs: StreamsReorg[]
1307
+ };
1308
+ type StreamsConsumeParams = {
1309
+ /** Resume strictly after this cursor; omit to start from the oldest seekable page. */
1310
+ cursor?: string | null
1311
+ types?: readonly StreamsEventType[]
1312
+ notTypes?: readonly StreamsEventType[]
1313
+ contractId?: StreamsFilterValue
1314
+ sender?: StreamsFilterValue
1315
+ recipient?: StreamsFilterValue
1316
+ assetIdentifier?: string
1317
+ /** Events per page (the `limit` query param). Default 100. */
1318
+ batchSize?: number
1319
+ /** Poll interval while caught up at the tip, in ms. Default 2000. */
1320
+ intervalMs?: number
1321
+ /** Abort to end the iteration. */
1322
+ signal?: AbortSignal
1323
+ };
1392
1324
  type StreamsEventsConsumeResult = {
1393
1325
  cursor: string | null
1394
1326
  pages: number
@@ -1457,6 +1389,21 @@ type StreamsDumps = {
1457
1389
  download(file: StreamsDumpFile): Promise<Uint8Array>
1458
1390
  };
1459
1391
  type StreamsClient = {
1392
+ /**
1393
+ * Follow Streams as an async iterator of page batches.
1394
+ *
1395
+ * Yields one {@link StreamsBatch} per `GET /v1/streams/events` page — the
1396
+ * existing envelope (`events`, `next_cursor` → `cursor`, `tip`, `reorgs`)
1397
+ * with zero extra API calls. Batches are chosen over per-block groupings
1398
+ * because the envelope is page-keyed, so every yield is exactly one fetch.
1399
+ * Empty pages are skipped; at the tip the iterator re-polls every
1400
+ * `intervalMs` (default 2000) until aborted via `signal`.
1401
+ *
1402
+ * Reorgs are surfaced on the batch (`batch.reorgs`) but the cursor is not
1403
+ * rewound automatically — use `events.consume` with `onReorg` for managed
1404
+ * rollback semantics.
1405
+ */
1406
+ consume(params?: StreamsConsumeParams): AsyncIterableIterator<StreamsBatch>
1460
1407
  events: {
1461
1408
  list(params?: StreamsEventsListParams): Promise<StreamsEventsEnvelope>
1462
1409
  byTxId(txId: string): Promise<StreamsEventsListEnvelope>
@@ -1601,7 +1548,6 @@ interface ContextSnapshot {
1601
1548
  declare class SecondLayer extends BaseClient {
1602
1549
  readonly streams: StreamsClient;
1603
1550
  readonly index: Index;
1604
- readonly datasets: Datasets;
1605
1551
  readonly contracts: Contracts;
1606
1552
  readonly subgraphs: Subgraphs;
1607
1553
  readonly subscriptions: Subscriptions;
@@ -1613,6 +1559,21 @@ declare class SecondLayer extends BaseClient {
1613
1559
  * from `secondlayer://context`, but available to any SDK/CLI consumer. Reads
1614
1560
  * run concurrently and degrade to `null` per field on failure.
1615
1561
  */
1562
+ /**
1563
+ * Up to 10 public reads in one round trip (`POST /v1/batch`). Each item
1564
+ * keeps its own auth/quota/x402 semantics; forwarded credentials (API key,
1565
+ * PAYMENT-BALANCE/SESSION) apply to every item.
1566
+ */
1567
+ batch(requests: Array<{
1568
+ path: string
1569
+ params?: Record<string, string | number | boolean>
1570
+ }>): Promise<{
1571
+ results: Array<{
1572
+ path: string | null
1573
+ status: number
1574
+ body: unknown
1575
+ }>
1576
+ }>;
1616
1577
  context(): Promise<ContextSnapshot>;
1617
1578
  }
1618
1579
  /**
@@ -1953,6 +1914,162 @@ declare const Cursor: {
1953
1914
  }
1954
1915
  };
1955
1916
  type DecodedEventRow = DecodedFtTransfer | DecodedNftTransfer | DecodedStxTransfer | DecodedStxMint | DecodedStxBurn | DecodedStxLock | DecodedFtMint | DecodedFtBurn | DecodedNftMint | DecodedNftBurn | DecodedPrint;
1917
+ import { X402TokenSymbol } from "@secondlayer/shared/x402";
1918
+ import { LocalAccount } from "@secondlayer/stacks/accounts";
1919
+ import { StacksChain } from "@secondlayer/stacks/chains";
1920
+ /**
1921
+ * Client for the x402 pay-per-request rail. Turns a 402 challenge into a signed
1922
+ * `PAYMENT-SIGNATURE` and retries — gasless (the agent signs origin-only; the
1923
+ * facilitator sponsors the STX fee) and accountless (no key/Stripe/session).
1924
+ *
1925
+ * Three layers:
1926
+ * - `withX402(fetch, opts)` — drop-in fetch that auto-pays on 402.
1927
+ * - `createX402Client(opts)` — `.get/.post` returning `{ data, payment }`.
1928
+ * - `buildSignedX402Payment` / `readX402Challenge` — primitives for custom transports.
1929
+ */
1930
+ type X402Accept = {
1931
+ scheme: "exact"
1932
+ network: string
1933
+ asset: string
1934
+ /** Atomic units. */
1935
+ amount: string
1936
+ payTo: string
1937
+ maxTimeoutSeconds: number
1938
+ extra: {
1939
+ nonce: string
1940
+ }
1941
+ };
1942
+ type X402Challenge = {
1943
+ x402Version: number
1944
+ accepts: X402Accept[]
1945
+ error?: string
1946
+ };
1947
+ /** Decoded `PAYMENT-RESPONSE` settlement receipt. */
1948
+ type X402Receipt = {
1949
+ success: boolean
1950
+ /** Settlement tier: `optimistic` (served on broadcast-accept, reconciled
1951
+ * async) or `confirmed` (canonical). Absent on older deployments. */
1952
+ state?: "optimistic" | "confirmed"
1953
+ txid: string
1954
+ payer: string
1955
+ network: string
1956
+ };
1957
+ /** Bitcoin-native first — sBTC is the compelling micropay asset; USDCx the
1958
+ * dollar peg; STX the fallback. Override via `preferAssets`. */
1959
+ declare const DEFAULT_PREFER_ASSETS: X402TokenSymbol[];
1960
+ /** Thrown when no offered asset is within the caller's spend guard / preferences. */
1961
+ declare class X402SpendGuardError extends Error {
1962
+ constructor(message: string);
1963
+ }
1964
+ /** Read the x402 challenge from a 402 response — prefer the wire header, fall
1965
+ * back to the JSON body. */
1966
+ declare function readX402Challenge(res: Response): Promise<X402Challenge | null>;
1967
+ /** Read the settlement receipt from a paid 200 response. */
1968
+ declare function readX402Receipt(res: Response): X402Receipt | null;
1969
+ type SelectOfferOptions = {
1970
+ preferAssets?: X402TokenSymbol[]
1971
+ maxAmountPerCall?: Partial<Record<X402TokenSymbol, bigint>>
1972
+ };
1973
+ /** Choose an `accepts[]` entry by preference order, skipping any that exceed the
1974
+ * per-asset spend cap. Throws {@link X402SpendGuardError} if none qualify. */
1975
+ declare function selectOffer(challenge: X402Challenge, opts?: SelectOfferOptions): {
1976
+ accept: X402Accept
1977
+ symbol: X402TokenSymbol
1978
+ };
1979
+ /** Fetch the payer account's next nonce from a Stacks node (`/v2/accounts`). */
1980
+ declare function resolveAccountNonce(address: string, nodeUrl?: string): Promise<number>;
1981
+ type BuildSignedX402PaymentOptions = {
1982
+ challenge: X402Challenge
1983
+ account: LocalAccount
1984
+ /** The payer account's next nonce. */
1985
+ accountNonce: bigint | number | string
1986
+ /** Preferred asset string (e.g. an sBTC/USDCx id). Defaults to the first offer. */
1987
+ asset?: string
1988
+ chain?: StacksChain
1989
+ };
1990
+ /** Build a signed, base64 `PAYMENT-SIGNATURE` header for one `accepts[]` entry. */
1991
+ declare function buildSignedX402Payment(opts: BuildSignedX402PaymentOptions): Promise<{
1992
+ header: string
1993
+ accept: X402Accept
1994
+ }>;
1995
+ type WithX402Options = SelectOfferOptions & {
1996
+ account: LocalAccount
1997
+ /** Prepaid-credit token (PAYMENT-BALANCE) from a prior deposit — calls
1998
+ * debit the tab server-side instead of settling on-chain per call. */
1999
+ balanceToken?: string
2000
+ /** Autonomous treasury policy: when the tab's remaining balance (read from
2001
+ * X-BALANCE-REMAINING-USD) drops below `whenBelow`, deposit `usd` more in
2002
+ * the background (one on-chain payment) and adopt the fresh token. */
2003
+ topUp?: {
2004
+ usd: number
2005
+ whenBelow: number
2006
+ }
2007
+ /** Override the payer nonce; auto-resolved from `nodeUrl` when omitted. */
2008
+ accountNonce?: bigint | number | string
2009
+ /** Node for auto-nonce lookup. Defaults to {@link DEFAULT_NONCE_NODE_URL}. */
2010
+ nodeUrl?: string
2011
+ chain?: StacksChain
2012
+ /** Fired just before the paid retry (the call then blocks on confirmed-tier
2013
+ * settle, or returns near-instantly on an optimistic surface). */
2014
+ onSettling?: (info: {
2015
+ asset: string
2016
+ amount: string
2017
+ }) => void
2018
+ /** Abort the paid retry after this long. */
2019
+ timeoutMs?: number
2020
+ };
2021
+ type X402Fetch = (input: string | URL, init?: RequestInit) => Promise<Response>;
2022
+ /**
2023
+ * Wrap a `fetch` so requests transparently pay on 402: select an offer (by
2024
+ * `preferAssets` + `maxAmountPerCall`), resolve the nonce, sign origin-only, and
2025
+ * retry once with `PAYMENT-SIGNATURE`. Returns the final `Response` (read the
2026
+ * receipt with {@link readX402Receipt}).
2027
+ *
2028
+ * @example
2029
+ * const x402fetch = withX402(fetch, { account });
2030
+ * const res = await x402fetch("https://api.secondlayer.tools/v1/index/events?event_type=ft_transfer");
2031
+ */
2032
+ declare function withX402(baseFetch: typeof fetch, opts: WithX402Options): X402Fetch;
2033
+ type X402ClientOptions = WithX402Options & {
2034
+ baseUrl: string
2035
+ /** Override the underlying fetch (tests). */
2036
+ fetch?: typeof fetch
2037
+ };
2038
+ type X402Result<T = unknown> = {
2039
+ data: T
2040
+ /** Settlement receipt, or null if the response carried none. */
2041
+ payment: X402Receipt | null
2042
+ response: Response
2043
+ };
2044
+ type X402Client = {
2045
+ get<T = unknown>(path: string, o?: {
2046
+ query?: Record<string, string>
2047
+ }): Promise<X402Result<T>>
2048
+ post<T = unknown>(path: string, o?: {
2049
+ body?: unknown
2050
+ }): Promise<X402Result<T>>
2051
+ };
2052
+ /**
2053
+ * A small client over {@link withX402}: `.get/.post` against `baseUrl`, returning
2054
+ * parsed JSON plus the settlement receipt.
2055
+ *
2056
+ * @example
2057
+ * const sl = createX402Client({ account, baseUrl: "https://api.secondlayer.tools" });
2058
+ * const { data, payment } = await sl.get("/v1/index/events", { query: { event_type: "ft_transfer" } });
2059
+ */
2060
+ declare function createX402Client(opts: X402ClientOptions): X402Client;
2061
+ /** Caller-supplied fetch that re-runs the request with the given extra headers. */
2062
+ type X402FetchFn = (extraHeaders: Record<string, string>) => Promise<Response>;
2063
+ type PayAndRetryOptions = Omit<WithX402Options, never> & {
2064
+ /** Required here (use `withX402` for auto-nonce). */
2065
+ accountNonce: bigint | number | string
2066
+ };
2067
+ /**
2068
+ * Low-level: run a request via a caller-controlled fetch; if it 402s, pay and
2069
+ * retry once. Prefer {@link withX402} for the common case (it auto-resolves the
2070
+ * nonce + selects the asset). Kept for custom transports.
2071
+ */
2072
+ declare function payAndRetry(doFetch: X402FetchFn, opts: PayAndRetryOptions): Promise<Response>;
1956
2073
  import { SubgraphAgentSchema as SubgraphAgentSchema3, SubgraphSpecFormat as SubgraphSpecFormat2, SubgraphSpecOptions as SubgraphSpecOptions3 } from "@secondlayer/shared/subgraphs/spec";
1957
2074
  import { ByoBreakingChangeDetails } from "@secondlayer/shared/errors";
1958
2075
  /**
@@ -2125,4 +2242,4 @@ declare function toJsonSafe(value: unknown): unknown;
2125
2242
  /** Decode a hex-encoded Clarity value to JSON-safe JS (uints as strings,
2126
2243
  * buffers as `0x…` hex, tuples as objects). Returns the input hex on failure. */
2127
2244
  declare function decodeClarityValue(hex: string): unknown;
2128
- export { verifyWebhookSignature, verifyTransactionProof, verifySecondlayerSignature, trigger, toJsonSafe, isStxTransfer, isStxMint, isStxLock, isStxBurn, isPrint, isNftTransfer, isNftMint, isNftBurn, isFtTransfer, isFtMint, isFtBurn, getSubgraph, fetchRewardSet, decodeStxTransfer, decodeStxMint, decodeStxLock, decodeStxBurn, decodePrint, decodeNftTransfer, decodeNftMint, decodeNftBurn, decodeFtTransfer, decodeFtMint, decodeFtBurn, decodeClarityValue, createStreamsClient, VersionConflictError, ValidationError, UpdateSubscriptionRequest2 as UpdateSubscriptionRequest, UpdateProjectParams, TransactionsWalkParams, TransactionsListParams, TransactionsEnvelope, TransactionProofVerifyResult, TransactionProof, TransactionEnvelope, Subscriptions, SubscriptionSummary2 as SubscriptionSummary, SubscriptionStatus, SubscriptionRuntime, SubscriptionKind, SubscriptionFormat, SubscriptionDetail2 as SubscriptionDetail, Subgraphs, SubgraphSpecOptions3 as SubgraphSpecOptions, SubgraphSpecFormat2 as SubgraphSpecFormat, SubgraphOperationStatus, SubgraphAgentSchema3 as SubgraphAgentSchema, StreamsUsage, StreamsTip, StreamsSignatureError, StreamsServerError, StreamsReorgsListParams, StreamsReorgsListEnvelope, StreamsReorgContext, StreamsReorg, StreamsEventsSubscribeParams, StreamsEventsStreamParams, StreamsEventsListParams, StreamsEventsListEnvelope, StreamsEventsEnvelope, StreamsEventsConsumeResult, StreamsEventsConsumeParams, StreamsEventType, StreamsEventPayload, StreamsEvent, StreamsDumpsManifest, StreamsDumps, StreamsDumpFile, StreamsClient, StreamsCanonicalBlock, StreamsBatchContext, StackingWalkParams, StackingListParams, StackingEnvelope, SecondLayerOptions, SecondLayer, ScopedKeyProduct, RotateSecretResponse2 as RotateSecretResponse, RewardSet2 as RewardSet, ReplayResult2 as ReplayResult, RateLimitError, Projects, ProjectTeamMember, ProjectTeam, ProjectInvitation, Project, Pox4CallsParams, NftTransfersWalkParams, NftTransfersListParams, NftTransfersEnvelope, NftTransferPayload, NftTransferEvent, NftTransfer, MempoolWalkParams, MempoolTransactionEnvelope, MempoolListParams, MempoolEnvelope, IndexUsage, IndexTransaction, IndexTip, IndexStackingAction, IndexReorg, IndexPostCondition, IndexMempoolTransaction, IndexEventTypeFilters, IndexEventType, IndexEvent, IndexDiscovery, IndexContractCall, IndexCanonicalBlock, IndexBlock, Index, FtTransfersWalkParams, FtTransfersListParams, FtTransfersEnvelope, FtTransferPayload, FtTransferEvent, FtTransfer, FetchLike2 as FetchLike, EventsWalkParams, EventsListParams, EventsEnvelope, DeliveryRow2 as DeliveryRow, DecodedStxTransferPayload, DecodedStxTransfer, DecodedStxMintPayload, DecodedStxMint, DecodedStxLockPayload, DecodedStxLock, DecodedStxBurnPayload, DecodedStxBurn, DecodedPrintValue, DecodedPrintPayload, DecodedPrint, DecodedNftTransferPayload, DecodedNftTransfer, DecodedNftMintPayload, DecodedNftMint, DecodedNftBurnPayload, DecodedNftBurn, DecodedFtTransferPayload, DecodedFtTransfer, DecodedFtMintPayload, DecodedFtMint, DecodedFtBurnPayload, DecodedFtBurn, DecodedEventRow, DecodedEventColumns, DeadRow2 as DeadRow, Datasets, DatasetRow, CursorListParams, CursorEnvelope, Cursor, CreateSubscriptionResponse2 as CreateSubscriptionResponse, CreateSubscriptionRequest2 as CreateSubscriptionRequest, CreateProjectParams, CreateApiKeyResponse, CreateApiKeyParams, ContractsListParams, ContractsEnvelope, Contracts, ContractSummary, ContractConformance, ContractCallsWalkParams, ContractCallsListParams, ContractCallsEnvelope, ContextSnapshot, ContextProject, ContextApiKey, ContextAccount, ChainTriggerType, ChainTrigger, CanonicalWalkParams, CanonicalListParams, CanonicalEnvelope, CURSOR_SLUGS, ByoBreakingChangeError, ByoBreakingChangeDetails, BlocksWalkParams, BlocksListParams, BlocksEnvelope, BlockEnvelope, AuthError, ApiKeys, ApiKeySummary, ApiError, ActiveSubgraphOperation };
2245
+ export { withX402, verifyWebhookSignature, verifyTransactionProof, verifySecondlayerSignature, trigger, toJsonSafe, selectOffer, resolveAccountNonce, readX402Receipt, readX402Challenge, payAndRetry, isStxTransfer, isStxMint, isStxLock, isStxBurn, isPrint, isNftTransfer, isNftMint, isNftBurn, isFtTransfer, isFtMint, isFtBurn, getSubgraph, fetchRewardSet, decodeStxTransfer, decodeStxMint, decodeStxLock, decodeStxBurn, decodePrint, decodeNftTransfer, decodeNftMint, decodeNftBurn, decodeFtTransfer, decodeFtMint, decodeFtBurn, decodeClarityValue, createX402Client, createStreamsClient, buildSignedX402Payment, X402SpendGuardError, X402Result, X402Receipt, X402Fetch, X402ClientOptions, X402Client, X402Challenge, X402Accept, WithX402Options, VersionConflictError, ValidationError, UpdateSubscriptionRequest2 as UpdateSubscriptionRequest, UpdateProjectParams, TransactionsWalkParams, TransactionsListParams, TransactionsEnvelope, TransactionProofVerifyResult, TransactionProof, TransactionEnvelope, Subscriptions, SubscriptionSummary2 as SubscriptionSummary, SubscriptionStatus, SubscriptionRuntime, SubscriptionKind, SubscriptionFormat, SubscriptionDetail2 as SubscriptionDetail, Subgraphs, SubgraphSpecOptions3 as SubgraphSpecOptions, SubgraphSpecFormat2 as SubgraphSpecFormat, SubgraphOperationStatus, SubgraphAgentSchema3 as SubgraphAgentSchema, StreamsUsage, StreamsTip, StreamsSignatureError, StreamsServerError, StreamsReorgsListParams, StreamsReorgsListEnvelope, StreamsReorgContext, StreamsReorg, StreamsEventsSubscribeParams, StreamsEventsStreamParams, StreamsEventsListParams, StreamsEventsListEnvelope, StreamsEventsEnvelope, StreamsEventsConsumeResult, StreamsEventsConsumeParams, StreamsEventType, StreamsEventPayload, StreamsEvent, StreamsDumpsManifest, StreamsDumps, StreamsDumpFile, StreamsConsumeParams, StreamsClient, StreamsCanonicalBlock, StreamsBatchContext, StreamsBatch, StackingWalkParams, StackingListParams, StackingEnvelope, SelectOfferOptions, SecondLayerOptions, SecondLayer, ScopedKeyProduct, RotateSecretResponse2 as RotateSecretResponse, RewardSet2 as RewardSet, ReplayResult2 as ReplayResult, RateLimitError, Projects, ProjectTeamMember, ProjectTeam, ProjectInvitation, Project, PayAndRetryOptions, NftTransfersWalkParams, NftTransfersResource, NftTransfersListParams, NftTransfersEnvelope, NftTransferPayload, NftTransferEvent, NftTransfer, MempoolWalkParams, MempoolTransactionEnvelope, MempoolListParams, MempoolEnvelope, IndexUsage, IndexTransaction, IndexTip, IndexStackingAction, IndexReorg, IndexPostCondition, IndexMempoolTransaction, IndexEventsResource, IndexEventTypeFilters, IndexEventType, IndexEvent, IndexDiscovery, IndexContractCall, IndexCanonicalBlock, IndexBlock, Index, FtTransfersWalkParams, FtTransfersResource, FtTransfersListParams, FtTransfersEnvelope, FtTransferPayload, FtTransferEvent, FtTransfer, FetchLike2 as FetchLike, EventsWalkParams, EventsListParams, EventsEnvelope, DeliveryRow2 as DeliveryRow, DecodedStxTransferPayload, DecodedStxTransfer, DecodedStxMintPayload, DecodedStxMint, DecodedStxLockPayload, DecodedStxLock, DecodedStxBurnPayload, DecodedStxBurn, DecodedPrintValue, DecodedPrintPayload, DecodedPrint, DecodedNftTransferPayload, DecodedNftTransfer, DecodedNftMintPayload, DecodedNftMint, DecodedNftBurnPayload, DecodedNftBurn, DecodedFtTransferPayload, DecodedFtTransfer, DecodedFtMintPayload, DecodedFtMint, DecodedFtBurnPayload, DecodedFtBurn, DecodedEventRow, DecodedEventColumns, DeadRow2 as DeadRow, DEFAULT_PREFER_ASSETS, Cursor, CreateSubscriptionResponse2 as CreateSubscriptionResponse, CreateSubscriptionRequest2 as CreateSubscriptionRequest, CreateProjectParams, CreateApiKeyResponse, CreateApiKeyParams, ContractsListParams, ContractsEnvelope, Contracts, ContractSummary, ContractConformance, ContractCallsWalkParams, ContractCallsListParams, ContractCallsEnvelope, ContextSnapshot, ContextProject, ContextApiKey, ContextAccount, ChainTriggerType, ChainTrigger, CanonicalWalkParams, CanonicalListParams, CanonicalEnvelope, ByoBreakingChangeError, ByoBreakingChangeDetails, BuildSignedX402PaymentOptions, BlocksWalkParams, BlocksListParams, BlocksEnvelope, BlockEnvelope, AuthError, ApiKeys, ApiKeySummary, ApiError, ActiveSubgraphOperation };