@secondlayer/sdk 10.1.1 → 10.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -234,6 +234,36 @@ await streams.events.replay({
234
234
  });
235
235
  ```
236
236
 
237
+ Archive.
238
+
239
+ Signed canonical partitions (`blocks` / `transactions` / `events`), distinct
240
+ from Streams dumps. `latest` follows `latest.json` and verifies the ed25519
241
+ manifest (default on). `quote` and `fetch` need an account key (`sk-sl_*`)
242
+ against `api.secondlayer.tools`, not the instance `baseUrl`. `download`
243
+ returns sha256-verified bytes; it does not decode parquet. Verify, repair,
244
+ and bootstrap remain CLI.
245
+
246
+ ```typescript
247
+ const sl = new SecondLayer({
248
+ apiKey: process.env.SL_API_KEY, // account key sk-sl_* for quote/fetch/credits
249
+ });
250
+
251
+ const ref = await sl.archive.latest();
252
+ const partitions = sl.archive.partitions(ref, { dataset: "blocks" });
253
+ const quote = await sl.archive.quote({
254
+ paths: partitions.map((p) => p.path),
255
+ flow: "bootstrap",
256
+ });
257
+ const fetched = await sl.archive.fetch({
258
+ paths: partitions.map((p) => p.path),
259
+ flow: "bootstrap",
260
+ });
261
+ for (const item of fetched.urls) {
262
+ const partition = partitions.find((p) => p.path === item.path)!;
263
+ const bytes = await sl.archive.download(partition, { url: item.url });
264
+ }
265
+ ```
266
+
237
267
  Decoder helper.
238
268
 
239
269
  ```typescript
