@secondlayer/sdk 10.1.1 → 10.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.
@@ -6,14 +6,23 @@ type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<
6
6
  interface SecondLayerOptions {
7
7
  /** Base URL of the instance API (trailing slashes are stripped). */
8
8
  baseUrl: string;
9
- /** Bearer token for authenticated requests. */
9
+ /** Bearer token for authenticated instance requests (`INSTANCE_TOKEN`). */
10
10
  apiKey?: string;
11
+ /** Hosted account key (`sk-sl_*`). Env `SECONDLAYER_API_KEY`. Used by
12
+ * `sl.archive` quote/fetch/credits, never by instance `/v1` or `/api`. */
13
+ accountKey?: string;
11
14
  /** Fetch implementation. Tests and edge runtimes can provide their own. */
12
15
  fetchImpl?: FetchLike;
13
16
  /** Public base URL for Streams bulk parquet dumps (the cold backfill plane).
14
17
  * Required for `streams.dumps.*`; without it the dumps client falls back to
15
18
  * its built-in default. */
16
19
  dumpsBaseUrl?: string;
20
+ /** Public base URL for the signed canonical archive tree. Defaults to
21
+ * `https://archive.secondlayer.tools`. Reaches `sl.archive`. */
22
+ archiveBaseUrl?: string;
23
+ /** Credits and fetch-gate API. Defaults to `https://api.secondlayer.tools`,
24
+ * not `baseUrl`. Reaches `sl.archive` quote/fetch/credits. */
25
+ archiveOpsUrl?: string;
17
26
  /** Deploy origin label sent as `x-sl-origin` (telemetry). Defaults to `cli`. */
18
27
  origin?: "cli" | "mcp" | "session";
19
28
  /** Check the ed25519 signature on every Streams read. Omit for lenient
@@ -207,7 +216,156 @@ declare class Subgraphs extends BaseClient {
207
216
  private createTableClient;
208
217
  }
209
218
  import { InferSubgraphClient as InferSubgraphClient2 } from "@secondlayer/subgraphs";
219
+ import { InstanceDiagnosis as InstanceDiagnosis2 } from "@secondlayer/shared/archive/instance-diagnosis";
210
220
  import { SubgraphSummary as SubgraphSummary2 } from "@secondlayer/shared/schemas";
221
+ import { InstanceDiagnosis, PublicStatus } from "@secondlayer/shared/archive/instance-diagnosis";
222
+ /** Structural `/public/status` payload. Extra fields are ignored by diagnosis. */
223
+ type InstanceStatus = PublicStatus;
224
+ type InstanceClient = {
225
+ status(): Promise<InstanceStatus>;
226
+ diagnose(): Promise<InstanceDiagnosis>;
227
+ };
228
+ type ArchiveVerifyInput = {
229
+ against: string;
230
+ target?: string;
231
+ fromBlock?: number;
232
+ toBlock?: number;
233
+ insecure?: boolean;
234
+ publicKeyPem?: string;
235
+ };
236
+ type ArchiveVerifyRangeStatus = "match" | "digest-mismatch" | "count-mismatch" | "missing";
237
+ type ArchiveVerifyResult = {
238
+ status: "clean" | "diverged" | "unanchored";
239
+ target: string;
240
+ against: string;
241
+ signature: {
242
+ verified: boolean;
243
+ reason?: string;
244
+ };
245
+ coverage?: {
246
+ from_block: number;
247
+ to_block: number;
248
+ };
249
+ ranges: Array<{
250
+ dataset: string;
251
+ from_block: number;
252
+ to_block: number;
253
+ status: ArchiveVerifyRangeStatus;
254
+ expected_digest: string | null;
255
+ actual_digest: string | null;
256
+ }>;
257
+ reason?: string;
258
+ };
259
+ import { RangeDigest } from "@secondlayer/shared/archive/range-digest";
260
+ type ArchiveDataset = "blocks" | "transactions" | "events";
261
+ type ArchiveFlow = "bootstrap" | "repair";
262
+ type ArchivePartition = {
263
+ dataset: string;
264
+ from_block: number;
265
+ to_block: number;
266
+ path: string;
267
+ row_count: number;
268
+ byte_size: number;
269
+ sha256: string;
270
+ };
271
+ type ArchiveManifest = {
272
+ network?: string;
273
+ coverage?: {
274
+ from_block: number;
275
+ to_block: number;
276
+ };
277
+ partition_size_blocks?: number;
278
+ range_digests?: RangeDigest[];
279
+ partitions?: ArchivePartition[];
280
+ signature?: string;
281
+ key_id?: string;
282
+ [key: string]: unknown;
283
+ };
284
+ type LoadedArchive = {
285
+ manifest: ArchiveManifest;
286
+ origin: string;
287
+ root: string;
288
+ isRemote: boolean;
289
+ signature: {
290
+ verified: boolean;
291
+ reason?: string;
292
+ };
293
+ };
294
+ type ArchiveQuote = {
295
+ partitions: number;
296
+ bundles: number;
297
+ usdMicros: number;
298
+ usd: string;
299
+ freeAllowanceAppliedMicros: number;
300
+ allowanceRemainingBundles: number;
301
+ balanceUsdMicros: number;
302
+ sufficient: boolean;
303
+ };
304
+ type ArchiveFetchItem = {
305
+ path: string;
306
+ url: string;
307
+ expiresAt: string;
308
+ chargedUsdMicros: number;
309
+ };
310
+ type ArchiveFetchResult = {
311
+ urls: ArchiveFetchItem[];
312
+ chargedTotalUsdMicros: number;
313
+ balanceAfterUsdMicros: number;
314
+ };
315
+ type ArchiveCreditsBalance = {
316
+ creditsUsdMicros: string;
317
+ refill: {
318
+ belowUsd: number | null;
319
+ packUsd: number | null;
320
+ lastAt: string | null;
321
+ };
322
+ };
323
+ type ArchiveLoadOptions = {
324
+ insecure?: boolean;
325
+ };
326
+ type ArchiveClient = {
327
+ latest(against?: string, opts?: ArchiveLoadOptions): Promise<LoadedArchive>;
328
+ load(against: string, opts?: ArchiveLoadOptions): Promise<LoadedArchive>;
329
+ status(): Promise<unknown>;
330
+ partitions(ref: LoadedArchive, filter?: {
331
+ dataset?: ArchiveDataset;
332
+ fromBlock?: number;
333
+ toBlock?: number;
334
+ }): ArchivePartition[];
335
+ quote(input: {
336
+ paths: string[];
337
+ flow: ArchiveFlow;
338
+ }): Promise<ArchiveQuote>;
339
+ fetch(input: {
340
+ paths: string[];
341
+ flow: ArchiveFlow;
342
+ }): Promise<ArchiveFetchResult>;
343
+ download(partition: ArchivePartition, opts?: {
344
+ url?: string;
345
+ }): Promise<Uint8Array>;
346
+ credits: {
347
+ balance(): Promise<ArchiveCreditsBalance>;
348
+ checkout(input: {
349
+ email: string;
350
+ pack: 10 | 25 | 50 | 100;
351
+ }): Promise<{
352
+ url: string;
353
+ }>;
354
+ refill(input: {
355
+ belowUsd: number;
356
+ packUsd: 10 | 25 | 50 | 100;
357
+ } | {
358
+ off: true;
359
+ }): Promise<{
360
+ belowUsd: number | null;
361
+ packUsd: number | null;
362
+ }>;
363
+ };
364
+ };
365
+ /** Hosted archive client plus instance `verify`. `status()` is still the public archive tree. */
366
+ type SecondLayerArchive = ArchiveClient & {
367
+ verify(input: ArchiveVerifyInput): Promise<ArchiveVerifyResult>;
368
+ };
211
369
  /**
212
370
  * Typed client for the contract-discovery API (`GET /v1/contracts`).
213
371
  *
@@ -2386,6 +2544,8 @@ interface ContextSnapshot {
2386
2544
  }>;
2387
2545
  /** In-flight reindex operations (bounded to subgraphs reporting `reindexing`). */
2388
2546
  activeOperations: ContextField<ActiveSubgraphOperation[]>;
2547
+ /** Decoder lag / empty-index from `GET /public/status`. */
2548
+ instance: ContextField<InstanceDiagnosis2>;
2389
2549
  }
