@secondlayer/sdk 6.36.0 → 6.37.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.d.ts CHANGED
@@ -641,6 +641,18 @@ type StreamsEventsConsumeParams = {
641
641
  * stale rows from an orphaned fork are left in place).
642
642
  */
643
643
  onReorg?: (reorg: StreamsReorg, ctx: StreamsReorgContext) => Promise<void> | void
644
+ /** Page-fetch retries after the first failure (429/5xx/network only —
645
+ * 4xx and handler throws always propagate). Default 3; `0` disables. */
646
+ retryCount?: number
647
+ /** Base retry delay in ms; the n-th retry waits `retryDelay * n`. A server
648
+ * `Retry-After` overrides it. Default 1000. */
649
+ retryDelay?: number
650
+ /** Void observer, called before each retry sleep (metrics/logging). */
651
+ onError?: (err: unknown, ctx: {
652
+ attempt: number
653
+ retriesLeft: number
654
+ delayMs: number
655
+ }) => void
644
656
  emptyBackoffMs?: number
645
657
  maxPages?: number
646
658
  maxEmptyPolls?: number
@@ -829,6 +841,23 @@ type StreamsUsage = {
829
841
  }
830
842
  };
831
843
  type Sleep = (ms: number, signal?: AbortSignal) => Promise<void>;
844
+ /** Options shared by both consume loops' page-fetch retry. Vocabulary matches
845
+ * `@secondlayer/stacks` transports (`retryCount`/`retryDelay`) — one retry
846
+ * language across the family, not a third. */
847
+ type PageRetryOptions = {
848
+ /** Retries after the first failure. Default 3; `0` disables. */
849
+ retryCount?: number
850
+ /** Base delay in ms; the n-th retry waits `retryDelay * n` (matches the
851
+ * stacks transport). A server `Retry-After` overrides it. Default 1000. */
852
+ retryDelay?: number
853
+ /** Void observer, called before each retry sleep (metrics/logging). The
854
+ * retry policy owns the decision; this cannot change it. */
855
+ onError?: (err: unknown, ctx: {
856
+ attempt: number
857
+ retriesLeft: number
858
+ delayMs: number
859
+ }) => void
860
+ };
832
861
  /** Minimum shape a consumed Index row must expose. */
833
862
  type IndexFeedItem = {
834
863
  cursor: string
@@ -878,6 +907,15 @@ type IndexConsumeOptions<
878
907
  maxPages?: number
879
908
  maxEmptyPolls?: number
880
909
  signal?: AbortSignal
910
+ /** Page-fetch retries after the first failure (429/5xx/network only —
911
+ * 4xx and handler throws always propagate). Default 3; `0` disables. */
912
+ retryCount?: number
913
+ /** Base retry delay in ms; the n-th retry waits `retryDelay * n`. A server
914
+ * `Retry-After` overrides it. Default 1000. */
915
+ retryDelay?: number
916
+ /** Void observer, called before each retry sleep. Cannot change the retry
917
+ * decision — the policy owns it. */
918
+ onError?: PageRetryOptions["onError"]
881
919
  };