package/dist/index.d.ts CHANGED
@@ -14,6 +14,12 @@ interface SecondLayerOptions {
14
14
  * Required for `streams.dumps.*`; without it the dumps client falls back to
15
15
  * its built-in default. */
16
16
  dumpsBaseUrl?: string;
17
+ /** Public base URL for the signed canonical archive tree. Defaults to
18
+ * `https://archive.secondlayer.tools`. Reaches `sl.archive`. */
19
+ archiveBaseUrl?: string;
20
+ /** Credits and fetch-gate API. Defaults to `https://api.secondlayer.tools`,
21
+ * not `baseUrl`. Reaches `sl.archive` quote/fetch/credits. */
22
+ archiveOpsUrl?: string;
17
23
  /** Deploy origin label sent as `x-sl-origin` (telemetry). Defaults to `cli`. */
18
24
  origin?: "cli" | "mcp" | "session";
19
25
  /** Check the ed25519 signature on every Streams read. Omit for lenient
@@ -238,7 +244,156 @@ declare class Subgraphs extends BaseClient {
238
244
  private createTableClient;
239
245
  }
240
246
  import { InferSubgraphClient as InferSubgraphClient2 } from "@secondlayer/subgraphs";
247
+ import { InstanceDiagnosis as InstanceDiagnosis2 } from "@secondlayer/shared/archive/instance-diagnosis";
241
248
  import { SubgraphSummary as SubgraphSummary2 } from "@secondlayer/shared/schemas";
249
+ import { InstanceDiagnosis, PublicStatus } from "@secondlayer/shared/archive/instance-diagnosis";
250
+ /** Structural `/public/status` payload. Extra fields are ignored by diagnosis. */
251
+ type InstanceStatus = PublicStatus;
252
+ type InstanceClient = {
253
+ status(): Promise<InstanceStatus>;
254
+ diagnose(): Promise<InstanceDiagnosis>;
255
+ };
256
+ type ArchiveVerifyInput = {
257
+ against: string;
258
+ target?: string;
259
+ fromBlock?: number;
260
+ toBlock?: number;
261
+ insecure?: boolean;
262
+ publicKeyPem?: string;
263
+ };
264
+ type ArchiveVerifyRangeStatus = "match" | "digest-mismatch" | "count-mismatch" | "missing";
265
+ type ArchiveVerifyResult = {
266
+ status: "clean" | "diverged" | "unanchored";
267
+ target: string;
268
+ against: string;
269
+ signature: {
270
+ verified: boolean;
271
+ reason?: string;
272
+ };
273
+ coverage?: {
274
+ from_block: number;
275
+ to_block: number;
276
+ };
277
+ ranges: Array<{
278
+ dataset: string;
279
+ from_block: number;
280
+ to_block: number;
281
+ status: ArchiveVerifyRangeStatus;
282
+ expected_digest: string | null;
283
+ actual_digest: string | null;
284
+ }>;
285
+ reason?: string;
286
+ };
287
+ import { RangeDigest } from "@secondlayer/shared/archive/range-digest";
288
+ type ArchiveDataset = "blocks" | "transactions" | "events";
289
+ type ArchiveFlow = "bootstrap" | "repair";
290
+ type ArchivePartition = {
291
+ dataset: string;
292
+ from_block: number;
293
+ to_block: number;
294
+ path: string;
295
+ row_count: number;
296
+ byte_size: number;
297
+ sha256: string;
298
+ };
299
+ type ArchiveManifest = {
300
+ network?: string;
301
+ coverage?: {
302
+ from_block: number;
303
+ to_block: number;
304
+ };
305
+ partition_size_blocks?: number;
306
+ range_digests?: RangeDigest[];
307
+ partitions?: ArchivePartition[];
308
+ signature?: string;
309
+ key_id?: string;
310
+ [key: string]: unknown;
311
+ };
312
+ type LoadedArchive = {
313
+ manifest: ArchiveManifest;
314
+ origin: string;
315
+ root: string;
316
+ isRemote: boolean;
317
+ signature: {
318
+ verified: boolean;
319
+ reason?: string;
320
+ };
321
+ };
322
+ type ArchiveQuote = {
323
+ partitions: number;
324
+ bundles: number;
325
+ usdMicros: number;
326
+ usd: string;
327
+ freeAllowanceAppliedMicros: number;
328
+ allowanceRemainingBundles: number;
329
+ balanceUsdMicros: number;
330
+ sufficient: boolean;
331
+ };
332
+ type ArchiveFetchItem = {
333
+ path: string;
334
+ url: string;
335
+ expiresAt: string;
336
+ chargedUsdMicros: number;
337
+ };
338
+ type ArchiveFetchResult = {
339
+ urls: ArchiveFetchItem[];
340
+ chargedTotalUsdMicros: number;
341
+ balanceAfterUsdMicros: number;
342
+ };
343
+ type ArchiveCreditsBalance = {
344
+ creditsUsdMicros: string;
345
+ refill: {
346
+ belowUsd: number | null;
347
+ packUsd: number | null;
348
+ lastAt: string | null;
349
+ };
350
+ };
351
+ type ArchiveLoadOptions = {
352
+ insecure?: boolean;
353
+ };
354
+ type ArchiveClient = {
355
+ latest(against?: string, opts?: ArchiveLoadOptions): Promise<LoadedArchive>;
356
+ load(against: string, opts?: ArchiveLoadOptions): Promise<LoadedArchive>;
357
+ status(): Promise<unknown>;
358
+ partitions(ref: LoadedArchive, filter?: {
359
+ dataset?: ArchiveDataset;
360
+ fromBlock?: number;
361
+ toBlock?: number;
362
+ }): ArchivePartition[];
363
+ quote(input: {
364
+ paths: string[];
365
+ flow: ArchiveFlow;
366
+ }): Promise<ArchiveQuote>;
367
+ fetch(input: {
368
+ paths: string[];
369
+ flow: ArchiveFlow;
370
+ }): Promise<ArchiveFetchResult>;
371
+ download(partition: ArchivePartition, opts?: {
372
+ url?: string;
373
+ }): Promise<Uint8Array>;
374
+ credits: {
375
+ balance(): Promise<ArchiveCreditsBalance>;
376
+ checkout(input: {
377
+ email: string;
378
+ pack: 10 | 25 | 50 | 100;
379
+ }): Promise<{
380
+ url: string;
381
+ }>;
382
+ refill(input: {
383
+ belowUsd: number;
384
+ packUsd: 10 | 25 | 50 | 100;
385
+ } | {
386
+ off: true;
387
+ }): Promise<{
388
+ belowUsd: number | null;
389
+ packUsd: number | null;
390
+ }>;
391
+ };
392
+ };
393
+ /** Hosted archive client plus instance `verify`. `status()` is still the public archive tree. */
394
+ type SecondLayerArchive = ArchiveClient & {
395
+ verify(input: ArchiveVerifyInput): Promise<ArchiveVerifyResult>;
396
+ };
242
397
  /**
243
398
  * Typed client for the contract-discovery API (`GET /v1/contracts`).
244
399
  *
@@ -2501,6 +2656,8 @@ interface ContextSnapshot {
2501
2656
  }>;
2502
2657
  /** In-flight reindex operations (bounded to subgraphs reporting `reindexing`). */
2503
2658
  activeOperations: ContextField<ActiveSubgraphOperation[]>;
2659
+ /** Decoder lag / empty-index from `GET /public/status`. */
2660
+ instance: ContextField<InstanceDiagnosis2>;
2504
2661
  }
