@secondlayer/sdk 3.3.2 → 3.5.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 +160 -2
- package/dist/index.d.ts +299 -1
- package/dist/index.js +509 -1
- package/dist/index.js.map +12 -5
- package/dist/streams/index.d.ts +208 -0
- package/dist/streams/index.js +399 -0
- package/dist/streams/index.js.map +15 -0
- package/dist/subgraphs/index.d.ts +209 -0
- package/dist/subgraphs/index.js +373 -1
- package/dist/subgraphs/index.js.map +9 -5
- package/package.json +6 -2
|
@@ -2,11 +2,14 @@ import { ReindexResponse, SubgraphDetail, SubgraphGapsResponse, SubgraphQueryPar
|
|
|
2
2
|
import { DeploySubgraphRequest, DeploySubgraphResponse } from "@secondlayer/shared/schemas/subgraphs";
|
|
3
3
|
import { SubgraphAgentSchema, SubgraphSpecOptions } from "@secondlayer/shared/subgraphs/spec";
|
|
4
4
|
import { InferSubgraphClient } from "@secondlayer/subgraphs";
|
|
5
|
+
type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
5
6
|
interface SecondLayerOptions {
|
|
6
7
|
/** Base URL of the Secondlayer API (trailing slashes are stripped). */
|
|
7
8
|
baseUrl: string;
|
|
8
9
|
/** Bearer token for authenticated requests. */
|
|
9
10
|
apiKey?: string;
|
|
11
|
+
/** Fetch implementation. Tests and edge runtimes can provide their own. */
|
|
12
|
+
fetchImpl?: FetchLike;
|
|
10
13
|
/** Deploy origin label sent as `x-sl-origin` (telemetry). Defaults to `cli`. */
|
|
11
14
|
origin?: "cli" | "mcp" | "session";
|
|
12
15
|
}
|
|
@@ -102,6 +105,210 @@ declare class Subgraphs extends BaseClient {
|
|
|
102
105
|
private createTableClient;
|
|
103
106
|
}
|
|
104
107
|
import { InferSubgraphClient as InferSubgraphClient2 } from "@secondlayer/subgraphs";
|
|
108
|
+
type IndexTip = {
|
|
109
|
+
block_height: number
|
|
110
|
+
lag_seconds: number
|
|
111
|
+
};
|
|
112
|
+
type FtTransfer = {
|
|
113
|
+
cursor: string
|
|
114
|
+
block_height: number
|
|
115
|
+
tx_id: string
|
|
116
|
+
tx_index: number
|
|
117
|
+
event_index: number
|
|
118
|
+
event_type: "ft_transfer"
|
|
119
|
+
contract_id: string
|
|
120
|
+
asset_identifier: string
|
|
121
|
+
sender: string
|
|
122
|
+
recipient: string
|
|
123
|
+
amount: string
|
|
124
|
+
};
|
|
125
|
+
type FtTransfersEnvelope = {
|
|
126
|
+
events: FtTransfer[]
|
|
127
|
+
next_cursor: string | null
|
|
128
|
+
tip: IndexTip
|
|
129
|
+
reorgs: never[]
|
|
130
|
+
};
|
|
131
|
+
type FtTransfersListParams = {
|
|
132
|
+
cursor?: string | null
|
|
133
|
+
fromCursor?: string | null
|
|
134
|
+
limit?: number
|
|
135
|
+
contractId?: string
|
|
136
|
+
sender?: string
|
|
137
|
+
recipient?: string
|
|
138
|
+
fromHeight?: number
|
|
139
|
+
toHeight?: number
|
|
140
|
+
};
|
|
141
|
+
type FtTransfersWalkParams = Omit<FtTransfersListParams, "limit"> & {
|
|
142
|
+
batchSize?: number
|
|
143
|
+
signal?: AbortSignal
|
|
144
|
+
};
|
|
145
|
+
type NftTransfer = {
|
|
146
|
+
cursor: string
|
|
147
|
+
block_height: number
|
|
148
|
+
tx_id: string
|
|
149
|
+
tx_index: number
|
|
150
|
+
event_index: number
|
|
151
|
+
event_type: "nft_transfer"
|
|
152
|
+
contract_id: string
|
|
153
|
+
asset_identifier: string
|
|
154
|
+
sender: string
|
|
155
|
+
recipient: string
|
|
156
|
+
value: string
|
|
157
|
+
};
|
|
158
|
+
type NftTransfersEnvelope = {
|
|
159
|
+
events: NftTransfer[]
|
|
160
|
+
next_cursor: string | null
|
|
161
|
+
tip: IndexTip
|
|
162
|
+
reorgs: never[]
|
|
163
|
+
};
|
|
164
|
+
type NftTransfersListParams = {
|
|
165
|
+
cursor?: string | null
|
|
166
|
+
fromCursor?: string | null
|
|
167
|
+
limit?: number
|
|
168
|
+
contractId?: string
|
|
169
|
+
assetIdentifier?: string
|
|
170
|
+
sender?: string
|
|
171
|
+
recipient?: string
|
|
172
|
+
fromHeight?: number
|
|
173
|
+
toHeight?: number
|
|
174
|
+
};
|
|
175
|
+
type NftTransfersWalkParams = Omit<NftTransfersListParams, "limit"> & {
|
|
176
|
+
batchSize?: number
|
|
177
|
+
signal?: AbortSignal
|
|
178
|
+
};
|
|
179
|
+
declare class Index extends BaseClient {
|
|
180
|
+
constructor(options?: Partial<SecondLayerOptions>);
|
|
181
|
+
readonly ftTransfers: {
|
|
182
|
+
list: (params?: FtTransfersListParams) => Promise<FtTransfersEnvelope>
|
|
183
|
+
walk: (params?: FtTransfersWalkParams) => AsyncIterable<FtTransfer>
|
|
184
|
+
};
|
|
185
|
+
readonly nftTransfers: {
|
|
186
|
+
list: (params?: NftTransfersListParams) => Promise<NftTransfersEnvelope>
|
|
187
|
+
walk: (params?: NftTransfersWalkParams) => AsyncIterable<NftTransfer>
|
|
188
|
+
};
|
|
189
|
+
private listFtTransfers;
|
|
190
|
+
private listNftTransfers;
|
|
191
|
+
private walkFtTransfers;
|
|
192
|
+
private walkNftTransfers;
|
|
193
|
+
}
|
|
194
|
+
declare const STREAMS_EVENT_TYPES: readonly ["stx_transfer", "stx_mint", "stx_burn", "stx_lock", "ft_transfer", "ft_mint", "ft_burn", "nft_transfer", "nft_mint", "nft_burn", "print"];
|
|
195
|
+
type StreamsEventType = (typeof STREAMS_EVENT_TYPES)[number];
|
|
196
|
+
type StreamsEventPayload = Record<string, unknown>;
|
|
197
|
+
type StreamsEvent = {
|
|
198
|
+
cursor: string
|
|
199
|
+
block_height: number
|
|
200
|
+
index_block_hash: string
|
|
201
|
+
burn_block_height: number
|
|
202
|
+
tx_id: string
|
|
203
|
+
tx_index: number
|
|
204
|
+
event_index: number
|
|
205
|
+
event_type: StreamsEventType
|
|
206
|
+
contract_id: string | null
|
|
207
|
+
payload: StreamsEventPayload
|
|
208
|
+
ts: string
|
|
209
|
+
};
|
|
210
|
+
type StreamsTip = {
|
|
211
|
+
block_height: number
|
|
212
|
+
index_block_hash: string
|
|
213
|
+
burn_block_height: number
|
|
214
|
+
lag_seconds: number
|
|
215
|
+
};
|
|
216
|
+
type StreamsCanonicalBlock = {
|
|
217
|
+
block_height: number
|
|
218
|
+
index_block_hash: string
|
|
219
|
+
burn_block_height: number
|
|
220
|
+
burn_block_hash: string | null
|
|
221
|
+
is_canonical: true
|
|
222
|
+
};
|
|
223
|
+
type StreamsReorg = {
|
|
224
|
+
detected_at: string
|
|
225
|
+
fork_point_height: number
|
|
226
|
+
orphaned_range: {
|
|
227
|
+
from: string
|
|
228
|
+
to: string
|
|
229
|
+
}
|
|
230
|
+
new_canonical_tip: string
|
|
231
|
+
};
|
|
232
|
+
type StreamsEventsEnvelope = {
|
|
233
|
+
events: StreamsEvent[]
|
|
234
|
+
next_cursor: string | null
|
|
235
|
+
tip: StreamsTip
|
|
236
|
+
reorgs: StreamsReorg[]
|
|
237
|
+
};
|
|
238
|
+
type StreamsEventsListEnvelope = Omit<StreamsEventsEnvelope, "next_cursor">;
|
|
239
|
+
type StreamsReorgsListParams = {
|
|
240
|
+
since: string
|
|
241
|
+
limit?: number
|
|
242
|
+
};
|
|
243
|
+
type StreamsReorgsListEnvelope = {
|
|
244
|
+
reorgs: StreamsReorg[]
|
|
245
|
+
next_since: string | null
|
|
246
|
+
};
|
|
247
|
+
type StreamsEventsListParams = {
|
|
248
|
+
cursor?: string | null
|
|
249
|
+
fromHeight?: number
|
|
250
|
+
toHeight?: number
|
|
251
|
+
types?: readonly StreamsEventType[]
|
|
252
|
+
contractId?: string
|
|
253
|
+
limit?: number
|
|
254
|
+
};
|
|
255
|
+
type StreamsEventsStreamParams = {
|
|
256
|
+
fromCursor?: string | null
|
|
257
|
+
types?: readonly StreamsEventType[]
|
|
258
|
+
batchSize?: number
|
|
259
|
+
emptyBackoffMs?: number
|
|
260
|
+
maxPages?: number
|
|
261
|
+
maxEmptyPolls?: number
|
|
262
|
+
signal?: AbortSignal
|
|
263
|
+
};
|
|
264
|
+
type StreamsEventsConsumeParams = {
|
|
265
|
+
fromCursor?: string | null
|
|
266
|
+
mode?: "tail" | "bounded"
|
|
267
|
+
types?: readonly StreamsEventType[]
|
|
268
|
+
batchSize?: number
|
|
269
|
+
onBatch: (events: StreamsEvent[], envelope: StreamsEventsEnvelope) => Promise<string | null | undefined> | string | null | undefined
|
|
270
|
+
emptyBackoffMs?: number
|
|
271
|
+
maxPages?: number
|
|
272
|
+
maxEmptyPolls?: number
|
|
273
|
+
signal?: AbortSignal
|
|
274
|
+
};
|
|
275
|
+
type StreamsEventsConsumeResult = {
|
|
276
|
+
cursor: string | null
|
|
277
|
+
pages: number
|
|
278
|
+
emptyPolls: number
|
|
279
|
+
};
|
|
280
|
+
type StreamsClient = {
|
|
281
|
+
events: {
|
|
282
|
+
list(params?: StreamsEventsListParams): Promise<StreamsEventsEnvelope>
|
|
283
|
+
byTxId(txId: string): Promise<StreamsEventsListEnvelope>
|
|
284
|
+
/**
|
|
285
|
+
* Pull pages from Streams and call `onBatch` after each page.
|
|
286
|
+
*
|
|
287
|
+
* Use `consume` for indexers and ETL jobs that own checkpointing. Return
|
|
288
|
+
* the checkpoint cursor from `onBatch`. Default `mode: "tail"` keeps
|
|
289
|
+
* polling when caught up; `mode: "bounded"` exits on the first empty page.
|
|
290
|
+
* The consumer also exits when `maxPages`, `maxEmptyPolls`, or `signal`
|
|
291
|
+
* stops it.
|
|
292
|
+
*/
|
|
293
|
+
consume(params: StreamsEventsConsumeParams): Promise<StreamsEventsConsumeResult>
|
|
294
|
+
/**
|
|
295
|
+
* Follow Streams as an async iterator.
|
|
296
|
+
*
|
|
297
|
+
* Use `stream` for live processors and watch-style apps. It tails
|
|
298
|
+
* indefinitely by default and stops when its `AbortSignal`, `maxPages`, or
|
|
299
|
+
* `maxEmptyPolls` stops it.
|
|
300
|
+
*/
|
|
301
|
+
stream(params?: StreamsEventsStreamParams): AsyncIterable<StreamsEvent>
|
|
302
|
+
}
|
|
303
|
+
blocks: {
|
|
304
|
+
events(heightOrHash: number | string): Promise<StreamsEventsListEnvelope>
|
|
305
|
+
}
|
|
306
|
+
reorgs: {
|
|
307
|
+
list(params: StreamsReorgsListParams): Promise<StreamsReorgsListEnvelope>
|
|
308
|
+
}
|
|
309
|
+
canonical(height: number): Promise<StreamsCanonicalBlock>
|
|
310
|
+
tip(): Promise<StreamsTip>
|
|
311
|
+
};
|
|
105
312
|
import { CreateSubscriptionRequest, CreateSubscriptionResponse, DeadRow, DeliveryRow, ReplayResult, RotateSecretResponse, SubscriptionDetail, SubscriptionSummary, UpdateSubscriptionRequest } from "@secondlayer/shared/schemas/subscriptions";
|
|
106
313
|
declare class Subscriptions extends BaseClient {
|
|
107
314
|
list(): Promise<{
|
|
@@ -131,6 +338,8 @@ declare class Subscriptions extends BaseClient {
|
|
|
131
338
|
}>;
|
|
132
339
|
}
|
|
133
340
|
declare class SecondLayer extends BaseClient {
|
|
341
|
+
readonly streams: StreamsClient;
|
|
342
|
+
readonly index: Index;
|
|
134
343
|
readonly subgraphs: Subgraphs;
|
|
135
344
|
readonly subscriptions: Subscriptions;
|
|
136
345
|
constructor(options?: Partial<SecondLayerOptions>);
|
package/dist/subgraphs/index.js
CHANGED
|
@@ -276,6 +276,370 @@ class Subgraphs extends BaseClient {
|
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
|
+
// src/index-api/client.ts
|
|
280
|
+
function appendSearchParam(params, name, value) {
|
|
281
|
+
if (value === undefined || value === null)
|
|
282
|
+
return;
|
|
283
|
+
params.set(name, String(value));
|
|
284
|
+
}
|
|
285
|
+
function firstWalkFromHeight(params) {
|
|
286
|
+
if (params.fromHeight !== undefined)
|
|
287
|
+
return params.fromHeight;
|
|
288
|
+
if (params.cursor || params.fromCursor)
|
|
289
|
+
return;
|
|
290
|
+
return 0;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
class Index extends BaseClient {
|
|
294
|
+
constructor(options = {}) {
|
|
295
|
+
super(options);
|
|
296
|
+
}
|
|
297
|
+
ftTransfers = {
|
|
298
|
+
list: (params = {}) => this.listFtTransfers(params),
|
|
299
|
+
walk: (params = {}) => this.walkFtTransfers(params)
|
|
300
|
+
};
|
|
301
|
+
nftTransfers = {
|
|
302
|
+
list: (params = {}) => this.listNftTransfers(params),
|
|
303
|
+
walk: (params = {}) => this.walkNftTransfers(params)
|
|
304
|
+
};
|
|
305
|
+
async listFtTransfers(params = {}) {
|
|
306
|
+
const searchParams = new URLSearchParams;
|
|
307
|
+
appendSearchParam(searchParams, "cursor", params.cursor);
|
|
308
|
+
appendSearchParam(searchParams, "from_cursor", params.fromCursor);
|
|
309
|
+
appendSearchParam(searchParams, "limit", params.limit);
|
|
310
|
+
appendSearchParam(searchParams, "contract_id", params.contractId);
|
|
311
|
+
appendSearchParam(searchParams, "sender", params.sender);
|
|
312
|
+
appendSearchParam(searchParams, "recipient", params.recipient);
|
|
313
|
+
appendSearchParam(searchParams, "from_height", params.fromHeight);
|
|
314
|
+
appendSearchParam(searchParams, "to_height", params.toHeight);
|
|
315
|
+
const query = searchParams.toString();
|
|
316
|
+
return this.request("GET", `/v1/index/ft-transfers${query ? `?${query}` : ""}`);
|
|
317
|
+
}
|
|
318
|
+
async listNftTransfers(params = {}) {
|
|
319
|
+
const searchParams = new URLSearchParams;
|
|
320
|
+
appendSearchParam(searchParams, "cursor", params.cursor);
|
|
321
|
+
appendSearchParam(searchParams, "from_cursor", params.fromCursor);
|
|
322
|
+
appendSearchParam(searchParams, "limit", params.limit);
|
|
323
|
+
appendSearchParam(searchParams, "contract_id", params.contractId);
|
|
324
|
+
appendSearchParam(searchParams, "asset_identifier", params.assetIdentifier);
|
|
325
|
+
appendSearchParam(searchParams, "sender", params.sender);
|
|
326
|
+
appendSearchParam(searchParams, "recipient", params.recipient);
|
|
327
|
+
appendSearchParam(searchParams, "from_height", params.fromHeight);
|
|
328
|
+
appendSearchParam(searchParams, "to_height", params.toHeight);
|
|
329
|
+
const query = searchParams.toString();
|
|
330
|
+
return this.request("GET", `/v1/index/nft-transfers${query ? `?${query}` : ""}`);
|
|
331
|
+
}
|
|
332
|
+
async* walkFtTransfers(params = {}) {
|
|
333
|
+
const batchSize = params.batchSize ?? 200;
|
|
334
|
+
let cursor = params.cursor ?? params.fromCursor ?? null;
|
|
335
|
+
let firstPage = true;
|
|
336
|
+
while (!params.signal?.aborted) {
|
|
337
|
+
const envelope = await this.listFtTransfers({
|
|
338
|
+
...params,
|
|
339
|
+
limit: batchSize,
|
|
340
|
+
cursor: firstPage ? params.cursor : cursor,
|
|
341
|
+
fromCursor: firstPage ? params.fromCursor : undefined,
|
|
342
|
+
fromHeight: firstPage ? firstWalkFromHeight(params) : undefined
|
|
343
|
+
});
|
|
344
|
+
for (const event of envelope.events) {
|
|
345
|
+
if (params.signal?.aborted)
|
|
346
|
+
return;
|
|
347
|
+
yield event;
|
|
348
|
+
}
|
|
349
|
+
const nextCursor = envelope.next_cursor;
|
|
350
|
+
if (!nextCursor || nextCursor === cursor || envelope.events.length < batchSize) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
cursor = nextCursor;
|
|
354
|
+
firstPage = false;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
async* walkNftTransfers(params = {}) {
|
|
358
|
+
const batchSize = params.batchSize ?? 200;
|
|
359
|
+
let cursor = params.cursor ?? params.fromCursor ?? null;
|
|
360
|
+
let firstPage = true;
|
|
361
|
+
while (!params.signal?.aborted) {
|
|
362
|
+
const envelope = await this.listNftTransfers({
|
|
363
|
+
...params,
|
|
364
|
+
limit: batchSize,
|
|
365
|
+
cursor: firstPage ? params.cursor : cursor,
|
|
366
|
+
fromCursor: firstPage ? params.fromCursor : undefined,
|
|
367
|
+
fromHeight: firstPage ? firstWalkFromHeight(params) : undefined
|
|
368
|
+
});
|
|
369
|
+
for (const event of envelope.events) {
|
|
370
|
+
if (params.signal?.aborted)
|
|
371
|
+
return;
|
|
372
|
+
yield event;
|
|
373
|
+
}
|
|
374
|
+
const nextCursor = envelope.next_cursor;
|
|
375
|
+
if (!nextCursor || nextCursor === cursor || envelope.events.length < batchSize) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
cursor = nextCursor;
|
|
379
|
+
firstPage = false;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/streams/consumer.ts
|
|
385
|
+
async function defaultSleep(ms, signal) {
|
|
386
|
+
if (signal?.aborted)
|
|
387
|
+
return;
|
|
388
|
+
await new Promise((resolve) => {
|
|
389
|
+
const timeout = setTimeout(resolve, ms);
|
|
390
|
+
if (!signal)
|
|
391
|
+
return;
|
|
392
|
+
signal.addEventListener("abort", () => {
|
|
393
|
+
clearTimeout(timeout);
|
|
394
|
+
resolve();
|
|
395
|
+
}, { once: true });
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
async function consumeStreamsEvents(opts) {
|
|
399
|
+
const sleep = opts.sleep ?? defaultSleep;
|
|
400
|
+
const mode = opts.mode ?? "tail";
|
|
401
|
+
const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
|
|
402
|
+
const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
|
|
403
|
+
const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
|
|
404
|
+
let cursor = opts.fromCursor ?? null;
|
|
405
|
+
let pages = 0;
|
|
406
|
+
let emptyPolls = 0;
|
|
407
|
+
while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
|
|
408
|
+
const envelope = await opts.fetchEvents({
|
|
409
|
+
cursor,
|
|
410
|
+
limit: opts.batchSize,
|
|
411
|
+
types: opts.types
|
|
412
|
+
});
|
|
413
|
+
pages++;
|
|
414
|
+
const returnedCursor = await opts.onBatch(envelope.events, envelope);
|
|
415
|
+
const nextCursor = returnedCursor ?? envelope.next_cursor;
|
|
416
|
+
if (nextCursor && nextCursor !== cursor) {
|
|
417
|
+
cursor = nextCursor;
|
|
418
|
+
emptyPolls = 0;
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
if (envelope.events.length === 0) {
|
|
422
|
+
emptyPolls++;
|
|
423
|
+
if (mode === "bounded") {
|
|
424
|
+
return { cursor, pages, emptyPolls };
|
|
425
|
+
}
|
|
426
|
+
await sleep(emptyBackoffMs, opts.signal);
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
return { cursor, pages, emptyPolls };
|
|
430
|
+
}
|
|
431
|
+
return { cursor, pages, emptyPolls };
|
|
432
|
+
}
|
|
433
|
+
async function* streamStreamsEvents(opts) {
|
|
434
|
+
const sleep = opts.sleep ?? defaultSleep;
|
|
435
|
+
const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
|
|
436
|
+
const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
|
|
437
|
+
const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
|
|
438
|
+
let cursor = opts.fromCursor ?? null;
|
|
439
|
+
let pages = 0;
|
|
440
|
+
let emptyPolls = 0;
|
|
441
|
+
while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
|
|
442
|
+
const envelope = await opts.fetchEvents({
|
|
443
|
+
cursor,
|
|
444
|
+
limit: opts.batchSize,
|
|
445
|
+
types: opts.types
|
|
446
|
+
});
|
|
447
|
+
pages++;
|
|
448
|
+
for (const event of envelope.events) {
|
|
449
|
+
if (opts.signal?.aborted)
|
|
450
|
+
return;
|
|
451
|
+
yield event;
|
|
452
|
+
}
|
|
453
|
+
const nextCursor = envelope.next_cursor;
|
|
454
|
+
if (nextCursor && nextCursor !== cursor) {
|
|
455
|
+
cursor = nextCursor;
|
|
456
|
+
emptyPolls = 0;
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
if (envelope.events.length === 0) {
|
|
460
|
+
emptyPolls++;
|
|
461
|
+
if (emptyPolls >= maxEmptyPolls || pages >= maxPages)
|
|
462
|
+
return;
|
|
463
|
+
await sleep(emptyBackoffMs, opts.signal);
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
// src/streams/errors.ts
|
|
471
|
+
class AuthError extends Error {
|
|
472
|
+
status = 401;
|
|
473
|
+
constructor(message = "API key invalid or expired.") {
|
|
474
|
+
super(message);
|
|
475
|
+
this.name = "AuthError";
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
class RateLimitError extends Error {
|
|
480
|
+
retryAfter;
|
|
481
|
+
status = 429;
|
|
482
|
+
constructor(message = "Rate limited. Try again later.", retryAfter) {
|
|
483
|
+
super(message);
|
|
484
|
+
this.retryAfter = retryAfter;
|
|
485
|
+
this.name = "RateLimitError";
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
class ValidationError extends Error {
|
|
490
|
+
status;
|
|
491
|
+
body;
|
|
492
|
+
constructor(message, status, body) {
|
|
493
|
+
super(message);
|
|
494
|
+
this.status = status;
|
|
495
|
+
this.body = body;
|
|
496
|
+
this.name = "ValidationError";
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
class StreamsServerError extends Error {
|
|
501
|
+
status;
|
|
502
|
+
body;
|
|
503
|
+
constructor(message, status, body) {
|
|
504
|
+
super(message);
|
|
505
|
+
this.status = status;
|
|
506
|
+
this.body = body;
|
|
507
|
+
this.name = "StreamsServerError";
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// src/streams/client.ts
|
|
512
|
+
var DEFAULT_STREAMS_BASE_URL = "https://api.secondlayer.tools";
|
|
513
|
+
function normalizeBaseUrl(baseUrl) {
|
|
514
|
+
return baseUrl.replace(/\/+$/, "");
|
|
515
|
+
}
|
|
516
|
+
function appendSearchParam2(params, name, value) {
|
|
517
|
+
if (value === undefined || value === null)
|
|
518
|
+
return;
|
|
519
|
+
params.set(name, String(value));
|
|
520
|
+
}
|
|
521
|
+
async function responseBody(response) {
|
|
522
|
+
const text = await response.text();
|
|
523
|
+
if (text.length === 0)
|
|
524
|
+
return;
|
|
525
|
+
try {
|
|
526
|
+
return JSON.parse(text);
|
|
527
|
+
} catch {
|
|
528
|
+
return text;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
function errorMessage(body, fallback) {
|
|
532
|
+
if (body && typeof body === "object") {
|
|
533
|
+
const record = body;
|
|
534
|
+
const message = record.error ?? record.message;
|
|
535
|
+
if (typeof message === "string" && message.length > 0)
|
|
536
|
+
return message;
|
|
537
|
+
}
|
|
538
|
+
if (typeof body === "string" && body.length > 0)
|
|
539
|
+
return body;
|
|
540
|
+
return fallback;
|
|
541
|
+
}
|
|
542
|
+
async function mapStreamsError(response) {
|
|
543
|
+
const body = await responseBody(response);
|
|
544
|
+
if (response.status === 401) {
|
|
545
|
+
throw new AuthError(errorMessage(body, "API key invalid or expired."));
|
|
546
|
+
}
|
|
547
|
+
if (response.status === 429) {
|
|
548
|
+
const retryAfter = response.headers.get("Retry-After") ?? undefined;
|
|
549
|
+
throw new RateLimitError(errorMessage(body, "Rate limited. Try again later."), retryAfter);
|
|
550
|
+
}
|
|
551
|
+
if (response.status >= 500) {
|
|
552
|
+
throw new StreamsServerError(errorMessage(body, `Streams server returned ${response.status}.`), response.status, body);
|
|
553
|
+
}
|
|
554
|
+
throw new ValidationError(errorMessage(body, `Streams request returned ${response.status}.`), response.status, body);
|
|
555
|
+
}
|
|
556
|
+
function createStreamsClient(options) {
|
|
557
|
+
const baseUrl = normalizeBaseUrl(options.baseUrl ?? DEFAULT_STREAMS_BASE_URL);
|
|
558
|
+
const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
559
|
+
async function request(path) {
|
|
560
|
+
const response = await fetchImpl(`${baseUrl}${path}`, {
|
|
561
|
+
headers: { Authorization: `Bearer ${options.apiKey}` }
|
|
562
|
+
});
|
|
563
|
+
if (!response.ok)
|
|
564
|
+
await mapStreamsError(response);
|
|
565
|
+
return await response.json();
|
|
566
|
+
}
|
|
567
|
+
const fetchEvents = async ({
|
|
568
|
+
cursor,
|
|
569
|
+
limit,
|
|
570
|
+
types
|
|
571
|
+
}) => {
|
|
572
|
+
return listEvents({ cursor, limit, types });
|
|
573
|
+
};
|
|
574
|
+
async function listEvents(params = {}) {
|
|
575
|
+
const searchParams = new URLSearchParams;
|
|
576
|
+
appendSearchParam2(searchParams, "cursor", params.cursor);
|
|
577
|
+
appendSearchParam2(searchParams, "from_height", params.fromHeight);
|
|
578
|
+
appendSearchParam2(searchParams, "to_height", params.toHeight);
|
|
579
|
+
appendSearchParam2(searchParams, "limit", params.limit);
|
|
580
|
+
appendSearchParam2(searchParams, "contract_id", params.contractId);
|
|
581
|
+
if (params.types?.length) {
|
|
582
|
+
searchParams.set("types", params.types.join(","));
|
|
583
|
+
}
|
|
584
|
+
const query = searchParams.toString();
|
|
585
|
+
return request(`/v1/streams/events${query ? `?${query}` : ""}`);
|
|
586
|
+
}
|
|
587
|
+
return {
|
|
588
|
+
events: {
|
|
589
|
+
list: listEvents,
|
|
590
|
+
byTxId(txId) {
|
|
591
|
+
return request(`/v1/streams/events/${encodeURIComponent(txId)}`);
|
|
592
|
+
},
|
|
593
|
+
consume(params) {
|
|
594
|
+
return consumeStreamsEvents({
|
|
595
|
+
fromCursor: params.fromCursor,
|
|
596
|
+
mode: params.mode,
|
|
597
|
+
types: params.types,
|
|
598
|
+
batchSize: params.batchSize ?? 100,
|
|
599
|
+
fetchEvents,
|
|
600
|
+
onBatch: params.onBatch,
|
|
601
|
+
emptyBackoffMs: params.emptyBackoffMs,
|
|
602
|
+
maxPages: params.maxPages,
|
|
603
|
+
maxEmptyPolls: params.maxEmptyPolls,
|
|
604
|
+
signal: params.signal
|
|
605
|
+
});
|
|
606
|
+
},
|
|
607
|
+
stream(params = {}) {
|
|
608
|
+
return streamStreamsEvents({
|
|
609
|
+
fromCursor: params.fromCursor,
|
|
610
|
+
types: params.types,
|
|
611
|
+
batchSize: params.batchSize ?? 100,
|
|
612
|
+
emptyBackoffMs: params.emptyBackoffMs,
|
|
613
|
+
maxPages: params.maxPages,
|
|
614
|
+
maxEmptyPolls: params.maxEmptyPolls,
|
|
615
|
+
signal: params.signal,
|
|
616
|
+
fetchEvents
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
},
|
|
620
|
+
blocks: {
|
|
621
|
+
events(heightOrHash) {
|
|
622
|
+
return request(`/v1/streams/blocks/${encodeURIComponent(String(heightOrHash))}/events`);
|
|
623
|
+
}
|
|
624
|
+
},
|
|
625
|
+
reorgs: {
|
|
626
|
+
list(params) {
|
|
627
|
+
const searchParams = new URLSearchParams;
|
|
628
|
+
appendSearchParam2(searchParams, "since", params.since);
|
|
629
|
+
appendSearchParam2(searchParams, "limit", params.limit);
|
|
630
|
+
const query = searchParams.toString();
|
|
631
|
+
return request(`/v1/streams/reorgs${query ? `?${query}` : ""}`);
|
|
632
|
+
}
|
|
633
|
+
},
|
|
634
|
+
canonical(height) {
|
|
635
|
+
return request(`/v1/streams/canonical/${height}`);
|
|
636
|
+
},
|
|
637
|
+
tip() {
|
|
638
|
+
return request("/v1/streams/tip");
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
|
|
279
643
|
// src/subscriptions/client.ts
|
|
280
644
|
class Subscriptions extends BaseClient {
|
|
281
645
|
async list() {
|
|
@@ -318,10 +682,18 @@ class Subscriptions extends BaseClient {
|
|
|
318
682
|
|
|
319
683
|
// src/client.ts
|
|
320
684
|
class SecondLayer extends BaseClient {
|
|
685
|
+
streams;
|
|
686
|
+
index;
|
|
321
687
|
subgraphs;
|
|
322
688
|
subscriptions;
|
|
323
689
|
constructor(options = {}) {
|
|
324
690
|
super(options);
|
|
691
|
+
this.streams = createStreamsClient({
|
|
692
|
+
apiKey: options.apiKey ?? "",
|
|
693
|
+
baseUrl: options.baseUrl,
|
|
694
|
+
fetchImpl: options.fetchImpl
|
|
695
|
+
});
|
|
696
|
+
this.index = new Index(options);
|
|
325
697
|
this.subgraphs = new Subgraphs(options);
|
|
326
698
|
this.subscriptions = new Subscriptions(options);
|
|
327
699
|
}
|
|
@@ -342,5 +714,5 @@ export {
|
|
|
342
714
|
Subgraphs
|
|
343
715
|
};
|
|
344
716
|
|
|
345
|
-
//# debugId=
|
|
717
|
+
//# debugId=E734D986870AD6AC64756E2164756E21
|
|
346
718
|
//# sourceMappingURL=index.js.map
|