882
920
  /**
883
921
  * Checkpointed pull loop over a cursor-paginated Index feed — the Index port
@@ -2217,27 +2255,141 @@ type CreateStreamsClientOptions = {
2217
2255
  verifyDumpsManifest?: boolean
2218
2256
  };
2219
2257
  declare function createStreamsClient(options: CreateStreamsClientOptions): StreamsClient;
2220
- declare class AuthError extends Error {
2221
- readonly status = 401;
2258
+ import { ByoBreakingChangeDetails } from "@secondlayer/shared/errors";
2259
+ /** Options accepted by every error in the family. */
2260
+ interface SecondLayerErrorOptions {
2261
+ cause?: Error;
2262
+ details?: string;
2263
+ /** Stable machine-readable code (e.g. `UPGRADE_REQUIRED`, `BYO_BREAKING_CHANGE`). */
2264
+ code?: string;
2265
+ /** Docs page that explains this failure and its fix. */
2266
+ docsUrl?: string;
2267
+ /** Extra context lines appended to the message (DDL to run, next steps). */
2268
+ metaMessages?: string[];
2269
+ /** Whether retrying the SAME request can succeed (429/5xx/network). */
2270
+ retryable?: boolean;
2271
+ /** Parsed `Retry-After`, in seconds — set on rate limits that carry it. */
2272
+ retryAfterSeconds?: number;
2273
+ }
2274
+ /**
2275
+ * Root of the SDK error family. Implements the same protocol as `BaseError`
2276
+ * in `@secondlayer/stacks` (`shortMessage`, `cause`, `toJSON`) so a failed
2277
+ * chain read and a failed platform read serialize and introspect identically.
2278
+ * It intentionally does NOT extend that class: `BaseError.details` is a
2279
+ * `string`, while {@link ByoBreakingChangeError.details} is the documented
2280
+ * structured migration plan — and cross-package `instanceof` is unreliable
2281
+ * under per-package bundling anyway (match on `code`/`name` across packages).
2282
+ *
2283
+ * `retryable` is the signal the consume loops act on: 429/5xx/network are
2284
+ * retryable, 4xx and body-serialization failures are not.
2285
+ */
2286
+ declare class SecondLayerError extends Error {
2287
+ name: string;
2288
+ /** The one-line failure, without the appended context blocks. */
2289
+ shortMessage: string;
2290
+ code?: string;
2291
+ docsUrl?: string;
2292
+ metaMessages?: string[];
2293
+ retryable: boolean;
2294
+ retryAfterSeconds?: number;
2295
+ constructor(shortMessage: string, options?: SecondLayerErrorOptions);
2296
+ /**
2297
+ * Walk the cause chain. With a predicate, returns the first error matching
2298
+ * it (or `null`); without one, returns the deepest cause. Mirrors viem's
2299
+ * `error.walk()` so cross-library error handling reads the same.
2300
+ */
2301
+ walk(fn?: (err: unknown) => boolean): unknown;
2302
+ toJSON(): {
2303
+ name: string
2304
+ message: string
2305
+ shortMessage: string
2306
+ cause: string | undefined
2307
+ code: string | undefined
2308
+ docsUrl: string | undefined
2309
+ retryable: boolean
2310
+ retryAfterSeconds: number | undefined
2311
+ };
2312
+ }
2313
+ /**
2314
+ * Error thrown by {@link SecondLayer} when an API request fails.
2315
+ * Includes the HTTP status code for programmatic error handling.
2316
+ *
2317
+ * @example
2318
+ * ```ts
2319
+ * try {
2320
+ * await client.subgraphs.get("my-subgraph");
2321
+ * } catch (err) {
2322
+ * if (err instanceof ApiError && err.status === 404) {
2323
+ * console.log("Subgraph not found");
2324
+ * }
2325
+ * }
2326
+ * ```
2327
+ */
2328
+ declare class ApiError extends SecondLayerError {
2329
+ /** HTTP status code (0 for network errors). */
2330
+ status: number;
2331
+ /** Raw response body (parsed JSON if possible) — preserved for callers that need error details. */
2332
+ body?: unknown;
2333
+ constructor(status: number, message: string, body?: unknown, code?: string, options?: SecondLayerErrorOptions);
2334
+ }
2335
+ /** Thrown on a 401 — by both the platform clients and Streams. */
2336
+ declare class AuthError extends ApiError {
2337
+ readonly status: 401;
2222
2338
  constructor(message?: string);
2223
2339
  }
