@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.
package/dist/index.js CHANGED
@@ -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) {
@@ -2073,6 +2153,174 @@ function decodePrint(event) {
2073
2153
  import {
2074
2154
  STREAMS_EVENT_TYPES
2075
2155
  } from "@secondlayer/shared";
2156
+ // src/x402.ts
2157
+ import {
2158
+ X402_TOKENS,
2159
+ findX402TokenByAsset
2160
+ } from "@secondlayer/shared/x402";
2161
+ import {
2162
+ serializeTransactionHex,
2163
+ signTransactionWithAccount
2164
+ } from "@secondlayer/stacks/transactions";
2165
+ import { buildExactTransfer } from "@secondlayer/stacks/x402";
2166
+ var DEFAULT_PREFER_ASSETS = [
2167
+ "sBTC",
2168
+ "USDCx",
2169
+ "STX"
2170
+ ];
2171
+ var DEFAULT_NONCE_NODE_URL = "https://api.hiro.so";
2172
+
2173
+ class X402SpendGuardError extends Error {
2174
+ constructor(message) {
2175
+ super(message);
2176
+ this.name = "X402SpendGuardError";
2177
+ }
2178
+ }
2179
+ function b64encode(value) {
2180
+ return Buffer.from(JSON.stringify(value), "utf8").toString("base64");
2181
+ }
2182
+ function b64decodeJson(value) {
2183
+ try {
2184
+ return JSON.parse(Buffer.from(value, "base64").toString("utf8"));
2185
+ } catch {
2186
+ return null;
2187
+ }
2188
+ }
2189
+ async function readX402Challenge(res) {
2190
+ const header = res.headers.get("PAYMENT-REQUIRED");
2191
+ if (header) {
2192
+ const decoded = b64decodeJson(header);
2193
+ if (decoded)
2194
+ return decoded;
2195
+ }
2196
+ try {
2197
+ return await res.clone().json();
2198
+ } catch {
2199
+ return null;
2200
+ }
2201
+ }
2202
+ function readX402Receipt(res) {
2203
+ const header = res.headers.get("PAYMENT-RESPONSE");
2204
+ return header ? b64decodeJson(header) : null;
2205
+ }
2206
+ function selectOffer(challenge, opts = {}) {
2207
+ const prefer = opts.preferAssets ?? DEFAULT_PREFER_ASSETS;
2208
+ for (const symbol of prefer) {
2209
+ const token = X402_TOKENS[symbol];
2210
+ const accept = challenge.accepts.find((a) => a.asset === token.asset);
2211
+ if (!accept)
2212
+ continue;
2213
+ const cap = opts.maxAmountPerCall?.[symbol];
2214
+ if (cap !== undefined && BigInt(accept.amount) > cap)
2215
+ continue;
2216
+ return { accept, symbol };
2217
+ }
2218
+ throw new X402SpendGuardError("no x402 offer matched preferAssets within maxAmountPerCall");
2219
+ }
2220
+ async function resolveAccountNonce(address, nodeUrl = DEFAULT_NONCE_NODE_URL) {
2221
+ const res = await fetch(`${nodeUrl.replace(/\/$/, "")}/v2/accounts/${address}?proof=0`);
2222
+ if (!res.ok)
2223
+ throw new Error(`x402 nonce lookup failed: ${res.status}`);
2224
+ const json = await res.json();
2225
+ return json.nonce;
2226
+ }
2227
+ async function buildSignedX402Payment(opts) {
2228
+ const accept = opts.asset ? opts.challenge.accepts.find((a) => a.asset === opts.asset) : opts.challenge.accepts[0];
2229
+ if (!accept) {
2230
+ throw new Error(`No x402 offer${opts.asset ? ` for asset ${opts.asset}` : ""}`);
2231
+ }
2232
+ const token = findX402TokenByAsset(accept.asset);
2233
+ if (!token)
2234
+ throw new Error(`Unknown x402 asset: ${accept.asset}`);
2235
+ const asset = token.contractId && token.assetName ? {
2236
+ kind: "sip010",
2237
+ contractId: token.contractId,
2238
+ assetName: token.assetName
2239
+ } : { kind: "stx" };
2240
+ const tx = buildExactTransfer({
2241
+ asset,
2242
+ amount: BigInt(accept.amount),
2243
+ payTo: accept.payTo,
2244
+ payer: opts.account.address,
2245
+ payerPublicKey: opts.account.publicKey,
2246
+ accountNonce: opts.accountNonce,
2247
+ nonce: accept.extra.nonce,
2248
+ chain: opts.chain
2249
+ });
2250
+ const signed = await signTransactionWithAccount(tx, opts.account);
2251
+ const header = b64encode({
2252
+ x402Version: opts.challenge.x402Version ?? 2,
2253
+ scheme: "exact",
2254
+ network: accept.network,
2255
+ asset: accept.asset,
2256
+ payload: { transaction: serializeTransactionHex(signed) },
2257
+ extra: { nonce: accept.extra.nonce }
2258
+ });
2259
+ return { header, accept };
2260
+ }
2261
+ function withX402(baseFetch, opts) {
2262
+ return async (input, init) => {
2263
+ const run = (extra, signal2) => baseFetch(input, {
2264
+ ...init,
2265
+ headers: { ...init?.headers, ...extra },
2266
+ ...signal2 ? { signal: signal2 } : {}
2267
+ });
2268
+ const first = await run({});
2269
+ if (first.status !== 402)
2270
+ return first;
2271
+ const challenge = await readX402Challenge(first);
2272
+ if (!challenge)
2273
+ return first;
2274
+ const { accept } = selectOffer(challenge, opts);
2275
+ const accountNonce = opts.accountNonce ?? await resolveAccountNonce(opts.account.address, opts.nodeUrl);
2276
+ const { header } = await buildSignedX402Payment({
2277
+ challenge,
2278
+ account: opts.account,
2279
+ accountNonce,
2280
+ asset: accept.asset,
2281
+ chain: opts.chain
2282
+ });
2283
+ opts.onSettling?.({ asset: accept.asset, amount: accept.amount });
2284
+ const signal = opts.timeoutMs ? AbortSignal.timeout(opts.timeoutMs) : undefined;
2285
+ return run({ "PAYMENT-SIGNATURE": header }, signal);
2286
+ };
2287
+ }
2288
+ function createX402Client(opts) {
2289
+ const f = withX402(opts.fetch ?? fetch, opts);
2290
+ const base = opts.baseUrl.replace(/\/$/, "");
2291
+ async function request(method, path, o = {}) {
2292
+ const qs = o.query ? `?${new URLSearchParams(o.query).toString()}` : "";
2293
+ const init = { method };
2294
+ if (o.body !== undefined) {
2295
+ init.body = JSON.stringify(o.body);
2296
+ init.headers = { "content-type": "application/json" };
2297
+ }
2298
+ const response = await f(`${base}${path}${qs}`, init);
2299
+ const data = await response.json().catch(() => null);
2300
+ return { data, payment: readX402Receipt(response), response };
2301
+ }
2302
+ return {
2303
+ get: (path, o) => request("GET", path, o),
2304
+ post: (path, o) => request("POST", path, o)
2305
+ };
2306
+ }
2307
+ async function payAndRetry(doFetch, opts) {
2308
+ const first = await doFetch({});
2309
+ if (first.status !== 402)
2310
+ return first;
2311
+ const challenge = await readX402Challenge(first);
2312
+ if (!challenge)
2313
+ return first;
2314
+ const { accept } = selectOffer(challenge, opts);
2315
+ const { header } = await buildSignedX402Payment({
2316
+ challenge,
2317
+ account: opts.account,
2318
+ accountNonce: opts.accountNonce,
2319
+ asset: accept.asset,
2320
+ chain: opts.chain
2321
+ });
2322
+ return doFetch({ "PAYMENT-SIGNATURE": header });
2323
+ }
2076
2324
  // src/webhooks.ts
2077
2325
  import { verifySecondlayerSignatureValues } from "@secondlayer/shared/crypto/secondlayer-webhook";
2078
2326
  import {
@@ -2198,11 +2446,17 @@ function verifyTransactionProof(proof, opts) {
2198
2446
  };
2199
2447
  }
2200
2448
  export {
2449
+ withX402,
2201
2450
  verifyWebhookSignature,
2202
2451
  verifyTransactionProof,
2203
2452
  verifySecondlayerSignature,
2204
2453
  trigger,
2205
2454
  toJsonSafe,
2455
+ selectOffer,
2456
+ resolveAccountNonce,
2457
+ readX402Receipt,
2458
+ readX402Challenge,
2459
+ payAndRetry,
2206
2460
  isStxTransfer,
2207
2461
  isStxMint,
2208
2462
  isStxLock,
@@ -2228,7 +2482,10 @@ export {
2228
2482
  decodeFtMint,
2229
2483
  decodeFtBurn,
2230
2484
  decodeClarityValue,
2485
+ createX402Client,
2231
2486
  createStreamsClient,
2487
+ buildSignedX402Payment,
2488
+ X402SpendGuardError,
2232
2489
  VersionConflictError,
2233
2490
  ValidationError,
2234
2491
  Subscriptions,
@@ -2240,6 +2497,7 @@ export {
2240
2497
  Projects,
2241
2498
  Index,
2242
2499
  Datasets,
2500
+ DEFAULT_PREFER_ASSETS,
2243
2501
  Cursor,
2244
2502
  Contracts,
2245
2503
  CURSOR_SLUGS,
@@ -2249,5 +2507,5 @@ export {
2249
2507
  ApiError
2250
2508
  };
2251
2509
 
2252
- //# debugId=DBAA238399806ED364756E2164756E21
2510
+ //# debugId=EFE64A13154F57C864756E2164756E21
2253
2511
  //# sourceMappingURL=index.js.map