@secondlayer/sdk 16.2.1 → 16.3.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
@@ -324,6 +324,33 @@ declare function resolveApiKey(apiKey?: string, baseUrl?: string): string | unde
324
324
  * Precedence: explicit `accountKey` → `SECONDLAYER_API_KEY`. Does not read
325
325
  * `INSTANCE_TOKEN`. */
326
326
  declare function resolveAccountKey(accountKey?: string): string | undefined;
327
+ /** Hosted account API for credits, archive fetches and login. Not the
328
+ * operator's loopback box. `SL_CREDITS_API_URL` (or the older
329
+ * `ARCHIVE_OPS_API_URL`) points it elsewhere, e.g. at a staging stack. */
330
+ declare function resolveAccountUrl(): string;
331
+ /** Where a resolved credential came from. `none` = nothing usable was found. */
332
+ type IdentitySource = "env" | "session" | "none";
333
+ interface Identity {
334
+ source: IdentitySource;
335
+ /** Bearer token, `undefined` when `source` is `none`. */
336
+ token: string | undefined;
337
+ /** The server this credential is for. */
338
+ url: string;
339
+ }
340
+ /**
341
+ * The one credential resolver the CLI and MCP share. One precedence, highest
342
+ * first: an env key, then the stored login session (`session`, supplied by
343
+ * callers that have one; the SDK itself never touches the filesystem).
344
+ *
345
+ * target "account" env = `SECONDLAYER_API_KEY` when it is an account
346
+ * credential (`sk-sl_` / `ss-sl_`); url = {@link resolveAccountUrl}
347
+ * target "instance" env = `INSTANCE_TOKEN`; url = {@link resolveBaseUrl}
348
+ *
349
+ * An env key of the wrong kind is ignored rather than sent to the wrong host.
350
+ */
351
+ declare function resolveIdentity(target: "account" | "instance", options?: {
352
+ session?: string | null;
353
+ }): Identity;
327
354
  declare abstract class BaseClient {
328
355
  protected baseUrl: string;
329
356
  protected apiKey?: string;
@@ -832,6 +859,8 @@ type StreamsEventsStreamBitcoinParams = StreamsEventsStreamCommon & {
832
859
  address?: string;
833
860
  };
834
861
  type StreamsEventsStreamParams = StreamsEventsStreamStacksParams | StreamsEventsStreamBitcoinParams;
862
+ /** Where a `subscribe` connection is in its lifecycle. */
863
+ type StreamsSubscriptionState = "connecting" | "open" | "reconnecting" | "closed";
835
864
  type StreamsEventsSubscribeCommon = {
836
865
  /** Resume strictly after this cursor; omit to live-tail from the tip. */
837
866
  fromCursor?: string | null;
@@ -845,6 +874,13 @@ type StreamsEventsSubscribeCommon = {
845
874
  */
846
875
  onError?: (err: unknown) => void;
847
876
  /**
877
+ * Lifecycle observer. `connecting` before each connection attempt, `open`
878
+ * once the server answers, `reconnecting` while backing off after a drop
879
+ * or error, `closed` once, when the subscription ends (unsubscribed,
880
+ * aborted, or stopped by an error a retry cannot fix).
881
+ */
882
+ onState?: (state: StreamsSubscriptionState) => void;
883
+ /**
848
884
  * First reconnect pause in ms (default 1000). Doubles per consecutive
849
885
  * failure up to 30 s with jitter, resets once a frame arrives, and never
850
886
  * undercuts a `Retry-After`.
@@ -2378,6 +2414,9 @@ type IndexSbtcWithdrawal = {
2378
2414
  btc_block_height: number | null;
2379
2415
  /** When the sweep crossed the confirmation threshold (ISO), null otherwise. */
2380
2416
  confirmed_at: string | null;
2417
+ /** Monotonic stamp taken when the sweep became confirmed; resume a scan
2418
+ * from it with `confirmed_after_seq`. Null while unsettled. */
2419
+ settlement_seq: number | null;
2381
2420
  requested_at?: string | null;
2382
2421
  resolved_at?: string | null;
2383
2422
  };
@@ -3985,11 +4024,11 @@ declare function buildDoctorReport(input: {
3985
4024
  * The list page's own reduced detector: computed from `WebhookSummary` alone
3986
4025
  * (no deliveries, no dead-letter rows — the list endpoint returns neither,
3987
4026
  * and fetching per-row detail or deliveries here would fan out one request
3988
- * per row). Only `status` and `circuitOpenedAt` distinguish a real problem
4027
+ * per row). Only `status` and `pauseReason` distinguish a real problem
3989
4028
  * from a manual pause at this level; deliveries-based rules (rate limits,
3990
4029
  * downtime, rejects, slowness, lag) only ever show on the detail page.
3991
4030
  */
3992
- declare function buildListIssue(webhook: Pick<WebhookSummary3, "status" | "circuitOpenedAt" | "lastSuccessAt">): DoctorIssue | null;
4031
+ declare function buildListIssue(webhook: Pick<WebhookSummary3, "status" | "pauseReason" | "circuitOpenedAt" | "lastSuccessAt">): DoctorIssue | null;
3993
4032
  /**
3994
4033
  * The two pieces every "deploy a consumer" guide leaves out, packaged:
3995
4034
  * a liveness endpoint and a graceful-shutdown signal. Both are
@@ -4325,6 +4364,13 @@ type CreateStreamsClientOptions = {
4325
4364
  origin?: "cli" | "mcp" | "session";
4326
4365
  fetchImpl?: FetchLike2;
4327
4366
  /**
4367
+ * Give up on a request that has not connected and returned response headers
4368
+ * within this many ms (default 30000; `0` disables). Retryable: the consume
4369
+ * loops retry it and `subscribe` reconnects. Body reads are not covered, so
4370
+ * a healthy long-lived stream is never cut off.
4371
+ */
4372
+ connectTimeoutMs?: number;
4373
+ /**
4328
4374
  * Public base URL for bulk parquet dumps (the R2/CDN bucket root). Required
4329
4375
  * to use `client.dumps`. See `GET /public/streams/dumps/manifest`.
4330
4376
  */
@@ -4423,4 +4469,4 @@ declare const Cursor: {
4423
4469
  };
4424
4470
  };
4425
4471
  import { decodeClarityValue, toJsonSafe } from "@secondlayer/shared/streams-rows";
4426
- export { ACCOUNT_KEY_ENV, ActiveSubgraphOperation, ApiError, ArchiveAuthError, ArchiveClient, ArchiveCreditsBalance, ArchiveDataset, ArchiveFetchItem, ArchiveFetchResult, ArchiveFlow, ArchiveGateNotConfiguredError, ArchiveLoadOptions, ArchiveManifest, ArchivePartition, ArchiveQuote, ArchiveSignatureError, ArchiveStatus, ArchiveVerifyInput, ArchiveVerifyRangeStatus, ArchiveVerifyResult, AuthError, BitcoinOutputSpent, BitcoinOutputUnspent, BitcoinOutspend, BitcoinResource, BlockEnvelope, BlocksEnvelope, BlocksListParams, BlocksWalkParams, CanonicalEnvelope, CanonicalListParams, CanonicalWalkParams, ChainApplyDeliveryOf, ChainApplyEnvelope, ChainApplyEnvelopeOf, ChainEventEnvelope, ChainFtBurnData, ChainFtMintData, ChainFtTransferData, ChainNftBurnData, ChainNftMintData, ChainNftTransferData, ChainPrintEventData, ChainReorgOrphanedEntry, ChainReorgRollbackDelivery, ChainReorgRollbackEnvelope, ChainStxBurnData, ChainStxLockData, ChainStxMintData, ChainStxTransferData, ChainTestDelivery, ChainTrigger, ChainTriggerType, ChainTxLevelEvent, ChainWebhookDelivery2 as ChainWebhookDelivery, ChainWebhookEnvelope, ConsumerBatchContext, ConsumerHealth, ConsumerSink, ContextAccount, ContextField, ContextFieldError, ContextSnapshot, ContractCallsConsumeParams, ContractCallsEnvelope, ContractCallsListParams, ContractCallsWalkParams, ContractConformance, ContractSummary, Contracts, ContractsEnvelope, ContractsListParams, CreateArchiveClientOptions, CreateWebhookRequest2 as CreateWebhookRequest, CreateWebhookResponse2 as CreateWebhookResponse, Cursor, DEFAULT_REQUEST_TIMEOUT_MS, DOWN_MIN_CONSECUTIVE, DeadRow2 as DeadRow, DecodedEventColumns, DecodedEventRow, DecodedFtBurn, DecodedFtBurnPayload, DecodedFtMint, DecodedFtMintPayload, DecodedFtTransfer, DecodedFtTransferPayload, DecodedNftBurn, DecodedNftBurnPayload, DecodedNftMint, DecodedNftMintPayload, DecodedNftTransfer, DecodedNftTransferPayload, DecodedPrint, DecodedPrintPayload, DecodedPrintValue, DecodedStxBurn, DecodedStxBurnPayload, DecodedStxLock, DecodedStxLockPayload, DecodedStxMint, DecodedStxMintPayload, DecodedStxTransfer, DecodedStxTransferPayload, DeliveryRow2 as DeliveryRow, DoctorEvidence, DoctorFix, DoctorIssue, DoctorIssueCode, DoctorReport, DoctorSeverity, EtagCache, EtagEntry, EventsConsumeParams, EventsEnvelope, EventsListParams, EventsWalkParams, FetchLike2 as FetchLike, FtTransfer, FtTransferEvent, FtTransferPayload2 as FtTransferPayload, FtTransfersEnvelope, FtTransfersListParams, FtTransfersResource, FtTransfersWalkParams, INDEX_MAX_PAGE_SIZE, INSTANCE_TOKEN_ENV, Index, IndexAlwaysFields, IndexBitcoinTip, IndexBlock, IndexBtcReorg, IndexCanonicalBlock, IndexConsumeOptions, IndexContractCall, IndexDiscovery, IndexEvent, IndexEventFields, IndexEventOf, IndexEventType, IndexEventTypeFilters, IndexEventsResource, IndexFeedEnvelope, IndexFeedFetcher, IndexFeedItem, IndexFtBurn, IndexFtMint, IndexFtTransfer, IndexMapDelete, IndexMapInsert, IndexMapSet, IndexMempoolTransaction, IndexNestedContractCall, IndexNftBurn, IndexNftMint, IndexNftTransfer, IndexOrder, IndexPostCondition, IndexPox5Event, IndexPox5EventTopic, IndexPoxCycle, IndexPoxCycleSigner, IndexPrint, IndexReorg, IndexRuneBalance, IndexRuneEntry, IndexRuneEvent, IndexRuneEventKind, IndexRuneRefSummary, IndexRuneTerms, IndexSbtcDeposit, IndexSbtcDepositDetail, IndexSbtcEvent, IndexSbtcSummary, IndexSbtcWithdrawal, IndexSbtcWithdrawalDetail, IndexSbtcWithdrawalPhase, IndexStackingAction, IndexStateWrite, IndexStxBurn, IndexStxLock, IndexStxMint, IndexStxTransfer, IndexTip, IndexTransaction, IndexVarSet, InstanceClient, InstanceDiagnosis3 as InstanceDiagnosis, InstanceIssue, InstanceState, InstanceStatus, InsufficientArchiveCreditsError, LOCAL_API_URL, LoadedArchive, MemoryEtagCache, MempoolEnvelope, MempoolListParams, MempoolTransactionEnvelope, MempoolWalkParams, NftTransfer, NftTransferEvent, NftTransferPayload2 as NftTransferPayload, NftTransfersEnvelope, NftTransfersListParams, NftTransfersResource, NftTransfersWalkParams, Pox5EventsConsumeParams, Pox5EventsEnvelope, Pox5EventsListParams, Pox5EventsWalkParams, Pox5Resource, PoxCycleEnvelope, PoxCyclesEnvelope, PoxCyclesListParams, PoxCyclesWalkParams, PoxResource, PrintSchemaResponse, PublicStatus2 as PublicStatus, RateLimitError, ReplayResult2 as ReplayResult, RequestOptions, RewardSet2 as RewardSet, RotateSecretResponse2 as RotateSecretResponse, RuneActivityEnvelope, RuneActivityListParams, RuneActivityWalkParams, RuneApplyDeliveryOf, RuneApplyEnvelope, RuneBalancesEnvelope, RuneBalancesListParams, RuneEnvelope, RuneEtchEntry, RuneEventPayload, RuneEventType, RuneId, RuneRef, RuneStreamsEvent, RunesEnvelope, RunesListParams, RunesResource, SbtcDepositEnvelope, SbtcDepositEvent, SbtcDepositsConsumeParams, SbtcDepositsEnvelope, SbtcDepositsListParams, SbtcDepositsWalkParams, SbtcEventTopic2 as SbtcEventTopic, SbtcEventsConsumeParams, SbtcEventsEnvelope, SbtcEventsListParams, SbtcEventsWalkParams, SbtcResource, SbtcSummaryEnvelope, SbtcWithdrawalEnvelope, SbtcWithdrawalEvent, SbtcWithdrawalStatus, SbtcWithdrawalSweptConfirmedEvent, SbtcWithdrawalsEnvelope, SbtcWithdrawalsListParams, SbtcWithdrawalsWalkParams, SecondLayer, SecondLayerArchive, SecondLayerError, SecondLayerErrorOptions, SecondLayerOptions, SinkTx, StackingEnvelope, StackingListParams, StackingWalkParams, StandardWebhooksHeaders2 as StandardWebhooksHeaders, StateWritesEnvelope, StateWritesListParams, StateWritesWalkParams, StreamsBatch, StreamsBitcoinCanonicalBlock, StreamsBitcoinTip, StreamsCanonicalBlock, StreamsClient, StreamsConsumeBitcoinParams, StreamsConsumeParams, StreamsConsumeStacksParams, StreamsDumpFile, StreamsDumps, StreamsDumpsManifest, StreamsEvent, StreamsEventPayload, StreamsEventType, StreamsEventsBitcoinListParams, StreamsEventsConsumeBitcoinParams, StreamsEventsConsumeParams, StreamsEventsConsumeResult, StreamsEventsEnvelope, StreamsEventsListEnvelope, StreamsEventsListParams, StreamsEventsStacksListParams, StreamsEventsStreamBitcoinParams, StreamsEventsStreamParams, StreamsEventsStreamStacksParams, StreamsEventsSubscribeBitcoinParams, StreamsEventsSubscribeParams, StreamsEventsSubscribeStacksParams, StreamsReorg, StreamsReorgContext, StreamsReorgsListEnvelope, StreamsReorgsListParams, StreamsServerError, StreamsSignatureError, StreamsSubscription, StreamsTip, StreamsWireEvent2 as StreamsWireEvent, SubgraphAgentSchema3 as SubgraphAgentSchema, SubgraphOperationStatus, SubgraphSpecFormat2 as SubgraphSpecFormat, SubgraphSpecOptions3 as SubgraphSpecOptions, Subgraphs, TransactionEnvelope, TransactionProof, TransactionProofVerifyResult, TransactionsEnvelope, TransactionsListParams, TransactionsWalkParams, UpdateWebhookRequest2 as UpdateWebhookRequest, ValidationError, VmStreamsEvent, WalkOptions, WebhookActivity2 as WebhookActivity, WebhookActivityHour, WebhookAuth, WebhookDeliveryDetail2 as WebhookDeliveryDetail, WebhookDetail2 as WebhookDetail, WebhookFormat, WebhookHeaderInput, WebhookKind, WebhookStatus, WebhookSummary2 as WebhookSummary, WebhookTestResult2 as WebhookTestResult, Webhooks, WithSinkTx, buildDoctorReport, buildListIssue, consumeIndexFeed, consumerHealth, contextField, createArchiveClient, createStreamsClient, decode, decodeChainWebhook, decodeClarityValue, fetchRewardSet, getSubgraph, isHostedApiUrl, isSuccessDelivery, parseRetryAfter, resolveAccountKey, resolveApiKey, resolveBaseUrl, shutdownSignal, toJsonSafe, trigger, verifySecondlayerSignature, verify as verifyStandardWebhooksHeaders, verifyTransactionProof, verifyWebhookSignature };
4472
+ export { ACCOUNT_KEY_ENV, ActiveSubgraphOperation, ApiError, ArchiveAuthError, ArchiveClient, ArchiveCreditsBalance, ArchiveDataset, ArchiveFetchItem, ArchiveFetchResult, ArchiveFlow, ArchiveGateNotConfiguredError, ArchiveLoadOptions, ArchiveManifest, ArchivePartition, ArchiveQuote, ArchiveSignatureError, ArchiveStatus, ArchiveVerifyInput, ArchiveVerifyRangeStatus, ArchiveVerifyResult, AuthError, BitcoinOutputSpent, BitcoinOutputUnspent, BitcoinOutspend, BitcoinResource, BlockEnvelope, BlocksEnvelope, BlocksListParams, BlocksWalkParams, CanonicalEnvelope, CanonicalListParams, CanonicalWalkParams, ChainApplyDeliveryOf, ChainApplyEnvelope, ChainApplyEnvelopeOf, ChainEventEnvelope, ChainFtBurnData, ChainFtMintData, ChainFtTransferData, ChainNftBurnData, ChainNftMintData, ChainNftTransferData, ChainPrintEventData, ChainReorgOrphanedEntry, ChainReorgRollbackDelivery, ChainReorgRollbackEnvelope, ChainStxBurnData, ChainStxLockData, ChainStxMintData, ChainStxTransferData, ChainTestDelivery, ChainTrigger, ChainTriggerType, ChainTxLevelEvent, ChainWebhookDelivery2 as ChainWebhookDelivery, ChainWebhookEnvelope, ConsumerBatchContext, ConsumerHealth, ConsumerSink, ContextAccount, ContextField, ContextFieldError, ContextSnapshot, ContractCallsConsumeParams, ContractCallsEnvelope, ContractCallsListParams, ContractCallsWalkParams, ContractConformance, ContractSummary, Contracts, ContractsEnvelope, ContractsListParams, CreateArchiveClientOptions, CreateWebhookRequest2 as CreateWebhookRequest, CreateWebhookResponse2 as CreateWebhookResponse, Cursor, DEFAULT_REQUEST_TIMEOUT_MS, DOWN_MIN_CONSECUTIVE, DeadRow2 as DeadRow, DecodedEventColumns, DecodedEventRow, DecodedFtBurn, DecodedFtBurnPayload, DecodedFtMint, DecodedFtMintPayload, DecodedFtTransfer, DecodedFtTransferPayload, DecodedNftBurn, DecodedNftBurnPayload, DecodedNftMint, DecodedNftMintPayload, DecodedNftTransfer, DecodedNftTransferPayload, DecodedPrint, DecodedPrintPayload, DecodedPrintValue, DecodedStxBurn, DecodedStxBurnPayload, DecodedStxLock, DecodedStxLockPayload, DecodedStxMint, DecodedStxMintPayload, DecodedStxTransfer, DecodedStxTransferPayload, DeliveryRow2 as DeliveryRow, DoctorEvidence, DoctorFix, DoctorIssue, DoctorIssueCode, DoctorReport, DoctorSeverity, EtagCache, EtagEntry, EventsConsumeParams, EventsEnvelope, EventsListParams, EventsWalkParams, FetchLike2 as FetchLike, FtTransfer, FtTransferEvent, FtTransferPayload2 as FtTransferPayload, FtTransfersEnvelope, FtTransfersListParams, FtTransfersResource, FtTransfersWalkParams, INDEX_MAX_PAGE_SIZE, INSTANCE_TOKEN_ENV, Identity, IdentitySource, Index, IndexAlwaysFields, IndexBitcoinTip, IndexBlock, IndexBtcReorg, IndexCanonicalBlock, IndexConsumeOptions, IndexContractCall, IndexDiscovery, IndexEvent, IndexEventFields, IndexEventOf, IndexEventType, IndexEventTypeFilters, IndexEventsResource, IndexFeedEnvelope, IndexFeedFetcher, IndexFeedItem, IndexFtBurn, IndexFtMint, IndexFtTransfer, IndexMapDelete, IndexMapInsert, IndexMapSet, IndexMempoolTransaction, IndexNestedContractCall, IndexNftBurn, IndexNftMint, IndexNftTransfer, IndexOrder, IndexPostCondition, IndexPox5Event, IndexPox5EventTopic, IndexPoxCycle, IndexPoxCycleSigner, IndexPrint, IndexReorg, IndexRuneBalance, IndexRuneEntry, IndexRuneEvent, IndexRuneEventKind, IndexRuneRefSummary, IndexRuneTerms, IndexSbtcDeposit, IndexSbtcDepositDetail, IndexSbtcEvent, IndexSbtcSummary, IndexSbtcWithdrawal, IndexSbtcWithdrawalDetail, IndexSbtcWithdrawalPhase, IndexStackingAction, IndexStateWrite, IndexStxBurn, IndexStxLock, IndexStxMint, IndexStxTransfer, IndexTip, IndexTransaction, IndexVarSet, InstanceClient, InstanceDiagnosis3 as InstanceDiagnosis, InstanceIssue, InstanceState, InstanceStatus, InsufficientArchiveCreditsError, LOCAL_API_URL, LoadedArchive, MemoryEtagCache, MempoolEnvelope, MempoolListParams, MempoolTransactionEnvelope, MempoolWalkParams, NftTransfer, NftTransferEvent, NftTransferPayload2 as NftTransferPayload, NftTransfersEnvelope, NftTransfersListParams, NftTransfersResource, NftTransfersWalkParams, Pox5EventsConsumeParams, Pox5EventsEnvelope, Pox5EventsListParams, Pox5EventsWalkParams, Pox5Resource, PoxCycleEnvelope, PoxCyclesEnvelope, PoxCyclesListParams, PoxCyclesWalkParams, PoxResource, PrintSchemaResponse, PublicStatus2 as PublicStatus, RateLimitError, ReplayResult2 as ReplayResult, RequestOptions, RewardSet2 as RewardSet, RotateSecretResponse2 as RotateSecretResponse, RuneActivityEnvelope, RuneActivityListParams, RuneActivityWalkParams, RuneApplyDeliveryOf, RuneApplyEnvelope, RuneBalancesEnvelope, RuneBalancesListParams, RuneEnvelope, RuneEtchEntry, RuneEventPayload, RuneEventType, RuneId, RuneRef, RuneStreamsEvent, RunesEnvelope, RunesListParams, RunesResource, SbtcDepositEnvelope, SbtcDepositEvent, SbtcDepositsConsumeParams, SbtcDepositsEnvelope, SbtcDepositsListParams, SbtcDepositsWalkParams, SbtcEventTopic2 as SbtcEventTopic, SbtcEventsConsumeParams, SbtcEventsEnvelope, SbtcEventsListParams, SbtcEventsWalkParams, SbtcResource, SbtcSummaryEnvelope, SbtcWithdrawalEnvelope, SbtcWithdrawalEvent, SbtcWithdrawalStatus, SbtcWithdrawalSweptConfirmedEvent, SbtcWithdrawalsEnvelope, SbtcWithdrawalsListParams, SbtcWithdrawalsWalkParams, SecondLayer, SecondLayerArchive, SecondLayerError, SecondLayerErrorOptions, SecondLayerOptions, SinkTx, StackingEnvelope, StackingListParams, StackingWalkParams, StandardWebhooksHeaders2 as StandardWebhooksHeaders, StateWritesEnvelope, StateWritesListParams, StateWritesWalkParams, StreamsBatch, StreamsBitcoinCanonicalBlock, StreamsBitcoinTip, StreamsCanonicalBlock, StreamsClient, StreamsConsumeBitcoinParams, StreamsConsumeParams, StreamsConsumeStacksParams, StreamsDumpFile, StreamsDumps, StreamsDumpsManifest, StreamsEvent, StreamsEventPayload, StreamsEventType, StreamsEventsBitcoinListParams, StreamsEventsConsumeBitcoinParams, StreamsEventsConsumeParams, StreamsEventsConsumeResult, StreamsEventsEnvelope, StreamsEventsListEnvelope, StreamsEventsListParams, StreamsEventsStacksListParams, StreamsEventsStreamBitcoinParams, StreamsEventsStreamParams, StreamsEventsStreamStacksParams, StreamsEventsSubscribeBitcoinParams, StreamsEventsSubscribeParams, StreamsEventsSubscribeStacksParams, StreamsReorg, StreamsReorgContext, StreamsReorgsListEnvelope, StreamsReorgsListParams, StreamsServerError, StreamsSignatureError, StreamsSubscription, StreamsSubscriptionState, StreamsTip, StreamsWireEvent2 as StreamsWireEvent, SubgraphAgentSchema3 as SubgraphAgentSchema, SubgraphOperationStatus, SubgraphSpecFormat2 as SubgraphSpecFormat, SubgraphSpecOptions3 as SubgraphSpecOptions, Subgraphs, TransactionEnvelope, TransactionProof, TransactionProofVerifyResult, TransactionsEnvelope, TransactionsListParams, TransactionsWalkParams, UpdateWebhookRequest2 as UpdateWebhookRequest, ValidationError, VmStreamsEvent, WalkOptions, WebhookActivity2 as WebhookActivity, WebhookActivityHour, WebhookAuth, WebhookDeliveryDetail2 as WebhookDeliveryDetail, WebhookDetail2 as WebhookDetail, WebhookFormat, WebhookHeaderInput, WebhookKind, WebhookStatus, WebhookSummary2 as WebhookSummary, WebhookTestResult2 as WebhookTestResult, Webhooks, WithSinkTx, buildDoctorReport, buildListIssue, consumeIndexFeed, consumerHealth, contextField, createArchiveClient, createStreamsClient, decode, decodeChainWebhook, decodeClarityValue, fetchRewardSet, getSubgraph, isHostedApiUrl, isSuccessDelivery, parseRetryAfter, resolveAccountKey, resolveAccountUrl, resolveApiKey, resolveBaseUrl, resolveIdentity, shutdownSignal, toJsonSafe, trigger, verifySecondlayerSignature, verify as verifyStandardWebhooksHeaders, verifyTransactionProof, verifyWebhookSignature };
package/dist/index.js CHANGED
@@ -251,6 +251,22 @@ function resolveAccountKey(accountKey) {
251
251
  return;
252
252
  return process.env?.SECONDLAYER_API_KEY || undefined;
253
253
  }
254
+ function resolveAccountUrl() {
255
+ const env = typeof process !== "undefined" ? process.env : undefined;
256
+ return (env?.SL_CREDITS_API_URL || env?.ARCHIVE_OPS_API_URL || HOSTED_API_URL).replace(/\/+$/, "");
257
+ }
258
+ var ACCOUNT_CREDENTIAL_RE = /^s[ks]-sl_/;
259
+ function resolveIdentity(target, options = {}) {
260
+ const url = target === "account" ? resolveAccountUrl() : resolveBaseUrl();
261
+ const envKey = target === "account" ? resolveAccountKey() : typeof process !== "undefined" ? process.env?.[INSTANCE_TOKEN_ENV] || undefined : undefined;
262
+ if (envKey && (target === "instance" || ACCOUNT_CREDENTIAL_RE.test(envKey))) {
263
+ return { source: "env", token: envKey, url };
264
+ }
265
+ if (options.session) {
266
+ return { source: "session", token: options.session, url };
267
+ }
268
+ return { source: "none", token: undefined, url };
269
+ }
254
270
  function seg(value) {
255
271
  return encodeURIComponent(String(value));
256
272
  }
@@ -1006,13 +1022,70 @@ async function consumeStreamsEvents(opts) {
1006
1022
  }
1007
1023
  return { cursor, pages, emptyPolls };
1008
1024
  }
1025
+ async function* pullFromLoop(start, external) {
1026
+ const controller = new AbortController;
1027
+ if (external) {
1028
+ if (external.aborted)
1029
+ controller.abort();
1030
+ else
1031
+ external.addEventListener("abort", () => controller.abort(), {
1032
+ once: true
1033
+ });
1034
+ }
1035
+ const state = {
1036
+ delivered: null,
1037
+ held: null,
1038
+ finished: false,
1039
+ failure: null,
1040
+ wake: null
1041
+ };
1042
+ const notify = () => {
1043
+ const resolve = state.wake;
1044
+ state.wake = null;
1045
+ resolve?.();
1046
+ };
1047
+ const loop = start((value) => new Promise((release) => {
1048
+ state.delivered = { value, release };
1049
+ notify();
1050
+ }), controller.signal).then(() => {
1051
+ state.finished = true;
1052
+ }, (error) => {
1053
+ state.failure = { error };
1054
+ state.finished = true;
1055
+ }).finally(notify);
1056
+ try {
1057
+ while (true) {
1058
+ if (state.delivered) {
1059
+ const { value, release } = state.delivered;
1060
+ state.delivered = null;
1061
+ state.held = release;
1062
+ yield value;
1063
+ state.held = null;
1064
+ release();
1065
+ continue;
1066
+ }
1067
+ if (state.finished)
1068
+ break;
1069
+ await new Promise((resolve) => {
1070
+ state.wake = resolve;
1071
+ if (state.delivered || state.finished)
1072
+ notify();
1073
+ });
1074
+ }
1075
+ if (state.failure)
1076
+ throw state.failure.error;
1077
+ } finally {
1078
+ controller.abort();
1079
+ state.held?.();
1080
+ state.delivered?.release();
1081
+ await loop;
1082
+ }
1083
+ }
1009
1084
  async function* iterateStreamsBatches(opts) {
1010
- const sleep = opts.sleep ?? defaultSleep;
1011
- let cursor = opts.fromCursor ?? null;
1012
- while (!opts.signal?.aborted) {
1013
- const envelope = await opts.fetchEvents({
1014
- cursor,
1015
- limit: opts.batchSize,
1085
+ yield* pullFromLoop(async (deliver, signal) => {
1086
+ const result = await consumeStreamsEvents({
1087
+ fromCursor: opts.fromCursor,
1088
+ batchSize: opts.batchSize,
1016
1089
  chain: opts.chain,
1017
1090
  types: opts.types,
1018
1091
  notTypes: opts.notTypes,
@@ -1022,38 +1095,41 @@ async function* iterateStreamsBatches(opts) {
1022
1095
  assetIdentifier: opts.assetIdentifier,
1023
1096
  rune: opts.rune,
1024
1097
  address: opts.address,
1025
- filters: opts.filters
1098
+ filters: opts.filters,
1099
+ fetchEvents: opts.fetchEvents,
1100
+ sleep: opts.sleep,
1101
+ emptyBackoffMs: opts.intervalMs,
1102
+ signal,
1103
+ onBatch: async (events, ctx) => {
1104
+ if (events.length === 0 && ctx.reorgs.length === 0)
1105
+ return;
1106
+ await deliver({
1107
+ events,
1108
+ cursor: ctx.cursor,
1109
+ tip: ctx.tip,
1110
+ reorgs: [...ctx.reorgs]
1111
+ });
1112
+ }
1026
1113
  });
1027
- const checkpoint = envelope.next_cursor ?? cursor;
1028
- if (envelope.events.length > 0 || envelope.reorgs.length > 0) {
1029
- yield {
1030
- events: envelope.events,
1031
- cursor: checkpoint,
1032
- tip: envelope.tip,
1033
- reorgs: envelope.reorgs
1034
- };
1035
- }
1036
- const advanced = checkpoint !== null && checkpoint !== cursor;
1037
- cursor = checkpoint;
1038
- if (!advanced && envelope.events.length === 0) {
1039
- if (opts.signal?.aborted)
1040
- return;
1041
- await sleep(opts.intervalMs, opts.signal);
1042
- }
1114
+ assertNotStalled(result, signal);
1115
+ }, opts.signal);
1116
+ }
1117
+ function assertNotStalled(result, signal, bounds = {}) {
1118
+ if (signal.aborted)
1119
+ return;
1120
+ if (bounds.maxPages !== undefined && (bounds.pages ?? 0) >= bounds.maxPages) {
1121
+ return;
1122
+ }
1123
+ if (bounds.maxEmptyPolls !== undefined && result.emptyPolls >= bounds.maxEmptyPolls) {
1124
+ return;
1043
1125
  }
1126
+ throw new StreamsServerError(`Streams returned events at cursor ${result.cursor ?? "(start)"} but the cursor did not advance, so the stream stopped instead of re-reading the same page.`, 0, undefined, "CURSOR_STALLED");
1044
1127
  }
1045
1128
  async function* streamStreamsEvents(opts) {
1046
- const sleep = opts.sleep ?? defaultSleep;
1047
- const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
1048
- const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
1049
- const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
1050
- let cursor = opts.fromCursor ?? null;
1051
- let pages = 0;
1052
- let emptyPolls = 0;
1053
- while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
1054
- const envelope = await opts.fetchEvents({
1055
- cursor,
1056
- limit: opts.batchSize,
1129
+ yield* pullFromLoop(async (deliver, signal) => {
1130
+ const result = await consumeStreamsEvents({
1131
+ fromCursor: opts.fromCursor,
1132
+ batchSize: opts.batchSize,
1057
1133
  chain: opts.chain,
1058
1134
  types: opts.types,
1059
1135
  notTypes: opts.notTypes,
@@ -1063,29 +1139,27 @@ async function* streamStreamsEvents(opts) {
1063
1139
  assetIdentifier: opts.assetIdentifier,
1064
1140
  rune: opts.rune,
1065
1141
  address: opts.address,
1066
- filters: opts.filters
1142
+ filters: opts.filters,
1143
+ fetchEvents: opts.fetchEvents,
1144
+ sleep: opts.sleep,
1145
+ emptyBackoffMs: opts.emptyBackoffMs,
1146
+ maxPages: opts.maxPages,
1147
+ maxEmptyPolls: opts.maxEmptyPolls,
1148
+ signal,
1149
+ onBatch: async (events) => {
1150
+ for (const event of events) {
1151
+ if (signal.aborted)
1152
+ return;
1153
+ await deliver(event);
1154
+ }
1155
+ }
1067
1156
  });
1068
- pages++;
1069
- for (const event of envelope.events) {
1070
- if (opts.signal?.aborted)
1071
- return;
1072
- yield event;
1073
- }
1074
- const nextCursor = envelope.next_cursor;
1075
- if (nextCursor && nextCursor !== cursor) {
1076
- cursor = nextCursor;
1077
- emptyPolls = 0;
1078
- continue;
1079
- }
1080
- if (envelope.events.length === 0) {
1081
- emptyPolls++;
1082
- if (emptyPolls >= maxEmptyPolls || pages >= maxPages)
1083
- return;
1084
- await sleep(emptyBackoffMs, opts.signal);
1085
- continue;
1086
- }
1087
- return;
1088
- }
1157
+ assertNotStalled(result, signal, {
1158
+ maxPages: opts.maxPages,
1159
+ maxEmptyPolls: opts.maxEmptyPolls,
1160
+ pages: result.pages
1161
+ });
1162
+ }, opts.signal);
1089
1163
  }
1090
1164
 
1091
1165
  // src/index-api/consumer.ts
@@ -1878,8 +1952,14 @@ function subscribeStreamsEvents(opts) {
1878
1952
  const baseDelayMs = opts.reconnectDelayMs ?? params.reconnectDelayMs ?? 1000;
1879
1953
  const staleAfterMs = opts.staleAfterMs ?? params.staleAfterMs ?? SUBSCRIBE_DEFAULT_STALE_AFTER_MS;
1880
1954
  let attempt = 0;
1955
+ const emit = (state) => {
1956
+ try {
1957
+ params.onState?.(state);
1958
+ } catch {}
1959
+ };
1881
1960
  const run = async () => {
1882
1961
  while (!controller.signal.aborted) {
1962
+ emit("connecting");
1883
1963
  try {
1884
1964
  const url = `${opts.baseUrl}/v1/streams/events/stream${buildQuery({
1885
1965
  chain: params.chain === "bitcoin" ? "bitcoin" : undefined,
@@ -1901,6 +1981,7 @@ function subscribeStreamsEvents(opts) {
1901
1981
  fetchImpl: opts.fetchImpl,
1902
1982
  staleAfterMs,
1903
1983
  mapError: mapStreamsError,
1984
+ onOpen: () => emit("open"),
1904
1985
  onFrame: async (frame) => {
1905
1986
  attempt = 0;
1906
1987
  if (frame.event === "ping" || !frame.data)
@@ -1929,6 +2010,8 @@ function subscribeStreamsEvents(opts) {
1929
2010
  cursor = parsed.event.cursor ?? cursor;
1930
2011
  }
1931
2012
  });
2013
+ if (!controller.signal.aborted)
2014
+ emit("reconnecting");
1932
2015
  await sleep(reconnectDelay(attempt, baseDelayMs, undefined, opts.random), controller.signal);
1933
2016
  attempt += 1;
1934
2017
  } catch (err) {
@@ -1937,13 +2020,14 @@ function subscribeStreamsEvents(opts) {
1937
2020
  params.onError?.(err);
1938
2021
  if (isTerminal(err))
1939
2022
  throw err;
2023
+ emit("reconnecting");
1940
2024
  const retryAfterSeconds = err.retryAfterSeconds;
1941
2025
  await sleep(reconnectDelay(attempt, baseDelayMs, retryAfterSeconds, opts.random), controller.signal);
1942
2026
  attempt += 1;
1943
2027
  }
1944
2028
  }
1945
2029
  };
1946
- const done = run();
2030
+ const done = run().finally(() => emit("closed"));
1947
2031
  done.catch(() => {});
1948
2032
  const unsubscribe = () => controller.abort();
1949
2033
  return Object.assign(unsubscribe, { done });
@@ -1961,6 +2045,7 @@ async function readSse(opts) {
1961
2045
  if (!res.body) {
1962
2046
  throw new StreamsServerError("Streams SSE response has no body.", 0);
1963
2047
  }
2048
+ opts.onOpen?.();
1964
2049
  for await (const frame of parseSseFrames(res.body, opts.signal, opts.staleAfterMs)) {
1965
2050
  await opts.onFrame(frame);
1966
2051
  }
@@ -2036,6 +2121,33 @@ function parseFrame(raw) {
2036
2121
  `) : undefined };
2037
2122
  }
2038
2123
 
2124
+ // src/streams/timeout-fetch.ts
2125
+ var STREAMS_CONNECT_TIMEOUT_MS = 30000;
2126
+ function withConnectTimeout(fetchImpl, timeoutMs) {
2127
+ if (!(timeoutMs > 0) || !Number.isFinite(timeoutMs))
2128
+ return fetchImpl;
2129
+ return async (input, init) => {
2130
+ const callerSignal = init?.signal ?? undefined;
2131
+ const timeout = new AbortController;
2132
+ let timedOut = false;
2133
+ const timer = setTimeout(() => {
2134
+ timedOut = true;
2135
+ timeout.abort();
2136
+ }, timeoutMs);
2137
+ const signal = callerSignal ? AbortSignal.any([callerSignal, timeout.signal]) : timeout.signal;
2138
+ try {
2139
+ return await fetchImpl(input, { ...init, signal });
2140
+ } catch (err) {
2141
+ if (timedOut && !callerSignal?.aborted) {
2142
+ throw new StreamsServerError(`No response headers within ${timeoutMs}ms. Retryable.`, 0, undefined, "REQUEST_TIMEOUT");
2143
+ }
2144
+ throw err;
2145
+ } finally {
2146
+ clearTimeout(timer);
2147
+ }
2148
+ };
2149
+ }
2150
+
2039
2151
  // src/streams/client.ts
2040
2152
  function cursorTuple(cursor) {
2041
2153
  if (!cursor)
@@ -2081,7 +2193,7 @@ function createStreamsClient(options) {
2081
2193
  "x-sl-origin": origin,
2082
2194
  ...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
2083
2195
  });
2084
- const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
2196
+ const fetchImpl = withConnectTimeout(options.fetchImpl ?? ((input, init) => fetch(input, init)), options.connectTimeoutMs ?? STREAMS_CONNECT_TIMEOUT_MS);
2085
2197
  const verify = options.verify;
2086
2198
  const verifyMode = verify === false ? "off" : verify === undefined ? "lenient" : "strict";
2087
2199
  if (verify === true && baseUrl.startsWith("http:") && !isLoopbackUrl(baseUrl)) {
@@ -2856,6 +2968,7 @@ import {
2856
2968
  SLOW_TIMEOUT_RATIO,
2857
2969
  SLOW_WINDOW
2858
2970
  } from "@secondlayer/shared/insights/thresholds";
2971
+ import { pauseReasonOf } from "@secondlayer/shared/webhooks/health";
2859
2972
  function isSuccessDelivery(row) {
2860
2973
  return row.statusCode !== null && row.statusCode >= 200 && row.statusCode < 300;
2861
2974
  }
@@ -3142,16 +3255,17 @@ function buildDoctorReport(input) {
3142
3255
  };
3143
3256
  }
3144
3257
  function buildListIssue(webhook) {
3145
- if (webhook.status !== "paused")
3258
+ const reason = pauseReasonOf(webhook);
3259
+ if (reason === null)
3146
3260
  return null;
3147
- if (webhook.circuitOpenedAt) {
3261
+ if (reason === "circuit") {
3148
3262
  return {
3149
3263
  code: "circuit",
3150
3264
  severity: "bad",
3151
3265
  evidence: [
3152
3266
  {
3153
3267
  label: "circuit opened",
3154
- value: formatShortDate(webhook.circuitOpenedAt)
3268
+ value: webhook.circuitOpenedAt ? formatShortDate(webhook.circuitOpenedAt) : "unknown"
3155
3269
  },
3156
3270
  {
3157
3271
  label: "last success",
@@ -3410,8 +3524,10 @@ export {
3410
3524
  isSuccessDelivery,
3411
3525
  parseRetryAfter,
3412
3526
  resolveAccountKey,
3527
+ resolveAccountUrl,
3413
3528
  resolveApiKey,
3414
3529
  resolveBaseUrl,
3530
+ resolveIdentity,
3415
3531
  shutdownSignal,
3416
3532
  toJsonSafe,
3417
3533
  trigger,
@@ -3421,5 +3537,5 @@ export {
3421
3537
  verifyWebhookSignature
3422
3538
  };
3423
3539
 
3424
- //# debugId=F50384CF029DB60E64756E2164756E21
3540
+ //# debugId=7941E39982D460D764756E2164756E21
3425
3541
  //# sourceMappingURL=index.js.map