@secondlayer/sdk 6.18.0 → 6.20.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.
@@ -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[]
@@ -232,6 +265,13 @@ declare class Contracts extends BaseClient {
232
265
  constructor(options?: Partial<SecondLayerOptions>);
233
266
  /** Find contracts conforming to `trait`. `trait` is required (server 400s without it). */
234
267
  list(params: ContractsListParams): Promise<ContractsEnvelope>;
268
+ /**
269
+ * Fetch a single contract from the registry by id (the prod-safe ABI source).
270
+ * Pass `{ includeAbi: true }` for the full ABI blob. Resolves null on 404.
271
+ */
272
+ get(contractId: string, opts?: {
273
+ includeAbi?: boolean
274
+ }): Promise<ContractSummary | null>;
235
275
  }
236
276
  /**
237
277
  * Typed client for the Foundation Datasets REST API (`/v1/datasets/*`).
@@ -377,6 +417,42 @@ declare class Datasets extends BaseClient {
377
417
  private paramsToQuery;
378
418
  private cursorDataset;
379
419
  }
420
+ import { RewardSet } from "@secondlayer/shared/node/consensus";
421
+ import { MerkleProofStep } from "@secondlayer/shared/node/nakamoto";
422
+ /**
423
+ * Trustless transaction-inclusion proof verification.
424
+ *
425
+ * Given a proof from `GET /v1/index/transactions/:txid/proof`, the consumer
426
+ * re-derives everything itself — it does NOT trust any value Secondlayer
427
+ * computed. Anchored level: (1) recompute the txid from the raw tx bytes, (2)
428
+ * fold it up the merkle path to the header's `tx_merkle_root`, (3) recompute the
429
+ * header's `block_hash` and `index_block_hash` from the raw header — "this tx is
430
+ * included in a header any node can corroborate". Consensus level (when the proof
431
+ * carries a `consensus` field, or a `rewardSet` is passed): additionally recover
432
+ * the header's signer signatures and confirm ≥70% of reward-set signer weight
433
+ * signed the block.
434
+ *
435
+ * Note: uses Node's crypto via `@secondlayer/shared` (same as the Streams
436
+ * signature verify); intended for Node/server verification.
437
+ */
438
+ interface TransactionProof {
439
+ txid: string;
440
+ index_block_hash: string;
441
+ block_height: number;
442
+ tx_index: number;
443
+ /** Raw consensus-serialized transaction bytes (hex). */
444
+ raw_tx: string;
445
+ /** Raw Nakamoto block-header bytes (hex) — parsed + re-hashed by the verifier. */
446
+ raw_header: string;
447
+ /** Authentication path from the tx leaf to `tx_merkle_root`. */
448
+ tx_merkle_path: MerkleProofStep[];
449
+ /** Present when consensus-level verification is available: the reward cycle and
450
+ * its signer set, against which the header's signer signatures are checked. */
451
+ consensus?: {
452
+ reward_cycle: number
453
+ reward_set: RewardSet
454
+ };
455
+ }
380
456
  type IndexTip = {
381
457
  block_height: number
382
458
  lag_seconds: number
@@ -877,6 +953,30 @@ type MempoolWalkParams = Omit<MempoolListParams, "limit"> & {
877
953
  batchSize?: number
878
954
  signal?: AbortSignal
879
955
  };
956
+ /**
957
+ * `index.ftTransfers` — callable shorthand for `.list()`, with `.list`/`.walk`
958
+ * still available: `await sl.index.ftTransfers({ contractId })`.
959
+ *
960
+ * The API accepts `contract_id`/`sender`/`recipient` equality filters only —
961
+ * no amount filtering and no asset-slug resolution on /v1/index/ft-transfers.
962
+ */
963
+ interface FtTransfersResource {
964
+ (params?: FtTransfersListParams): Promise<FtTransfersEnvelope>;
965
+ list(params?: FtTransfersListParams): Promise<FtTransfersEnvelope>;
966
+ walk(params?: FtTransfersWalkParams): AsyncIterable<FtTransfer>;
967
+ }
968
+ /** `index.nftTransfers` — callable shorthand for `.list()` (see {@link FtTransfersResource}). */
969
+ interface NftTransfersResource {
970
+ (params?: NftTransfersListParams): Promise<NftTransfersEnvelope>;
971
+ list(params?: NftTransfersListParams): Promise<NftTransfersEnvelope>;
972
+ walk(params?: NftTransfersWalkParams): AsyncIterable<NftTransfer>;
973
+ }
974
+ /** `index.events` — callable shorthand for `.list()`; `eventType` is required. */
975
+ interface IndexEventsResource {
976
+ (params: EventsListParams): Promise<EventsEnvelope>;
977
+ list(params: EventsListParams): Promise<EventsEnvelope>;
978
+ walk(params: EventsWalkParams): AsyncIterable<IndexEvent>;
979
+ }
880
980
  /** Per-event-type filter vocabulary in the {@link IndexDiscovery} doc. */
881
981
  type IndexEventTypeFilters = {
882
982
  columns?: string[]
@@ -901,19 +1001,13 @@ declare class Index extends BaseClient {
901
1001
  * learn what's queryable (and which types accept `trait`) instead of hardcoding.
902
1002
  */
903
1003
  discover(): Promise<IndexDiscovery>;
904
- readonly ftTransfers: {
905
- list: (params?: FtTransfersListParams) => Promise<FtTransfersEnvelope>
906
- walk: (params?: FtTransfersWalkParams) => AsyncIterable<FtTransfer>
907
- };
908
- readonly nftTransfers: {
909
- list: (params?: NftTransfersListParams) => Promise<NftTransfersEnvelope>
910
- walk: (params?: NftTransfersWalkParams) => AsyncIterable<NftTransfer>
911
- };
912
- /** Generic decoded events by `event_type` (the full /v1/index/events surface). */
913
- readonly events: {
914
- list: (params: EventsListParams) => Promise<EventsEnvelope>
915
- walk: (params: EventsWalkParams) => AsyncIterable<IndexEvent>
916
- };
1004
+ /** Callable: `index.ftTransfers(params)` ≡ `index.ftTransfers.list(params)`. */
1005
+ readonly ftTransfers: FtTransfersResource;
1006
+ /** Callable: `index.nftTransfers(params)` ≡ `index.nftTransfers.list(params)`. */
1007
+ readonly nftTransfers: NftTransfersResource;
1008
+ /** Generic decoded events by `event_type` (the full /v1/index/events surface).
1009
+ * Callable: `index.events(params)` ≡ `index.events.list(params)`. */
1010
+ readonly events: IndexEventsResource;
917
1011
  readonly contractCalls: {
918
1012
  list: (params?: ContractCallsListParams) => Promise<ContractCallsEnvelope>
919
1013
  walk: (params?: ContractCallsWalkParams) => AsyncIterable<IndexContractCall>
@@ -936,6 +1030,7 @@ declare class Index extends BaseClient {
936
1030
  list: (params?: TransactionsListParams) => Promise<TransactionsEnvelope>
937
1031
  walk: (params?: TransactionsWalkParams) => AsyncIterable<IndexTransaction>
938
1032
  get: (txId: string) => Promise<TransactionEnvelope | null>
1033
+ getProof: (txId: string) => Promise<TransactionProof | null>
939
1034
  };
940
1035
  /** Decoded PoX-4 stacking actions. Empty (with a `notes` hint) when the
941
1036
  * platform's PoX-4 decoder is disabled. */
@@ -965,6 +1060,11 @@ declare class Index extends BaseClient {
965
1060
  private walkBlocks;
966
1061
  private listTransactions;
967
1062
  private getTransaction;
1063
+ /** Fetch the inclusion proof for a tx (raw tx + Nakamoto header + merkle path)
1064
+ * to verify client-side with `verifyTransactionProof`. 404 → null. A 503
1065
+ * (`PROOF_TX_SET_INCOMPLETE` / `PROOF_NODE_UNAVAILABLE`) surfaces as an
1066
+ * ApiError — the proof can't be assembled on this deployment right now. */
1067
+ private getTransactionProof;
968
1068
  private walkTransactions;
969
1069
  private listStacking;
970
1070
  private walkStacking;
@@ -1289,6 +1389,36 @@ type StreamsEventsConsumeParams = {
1289
1389
  maxEmptyPolls?: number
1290
1390
  signal?: AbortSignal
1291
1391
  };
1392
+ /**
1393
+ * One yielded page from {@link StreamsClient.consume} — the
1394
+ * `GET /v1/streams/events` envelope verbatim, with `next_cursor` renamed to
1395
+ * `cursor` (the checkpoint to persist and resume from).
1396
+ */
1397
+ type StreamsBatch = {
1398
+ /** Canonical events of this page, in cursor order. */
1399
+ events: StreamsEvent[]
1400
+ /** Checkpoint after this page — pass back as `consume({ cursor })` to resume. */
1401
+ cursor: string | null
1402
+ tip: StreamsTip
1403
+ /** Chain reorgs reported alongside this page; empty when none. */
1404
+ reorgs: StreamsReorg[]
1405
+ };
1406
+ type StreamsConsumeParams = {
1407
+ /** Resume strictly after this cursor; omit to start from the oldest seekable page. */
1408
+ cursor?: string | null
1409
+ types?: readonly StreamsEventType[]
1410
+ notTypes?: readonly StreamsEventType[]
1411
+ contractId?: StreamsFilterValue
1412
+ sender?: StreamsFilterValue
1413
+ recipient?: StreamsFilterValue
1414
+ assetIdentifier?: string
1415
+ /** Events per page (the `limit` query param). Default 100. */
1416
+ batchSize?: number
1417
+ /** Poll interval while caught up at the tip, in ms. Default 2000. */
1418
+ intervalMs?: number
1419
+ /** Abort to end the iteration. */
1420
+ signal?: AbortSignal
1421
+ };
1292
1422
  type StreamsEventsConsumeResult = {
1293
1423
  cursor: string | null
1294
1424
  pages: number
@@ -1356,6 +1486,21 @@ type StreamsDumps = {
1356
1486
  download(file: StreamsDumpFile): Promise<Uint8Array>
1357
1487
  };
1358
1488
  type StreamsClient = {
1489
+ /**
1490
+ * Follow Streams as an async iterator of page batches.
1491
+ *
1492
+ * Yields one {@link StreamsBatch} per `GET /v1/streams/events` page — the
1493
+ * existing envelope (`events`, `next_cursor` → `cursor`, `tip`, `reorgs`)
1494
+ * with zero extra API calls. Batches are chosen over per-block groupings
1495
+ * because the envelope is page-keyed, so every yield is exactly one fetch.
1496
+ * Empty pages are skipped; at the tip the iterator re-polls every
1497
+ * `intervalMs` (default 2000) until aborted via `signal`.
1498
+ *
1499
+ * Reorgs are surfaced on the batch (`batch.reorgs`) but the cursor is not
1500
+ * rewound automatically — use `events.consume` with `onReorg` for managed
1501
+ * rollback semantics.
1502
+ */
1503
+ consume(params?: StreamsConsumeParams): AsyncIterableIterator<StreamsBatch>
1359
1504
  events: {
1360
1505
  list(params?: StreamsEventsListParams): Promise<StreamsEventsEnvelope>
1361
1506
  byTxId(txId: string): Promise<StreamsEventsListEnvelope>
@@ -281,6 +281,19 @@ class Subgraphs extends BaseClient {
281
281
  const qs = options?.force ? "?force=true" : "";
282
282
  return this.request("DELETE", `/api/subgraphs/${name}${qs}`);
283
283
  }
284
+ async publish(name) {
285
+ return this.request("POST", `/api/subgraphs/${name}/publish`);
286
+ }
287
+ async unpublish(name) {
288
+ return this.request("POST", `/api/subgraphs/${name}/unpublish`);
289
+ }
290
+ async rows(name, table, params = {}) {
291
+ const { cursor, ...rest } = params;
292
+ const qs = buildSubgraphQueryString(rest);
293
+ const sep = qs ? "&" : "?";
294
+ const cursorQs = cursor ? `${sep}cursor=${encodeURIComponent(cursor)}` : "";
295
+ return this.request("GET", `/v1/subgraphs/${name}/${table}${qs}${cursorQs}`);
296
+ }
284
297
  async operations(name) {
285
298
  return this.request("GET", `/api/subgraphs/${name}/operations`);
286
299
  }
@@ -417,6 +430,16 @@ class Contracts extends BaseClient {
417
430
  cursor: params.cursor
418
431
  })}`);
419
432
  }
433
+ async get(contractId, opts = {}) {
434
+ try {
435
+ const { contract } = await this.request("GET", `/v1/contracts/${encodeURIComponent(contractId)}${opts.includeAbi ? "?include=abi" : ""}`);
436
+ return contract;
437
+ } catch (err) {
438
+ if (err instanceof ApiError && err.status === 404)
439
+ return null;
440
+ throw err;
441
+ }
442
+ }
420
443
  }
421
444
 
422
445
  // src/datasets/client.ts
@@ -596,18 +619,18 @@ class Index extends BaseClient {
596
619
  discover() {
597
620
  return this.request("GET", "/v1/index");
598
621
  }
599
- ftTransfers = {
622
+ ftTransfers = Object.assign((params = {}) => this.listFtTransfers(params), {
600
623
  list: (params = {}) => this.listFtTransfers(params),
601
624
  walk: (params = {}) => this.walkFtTransfers(params)
602
- };
603
- nftTransfers = {
625
+ });
626
+ nftTransfers = Object.assign((params = {}) => this.listNftTransfers(params), {
604
627
  list: (params = {}) => this.listNftTransfers(params),
605
628
  walk: (params = {}) => this.walkNftTransfers(params)
606
- };
607
- events = {
629
+ });
630
+ events = Object.assign((params) => this.listEvents(params), {
608
631
  list: (params) => this.listEvents(params),
609
632
  walk: (params) => this.walkEvents(params)
610
- };
633
+ });
611
634
  contractCalls = {
612
635
  list: (params = {}) => this.listContractCalls(params),
613
636
  walk: (params = {}) => this.walkContractCalls(params)
@@ -624,7 +647,8 @@ class Index extends BaseClient {
624
647
  transactions = {
625
648
  list: (params = {}) => this.listTransactions(params),
626
649
  walk: (params = {}) => this.walkTransactions(params),
627
- get: (txId) => this.getTransaction(txId)
650
+ get: (txId) => this.getTransaction(txId),
651
+ getProof: (txId) => this.getTransactionProof(txId)
628
652
  };
629
653
  stacking = {
630
654
  list: (params = {}) => this.listStacking(params),
@@ -886,6 +910,15 @@ class Index extends BaseClient {
886
910
  throw err;
887
911
  }
888
912
  }
913
+ async getTransactionProof(txId) {
914
+ try {
915
+ return await this.request("GET", `/v1/index/transactions/${encodeURIComponent(txId)}/proof`);
916
+ } catch (err) {
917
+ if (err instanceof ApiError && err.status === 404)
918
+ return null;
919
+ throw err;
920
+ }
921
+ }
889
922
  async* walkTransactions(params = {}) {
890
923
  const batchSize = params.batchSize ?? 200;
891
924
  let cursor = params.cursor ?? params.fromCursor ?? null;
@@ -1162,6 +1195,38 @@ async function consumeStreamsEvents(opts) {
1162
1195
  }
1163
1196
  return { cursor, pages, emptyPolls };
1164
1197
  }
1198
+ async function* iterateStreamsBatches(opts) {
1199
+ const sleep = opts.sleep ?? defaultSleep;
1200
+ let cursor = opts.fromCursor ?? null;
1201
+ while (!opts.signal?.aborted) {
1202
+ const envelope = await opts.fetchEvents({
1203
+ cursor,
1204
+ limit: opts.batchSize,
1205
+ types: opts.types,
1206
+ notTypes: opts.notTypes,
1207
+ contractId: opts.contractId,
1208
+ sender: opts.sender,
1209
+ recipient: opts.recipient,
1210
+ assetIdentifier: opts.assetIdentifier
1211
+ });
1212
+ const checkpoint = envelope.next_cursor ?? cursor;
1213
+ if (envelope.events.length > 0 || envelope.reorgs.length > 0) {
1214
+ yield {
1215
+ events: envelope.events,
1216
+ cursor: checkpoint,
1217
+ tip: envelope.tip,
1218
+ reorgs: envelope.reorgs
1219
+ };
1220
+ }
1221
+ const advanced = checkpoint !== null && checkpoint !== cursor;
1222
+ cursor = checkpoint;
1223
+ if (!advanced && envelope.events.length === 0) {
1224
+ if (opts.signal?.aborted)
1225
+ return;
1226
+ await sleep(opts.intervalMs, opts.signal);
1227
+ }
1228
+ }
1229
+ }
1165
1230
  async function* streamStreamsEvents(opts) {
1166
1231
  const sleep = opts.sleep ?? defaultSleep;
1167
1232
  const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
@@ -1539,6 +1604,21 @@ function createStreamsClient(options) {
1539
1604
  })}`);
1540
1605
  }
1541
1606
  return {
1607
+ consume(params = {}) {
1608
+ return iterateStreamsBatches({
1609
+ fromCursor: params.cursor,
1610
+ batchSize: params.batchSize ?? 100,
1611
+ intervalMs: params.intervalMs ?? 2000,
1612
+ types: params.types,
1613
+ notTypes: params.notTypes,
1614
+ contractId: params.contractId,
1615
+ sender: params.sender,
1616
+ recipient: params.recipient,
1617
+ assetIdentifier: params.assetIdentifier,
1618
+ signal: params.signal,
1619
+ fetchEvents
1620
+ });
1621
+ },
1542
1622
  events: {
1543
1623
  list: listEvents,
1544
1624
  byTxId(txId) {
@@ -1795,5 +1875,5 @@ export {
1795
1875
  Subgraphs
1796
1876
  };
1797
1877
 
1798
- //# debugId=A5185B837644857464756E2164756E21
1878
+ //# debugId=DD9EE9C3CECE53B564756E2164756E21
1799
1879
  //# sourceMappingURL=index.js.map