2224
- declare class RateLimitError extends Error {
2340
+ /** Thrown on a 429 — by both the platform clients and Streams. `retryable`,
2341
+ * with `retryAfterSeconds` parsed from the `Retry-After` header when sent. */
2342
+ declare class RateLimitError extends ApiError {
2343
+ /** Raw `Retry-After` header value (seconds or HTTP-date). */
2225
2344
  readonly retryAfter?: string;
2226
- readonly status = 429;
2345
+ readonly status: 429;
2227
2346
  constructor(message?: string, retryAfter?: string);
2228
2347
  }
2229
- declare class ValidationError extends Error {
2230
- readonly status: number;
2231
- readonly body?: unknown;
2348
+ /** Thrown on a 4xx the caller can fix (bad cursor, bad params). Never retried. */
2349
+ declare class ValidationError extends ApiError {
2232
2350
  constructor(message: string, status: number, body?: unknown);
2233
2351
  }
2234
- declare class StreamsServerError extends Error {
2235
- readonly status: number;
2236
- readonly body?: unknown;
2352
+ /** Parse a `Retry-After` header: delta-seconds or an HTTP-date. */
2353
+ declare function parseRetryAfter(value?: string | null): number | undefined;
2354
+ /**
2355
+ * Thrown on optimistic-concurrency conflict when a deploy supplies an
2356
+ * `expectedVersion` that no longer matches the server's stored version.
2357
+ */
2358
+ declare class VersionConflictError extends ApiError {
2359
+ currentVersion: string;
2360
+ expectedVersion: string;
2361
+ constructor(currentVersion: string, expectedVersion: string, message?: string);
2362
+ }
2363
+ /**
2364
+ * Thrown when a BYO subgraph deploy is refused for a breaking schema change.
2365
+ * The deploy did NOT run — `details.plan` carries the DROP + rebuild DDL to run
2366
+ * manually on your own database, plus the breaking `reasons` and the `diff`.
2367
+ * The same DDL is surfaced on `metaMessages`, so a bare `console.error(err)`
2368
+ * already shows the operator what to run.
2369
+ *
2370
+ * @example
2371
+ * ```ts
2372
+ * try {
2373
+ * await client.subgraphs.deploy(bundle);
2374
+ * } catch (err) {
2375
+ * if (err instanceof ByoBreakingChangeError) {
2376
+ * console.log(err.details.plan.dropStatement);
2377
+ * console.log(err.details.plan.statements.join(";
2378
+ "));
2379
+ * }
2380
+ * }
2381
+ * ```
2382
+ */
2383
+ declare class ByoBreakingChangeError extends ApiError {
2384
+ readonly details: ByoBreakingChangeDetails;
2385
+ constructor(message: string, details: ByoBreakingChangeDetails);
2386
+ }
2387
+ /** Thrown on a 5xx from the Streams API. `retryable`. */
2388
+ declare class StreamsServerError extends ApiError {
2237
2389
  constructor(message: string, status: number, body?: unknown);
2238
2390
  }
2239
2391
  /** Thrown when response signature verification is enabled and fails. */
2240
- declare class StreamsSignatureError extends Error {
2392
+ declare class StreamsSignatureError extends SecondLayerError {
2241
2393
  constructor(message?: string);
2242
2394
  }
2243
2395
  type FtTransferEvent = Extract<StreamsEvent, {
@@ -2677,62 +2829,6 @@ type PayAndRetryOptions = Omit<WithX402Options, never> & {
2677
2829
  */
2678
2830
  declare function payAndRetry(doFetch: X402FetchFn, opts: PayAndRetryOptions): Promise<Response>;
2679
2831
  import { SubgraphAgentSchema as SubgraphAgentSchema3, SubgraphSpecFormat as SubgraphSpecFormat2, SubgraphSpecOptions as SubgraphSpecOptions3 } from "@secondlayer/shared/subgraphs/spec";
2680
- import { ByoBreakingChangeDetails } from "@secondlayer/shared/errors";
2681
- /**
2682
- * Error thrown by {@link SecondLayer} when an API request fails.
2683
- * Includes the HTTP status code for programmatic error handling.
2684
- *
2685
- * @example
2686
- * ```ts
2687
- * try {
2688
- * await client.subgraphs.get("my-subgraph");
2689
- * } catch (err) {
2690
- * if (err instanceof ApiError && err.status === 404) {
2691
- * console.log("Subgraph not found");
2692
- * }
2693
- * }
2694
- * ```
2695
- */
2696
- declare class ApiError extends Error {
2697
- /** HTTP status code (0 for network errors). */
2698
- status: number;
2699
- /** Raw response body (parsed JSON if possible) — preserved for callers that need error details. */
2700
- body?: unknown;
2701
- /** Stable machine-readable code from the API's `{error, code}` error envelope. */
2702
- code?: string;
2703
- constructor(status: number, message: string, body?: unknown, code?: string);
2704
- }
2705
- /**
2706
- * Thrown on optimistic-concurrency conflict when a deploy supplies an
2707
- * `expectedVersion` that no longer matches the server's stored version.
2708
- */
2709
- declare class VersionConflictError extends ApiError {
2710
- currentVersion: string;
2711
- expectedVersion: string;
2712
- constructor(currentVersion: string, expectedVersion: string, message?: string);
2713
- }
2714
- /**
2715
- * Thrown when a BYO subgraph deploy is refused for a breaking schema change.
2716
- * The deploy did NOT run — `details.plan` carries the DROP + rebuild DDL to run
2717
- * manually on your own database, plus the breaking `reasons` and the `diff`.
2718
- *
2719
- * @example
2720
- * ```ts
2721
- * try {
2722
- * await client.subgraphs.deploy(bundle);
2723
- * } catch (err) {
2724
- * if (err instanceof ByoBreakingChangeError) {
2725
- * console.log(err.details.plan.dropStatement);
2726
- * console.log(err.details.plan.statements.join(";
2727
- "));
2728
- * }
2729
- * }
2730
- * ```
2731
- */
2732
- declare class ByoBreakingChangeError extends ApiError {
2733
- readonly details: ByoBreakingChangeDetails;
2734
- constructor(message: string, details: ByoBreakingChangeDetails);
2735
- }
2736
2832
  import { ChainWebhookDelivery } from "@secondlayer/shared";
2737
2833
  import { StandardWebhooksHeaders } from "@secondlayer/shared/crypto/standard-webhooks";
2738
2834
  import { StandardWebhooksHeaders as StandardWebhooksHeaders2, verify } from "@secondlayer/shared/crypto/standard-webhooks";
@@ -2896,4 +2992,4 @@ declare function toJsonSafe(value: unknown): unknown;
2896
2992
  /** Decode a hex-encoded Clarity value to JSON-safe JS (uints as strings,
2897
2993
  * buffers as `0x…` hex, tuples as objects). Returns the input hex on failure. */
2898
2994
  declare function decodeClarityValue(hex: string): unknown;
2899
- export { withX402, verifyWebhookSignature, verifyTransactionProof, verify as verifyStandardWebhooksHeaders, verifySecondlayerSignature, trigger, toJsonSafe, selectOffer, resolveApiKey, 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, decodeChainWebhook, createX402Client, createStreamsClient, consumeIndexFeed, buildSignedX402Payment, X402SpendGuardError, X402Result, X402Receipt, X402Fetch, X402ClientOptions, X402Client, X402Challenge, X402Accept, WithX402Options, WebhookHeaderInput, 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, StandardWebhooksHeaders2 as StandardWebhooksHeaders, StackingWalkParams, StackingListParams, StackingEnvelope, SelectOfferOptions, SecondLayerOptions, SecondLayer, ScopedKeyProduct, SbtcWithdrawalsWalkParams, SbtcWithdrawalsListParams, SbtcWithdrawalsEnvelope, SbtcWithdrawalSweptConfirmedEvent, SbtcWithdrawalStatus, SbtcWithdrawalEvent, SbtcWithdrawalEnvelope, SbtcSummaryEnvelope, SbtcResource, SbtcEventsWalkParams, SbtcEventsListParams, SbtcEventsEnvelope, SbtcEventsConsumeParams, SbtcEventTopic, SbtcDepositsWalkParams, SbtcDepositsListParams, SbtcDepositsEnvelope, SbtcDepositsConsumeParams, SbtcDepositEvent, SbtcDepositEnvelope, RotateSecretResponse2 as RotateSecretResponse, RewardSet2 as RewardSet, ReplayResult2 as ReplayResult, RateLimitError, Projects, ProjectTeamMember, ProjectTeam, ProjectInvitation, Project, PrintSchemaResponse, PoxResource, PoxCyclesWalkParams, PoxCyclesListParams, PoxCyclesEnvelope, PoxCycleEnvelope, Pox5Resource, Pox5EventsWalkParams, Pox5EventsListParams, Pox5EventsEnvelope, PayAndRetryOptions, NftTransfersWalkParams, NftTransfersResource, NftTransfersListParams, NftTransfersEnvelope, NftTransferPayload, NftTransferEvent, NftTransfer, MempoolWalkParams, MempoolTransactionEnvelope, MempoolListParams, MempoolEnvelope, IndexUsage, IndexTransaction, IndexTip, IndexStxTransfer, IndexStxMint, IndexStxLock, IndexStxBurn, IndexStackingAction, IndexSbtcWithdrawalPhase, IndexSbtcWithdrawalDetail, IndexSbtcWithdrawal, IndexSbtcSummary, IndexSbtcEvent, IndexSbtcDepositDetail, IndexSbtcDeposit, IndexReorg, IndexPrint, IndexPoxFunctionCount, IndexPoxCycle, IndexPox5EventTopic, IndexPox5Event, IndexPostCondition, IndexNftTransfer, IndexNftMint, IndexNftBurn, IndexMempoolTransaction, IndexFtTransfer, IndexFtMint, IndexFtBurn, IndexFeedItem, IndexFeedFetcher, IndexFeedEnvelope, IndexEventsResource, IndexEventTypeFilters, IndexEventType, IndexEventOf, IndexEvent, IndexDiscovery, IndexContractCall, IndexConsumeOptions, IndexCanonicalBlock, IndexBlock, Index, FtTransfersWalkParams, FtTransfersResource, FtTransfersListParams, FtTransfersEnvelope, FtTransferPayload, FtTransferEvent, FtTransfer, FetchLike2 as FetchLike, EventsWalkParams, EventsListParams, EventsEnvelope, EventsConsumeParams, 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, ContractCallsConsumeParams, ContextSnapshot, ContextProject, ContextApiKey, ContextAccount, ConsumerBatchContext, ChainWebhookEnvelope, ChainWebhookDelivery2 as ChainWebhookDelivery, ChainTxLevelEvent, ChainTriggerType, ChainTrigger, ChainTestDelivery, ChainStxTransferData, ChainStxMintData, ChainStxLockData, ChainStxBurnData, ChainReorgRollbackEnvelope, ChainReorgRollbackDelivery, ChainReorgOrphanedEntry, ChainPrintEventData, ChainNftTransferData, ChainNftMintData, ChainNftBurnData, ChainFtTransferData, ChainFtMintData, ChainFtBurnData, ChainEventEnvelope, ChainApplyEnvelopeOf, ChainApplyEnvelope, ChainApplyDeliveryOf, CanonicalWalkParams, CanonicalListParams, CanonicalEnvelope, ByoBreakingChangeError, ByoBreakingChangeDetails, BuildSignedX402PaymentOptions, BlocksWalkParams, BlocksListParams, BlocksEnvelope, BlockEnvelope, AuthError, ApiKeys, ApiKeySummary, ApiError, ActiveSubgraphOperation };
2995
+ export { withX402, verifyWebhookSignature, verifyTransactionProof, verify as verifyStandardWebhooksHeaders, verifySecondlayerSignature, trigger, toJsonSafe, selectOffer, resolveApiKey, resolveAccountNonce, readX402Receipt, readX402Challenge, payAndRetry, parseRetryAfter, 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, decodeChainWebhook, createX402Client, createStreamsClient, consumeIndexFeed, buildSignedX402Payment, X402SpendGuardError, X402Result, X402Receipt, X402Fetch, X402ClientOptions, X402Client, X402Challenge, X402Accept, WithX402Options, WebhookHeaderInput, 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, StandardWebhooksHeaders2 as StandardWebhooksHeaders, StackingWalkParams, StackingListParams, StackingEnvelope, SelectOfferOptions, SecondLayerOptions, SecondLayerErrorOptions, SecondLayerError, SecondLayer, ScopedKeyProduct, SbtcWithdrawalsWalkParams, SbtcWithdrawalsListParams, SbtcWithdrawalsEnvelope, SbtcWithdrawalSweptConfirmedEvent, SbtcWithdrawalStatus, SbtcWithdrawalEvent, SbtcWithdrawalEnvelope, SbtcSummaryEnvelope, SbtcResource, SbtcEventsWalkParams, SbtcEventsListParams, SbtcEventsEnvelope, SbtcEventsConsumeParams, SbtcEventTopic, SbtcDepositsWalkParams, SbtcDepositsListParams, SbtcDepositsEnvelope, SbtcDepositsConsumeParams, SbtcDepositEvent, SbtcDepositEnvelope, RotateSecretResponse2 as RotateSecretResponse, RewardSet2 as RewardSet, ReplayResult2 as ReplayResult, RateLimitError, Projects, ProjectTeamMember, ProjectTeam, ProjectInvitation, Project, PrintSchemaResponse, PoxResource, PoxCyclesWalkParams, PoxCyclesListParams, PoxCyclesEnvelope, PoxCycleEnvelope, Pox5Resource, Pox5EventsWalkParams, Pox5EventsListParams, Pox5EventsEnvelope, PayAndRetryOptions, NftTransfersWalkParams, NftTransfersResource, NftTransfersListParams, NftTransfersEnvelope, NftTransferPayload, NftTransferEvent, NftTransfer, MempoolWalkParams, MempoolTransactionEnvelope, MempoolListParams, MempoolEnvelope, IndexUsage, IndexTransaction, IndexTip, IndexStxTransfer, IndexStxMint, IndexStxLock, IndexStxBurn, IndexStackingAction, IndexSbtcWithdrawalPhase, IndexSbtcWithdrawalDetail, IndexSbtcWithdrawal, IndexSbtcSummary, IndexSbtcEvent, IndexSbtcDepositDetail, IndexSbtcDeposit, IndexReorg, IndexPrint, IndexPoxFunctionCount, IndexPoxCycle, IndexPox5EventTopic, IndexPox5Event, IndexPostCondition, IndexNftTransfer, IndexNftMint, IndexNftBurn, IndexMempoolTransaction, IndexFtTransfer, IndexFtMint, IndexFtBurn, IndexFeedItem, IndexFeedFetcher, IndexFeedEnvelope, IndexEventsResource, IndexEventTypeFilters, IndexEventType, IndexEventOf, IndexEvent, IndexDiscovery, IndexContractCall, IndexConsumeOptions, IndexCanonicalBlock, IndexBlock, Index, FtTransfersWalkParams, FtTransfersResource, FtTransfersListParams, FtTransfersEnvelope, FtTransferPayload, FtTransferEvent, FtTransfer, FetchLike2 as FetchLike, EventsWalkParams, EventsListParams, EventsEnvelope, EventsConsumeParams, 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, ContractCallsConsumeParams, ContextSnapshot, ContextProject, ContextApiKey, ContextAccount, ConsumerBatchContext, ChainWebhookEnvelope, ChainWebhookDelivery2 as ChainWebhookDelivery, ChainTxLevelEvent, ChainTriggerType, ChainTrigger, ChainTestDelivery, ChainStxTransferData, ChainStxMintData, ChainStxLockData, ChainStxBurnData, ChainReorgRollbackEnvelope, ChainReorgRollbackDelivery, ChainReorgOrphanedEntry, ChainPrintEventData, ChainNftTransferData, ChainNftMintData, ChainNftBurnData, ChainFtTransferData, ChainFtMintData, ChainFtBurnData, ChainEventEnvelope, ChainApplyEnvelopeOf, ChainApplyEnvelope, ChainApplyDeliveryOf, CanonicalWalkParams, CanonicalListParams, CanonicalEnvelope, ByoBreakingChangeError, ByoBreakingChangeDetails, BuildSignedX402PaymentOptions, BlocksWalkParams, BlocksListParams, BlocksEnvelope, BlockEnvelope, AuthError, ApiKeys, ApiKeySummary, ApiError, ActiveSubgraphOperation };
package/dist/index.js CHANGED
@@ -1,17 +1,127 @@
1
1
  // src/errors.ts
2
- class ApiError extends Error {
2
+ var DOCS_BASE = "https://www.secondlayer.tools";
3
+
4
+ class SecondLayerError extends Error {
5
+ name = "SecondLayerError";
6
+ shortMessage;
7
+ code;
8
+ docsUrl;
9
+ metaMessages;
10
+ retryable;
11
+ retryAfterSeconds;
12
+ constructor(shortMessage, options = {}) {
13
+ const detailBlocks = [
14
+ ...options.metaMessages ?? [],
15
+ ...options.details ? [options.details] : [],
16
+ ...options.docsUrl ? [`Docs: ${options.docsUrl}`] : []
17
+ ];
18
+ const message = [
19
+ shortMessage,
20
+ detailBlocks.length > 0 ? `
21
+ ${detailBlocks.join(`
22
+ `)}` : ""
23
+ ].join("");
24
+ super(message, options.cause ? { cause: options.cause } : undefined);
25
+ this.shortMessage = shortMessage;
26
+ this.code = options.code;
27
+ this.docsUrl = options.docsUrl;
28
+ this.metaMessages = options.metaMessages;
29
+ this.retryable = options.retryable ?? false;
30
+ this.retryAfterSeconds = options.retryAfterSeconds;
31
+ }
32
+ walk(fn) {
33
+ let err = this;
34
+ let last = this;
35
+ while (err != null) {
36
+ if (fn?.(err))
37
+ return err;
38
+ last = err;
39
+ err = err.cause;
40
+ }
41
+ return fn ? null : last;
42
+ }
43
+ toJSON() {
44
+ return {
45
+ name: this.name,
46
+ message: this.message,
47
+ shortMessage: this.shortMessage,
48
+ cause: this.cause instanceof Error ? this.cause.message : undefined,
49
+ code: this.code,
50
+ docsUrl: this.docsUrl,
51
+ retryable: this.retryable,
52
+ retryAfterSeconds: this.retryAfterSeconds
53
+ };
54
+ }
55
+ }
56
+ function statusRetryable(status) {
57
+ return status === 429 || status >= 500;
58
+ }
59
+ function docsFor(status, code) {
60
+ if (code === "UPGRADE_REQUIRED" || code === "PLAN_REQUIRED" || status === 402)
61
+ return `${DOCS_BASE}/docs/authentication#pay-as-you-go-credits`;
62
+ if (status === 429 || status === 401)
63
+ return `${DOCS_BASE}/docs/authentication`;
64
+ return;
65
+ }
66
+
67
+ class ApiError extends SecondLayerError {
3
68
  status;
4
69
  body;
5
- code;
6
- constructor(status, message, body, code) {
7
- super(message);
70
+ constructor(status, message, body, code, options = {}) {
71
+ super(message, {
72
+ code,
73
+ retryable: options.retryable ?? statusRetryable(status),
74
+ docsUrl: options.docsUrl ?? docsFor(status, code),
75
+ ...options.cause ? { cause: options.cause } : {},
76
+ ...options.details ? { details: options.details } : {},
77
+ ...options.metaMessages ? { metaMessages: options.metaMessages } : {},
78
+ ...options.retryAfterSeconds !== undefined ? { retryAfterSeconds: options.retryAfterSeconds } : {}
79
+ });
8
80
  this.status = status;
9
81
  this.body = body;
10
- this.code = code;
11
82
  this.name = "ApiError";
12
83
  }
13
84
  }
14
85
 
86
+ class AuthError extends ApiError {
87
+ status = 401;
88
+ constructor(message = "API key invalid or expired.") {
89
+ super(401, message);
90
+ this.name = "AuthError";
91
+ }
92
+ }
93
+
94
+ class RateLimitError extends ApiError {
95
+ retryAfter;
96
+ status = 429;
97
+ constructor(message = "Rate limited. Try again later.", retryAfter) {
98
+ super(429, message, undefined, undefined, {
99
+ retryable: true,
100
+ retryAfterSeconds: parseRetryAfter(retryAfter)
101
+ });
102
+ this.retryAfter = retryAfter;
103
+ this.name = "RateLimitError";
104
+ }
105
+ }
106
+
107
+ class ValidationError extends ApiError {
108
+ constructor(message, status, body) {
109
+ super(status, message, body, undefined, { retryable: false });
110
+ this.name = "ValidationError";
111
+ }
112
+ }
113
+ function parseRetryAfter(value) {
114
+ if (!value)
115
+ return;
116
+ const seconds = Number(value);
117
+ if (Number.isFinite(seconds) && seconds >= 0)
118
+ return seconds;
119
+ const date = Date.parse(value);
120
+ if (!Number.isNaN(date))
121
+ return Math.max(0, (date - Date.now()) / 1000);
122
+ return;
123
+ }
124
+
15
125
  class VersionConflictError extends ApiError {
16
126
  currentVersion;
17
127
  expectedVersion;
@@ -26,7 +136,13 @@ class VersionConflictError extends ApiError {
26
136
  class ByoBreakingChangeError extends ApiError {
27
137
  details;
28
138
  constructor(message, details) {
29
- super(422, message, details, "BYO_BREAKING_CHANGE");
139
+ super(422, message, details, "BYO_BREAKING_CHANGE", {
140
+ metaMessages: [
141
+ "Review and run manually on your database:",
142
+ details.plan.dropStatement,
143
+ ...details.plan.statements
144
+ ]
145
+ });
30
146
  this.name = "ByoBreakingChangeError";
31
147
  this.details = details;
32
148
  }
@@ -112,7 +228,7 @@ class BaseClient {
112
228
  serializedBody = JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value);
113
229
  } catch (err) {
114
230
  const detail = err instanceof Error ? err.message : String(err);
115
- throw new ApiError(0, `Failed to serialize request body: ${detail}`);
231
+ throw new ApiError(0, `Failed to serialize request body: ${detail}`, undefined, undefined, { retryable: false });
116
232
  }
117
233
  }
118
234
  let response;
@@ -122,17 +238,17 @@ class BaseClient {
122
238
  headers,
123
239
  body: serializedBody
124
240
  });
125
- } catch {
126
- throw new ApiError(0, `Cannot reach API at ${this.baseUrl}. Check your connection or try again.`);
241
+ } catch (err) {
242
+ throw new ApiError(0, `Cannot reach API at ${this.baseUrl}. Check your connection or try again.`, undefined, undefined, { retryable: true, cause: err instanceof Error ? err : undefined });
127
243
  }
128
244
  if (!response.ok) {
129
245
  if (response.status === 401) {
130
- throw new ApiError(401, "API key invalid or expired.");
246
+ throw new AuthError;
131
247
  }
132
248
  if (response.status === 429) {
133
249
  const retryAfter = response.headers.get("Retry-After");
134
250
  const msg = retryAfter ? `Rate limited. Wait ${retryAfter} seconds.` : "Rate limited. Try again later.";
135
- throw new ApiError(429, msg);
251
+ throw new RateLimitError(msg, retryAfter ?? undefined);
136
252
  }
137
253
  if (response.status >= 500) {
138
254
  throw new ApiError(response.status, `Server error. Try again or check status at ${this.baseUrl}/health`);
@@ -426,47 +542,14 @@ class Contracts extends BaseClient {
426
542
  }
427
543
 
428
544
  // src/streams/errors.ts
429
- class AuthError extends Error {
430
- status = 401;
431
- constructor(message = "API key invalid or expired.") {
432
- super(message);
433
- this.name = "AuthError";
434
- }
435
- }
436
-
437
- class RateLimitError extends Error {
438
- retryAfter;
439
- status = 429;
440
- constructor(message = "Rate limited. Try again later.", retryAfter) {
441
- super(message);
442
- this.retryAfter = retryAfter;
443
- this.name = "RateLimitError";
444
- }
445
- }
446
-
447
- class ValidationError extends Error {
448
- status;
449
- body;
450
- constructor(message, status, body) {
451
- super(message);
452
- this.status = status;
453
- this.body = body;
454
- this.name = "ValidationError";
455
- }
456
- }
457
-
458
- class StreamsServerError extends Error {
459
- status;
460
- body;
545
+ class StreamsServerError extends ApiError {
461
546
  constructor(message, status, body) {
462
- super(message);
463
- this.status = status;
464
- this.body = body;
547
+ super(status, message, body, undefined, { retryable: true });
465
548
  this.name = "StreamsServerError";
466
549
  }
467
550
  }
468
551
 
469
- class StreamsSignatureError extends Error {
552
+ class StreamsSignatureError extends SecondLayerError {
470
553
  constructor(message = "Streams response signature verification failed.") {
471
554
  super(message);
472
555
  this.name = "StreamsSignatureError";
@@ -517,6 +600,41 @@ function batchContext(cursor, height, tipHeight) {
517
600
  blocksBehind: height === null ? null : Math.max(0, tipHeight - height)
518
601
  };
519
602
  }
603
+ var MAX_RETRY_AFTER_MS = 300000;
604
+ function errRetryable(err) {
605
+ if (err && typeof err === "object" && "retryable" in err) {
606
+ return err.retryable === true;
607
+ }
608
+ return err instanceof TypeError;
609
+ }
610
+ function errRetryAfterMs(err) {
611
+ if (err && typeof err === "object" && "retryAfterSeconds" in err) {
612
+ const seconds = err.retryAfterSeconds;
613
+ if (typeof seconds === "number" && Number.isFinite(seconds)) {
614
+ return Math.min(seconds * 1000, MAX_RETRY_AFTER_MS);
615
+ }
616
+ }
617
+ return;
618
+ }
619
+ async function fetchPageWithRetry(fetchPage, opts) {
620
+ const retryCount = opts.retryCount ?? 3;
621
+ const retryDelay = opts.retryDelay ?? 1000;
622
+ for (let attempt = 0;; attempt++) {
623
+ try {
624
+ return await fetchPage();
625
+ } catch (err) {
626
+ const retriesLeft = retryCount - attempt;
627
+ if (retriesLeft <= 0 || !errRetryable(err) || opts.signal?.aborted) {
628
+ throw err;
629
+ }
630
+ const delayMs = errRetryAfterMs(err) ?? retryDelay * (attempt + 1);
631
+ opts.onError?.(err, { attempt, retriesLeft, delayMs });
632
+ await opts.sleep(delayMs, opts.signal);
633
+ if (opts.signal?.aborted)
634
+ throw err;
635
+ }
636
+ }
637
+ }
520
638
  async function defaultSleep(ms, signal) {
521
639
  if (signal?.aborted)
522
640
  return;
@@ -543,7 +661,7 @@ async function consumeStreamsEvents(opts) {
543
661
  let emptyPolls = 0;
544
662
  let height = null;
545
663
  while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
546
- const envelope = await opts.fetchEvents({
664
+ const envelope = await fetchPageWithRetry(() => opts.fetchEvents({
547
665
  cursor,
548
666
  limit: opts.batchSize,
549
667
  types: opts.types,
@@ -552,6 +670,12 @@ async function consumeStreamsEvents(opts) {
552
670
  sender: opts.sender,
553
671
  recipient: opts.recipient,
554
672
  assetIdentifier: opts.assetIdentifier
673
+ }), {
674
+ retryCount: opts.retryCount,
675
+ retryDelay: opts.retryDelay,
676
+ onError: opts.onError,
677
+ sleep,
678
+ signal: opts.signal
555
679
  });
556
680
  pages++;
557
681
  if (!finalizedOnly && opts.onReorg) {
@@ -682,10 +806,16 @@ async function consumeIndexFeed(opts) {
682
806
  let emptyPolls = 0;
683
807
  let height = null;
684
808
  while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
685
- const envelope = await opts.fetchPage({
809
+ const envelope = await fetchPageWithRetry(() => opts.fetchPage({
686
810
  cursor,
687
811
  fromHeight: cursor === null ? opts.fromHeight : undefined,
688
812
  limit: batchSize
813
+ }), {
814
+ retryCount: opts.retryCount,
815
+ retryDelay: opts.retryDelay,
816
+ onError: opts.onError,
817
+ sleep,
818
+ signal: opts.signal
689
819
  });
690
820
  pages++;
691
821
  if (!finalizedOnly && opts.onReorg) {
@@ -1574,7 +1704,10 @@ function createStreamsClient(options) {
1574
1704
  emptyBackoffMs: params.emptyBackoffMs,
1575
1705
  maxPages: params.maxPages,
1576
1706
  maxEmptyPolls: params.maxEmptyPolls,
1577
- signal: params.signal
1707
+ signal: params.signal,
1708
+ retryCount: params.retryCount,
1709
+ retryDelay: params.retryDelay,
1710
+ onError: params.onError
1578
1711
  });
1579
1712
  },
1580
1713
  stream(params = {}) {
@@ -2472,6 +2605,7 @@ export {
2472
2605
  readX402Receipt,
2473
2606
  readX402Challenge,
2474
2607
  payAndRetry,
2608
+ parseRetryAfter,
2475
2609
  isStxTransfer,
2476
2610
  isStxMint,
2477
2611
  isStxLock,
@@ -2509,6 +2643,7 @@ export {
2509
2643
  Subgraphs,
2510
2644
  StreamsSignatureError,
2511
2645
  StreamsServerError,
2646
+ SecondLayerError,
2512
2647
  SecondLayer,
2513
2648
  RateLimitError,
2514
2649
  Projects,
@@ -2522,5 +2657,5 @@ export {
2522
2657
  ApiError
2523
2658
  };
2524
2659
 
2525
- //# debugId=7D05343D5E23B9E764756E2164756E21
2660
+ //# debugId=D57E218C0E8C77C464756E2164756E21
2526
2661
  //# sourceMappingURL=index.js.map