2505
2662
  /** Fold one read into a {@link ContextField}: the value, or `null` with the
2506
2663
  * failure described. Exported for callers that assemble their own snapshot
@@ -2512,6 +2669,8 @@ declare class SecondLayer extends BaseClient {
2512
2669
  readonly contracts: Contracts;
2513
2670
  readonly subgraphs: Subgraphs;
2514
2671
  readonly subscriptions: Subscriptions;
2672
+ readonly archive: SecondLayerArchive;
2673
+ readonly instance: InstanceClient;
2515
2674
  constructor(options?: Partial<SecondLayerOptions>);
2516
2675
  /**
2517
2676
  * Up to 10 public reads in one round trip (`POST /v1/batch`). Each item
@@ -2705,6 +2864,23 @@ declare class RateLimitError extends ApiError {
2705
2864
  declare class ValidationError extends ApiError {
2706
2865
  constructor(message: string, status: number, body?: unknown, code?: string);
2707
2866
  }
2867
+ /** Thrown when an archive manifest signature is missing or does not verify. */
2868
+ declare class ArchiveSignatureError extends SecondLayerError {
2869
+ constructor(message?: string);
2870
+ }
2871
+ /** Thrown on a 401 from the archive ops host (quote/fetch/credits). */
2872
+ declare class ArchiveAuthError extends SecondLayerError {
2873
+ constructor(message?: string);
2874
+ }
2875
+ /** Thrown on a 402 from archive fetch — prepaid credits do not cover the quote. */
2876
+ declare class InsufficientArchiveCreditsError extends SecondLayerError {
2877
+ shortfallUsdMicros?: number;
2878
+ constructor(message?: string, shortfallUsdMicros?: number);
2879
+ }
2880
+ /** Thrown on a 503 when the archive fetch gate is unconfigured. */
2881
+ declare class ArchiveGateNotConfiguredError extends SecondLayerError {
2882
+ constructor(message?: string);
2883
+ }
2708
2884
  /** Parse a `Retry-After` header: delta-seconds or an HTTP-date. */
2709
2885
  declare function parseRetryAfter(value?: string | null): number | undefined;