2390
2550
  declare class SecondLayer extends BaseClient {
2391
2551
  readonly streams: StreamsClient;
@@ -2393,6 +2553,8 @@ declare class SecondLayer extends BaseClient {
2393
2553
  readonly contracts: Contracts;
2394
2554
  readonly subgraphs: Subgraphs;
2395
2555
  readonly subscriptions: Subscriptions;
2556
+ readonly archive: SecondLayerArchive;
2557
+ readonly instance: InstanceClient;
2396
2558
  constructor(options?: Partial<SecondLayerOptions>);
2397
2559
  /**
2398
2560
  * Up to 10 public reads in one round trip (`POST /v1/batch`). Each item
@@ -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;
@@ -139,33 +172,55 @@ function raceAbort(promise, signal) {
139
172
  });
140
173
  }
141
174
  var LOCAL_API_URL = "http://127.0.0.1:3800";
175
+ var INSTANCE_TOKEN_ENV = "INSTANCE_TOKEN";
176
+ var ACCOUNT_KEY_ENV = "SECONDLAYER_API_KEY";
177
+ var warnedUrlAlias = false;
142
178
  function resolveBaseUrl(explicit) {
143
179
  if (explicit && explicit.length > 0)
144
180
  return explicit.replace(/\/+$/, "");
145
181
  if (typeof process !== "undefined") {
146
- const fromEnv = process.env?.SL_API_URL || process.env?.SECONDLAYER_API_URL;
147
- if (fromEnv)
148
- return fromEnv.replace(/\/+$/, "");
182
+ const primary = process.env?.SECONDLAYER_API_URL || undefined;
183
+ if (primary)
184
+ return primary.replace(/\/+$/, "");
185
+ const legacy = process.env?.SL_API_URL || undefined;
186
+ if (legacy) {
187
+ if (!warnedUrlAlias) {
188
+ warnedUrlAlias = true;
189
+ console.warn("[secondlayer] SL_API_URL is a legacy alias of SECONDLAYER_API_URL; using the alias this once.");
190
+ }
191
+ return legacy.replace(/\/+$/, "");
192
+ }
149
193
  }
150
194
  return LOCAL_API_URL;
151
195
  }
152
- var CREDENTIAL_ENV_VARS = ["INSTANCE_TOKEN", "SL_API_KEY"];
153
- var warnedConflicts = new Set;
154
196
  function resolveApiKey(apiKey) {
155
197
  if (apiKey !== undefined)
156
198
  return apiKey;
157
199
  if (typeof process === "undefined")
158
200
  return;
159
- const instanceToken = process.env?.INSTANCE_TOKEN || undefined;
160
- const legacyKey = process.env?.SL_API_KEY || undefined;
161
- if (instanceToken && legacyKey && instanceToken !== legacyKey) {
162
- const pair = `${instanceToken}\x00${legacyKey}`;
163
- if (!warnedConflicts.has(pair)) {
164
- warnedConflicts.add(pair);
165
- console.warn("[secondlayer] INSTANCE_TOKEN and SL_API_KEY are set to different values — using INSTANCE_TOKEN (SL_API_KEY is a legacy alias for it).");
201
+ const token = process.env?.INSTANCE_TOKEN || undefined;
202
+ return token;
203
+ }
204
+ var warnedArchiveAlias = false;
205
+ function resolveAccountKey(accountKey) {
206
+ if (accountKey !== undefined)
207
+ return accountKey;
208
+ if (typeof process === "undefined")
209
+ return;
210
+ const primary = process.env?.SECONDLAYER_API_KEY || undefined;
211
+ const slAlias = process.env?.SL_API_KEY || undefined;
212
+ const archiveAlias = process.env?.SL_ARCHIVE_API_KEY || undefined;
213
+ if (primary)
214
+ return primary;
215
+ const legacy = slAlias ?? archiveAlias;
216
+ if (legacy) {
217
+ if (!warnedArchiveAlias) {
218
+ warnedArchiveAlias = true;
219
+ console.warn("[secondlayer] SL_API_KEY / SL_ARCHIVE_API_KEY are legacy aliases of SECONDLAYER_API_KEY; using the alias this once.");
166
220
  }
221
+ return legacy;
167
222
  }
168
- return instanceToken ?? legacyKey;
223
+ return;
169
224
  }
170
225
  function seg(value) {
171
226
  return encodeURIComponent(String(value));
@@ -814,6 +869,244 @@ class Subgraphs extends BaseClient {
814
869
  };
815
870
  }
816
871
  }
872
+ // src/archive/client.ts
873
+ import { createHash } from "node:crypto";
874
+ import {
875
+ checkSignature,
876
+ loadReference
877
+ } from "@secondlayer/shared/archive/reference";
878
+ var OFFICIAL_ARCHIVE_HOST = "archive.secondlayer.tools";
879
+ var DEFAULT_ARCHIVE_BASE_URL = "https://archive.secondlayer.tools";
880
+ var DEFAULT_ARCHIVE_OPS_URL = "https://api.secondlayer.tools";
881
+ var MAX_FETCH_BATCH = 64;
882
+ var ARCHIVE_CREDENTIAL_RE = /^s[ks]-sl_/;
883
+ function quoteFromBody(body) {
884
+ return {
885
+ partitions: body.partitions,
886
+ bundles: body.bundles,
887
+ usdMicros: body.usd_micros,
888
+ usd: body.usd,
889
+ freeAllowanceAppliedMicros: body.free_allowance_applied_micros,
890
+ allowanceRemainingBundles: body.allowance_remaining_bundles,
891
+ balanceUsdMicros: body.balance_usd_micros,
892
+ sufficient: body.sufficient
893
+ };
894
+ }
895
+ function stripSlash(url) {
896
+ return url.replace(/\/+$/, "");
897
+ }
898
+ function createArchiveClient(options = {}) {
899
+ const accountKey = resolveAccountKey(options.accountKey ?? options.apiKey);
900
+ const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
901
+ const archiveBaseUrl = stripSlash(options.archiveBaseUrl ?? DEFAULT_ARCHIVE_BASE_URL);
902
+ const archiveOpsUrl = stripSlash(options.archiveOpsUrl ?? DEFAULT_ARCHIVE_OPS_URL);
903
+ const verifyManifest = options.verifyManifest ?? true;
904
+ const pinnedPem = options.publicKeyPem;
905
+ let keyPromise = null;
906
+ async function fetchSigningKey() {
907
+ if (pinnedPem)
908
+ return pinnedPem;
909
+ if (keyPromise)
910
+ return keyPromise;
911
+ const pending = (async () => {
912
+ const res = await fetchImpl(`${archiveOpsUrl}/public/streams/signing-key`);
913
+ if (!res.ok) {
914
+ throw new ArchiveSignatureError(`Could not fetch archive signing key (${res.status}).`);
915
+ }
916
+ const body = await res.json();
917
+ if (typeof body.public_key_pem !== "string") {
918
+ throw new ArchiveSignatureError("Signing key response missing key.");
919
+ }
920
+ return body.public_key_pem;
921
+ })();
922
+ keyPromise = pending;
923
+ pending.catch(() => {
924
+ if (keyPromise === pending)
925
+ keyPromise = null;
926
+ });
927
+ return pending;
928
+ }
929
+ async function throwOpsError(response) {
930
+ const envelope = parseErrorEnvelope(await response.text());
931
+ if (response.status === 401) {
932
+ throw new ArchiveAuthError(envelope.message ?? "Archive ops request was not authenticated.");
933
+ }
934
+ if (response.status === 402) {
935
+ const raw = envelope.body && typeof envelope.body === "object" && "shortfall_usd_micros" in envelope.body ? Number(envelope.body.shortfall_usd_micros) : undefined;
936
+ throw new InsufficientArchiveCreditsError(envelope.message ?? "Insufficient archive credits.", Number.isFinite(raw) ? raw : undefined);
937
+ }
938
+ if (response.status === 503) {
939
+ throw new ArchiveGateNotConfiguredError(envelope.message ?? "The archive gate is not configured on the server.");
940
+ }
941
+ throw new ApiError(response.status, envelope.message ?? `Archive ops returned ${response.status}.`, envelope.body, envelope.code);
942
+ }
943
+ async function opsRequest(method, path, body, authed = true) {
944
+ const headers = {
945
+ "Content-Type": "application/json"
946
+ };
947
+ if (authed && accountKey) {
948
+ if (!ARCHIVE_CREDENTIAL_RE.test(accountKey)) {
949
+ throw new ArchiveAuthError("archive ops need SECONDLAYER_API_KEY (sk-sl_*), not INSTANCE_TOKEN");
950
+ }
951
+ headers.Authorization = `Bearer ${accountKey}`;
952
+ }
953
+ const response = await fetchImpl(`${archiveOpsUrl}${path}`, {
954
+ method,
955
+ headers,
956
+ body: body !== undefined ? JSON.stringify(body) : undefined
957
+ });
958
+ if (!response.ok)
959
+ await throwOpsError(response);
960
+ return await response.json();
961
+ }
962
+ async function load(against, opts = {}) {
963
+ if (!/^https?:\/\//i.test(against)) {
964
+ throw new ValidationError("archive.load() accepts only http(s) URLs; local paths stay on the CLI.", 400);
965
+ }
966
+ const insecure = opts.insecure === true;
967
+ const publicKeyPem = pinnedPem ?? (verifyManifest && !insecure ? await fetchSigningKey() : undefined);
968
+ const ref = await loadReference(against, {
969
+ publicKeyPem,
970
+ fetchImpl
971
+ });
972
+ const signature = checkSignature(ref.manifest, publicKeyPem, insecure);
973
+ if (verifyManifest && !insecure && !signature.verified) {
974
+ throw new ArchiveSignatureError(signature.reason ?? "Archive manifest signature is missing or invalid.");
975
+ }
976
+ return { ...ref, signature };
977
+ }
978
+ async function latest(against, opts = {}) {
979
+ return load(against ?? `${archiveBaseUrl}/latest.json`, opts);
980
+ }
981
+ async function status() {
982
+ const response = await fetchImpl(`${archiveBaseUrl}/status.json`);
983
+ if (!response.ok) {
984
+ throw new ApiError(response.status, `Could not fetch archive status (${response.status}).`);
985
+ }
986
+ return response.json();
987
+ }
988
+ function partitions(ref, filter) {
989
+ let list = ref.manifest.partitions ?? [];
990
+ if (!filter)
991
+ return list;
992
+ if (filter.dataset) {
993
+ list = list.filter((p) => p.dataset === filter.dataset);
994
+ }
995
+ const fromBlock = filter.fromBlock;
996
+ if (fromBlock !== undefined) {
997
+ list = list.filter((p) => p.to_block >= fromBlock);
998
+ }
999
+ const toBlock = filter.toBlock;
1000
+ if (toBlock !== undefined) {
1001
+ list = list.filter((p) => p.from_block <= toBlock);
1002
+ }
1003
+ return list;
1004
+ }
1005
+ async function quote(input) {
1006
+ const body = await opsRequest("POST", "/api/archive/quote", { paths: input.paths, flow: input.flow });
1007
+ return quoteFromBody(body);
1008
+ }
1009
+ async function fetchPartitions(input) {
1010
+ const urls = [];
1011
+ let chargedTotalUsdMicros = 0;
1012
+ let balanceAfterUsdMicros = 0;
1013
+ for (let i = 0;i < input.paths.length; i += MAX_FETCH_BATCH) {
1014
+ const chunk = input.paths.slice(i, i + MAX_FETCH_BATCH);
1015
+ const body = await opsRequest("POST", "/api/archive/fetch", { paths: chunk, flow: input.flow });
1016
+ for (const item of body.urls) {
1017
+ urls.push({
1018
+ path: item.path,
1019
+ url: item.url,
1020
+ expiresAt: item.expires_at,
1021
+ chargedUsdMicros: item.charged_usd_micros
1022
+ });
1023
+ }
1024
+ chargedTotalUsdMicros += body.charged_total_usd_micros;
1025
+ balanceAfterUsdMicros = body.balance_after_usd_micros;
1026
+ }
1027
+ return { urls, chargedTotalUsdMicros, balanceAfterUsdMicros };
1028
+ }
1029
+ async function download(partition, opts) {
1030
+ let url = opts?.url;
1031
+ if (!url) {
1032
+ let official = false;
1033
+ try {
1034
+ official = new URL(archiveBaseUrl).hostname === OFFICIAL_ARCHIVE_HOST;
1035
+ } catch {
1036
+ official = false;
1037
+ }
1038
+ if (official) {
1039
+ throw new ValidationError("Official archive host requires a presigned URL from archive.fetch() before download.", 400);
1040
+ }
1041
+ url = `${archiveBaseUrl}/${partition.path.replace(/^\/+/, "")}`;
1042
+ }
1043
+ const response = await fetchImpl(url);
1044
+ if (!response.ok) {
1045
+ throw new ApiError(response.status, `Could not download ${partition.path} (${response.status}).`);
1046
+ }
1047
+ const bytes = new Uint8Array(await response.arrayBuffer());
1048
+ const digest = createHash("sha256").update(bytes).digest("hex");
1049
+ if (digest !== partition.sha256) {
1050
+ throw new ArchiveSignatureError(`${partition.path} sha256 mismatch (expected ${partition.sha256}, got ${digest}).`);
1051
+ }
1052
+ return bytes;
1053
+ }
1054
+ return {
1055
+ latest,
1056
+ load,
1057
+ status,
1058
+ partitions,
1059
+ quote,
1060
+ fetch: fetchPartitions,
1061
+ download,
1062
+ credits: {
1063
+ async balance() {
1064
+ const body = await opsRequest("GET", "/api/billing/status");
1065
+ return {
1066
+ creditsUsdMicros: body.creditsUsdMicros,
1067
+ refill: body.refill
1068
+ };
1069
+ },
1070
+ async checkout(input) {
1071
+ const body = await opsRequest("POST", "/api/public/credits/checkout", { email: input.email, amount: input.pack }, false);
1072
+ return { url: body.url };
1073
+ },
1074
+ async refill(input) {
1075
+ const payload = "off" in input && input.off ? { belowUsd: null } : {
1076
+ belowUsd: input.belowUsd,
1077
+ packUsd: input.packUsd
1078
+ };
1079
+ const body = await opsRequest("POST", "/api/billing/refill", payload);
1080
+ return { belowUsd: body.belowUsd, packUsd: body.packUsd };
1081
+ }
1082
+ }
1083
+ };
1084
+ }
1085
+
1086
+ // src/archive/instance.ts
1087
+ import {
1088
+ diagnoseInstanceStatus
1089
+ } from "@secondlayer/shared/archive/instance-diagnosis";
1090
+ function createArchiveVerify(request) {
1091
+ return (input) => request("POST", "/v1/archive/verify", {
1092
+ against: input.against,
1093
+ target: input.target ?? "raw",
1094
+ from_block: input.fromBlock,
1095
+ to_block: input.toBlock,
1096
+ insecure: input.insecure,
1097
+ public_key_pem: input.publicKeyPem
1098
+ });
1099
+ }
1100
+ function createInstanceClient(request) {
1101
+ async function status() {
1102
+ return request("GET", "/public/status");
1103
+ }
1104
+ async function diagnose() {
1105
+ return diagnoseInstanceStatus(await status());
1106
+ }
1107
+ return { status, diagnose };
1108
+ }
1109
+
817
1110
  // src/contracts/client.ts
818
1111
  class Contracts extends BaseClient {
819
1112
  constructor(options = {}) {
@@ -1786,7 +2079,7 @@ function decode(event) {
1786
2079
  }
1787
2080
 
1788
2081
  // src/streams/dumps.ts
1789
- import { createHash } from "node:crypto";
2082
+ import { createHash as createHash2 } from "node:crypto";
1790
2083
  import { verifyStreamsBulkManifestSignature } from "@secondlayer/shared/streams-bulk-manifest";
1791
2084
  function createStreamsDumps(opts) {
1792
2085
  const baseUrl = opts.baseUrl?.replace(/\/+$/, "");
@@ -1838,7 +2131,7 @@ function createStreamsDumps(opts) {
1838
2131
  if (!res.body) {
1839
2132
  throw new StreamsServerError(`Dump ${file.path} response has no body.`, 0);
1840
2133
  }
1841
- const hash = createHash("sha256");
2134
+ const hash = createHash2("sha256");
1842
2135
  const chunks = [];
1843
2136
  let total = 0;
1844
2137
  const reader = res.body.getReader();
@@ -2232,6 +2525,8 @@ class SecondLayer extends BaseClient {
2232
2525
  contracts;
2233
2526
  subgraphs;
2234
2527
  subscriptions;
2528
+ archive;
2529
+ instance;
2235
2530
  constructor(options = {}) {
2236
2531
  super(options);
2237
2532
  this.streams = createStreamsClient({
@@ -2247,17 +2542,36 @@ class SecondLayer extends BaseClient {
2247
2542
  this.contracts = new Contracts(options);
2248
2543
  this.subgraphs = new Subgraphs(options);
2249
2544
  this.subscriptions = new Subscriptions(options);
2545
+ const request = (method, path, body) => this.request(method, path, body);
2546
+ this.archive = {
2547
+ ...createArchiveClient({
2548
+ accountKey: options.accountKey,
2549
+ fetchImpl: options.fetchImpl,
2550
+ archiveBaseUrl: options.archiveBaseUrl,
2551
+ archiveOpsUrl: options.archiveOpsUrl
2552
+ }),
2553
+ verify: createArchiveVerify(request)
2554
+ };
2555
+ this.instance = createInstanceClient(request);
2250
2556
  }
2251
2557
  async batch(requests) {
2252
2558
  return this.request("POST", "/v1/batch", { requests });
2253
2559
  }
2254
2560
  async context() {
2255
- const [account, streamsTip, indexEnv, subgraphsRes, subscriptionsRes] = await Promise.all([
2561
+ const [
2562
+ account,
2563
+ streamsTip,
2564
+ indexEnv,
2565
+ subgraphsRes,
2566
+ subscriptionsRes,
2567
+ instance
2568
+ ] = await Promise.all([
2256
2569
  contextField(this.request("GET", "/api/accounts/me")),
2257
2570
  contextField(this.streams.tip()),
2258
2571
  contextField(this.index.canonical.list({ limit: 1 })),
2259
2572
  contextField(this.subgraphs.list()),
2260
- contextField(this.subscriptions.list())
2573
+ contextField(this.subscriptions.list()),
2574
+ contextField(this.instance.diagnose())
2261
2575
  ]);
2262
2576
  const subgraphs = {
2263
2577
  value: subgraphsRes.value?.data ?? null,
@@ -2309,7 +2623,8 @@ class SecondLayer extends BaseClient {
2309
2623
  },
2310
2624
  subgraphs,
2311
2625
  subscriptions,
2312
- activeOperations
2626
+ activeOperations,
2627
+ instance
2313
2628
  };
2314
2629
  }
2315
2630
  }
@@ -2329,5 +2644,5 @@ export {
2329
2644
  Subgraphs
2330
2645
  };
2331
2646
 
2332
- //# debugId=10070F0E5755447564756E2164756E21
2647
+ //# debugId=B1E5E37D297ADB5664756E2164756E21
2333
2648
  //# sourceMappingURL=index.js.map