2710
2886
  /** Thrown on a 5xx from the Streams API, and on a failed signing-key fetch.
@@ -2755,6 +2931,7 @@ declare const Cursor: {
2755
2931
  eventIndex: number;
2756
2932
  };
2757
2933
  };
2934
+ import { InstanceDiagnosis as InstanceDiagnosis3, InstanceIssue, InstanceState, PublicStatus as PublicStatus2 } from "@secondlayer/shared/archive/instance-diagnosis";
2758
2935
  import { SubgraphAgentSchema as SubgraphAgentSchema3, SubgraphSpecFormat as SubgraphSpecFormat2, SubgraphSpecOptions as SubgraphSpecOptions3 } from "@secondlayer/shared/subgraphs/spec";
2759
2936
  /**
2760
2937
  * The two pieces every "deploy a consumer" guide leaves out, packaged:
@@ -2797,6 +2974,15 @@ declare function consumerHealth(options?: {
2797
2974
  declare function shutdownSignal(options?: {
2798
2975
  signals?: readonly ("SIGTERM" | "SIGINT")[];
2799
2976
  }): AbortSignal;
2977
+ type CreateArchiveClientOptions = {
2978
+ apiKey?: string;
2979
+ fetchImpl?: FetchLike;
2980
+ archiveBaseUrl?: string;
2981
+ archiveOpsUrl?: string;
2982
+ verifyManifest?: boolean;
2983
+ publicKeyPem?: string;
2984
+ };
2985
+ declare function createArchiveClient(options?: CreateArchiveClientOptions): ArchiveClient;
2800
2986
  import { ChainWebhookDelivery } from "@secondlayer/shared";
2801
2987
  import { StandardWebhooksHeaders } from "@secondlayer/shared/crypto/standard-webhooks";
2802
2988
  import { StandardWebhooksHeaders as StandardWebhooksHeaders2, verify } from "@secondlayer/shared/crypto/standard-webhooks";
@@ -2955,4 +3141,4 @@ declare function verifySecondlayerSignature(rawBody: string, headers: WebhookHea
2955
3141
  declare function decodeChainWebhook(rawBody: string): ChainWebhookDelivery;
2956
3142
  import { RewardSet as RewardSet2 } from "@secondlayer/shared/node/consensus";
2957
3143
  import { decodeClarityValue, toJsonSafe } from "@secondlayer/shared/streams-rows";
2958
- export { verifyWebhookSignature, verifyTransactionProof, verify as verifyStandardWebhooksHeaders, verifySecondlayerSignature, trigger, toJsonSafe, shutdownSignal, resolveBaseUrl, resolveApiKey, 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, decode, createStreamsClient, contextField, consumerHealth, consumeIndexFeed, WithSinkTx, WebhookHeaderInput, WalkOptions, ValidationError, UpdateSubscriptionRequest2 as UpdateSubscriptionRequest, 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, StreamsTip, StreamsSubscription, 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, SinkTx, SecondLayerOptions, SecondLayerErrorOptions, SecondLayerError, SecondLayer, SbtcWithdrawalsWalkParams, SbtcWithdrawalsListParams, SbtcWithdrawalsEnvelope, SbtcWithdrawalSweptConfirmedEvent, SbtcWithdrawalStatus, SbtcWithdrawalEvent, SbtcWithdrawalEnvelope, SbtcSummaryEnvelope, SbtcResource, SbtcEventsWalkParams, SbtcEventsListParams, SbtcEventsEnvelope, SbtcEventsConsumeParams, SbtcEventTopic2 as SbtcEventTopic, SbtcDepositsWalkParams, SbtcDepositsListParams, SbtcDepositsEnvelope, SbtcDepositsConsumeParams, SbtcDepositEvent, SbtcDepositEnvelope, RotateSecretResponse2 as RotateSecretResponse, RewardSet2 as RewardSet, RequestOptions, ReplayResult2 as ReplayResult, RateLimitError, PrintSchemaResponse, PoxResource, PoxCyclesWalkParams, PoxCyclesListParams, PoxCyclesEnvelope, PoxCycleEnvelope, Pox5Resource, Pox5EventsWalkParams, Pox5EventsListParams, Pox5EventsEnvelope, NftTransfersWalkParams, NftTransfersResource, NftTransfersListParams, NftTransfersEnvelope, NftTransferPayload2 as NftTransferPayload, NftTransferEvent, NftTransfer, MempoolWalkParams, MempoolTransactionEnvelope, MempoolListParams, MempoolEnvelope, LOCAL_API_URL, 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, IndexEventFields, IndexEvent, IndexDiscovery, IndexContractCall, IndexConsumeOptions, IndexCanonicalBlock, IndexBlock, IndexAlwaysFields, Index, INDEX_MAX_PAGE_SIZE, FtTransfersWalkParams, FtTransfersResource, FtTransfersListParams, FtTransfersEnvelope, FtTransferPayload2 as 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_REQUEST_TIMEOUT_MS, Cursor, CreateSubscriptionResponse2 as CreateSubscriptionResponse, CreateSubscriptionRequest2 as CreateSubscriptionRequest, ContractsListParams, ContractsEnvelope, Contracts, ContractSummary, ContractConformance, ContractCallsWalkParams, ContractCallsListParams, ContractCallsEnvelope, ContractCallsConsumeParams, ContextSnapshot, ContextFieldError, ContextField, ContextAccount, ConsumerSink, ConsumerHealth, 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, CREDENTIAL_ENV_VARS, BlocksWalkParams, BlocksListParams, BlocksEnvelope, BlockEnvelope, AuthError, ApiError, ActiveSubgraphOperation };
3144
+ export { verifyWebhookSignature, verifyTransactionProof, verify as verifyStandardWebhooksHeaders, verifySecondlayerSignature, trigger, toJsonSafe, shutdownSignal, resolveBaseUrl, resolveApiKey, 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, decode, createStreamsClient, createArchiveClient, contextField, consumerHealth, consumeIndexFeed, WithSinkTx, WebhookHeaderInput, WalkOptions, ValidationError, UpdateSubscriptionRequest2 as UpdateSubscriptionRequest, 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, StreamsTip, StreamsSubscription, 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, SinkTx, SecondLayerOptions, SecondLayerErrorOptions, SecondLayerError, SecondLayerArchive, SecondLayer, SbtcWithdrawalsWalkParams, SbtcWithdrawalsListParams, SbtcWithdrawalsEnvelope, SbtcWithdrawalSweptConfirmedEvent, SbtcWithdrawalStatus, SbtcWithdrawalEvent, SbtcWithdrawalEnvelope, SbtcSummaryEnvelope, SbtcResource, SbtcEventsWalkParams, SbtcEventsListParams, SbtcEventsEnvelope, SbtcEventsConsumeParams, SbtcEventTopic2 as SbtcEventTopic, SbtcDepositsWalkParams, SbtcDepositsListParams, SbtcDepositsEnvelope, SbtcDepositsConsumeParams, SbtcDepositEvent, SbtcDepositEnvelope, RotateSecretResponse2 as RotateSecretResponse, RewardSet2 as RewardSet, RequestOptions, ReplayResult2 as ReplayResult, RateLimitError, PublicStatus2 as PublicStatus, PrintSchemaResponse, PoxResource, PoxCyclesWalkParams, PoxCyclesListParams, PoxCyclesEnvelope, PoxCycleEnvelope, Pox5Resource, Pox5EventsWalkParams, Pox5EventsListParams, Pox5EventsEnvelope, NftTransfersWalkParams, NftTransfersResource, NftTransfersListParams, NftTransfersEnvelope, NftTransferPayload2 as NftTransferPayload, NftTransferEvent, NftTransfer, MempoolWalkParams, MempoolTransactionEnvelope, MempoolListParams, MempoolEnvelope, LoadedArchive, LOCAL_API_URL, InsufficientArchiveCreditsError, InstanceStatus, InstanceState, InstanceIssue, InstanceDiagnosis3 as InstanceDiagnosis, InstanceClient, 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, IndexEventFields, IndexEvent, IndexDiscovery, IndexContractCall, IndexConsumeOptions, IndexCanonicalBlock, IndexBlock, IndexAlwaysFields, Index, INDEX_MAX_PAGE_SIZE, FtTransfersWalkParams, FtTransfersResource, FtTransfersListParams, FtTransfersEnvelope, FtTransferPayload2 as 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_REQUEST_TIMEOUT_MS, Cursor, CreateSubscriptionResponse2 as CreateSubscriptionResponse, CreateSubscriptionRequest2 as CreateSubscriptionRequest, CreateArchiveClientOptions, ContractsListParams, ContractsEnvelope, Contracts, ContractSummary, ContractConformance, ContractCallsWalkParams, ContractCallsListParams, ContractCallsEnvelope, ContractCallsConsumeParams, ContextSnapshot, ContextFieldError, ContextField, ContextAccount, ConsumerSink, ConsumerHealth, 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, CREDENTIAL_ENV_VARS, BlocksWalkParams, BlocksListParams, BlocksEnvelope, BlockEnvelope, AuthError, ArchiveVerifyResult, ArchiveVerifyRangeStatus, ArchiveVerifyInput, ArchiveSignatureError, ArchiveQuote, ArchivePartition, ArchiveManifest, ArchiveLoadOptions, ArchiveGateNotConfiguredError, ArchiveFlow, ArchiveFetchResult, ArchiveFetchItem, ArchiveDataset, ArchiveCreditsBalance, ArchiveClient, ArchiveAuthError, ApiError, ActiveSubgraphOperation };
package/dist/index.js CHANGED
@@ -110,6 +110,39 @@ class ValidationError extends ApiError {
110
110
  this.name = "ValidationError";
111
111
  }
112
112
  }
113
+
114
+ class ArchiveSignatureError extends SecondLayerError {
115
+ constructor(message = "Archive manifest signature is missing or invalid.") {
116
+ super(message, { code: "ARCHIVE_SIGNATURE", retryable: false });
117
+ this.name = "ArchiveSignatureError";
118
+ }
119
+ }
120
+
121
+ class ArchiveAuthError extends SecondLayerError {
122
+ constructor(message = "Archive ops request was not authenticated.") {
123
+ super(message, { code: "ARCHIVE_AUTH", retryable: false });
124
+ this.name = "ArchiveAuthError";
125
+ }
126
+ }
127
+
128
+ class InsufficientArchiveCreditsError extends SecondLayerError {
129
+ shortfallUsdMicros;
130
+ constructor(message = "Insufficient archive credits.", shortfallUsdMicros) {
131
+ super(message, {
132
+ code: "INSUFFICIENT_ARCHIVE_CREDITS",
133
+ retryable: false
134
+ });
135
+ this.name = "InsufficientArchiveCreditsError";
136
+ this.shortfallUsdMicros = shortfallUsdMicros;
137
+ }
138
+ }
139
+
140
+ class ArchiveGateNotConfiguredError extends SecondLayerError {
141
+ constructor(message = "The archive gate is not configured on the server.") {
142
+ super(message, { code: "ARCHIVE_GATE_NOT_CONFIGURED", retryable: false });
143
+ this.name = "ArchiveGateNotConfiguredError";
144
+ }
145
+ }
113
146
  function parseRetryAfter(value) {
114
147
  if (!value)
115
148
  return;
@@ -814,6 +847,239 @@ class Subgraphs extends BaseClient {
814
847
  };
815
848
  }
816
849
  }
850
+ // src/archive/client.ts
851
+ import { createHash } from "node:crypto";
852
+ import {
853
+ checkSignature,
854
+ loadReference
855
+ } from "@secondlayer/shared/archive/reference";
856
+ var OFFICIAL_ARCHIVE_HOST = "archive.secondlayer.tools";
857
+ var DEFAULT_ARCHIVE_BASE_URL = "https://archive.secondlayer.tools";
858
+ var DEFAULT_ARCHIVE_OPS_URL = "https://api.secondlayer.tools";
859
+ var MAX_FETCH_BATCH = 64;
860
+ function quoteFromBody(body) {
861
+ return {
862
+ partitions: body.partitions,
863
+ bundles: body.bundles,
864
+ usdMicros: body.usd_micros,
865
+ usd: body.usd,
866
+ freeAllowanceAppliedMicros: body.free_allowance_applied_micros,
867
+ allowanceRemainingBundles: body.allowance_remaining_bundles,
868
+ balanceUsdMicros: body.balance_usd_micros,
869
+ sufficient: body.sufficient
870
+ };
871
+ }
872
+ function stripSlash(url) {
873
+ return url.replace(/\/+$/, "");
874
+ }
875
+ function createArchiveClient(options = {}) {
876
+ const apiKey = resolveApiKey(options.apiKey);
877
+ const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
878
+ const archiveBaseUrl = stripSlash(options.archiveBaseUrl ?? DEFAULT_ARCHIVE_BASE_URL);
879
+ const archiveOpsUrl = stripSlash(options.archiveOpsUrl ?? DEFAULT_ARCHIVE_OPS_URL);
880
+ const verifyManifest = options.verifyManifest ?? true;
881
+ const pinnedPem = options.publicKeyPem;
882
+ let keyPromise = null;
883
+ async function fetchSigningKey() {
884
+ if (pinnedPem)
885
+ return pinnedPem;
886
+ if (keyPromise)
887
+ return keyPromise;
888
+ const pending = (async () => {
889
+ const res = await fetchImpl(`${archiveOpsUrl}/public/streams/signing-key`);
890
+ if (!res.ok) {
891
+ throw new ArchiveSignatureError(`Could not fetch archive signing key (${res.status}).`);
892
+ }
893
+ const body = await res.json();
894
+ if (typeof body.public_key_pem !== "string") {
895
+ throw new ArchiveSignatureError("Signing key response missing key.");
896
+ }
897
+ return body.public_key_pem;
898
+ })();
899
+ keyPromise = pending;
900
+ pending.catch(() => {
901
+ if (keyPromise === pending)
902
+ keyPromise = null;
903
+ });
904
+ return pending;
905
+ }
906
+ async function throwOpsError(response) {
907
+ const envelope = parseErrorEnvelope(await response.text());
908
+ if (response.status === 401) {
909
+ throw new ArchiveAuthError(envelope.message ?? "Archive ops request was not authenticated.");
910
+ }
911
+ if (response.status === 402) {
912
+ const raw = envelope.body && typeof envelope.body === "object" && "shortfall_usd_micros" in envelope.body ? Number(envelope.body.shortfall_usd_micros) : undefined;
913
+ throw new InsufficientArchiveCreditsError(envelope.message ?? "Insufficient archive credits.", Number.isFinite(raw) ? raw : undefined);
914
+ }
915
+ if (response.status === 503) {
916
+ throw new ArchiveGateNotConfiguredError(envelope.message ?? "The archive gate is not configured on the server.");
917
+ }
918
+ throw new ApiError(response.status, envelope.message ?? `Archive ops returned ${response.status}.`, envelope.body, envelope.code);
919
+ }
920
+ async function opsRequest(method, path, body, authed = true) {
921
+ const headers = {
922
+ "Content-Type": "application/json"
923
+ };
924
+ if (authed && apiKey)
925
+ headers.Authorization = `Bearer ${apiKey}`;
926
+ const response = await fetchImpl(`${archiveOpsUrl}${path}`, {
927
+ method,
928
+ headers,
929
+ body: body !== undefined ? JSON.stringify(body) : undefined
930
+ });
931
+ if (!response.ok)
932
+ await throwOpsError(response);
933
+ return await response.json();
934
+ }
935
+ async function load(against, opts = {}) {
936
+ if (!/^https?:\/\//i.test(against)) {
937
+ throw new ValidationError("archive.load() accepts only http(s) URLs; local paths stay on the CLI.", 400);
938
+ }
939
+ const insecure = opts.insecure === true;
940
+ const publicKeyPem = pinnedPem ?? (verifyManifest && !insecure ? await fetchSigningKey() : undefined);
941
+ const ref = await loadReference(against, {
942
+ publicKeyPem,
943
+ fetchImpl
944
+ });
945
+ const signature = checkSignature(ref.manifest, publicKeyPem, insecure);
946
+ if (verifyManifest && !insecure && !signature.verified) {
947
+ throw new ArchiveSignatureError(signature.reason ?? "Archive manifest signature is missing or invalid.");
948
+ }
949
+ return { ...ref, signature };
950
+ }
951
+ async function latest(against, opts = {}) {
952
+ return load(against ?? `${archiveBaseUrl}/latest.json`, opts);
953
+ }
954
+ async function status() {
955
+ const response = await fetchImpl(`${archiveBaseUrl}/status.json`);
956
+ if (!response.ok) {
957
+ throw new ApiError(response.status, `Could not fetch archive status (${response.status}).`);
958
+ }
959
+ return response.json();
960
+ }
961
+ function partitions(ref, filter) {
962
+ let list = ref.manifest.partitions ?? [];
963
+ if (!filter)
964
+ return list;
965
+ if (filter.dataset) {
966
+ list = list.filter((p) => p.dataset === filter.dataset);
967
+ }
968
+ const fromBlock = filter.fromBlock;
969
+ if (fromBlock !== undefined) {
970
+ list = list.filter((p) => p.to_block >= fromBlock);
971
+ }
972
+ const toBlock = filter.toBlock;
973
+ if (toBlock !== undefined) {
974
+ list = list.filter((p) => p.from_block <= toBlock);
975
+ }
976
+ return list;
977
+ }
978
+ async function quote(input) {
979
+ const body = await opsRequest("POST", "/api/archive/quote", { paths: input.paths, flow: input.flow });
980
+ return quoteFromBody(body);
981
+ }
982
+ async function fetchPartitions(input) {
983
+ const urls = [];
984
+ let chargedTotalUsdMicros = 0;
985
+ let balanceAfterUsdMicros = 0;
986
+ for (let i = 0;i < input.paths.length; i += MAX_FETCH_BATCH) {
987
+ const chunk = input.paths.slice(i, i + MAX_FETCH_BATCH);
988
+ const body = await opsRequest("POST", "/api/archive/fetch", { paths: chunk, flow: input.flow });
989
+ for (const item of body.urls) {
990
+ urls.push({
991
+ path: item.path,
992
+ url: item.url,
993
+ expiresAt: item.expires_at,
994
+ chargedUsdMicros: item.charged_usd_micros
995
+ });
996
+ }
997
+ chargedTotalUsdMicros += body.charged_total_usd_micros;
998
+ balanceAfterUsdMicros = body.balance_after_usd_micros;
999
+ }
1000
+ return { urls, chargedTotalUsdMicros, balanceAfterUsdMicros };
1001
+ }
1002
+ async function download(partition, opts) {
1003
+ let url = opts?.url;
1004
+ if (!url) {
1005
+ let official = false;
1006
+ try {
1007
+ official = new URL(archiveBaseUrl).hostname === OFFICIAL_ARCHIVE_HOST;
1008
+ } catch {
1009
+ official = false;
1010
+ }
1011
+ if (official) {
1012
+ throw new ValidationError("Official archive host requires a presigned URL from archive.fetch() before download.", 400);
1013
+ }
1014
+ url = `${archiveBaseUrl}/${partition.path.replace(/^\/+/, "")}`;
1015
+ }
1016
+ const response = await fetchImpl(url);
1017
+ if (!response.ok) {
1018
+ throw new ApiError(response.status, `Could not download ${partition.path} (${response.status}).`);
1019
+ }
1020
+ const bytes = new Uint8Array(await response.arrayBuffer());
1021
+ const digest = createHash("sha256").update(bytes).digest("hex");
1022
+ if (digest !== partition.sha256) {
1023
+ throw new ArchiveSignatureError(`${partition.path} sha256 mismatch (expected ${partition.sha256}, got ${digest}).`);
1024
+ }
1025
+ return bytes;
1026
+ }
1027
+ return {
1028
+ latest,
1029
+ load,
1030
+ status,
1031
+ partitions,
1032
+ quote,
1033
+ fetch: fetchPartitions,
1034
+ download,
1035
+ credits: {
1036
+ async balance() {
1037
+ const body = await opsRequest("GET", "/api/billing/status");
1038
+ return {
1039
+ creditsUsdMicros: body.creditsUsdMicros,
1040
+ refill: body.refill
1041
+ };
1042
+ },
1043
+ async checkout(input) {
1044
+ const body = await opsRequest("POST", "/api/public/credits/checkout", { email: input.email, amount: input.pack }, false);
1045
+ return { url: body.url };
1046
+ },
1047
+ async refill(input) {
1048
+ const payload = "off" in input && input.off ? { belowUsd: null } : {
1049
+ belowUsd: input.belowUsd,
1050
+ packUsd: input.packUsd
1051
+ };
1052
+ const body = await opsRequest("POST", "/api/billing/refill", payload);
1053
+ return { belowUsd: body.belowUsd, packUsd: body.packUsd };
1054
+ }
1055
+ }
1056
+ };
1057
+ }
1058
+
1059
+ // src/archive/instance.ts
1060
+ import {
1061
+ diagnoseInstanceStatus
1062
+ } from "@secondlayer/shared/archive/instance-diagnosis";
1063
+ function createArchiveVerify(request) {
1064
+ return (input) => request("POST", "/v1/archive/verify", {
1065
+ against: input.against,
1066
+ target: input.target ?? "raw",
1067
+ from_block: input.fromBlock,
1068
+ to_block: input.toBlock,
1069
+ insecure: input.insecure,
1070
+ public_key_pem: input.publicKeyPem
1071
+ });
1072
+ }
1073
+ function createInstanceClient(request) {
1074
+ async function status() {
1075
+ return request("GET", "/public/status");
1076
+ }
1077
+ async function diagnose() {
1078
+ return diagnoseInstanceStatus(await status());
1079
+ }
1080
+ return { status, diagnose };
1081
+ }
1082
+
817
1083
  // src/contracts/client.ts
818
1084
  class Contracts extends BaseClient {
819
1085
  constructor(options = {}) {
@@ -1786,7 +2052,7 @@ function decode(event) {
1786
2052
  }
1787
2053
 
1788
2054
  // src/streams/dumps.ts
1789
- import { createHash } from "node:crypto";
2055
+ import { createHash as createHash2 } from "node:crypto";
1790
2056
  import { verifyStreamsBulkManifestSignature } from "@secondlayer/shared/streams-bulk-manifest";
1791
2057
  function createStreamsDumps(opts) {
1792
2058
  const baseUrl = opts.baseUrl?.replace(/\/+$/, "");
@@ -1838,7 +2104,7 @@ function createStreamsDumps(opts) {
1838
2104
  if (!res.body) {
1839
2105
  throw new StreamsServerError(`Dump ${file.path} response has no body.`, 0);
1840
2106
  }
1841
- const hash = createHash("sha256");
2107
+ const hash = createHash2("sha256");
1842
2108
  const chunks = [];
1843
2109
  let total = 0;
1844
2110
  const reader = res.body.getReader();
@@ -2232,6 +2498,8 @@ class SecondLayer extends BaseClient {
2232
2498
  contracts;
2233
2499
  subgraphs;
2234
2500
  subscriptions;
2501
+ archive;
2502
+ instance;
2235
2503
  constructor(options = {}) {
2236
2504
  super(options);
2237
2505
  this.streams = createStreamsClient({
@@ -2247,17 +2515,36 @@ class SecondLayer extends BaseClient {
2247
2515
  this.contracts = new Contracts(options);
2248
2516
  this.subgraphs = new Subgraphs(options);
2249
2517
  this.subscriptions = new Subscriptions(options);
2518
+ const request = (method, path, body) => this.request(method, path, body);
2519
+ this.archive = {
2520
+ ...createArchiveClient({
2521
+ apiKey: this.apiKey,
2522
+ fetchImpl: options.fetchImpl,
2523
+ archiveBaseUrl: options.archiveBaseUrl,
2524
+ archiveOpsUrl: options.archiveOpsUrl
2525
+ }),
2526
+ verify: createArchiveVerify(request)
2527
+ };
2528
+ this.instance = createInstanceClient(request);
2250
2529
  }
2251
2530
  async batch(requests) {
2252
2531
  return this.request("POST", "/v1/batch", { requests });
2253
2532
  }
2254
2533
  async context() {
2255
- const [account, streamsTip, indexEnv, subgraphsRes, subscriptionsRes] = await Promise.all([
2534
+ const [
2535
+ account,
2536
+ streamsTip,
2537
+ indexEnv,
2538
+ subgraphsRes,
2539
+ subscriptionsRes,
2540
+ instance
2541
+ ] = await Promise.all([
2256
2542
  contextField(this.request("GET", "/api/accounts/me")),
2257
2543
  contextField(this.streams.tip()),
2258
2544
  contextField(this.index.canonical.list({ limit: 1 })),
2259
2545
  contextField(this.subgraphs.list()),
2260
- contextField(this.subscriptions.list())
2546
+ contextField(this.subscriptions.list()),
2547
+ contextField(this.instance.diagnose())
2261
2548
  ]);
2262
2549
  const subgraphs = {
2263
2550
  value: subgraphsRes.value?.data ?? null,
@@ -2309,7 +2596,8 @@ class SecondLayer extends BaseClient {
2309
2596
  },
2310
2597
  subgraphs,
2311
2598
  subscriptions,
2312
- activeOperations
2599
+ activeOperations,
2600
+ instance
2313
2601
  };
2314
2602
  }
2315
2603
  }
@@ -2591,6 +2879,7 @@ export {
2591
2879
  decodeChainWebhook,
2592
2880
  decode,
2593
2881
  createStreamsClient,
2882
+ createArchiveClient,
2594
2883
  contextField,
2595
2884
  consumerHealth,
2596
2885
  consumeIndexFeed,
@@ -2603,6 +2892,7 @@ export {
2603
2892
  SecondLayer,
2604
2893
  RateLimitError,
2605
2894
  LOCAL_API_URL,
2895
+ InsufficientArchiveCreditsError,
2606
2896
  Index,
2607
2897
  INDEX_MAX_PAGE_SIZE,
2608
2898
  DEFAULT_REQUEST_TIMEOUT_MS,
@@ -2610,8 +2900,11 @@ export {
2610
2900
  Contracts,
2611
2901
  CREDENTIAL_ENV_VARS,
2612
2902
  AuthError,
2903
+ ArchiveSignatureError,
2904
+ ArchiveGateNotConfiguredError,
2905
+ ArchiveAuthError,
2613
2906
  ApiError
2614
2907
  };
2615
2908
 
2616
- //# debugId=CDF488058C75012864756E2164756E21
2909
+ //# debugId=ACBBAC86B270FAEA64756E2164756E21
2617
2910
  //# sourceMappingURL=index.js.map