@secondlayer/sdk 5.9.0 → 6.1.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 +62 -6
- package/dist/index.d.ts +165 -36
- package/dist/index.js +285 -302
- package/dist/index.js.map +15 -14
- package/dist/streams/index.d.ts +162 -35
- package/dist/streams/index.js +343 -226
- package/dist/streams/index.js.map +12 -9
- package/dist/subgraphs/index.d.ts +135 -14
- package/dist/subgraphs/index.js +204 -141
- package/dist/subgraphs/index.js.map +10 -9
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -25,6 +25,19 @@ class VersionConflictError extends ApiError {
|
|
|
25
25
|
|
|
26
26
|
// src/base.ts
|
|
27
27
|
var DEFAULT_BASE_URL = "https://api.secondlayer.tools";
|
|
28
|
+
function buildQuery(params) {
|
|
29
|
+
const search = new URLSearchParams;
|
|
30
|
+
for (const [name, value] of Object.entries(params)) {
|
|
31
|
+
if (value === undefined || value === null)
|
|
32
|
+
continue;
|
|
33
|
+
const serialized = Array.isArray(value) ? value.join(",") : String(value);
|
|
34
|
+
if (serialized.length === 0)
|
|
35
|
+
continue;
|
|
36
|
+
search.set(name, serialized);
|
|
37
|
+
}
|
|
38
|
+
const query = search.toString();
|
|
39
|
+
return query ? `?${query}` : "";
|
|
40
|
+
}
|
|
28
41
|
|
|
29
42
|
class BaseClient {
|
|
30
43
|
baseUrl;
|
|
@@ -312,11 +325,6 @@ class Subgraphs extends BaseClient {
|
|
|
312
325
|
}
|
|
313
326
|
}
|
|
314
327
|
// src/index-api/client.ts
|
|
315
|
-
function appendSearchParam(params, name, value) {
|
|
316
|
-
if (value === undefined || value === null)
|
|
317
|
-
return;
|
|
318
|
-
params.set(name, String(value));
|
|
319
|
-
}
|
|
320
328
|
function firstWalkFromHeight(params) {
|
|
321
329
|
if (params.fromHeight !== undefined)
|
|
322
330
|
return params.fromHeight;
|
|
@@ -346,31 +354,29 @@ class Index extends BaseClient {
|
|
|
346
354
|
walk: (params = {}) => this.walkContractCalls(params)
|
|
347
355
|
};
|
|
348
356
|
async listFtTransfers(params = {}) {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
return this.request("GET", `/v1/index/ft-transfers${query ? `?${query}` : ""}`);
|
|
357
|
+
return this.request("GET", `/v1/index/ft-transfers${buildQuery({
|
|
358
|
+
cursor: params.cursor,
|
|
359
|
+
from_cursor: params.fromCursor,
|
|
360
|
+
limit: params.limit,
|
|
361
|
+
contract_id: params.contractId,
|
|
362
|
+
sender: params.sender,
|
|
363
|
+
recipient: params.recipient,
|
|
364
|
+
from_height: params.fromHeight,
|
|
365
|
+
to_height: params.toHeight
|
|
366
|
+
})}`);
|
|
360
367
|
}
|
|
361
368
|
async listNftTransfers(params = {}) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
return this.request("GET", `/v1/index/nft-transfers${query ? `?${query}` : ""}`);
|
|
369
|
+
return this.request("GET", `/v1/index/nft-transfers${buildQuery({
|
|
370
|
+
cursor: params.cursor,
|
|
371
|
+
from_cursor: params.fromCursor,
|
|
372
|
+
limit: params.limit,
|
|
373
|
+
contract_id: params.contractId,
|
|
374
|
+
asset_identifier: params.assetIdentifier,
|
|
375
|
+
sender: params.sender,
|
|
376
|
+
recipient: params.recipient,
|
|
377
|
+
from_height: params.fromHeight,
|
|
378
|
+
to_height: params.toHeight
|
|
379
|
+
})}`);
|
|
374
380
|
}
|
|
375
381
|
async* walkFtTransfers(params = {}) {
|
|
376
382
|
const batchSize = params.batchSize ?? 200;
|
|
@@ -423,18 +429,18 @@ class Index extends BaseClient {
|
|
|
423
429
|
}
|
|
424
430
|
}
|
|
425
431
|
async listEvents(params) {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
432
|
+
return this.request("GET", `/v1/index/events${buildQuery({
|
|
433
|
+
event_type: params.eventType,
|
|
434
|
+
cursor: params.cursor,
|
|
435
|
+
from_cursor: params.fromCursor,
|
|
436
|
+
limit: params.limit,
|
|
437
|
+
contract_id: params.contractId,
|
|
438
|
+
asset_identifier: params.assetIdentifier,
|
|
439
|
+
sender: params.sender,
|
|
440
|
+
recipient: params.recipient,
|
|
441
|
+
from_height: params.fromHeight,
|
|
442
|
+
to_height: params.toHeight
|
|
443
|
+
})}`);
|
|
438
444
|
}
|
|
439
445
|
async* walkEvents(params) {
|
|
440
446
|
const batchSize = params.batchSize ?? 200;
|
|
@@ -462,17 +468,16 @@ class Index extends BaseClient {
|
|
|
462
468
|
}
|
|
463
469
|
}
|
|
464
470
|
async listContractCalls(params = {}) {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
return this.request("GET", `/v1/index/contract-calls${query ? `?${query}` : ""}`);
|
|
471
|
+
return this.request("GET", `/v1/index/contract-calls${buildQuery({
|
|
472
|
+
cursor: params.cursor,
|
|
473
|
+
from_cursor: params.fromCursor,
|
|
474
|
+
limit: params.limit,
|
|
475
|
+
contract_id: params.contractId,
|
|
476
|
+
function_name: params.functionName,
|
|
477
|
+
sender: params.sender,
|
|
478
|
+
from_height: params.fromHeight,
|
|
479
|
+
to_height: params.toHeight
|
|
480
|
+
})}`);
|
|
476
481
|
}
|
|
477
482
|
async* walkContractCalls(params = {}) {
|
|
478
483
|
const batchSize = params.batchSize ?? 200;
|
|
@@ -504,7 +509,74 @@ class Index extends BaseClient {
|
|
|
504
509
|
// src/streams/client.ts
|
|
505
510
|
import { ed25519 } from "@secondlayer/shared";
|
|
506
511
|
|
|
512
|
+
// src/streams/errors.ts
|
|
513
|
+
class AuthError extends Error {
|
|
514
|
+
status = 401;
|
|
515
|
+
constructor(message = "API key invalid or expired.") {
|
|
516
|
+
super(message);
|
|
517
|
+
this.name = "AuthError";
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
class RateLimitError extends Error {
|
|
522
|
+
retryAfter;
|
|
523
|
+
status = 429;
|
|
524
|
+
constructor(message = "Rate limited. Try again later.", retryAfter) {
|
|
525
|
+
super(message);
|
|
526
|
+
this.retryAfter = retryAfter;
|
|
527
|
+
this.name = "RateLimitError";
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
class ValidationError extends Error {
|
|
532
|
+
status;
|
|
533
|
+
body;
|
|
534
|
+
constructor(message, status, body) {
|
|
535
|
+
super(message);
|
|
536
|
+
this.status = status;
|
|
537
|
+
this.body = body;
|
|
538
|
+
this.name = "ValidationError";
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
class StreamsServerError extends Error {
|
|
543
|
+
status;
|
|
544
|
+
body;
|
|
545
|
+
constructor(message, status, body) {
|
|
546
|
+
super(message);
|
|
547
|
+
this.status = status;
|
|
548
|
+
this.body = body;
|
|
549
|
+
this.name = "StreamsServerError";
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
class StreamsSignatureError extends Error {
|
|
554
|
+
constructor(message = "Streams response signature verification failed.") {
|
|
555
|
+
super(message);
|
|
556
|
+
this.name = "StreamsSignatureError";
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// src/streams/cursor.ts
|
|
561
|
+
var Cursor = {
|
|
562
|
+
atHeight(height) {
|
|
563
|
+
return `${height}:0`;
|
|
564
|
+
},
|
|
565
|
+
parse(cursor) {
|
|
566
|
+
const parts = cursor.split(":");
|
|
567
|
+
const blockHeight = Number(parts[0]);
|
|
568
|
+
const eventIndex = Number(parts[1]);
|
|
569
|
+
if (parts.length !== 2 || !Number.isInteger(blockHeight) || !Number.isInteger(eventIndex)) {
|
|
570
|
+
throw new ValidationError(`Invalid stream cursor "${cursor}"; expected "<block>:<index>" (e.g. "951475:3").`, 400);
|
|
571
|
+
}
|
|
572
|
+
return { blockHeight, eventIndex };
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
|
|
507
576
|
// src/streams/consumer.ts
|
|
577
|
+
function reorgKey(reorg) {
|
|
578
|
+
return `${reorg.detected_at}|${reorg.fork_point_height}|${reorg.new_canonical_tip}`;
|
|
579
|
+
}
|
|
508
580
|
async function defaultSleep(ms, signal) {
|
|
509
581
|
if (signal?.aborted)
|
|
510
582
|
return;
|
|
@@ -521,10 +593,12 @@ async function defaultSleep(ms, signal) {
|
|
|
521
593
|
async function consumeStreamsEvents(opts) {
|
|
522
594
|
const sleep = opts.sleep ?? defaultSleep;
|
|
523
595
|
const mode = opts.mode ?? "tail";
|
|
596
|
+
const finalizedOnly = opts.finalizedOnly ?? false;
|
|
524
597
|
const emptyBackoffMs = opts.emptyBackoffMs ?? 500;
|
|
525
598
|
const maxPages = opts.maxPages ?? Number.POSITIVE_INFINITY;
|
|
526
599
|
const maxEmptyPolls = opts.maxEmptyPolls ?? Number.POSITIVE_INFINITY;
|
|
527
600
|
let cursor = opts.fromCursor ?? null;
|
|
601
|
+
const handledReorgs = new Set;
|
|
528
602
|
let pages = 0;
|
|
529
603
|
let emptyPolls = 0;
|
|
530
604
|
while (pages < maxPages && emptyPolls < maxEmptyPolls && !opts.signal?.aborted) {
|
|
@@ -532,20 +606,39 @@ async function consumeStreamsEvents(opts) {
|
|
|
532
606
|
cursor,
|
|
533
607
|
limit: opts.batchSize,
|
|
534
608
|
types: opts.types,
|
|
609
|
+
notTypes: opts.notTypes,
|
|
535
610
|
contractId: opts.contractId,
|
|
536
611
|
sender: opts.sender,
|
|
537
612
|
recipient: opts.recipient,
|
|
538
613
|
assetIdentifier: opts.assetIdentifier
|
|
539
614
|
});
|
|
540
615
|
pages++;
|
|
541
|
-
|
|
542
|
-
|
|
616
|
+
if (!finalizedOnly && opts.onReorg) {
|
|
617
|
+
const fresh = envelope.reorgs.filter((reorg) => !handledReorgs.has(reorgKey(reorg))).sort((a, b) => a.fork_point_height - b.fork_point_height);
|
|
618
|
+
if (fresh.length > 0) {
|
|
619
|
+
const forkPoint = Math.min(...fresh.map((reorg) => reorg.fork_point_height));
|
|
620
|
+
const rewind = Cursor.atHeight(forkPoint);
|
|
621
|
+
for (const reorg of fresh) {
|
|
622
|
+
await opts.onReorg(reorg, { cursor: rewind });
|
|
623
|
+
handledReorgs.add(reorgKey(reorg));
|
|
624
|
+
}
|
|
625
|
+
cursor = rewind;
|
|
626
|
+
emptyPolls = 0;
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
const emitted = finalizedOnly ? envelope.events.filter((event) => event.finalized) : envelope.events;
|
|
631
|
+
const checkpoint = finalizedOnly ? emitted.at(-1)?.cursor ?? cursor : envelope.next_cursor;
|
|
632
|
+
const returnedCursor = await opts.onBatch(emitted, envelope, {
|
|
633
|
+
cursor: checkpoint
|
|
634
|
+
});
|
|
635
|
+
const nextCursor = returnedCursor ?? checkpoint;
|
|
543
636
|
if (nextCursor && nextCursor !== cursor) {
|
|
544
637
|
cursor = nextCursor;
|
|
545
638
|
emptyPolls = 0;
|
|
546
639
|
continue;
|
|
547
640
|
}
|
|
548
|
-
if (
|
|
641
|
+
if (emitted.length === 0) {
|
|
549
642
|
emptyPolls++;
|
|
550
643
|
if (mode === "bounded") {
|
|
551
644
|
return { cursor, pages, emptyPolls };
|
|
@@ -570,6 +663,7 @@ async function* streamStreamsEvents(opts) {
|
|
|
570
663
|
cursor,
|
|
571
664
|
limit: opts.batchSize,
|
|
572
665
|
types: opts.types,
|
|
666
|
+
notTypes: opts.notTypes,
|
|
573
667
|
contractId: opts.contractId,
|
|
574
668
|
sender: opts.sender,
|
|
575
669
|
recipient: opts.recipient,
|
|
@@ -600,56 +694,6 @@ async function* streamStreamsEvents(opts) {
|
|
|
600
694
|
|
|
601
695
|
// src/streams/dumps.ts
|
|
602
696
|
import { createHash } from "node:crypto";
|
|
603
|
-
|
|
604
|
-
// src/streams/errors.ts
|
|
605
|
-
class AuthError extends Error {
|
|
606
|
-
status = 401;
|
|
607
|
-
constructor(message = "API key invalid or expired.") {
|
|
608
|
-
super(message);
|
|
609
|
-
this.name = "AuthError";
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
class RateLimitError extends Error {
|
|
614
|
-
retryAfter;
|
|
615
|
-
status = 429;
|
|
616
|
-
constructor(message = "Rate limited. Try again later.", retryAfter) {
|
|
617
|
-
super(message);
|
|
618
|
-
this.retryAfter = retryAfter;
|
|
619
|
-
this.name = "RateLimitError";
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
class ValidationError extends Error {
|
|
624
|
-
status;
|
|
625
|
-
body;
|
|
626
|
-
constructor(message, status, body) {
|
|
627
|
-
super(message);
|
|
628
|
-
this.status = status;
|
|
629
|
-
this.body = body;
|
|
630
|
-
this.name = "ValidationError";
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
class StreamsServerError extends Error {
|
|
635
|
-
status;
|
|
636
|
-
body;
|
|
637
|
-
constructor(message, status, body) {
|
|
638
|
-
super(message);
|
|
639
|
-
this.status = status;
|
|
640
|
-
this.body = body;
|
|
641
|
-
this.name = "StreamsServerError";
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
class StreamsSignatureError extends Error {
|
|
646
|
-
constructor(message = "Streams response signature verification failed.") {
|
|
647
|
-
super(message);
|
|
648
|
-
this.name = "StreamsSignatureError";
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
// src/streams/dumps.ts
|
|
653
697
|
function createStreamsDumps(opts) {
|
|
654
698
|
const baseUrl = opts.baseUrl?.replace(/\/+$/, "");
|
|
655
699
|
function requireBaseUrl() {
|
|
@@ -688,8 +732,12 @@ function createStreamsDumps(opts) {
|
|
|
688
732
|
function cursorTuple(cursor) {
|
|
689
733
|
if (!cursor)
|
|
690
734
|
return [-1, -1];
|
|
691
|
-
const
|
|
692
|
-
|
|
735
|
+
const parts = cursor.split(":");
|
|
736
|
+
const [block, index] = parts.map(Number);
|
|
737
|
+
if (parts.length !== 2 || !Number.isInteger(block) || !Number.isInteger(index)) {
|
|
738
|
+
throw new ValidationError(`Invalid stream cursor "${cursor}"; expected "<block>:<index>" (e.g. "951475:3").`, 400);
|
|
739
|
+
}
|
|
740
|
+
return [block, index];
|
|
693
741
|
}
|
|
694
742
|
function maxCursor(a, b) {
|
|
695
743
|
const [ah, ai] = cursorTuple(a);
|
|
@@ -700,11 +748,6 @@ var DEFAULT_STREAMS_BASE_URL = "https://api.secondlayer.tools";
|
|
|
700
748
|
function normalizeBaseUrl(baseUrl) {
|
|
701
749
|
return baseUrl.replace(/\/+$/, "");
|
|
702
750
|
}
|
|
703
|
-
function appendSearchParam2(params, name, value) {
|
|
704
|
-
if (value === undefined || value === null)
|
|
705
|
-
return;
|
|
706
|
-
params.set(name, String(value));
|
|
707
|
-
}
|
|
708
751
|
async function responseBody(response) {
|
|
709
752
|
const text = await response.text();
|
|
710
753
|
if (text.length === 0)
|
|
@@ -748,13 +791,16 @@ function createStreamsClient(options) {
|
|
|
748
791
|
baseUrl: options.dumpsBaseUrl,
|
|
749
792
|
fetchImpl
|
|
750
793
|
});
|
|
751
|
-
let
|
|
752
|
-
function
|
|
753
|
-
if (
|
|
754
|
-
return
|
|
755
|
-
|
|
794
|
+
let keyPromise = null;
|
|
795
|
+
function loadKey() {
|
|
796
|
+
if (keyPromise)
|
|
797
|
+
return keyPromise;
|
|
798
|
+
keyPromise = (async () => {
|
|
756
799
|
if (typeof verify === "object") {
|
|
757
|
-
return
|
|
800
|
+
return {
|
|
801
|
+
keyId: ed25519.ed25519KeyId(verify.publicKey),
|
|
802
|
+
publicKey: ed25519.loadEd25519PublicKey(verify.publicKey)
|
|
803
|
+
};
|
|
758
804
|
}
|
|
759
805
|
const res = await fetchImpl(`${baseUrl}/public/streams/signing-key`);
|
|
760
806
|
if (!res.ok) {
|
|
@@ -764,9 +810,12 @@ function createStreamsClient(options) {
|
|
|
764
810
|
if (!body.public_key_pem) {
|
|
765
811
|
throw new StreamsSignatureError("Signing key response missing key.");
|
|
766
812
|
}
|
|
767
|
-
return
|
|
813
|
+
return {
|
|
814
|
+
keyId: body.key_id ?? ed25519.ed25519KeyId(body.public_key_pem),
|
|
815
|
+
publicKey: ed25519.loadEd25519PublicKey(body.public_key_pem)
|
|
816
|
+
};
|
|
768
817
|
})();
|
|
769
|
-
return
|
|
818
|
+
return keyPromise;
|
|
770
819
|
}
|
|
771
820
|
async function request(path) {
|
|
772
821
|
const response = await fetchImpl(`${baseUrl}${path}`, {
|
|
@@ -780,8 +829,19 @@ function createStreamsClient(options) {
|
|
|
780
829
|
if (!signature) {
|
|
781
830
|
throw new StreamsSignatureError("Response is missing X-Signature.");
|
|
782
831
|
}
|
|
783
|
-
const
|
|
784
|
-
|
|
832
|
+
const responseKeyId = response.headers.get("X-Signature-KeyId");
|
|
833
|
+
let key = await loadKey();
|
|
834
|
+
if (responseKeyId && responseKeyId !== key.keyId) {
|
|
835
|
+
if (typeof verify === "object") {
|
|
836
|
+
throw new StreamsSignatureError(`Response signed with key '${responseKeyId}', expected pinned key '${key.keyId}'.`);
|
|
837
|
+
}
|
|
838
|
+
keyPromise = null;
|
|
839
|
+
key = await loadKey();
|
|
840
|
+
if (responseKeyId !== key.keyId) {
|
|
841
|
+
throw new StreamsSignatureError(`Response signed with key '${responseKeyId}' not served by the signing-key endpoint.`);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
if (!ed25519.verifyEd25519(text, signature, key.publicKey)) {
|
|
785
845
|
throw new StreamsSignatureError;
|
|
786
846
|
}
|
|
787
847
|
}
|
|
@@ -791,6 +851,7 @@ function createStreamsClient(options) {
|
|
|
791
851
|
cursor,
|
|
792
852
|
limit,
|
|
793
853
|
types,
|
|
854
|
+
notTypes,
|
|
794
855
|
contractId,
|
|
795
856
|
sender,
|
|
796
857
|
recipient,
|
|
@@ -800,6 +861,7 @@ function createStreamsClient(options) {
|
|
|
800
861
|
cursor,
|
|
801
862
|
limit,
|
|
802
863
|
types,
|
|
864
|
+
notTypes,
|
|
803
865
|
contractId,
|
|
804
866
|
sender,
|
|
805
867
|
recipient,
|
|
@@ -807,20 +869,18 @@ function createStreamsClient(options) {
|
|
|
807
869
|
});
|
|
808
870
|
};
|
|
809
871
|
async function listEvents(params = {}) {
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
}
|
|
822
|
-
const query = searchParams.toString();
|
|
823
|
-
return request(`/v1/streams/events${query ? `?${query}` : ""}`);
|
|
872
|
+
return request(`/v1/streams/events${buildQuery({
|
|
873
|
+
cursor: params.cursor,
|
|
874
|
+
from_height: params.fromHeight,
|
|
875
|
+
to_height: params.toHeight,
|
|
876
|
+
limit: params.limit,
|
|
877
|
+
contract_id: params.contractId,
|
|
878
|
+
sender: params.sender,
|
|
879
|
+
recipient: params.recipient,
|
|
880
|
+
asset_identifier: params.assetIdentifier,
|
|
881
|
+
types: params.types,
|
|
882
|
+
not_types: params.notTypes
|
|
883
|
+
})}`);
|
|
824
884
|
}
|
|
825
885
|
return {
|
|
826
886
|
events: {
|
|
@@ -832,7 +892,9 @@ function createStreamsClient(options) {
|
|
|
832
892
|
return consumeStreamsEvents({
|
|
833
893
|
fromCursor: params.fromCursor,
|
|
834
894
|
mode: params.mode,
|
|
895
|
+
finalizedOnly: params.finalizedOnly,
|
|
835
896
|
types: params.types,
|
|
897
|
+
notTypes: params.notTypes,
|
|
836
898
|
contractId: params.contractId,
|
|
837
899
|
sender: params.sender,
|
|
838
900
|
recipient: params.recipient,
|
|
@@ -840,6 +902,7 @@ function createStreamsClient(options) {
|
|
|
840
902
|
batchSize: params.batchSize ?? 100,
|
|
841
903
|
fetchEvents,
|
|
842
904
|
onBatch: params.onBatch,
|
|
905
|
+
onReorg: params.onReorg,
|
|
843
906
|
emptyBackoffMs: params.emptyBackoffMs,
|
|
844
907
|
maxPages: params.maxPages,
|
|
845
908
|
maxEmptyPolls: params.maxEmptyPolls,
|
|
@@ -850,6 +913,7 @@ function createStreamsClient(options) {
|
|
|
850
913
|
return streamStreamsEvents({
|
|
851
914
|
fromCursor: params.fromCursor,
|
|
852
915
|
types: params.types,
|
|
916
|
+
notTypes: params.notTypes,
|
|
853
917
|
contractId: params.contractId,
|
|
854
918
|
sender: params.sender,
|
|
855
919
|
recipient: params.recipient,
|
|
@@ -893,11 +957,10 @@ function createStreamsClient(options) {
|
|
|
893
957
|
},
|
|
894
958
|
reorgs: {
|
|
895
959
|
list(params) {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
return request(`/v1/streams/reorgs${query ? `?${query}` : ""}`);
|
|
960
|
+
return request(`/v1/streams/reorgs${buildQuery({
|
|
961
|
+
since: params.since,
|
|
962
|
+
limit: params.limit
|
|
963
|
+
})}`);
|
|
901
964
|
}
|
|
902
965
|
},
|
|
903
966
|
dumps,
|
|
@@ -979,127 +1042,8 @@ function getSubgraph(def, options = {}) {
|
|
|
979
1042
|
}
|
|
980
1043
|
return new Subgraphs(options).typed(def);
|
|
981
1044
|
}
|
|
982
|
-
// src/streams/ft-transfer.ts
|
|
983
|
-
function requireString(payload, field) {
|
|
984
|
-
const value = payload[field];
|
|
985
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
986
|
-
throw new Error(`ft_transfer payload missing ${field}`);
|
|
987
|
-
}
|
|
988
|
-
return value;
|
|
989
|
-
}
|
|
990
|
-
function parseAssetIdentifier(assetIdentifier) {
|
|
991
|
-
const [contractId, tokenName] = assetIdentifier.split("::");
|
|
992
|
-
if (!contractId) {
|
|
993
|
-
throw new Error("ft_transfer payload has malformed asset_identifier");
|
|
994
|
-
}
|
|
995
|
-
return {
|
|
996
|
-
contract_id: contractId,
|
|
997
|
-
token_name: tokenName && tokenName.length > 0 ? tokenName : null
|
|
998
|
-
};
|
|
999
|
-
}
|
|
1000
|
-
function isFtTransfer(event) {
|
|
1001
|
-
return event.event_type === "ft_transfer";
|
|
1002
|
-
}
|
|
1003
|
-
function decodeFtTransfer(event) {
|
|
1004
|
-
if (!isFtTransfer(event)) {
|
|
1005
|
-
throw new Error(`Expected ft_transfer event, got ${event.event_type}`);
|
|
1006
|
-
}
|
|
1007
|
-
const payload = event.payload;
|
|
1008
|
-
const assetIdentifier = requireString(payload, "asset_identifier");
|
|
1009
|
-
const sender = requireString(payload, "sender");
|
|
1010
|
-
const recipient = requireString(payload, "recipient");
|
|
1011
|
-
const amount = requireString(payload, "amount");
|
|
1012
|
-
if (!/^(0|[1-9]\d*)$/.test(amount)) {
|
|
1013
|
-
throw new Error("ft_transfer payload has malformed amount");
|
|
1014
|
-
}
|
|
1015
|
-
const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier);
|
|
1016
|
-
return {
|
|
1017
|
-
cursor: event.cursor,
|
|
1018
|
-
block_height: event.block_height,
|
|
1019
|
-
tx_id: event.tx_id,
|
|
1020
|
-
tx_index: event.tx_index,
|
|
1021
|
-
event_index: event.event_index,
|
|
1022
|
-
event_type: event.event_type,
|
|
1023
|
-
decoded_payload: {
|
|
1024
|
-
asset_identifier: assetIdentifier,
|
|
1025
|
-
contract_id: event.contract_id ?? contract_id,
|
|
1026
|
-
token_name,
|
|
1027
|
-
sender,
|
|
1028
|
-
recipient,
|
|
1029
|
-
amount
|
|
1030
|
-
},
|
|
1031
|
-
source_cursor: event.cursor
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
// src/streams/nft-transfer.ts
|
|
1035
|
-
function requireString2(payload, field) {
|
|
1036
|
-
const value = payload[field];
|
|
1037
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
1038
|
-
throw new Error(`nft_transfer payload missing ${field}`);
|
|
1039
|
-
}
|
|
1040
|
-
return value;
|
|
1041
|
-
}
|
|
1042
|
-
function requireHexValue(payload) {
|
|
1043
|
-
const rawValue = payload.raw_value;
|
|
1044
|
-
if (typeof rawValue === "string") {
|
|
1045
|
-
if (!/^0x[0-9a-fA-F]*$/.test(rawValue)) {
|
|
1046
|
-
throw new Error("nft_transfer payload has malformed value");
|
|
1047
|
-
}
|
|
1048
|
-
return rawValue;
|
|
1049
|
-
}
|
|
1050
|
-
const value = payload.value;
|
|
1051
|
-
const hex = typeof value === "string" ? value : value && typeof value === "object" && typeof value.hex === "string" ? value.hex : null;
|
|
1052
|
-
if (!hex) {
|
|
1053
|
-
throw new Error("nft_transfer payload missing value");
|
|
1054
|
-
}
|
|
1055
|
-
if (!/^0x[0-9a-fA-F]*$/.test(hex)) {
|
|
1056
|
-
throw new Error("nft_transfer payload has malformed value");
|
|
1057
|
-
}
|
|
1058
|
-
return hex;
|
|
1059
|
-
}
|
|
1060
|
-
function parseAssetIdentifier2(assetIdentifier) {
|
|
1061
|
-
const [contractId, tokenName] = assetIdentifier.split("::");
|
|
1062
|
-
if (!contractId) {
|
|
1063
|
-
throw new Error("nft_transfer payload has malformed asset_identifier");
|
|
1064
|
-
}
|
|
1065
|
-
return {
|
|
1066
|
-
contract_id: contractId,
|
|
1067
|
-
token_name: tokenName && tokenName.length > 0 ? tokenName : null
|
|
1068
|
-
};
|
|
1069
|
-
}
|
|
1070
|
-
function isNftTransfer(event) {
|
|
1071
|
-
return event.event_type === "nft_transfer";
|
|
1072
|
-
}
|
|
1073
|
-
function decodeNftTransfer(event) {
|
|
1074
|
-
if (!isNftTransfer(event)) {
|
|
1075
|
-
throw new Error(`Expected nft_transfer event, got ${event.event_type}`);
|
|
1076
|
-
}
|
|
1077
|
-
const payload = event.payload;
|
|
1078
|
-
const assetIdentifier = requireString2(payload, "asset_identifier");
|
|
1079
|
-
const sender = requireString2(payload, "sender");
|
|
1080
|
-
const recipient = requireString2(payload, "recipient");
|
|
1081
|
-
const value = requireHexValue(payload);
|
|
1082
|
-
const { contract_id, token_name } = parseAssetIdentifier2(assetIdentifier);
|
|
1083
|
-
return {
|
|
1084
|
-
cursor: event.cursor,
|
|
1085
|
-
block_height: event.block_height,
|
|
1086
|
-
tx_id: event.tx_id,
|
|
1087
|
-
tx_index: event.tx_index,
|
|
1088
|
-
event_index: event.event_index,
|
|
1089
|
-
event_type: event.event_type,
|
|
1090
|
-
decoded_payload: {
|
|
1091
|
-
asset_identifier: assetIdentifier,
|
|
1092
|
-
contract_id: event.contract_id ?? contract_id,
|
|
1093
|
-
token_name,
|
|
1094
|
-
sender,
|
|
1095
|
-
recipient,
|
|
1096
|
-
value
|
|
1097
|
-
},
|
|
1098
|
-
source_cursor: event.cursor
|
|
1099
|
-
};
|
|
1100
|
-
}
|
|
1101
1045
|
// src/streams/_payload.ts
|
|
1102
|
-
function
|
|
1046
|
+
function requireString(payload, field, eventType) {
|
|
1103
1047
|
const value = payload[field];
|
|
1104
1048
|
if (typeof value !== "string" || value.length === 0) {
|
|
1105
1049
|
throw new Error(`${eventType} payload missing ${field}`);
|
|
@@ -1110,7 +1054,7 @@ function optionalString(value) {
|
|
|
1110
1054
|
return typeof value === "string" && value.length > 0 ? value : null;
|
|
1111
1055
|
}
|
|
1112
1056
|
function requireAmountField(payload, field, eventType) {
|
|
1113
|
-
const amount =
|
|
1057
|
+
const amount = requireString(payload, field, eventType);
|
|
1114
1058
|
if (!/^(0|[1-9]\d*)$/.test(amount)) {
|
|
1115
1059
|
throw new Error(`${eventType} payload has malformed ${field}`);
|
|
1116
1060
|
}
|
|
@@ -1119,7 +1063,7 @@ function requireAmountField(payload, field, eventType) {
|
|
|
1119
1063
|
function requireAmount(payload, eventType) {
|
|
1120
1064
|
return requireAmountField(payload, "amount", eventType);
|
|
1121
1065
|
}
|
|
1122
|
-
function
|
|
1066
|
+
function parseAssetIdentifier(assetIdentifier, eventType) {
|
|
1123
1067
|
const [contractId, tokenName] = assetIdentifier.split("::");
|
|
1124
1068
|
if (!contractId) {
|
|
1125
1069
|
throw new Error(`${eventType} payload has malformed asset_identifier`);
|
|
@@ -1129,7 +1073,7 @@ function parseAssetIdentifier3(assetIdentifier, eventType) {
|
|
|
1129
1073
|
token_name: tokenName && tokenName.length > 0 ? tokenName : null
|
|
1130
1074
|
};
|
|
1131
1075
|
}
|
|
1132
|
-
function
|
|
1076
|
+
function requireHexValue(payload, eventType) {
|
|
1133
1077
|
const rawValue = payload.raw_value;
|
|
1134
1078
|
if (typeof rawValue === "string") {
|
|
1135
1079
|
if (!/^0x[0-9a-fA-F]*$/.test(rawValue)) {
|
|
@@ -1160,6 +1104,52 @@ function decodedRow(event, eventType, decoded_payload) {
|
|
|
1160
1104
|
};
|
|
1161
1105
|
}
|
|
1162
1106
|
|
|
1107
|
+
// src/streams/ft-transfer.ts
|
|
1108
|
+
function isFtTransfer(event) {
|
|
1109
|
+
return event.event_type === "ft_transfer";
|
|
1110
|
+
}
|
|
1111
|
+
function decodeFtTransfer(event) {
|
|
1112
|
+
if (!isFtTransfer(event)) {
|
|
1113
|
+
throw new Error(`Expected ft_transfer event, got ${event.event_type}`);
|
|
1114
|
+
}
|
|
1115
|
+
const payload = event.payload;
|
|
1116
|
+
const assetIdentifier = requireString(payload, "asset_identifier", "ft_transfer");
|
|
1117
|
+
const sender = requireString(payload, "sender", "ft_transfer");
|
|
1118
|
+
const recipient = requireString(payload, "recipient", "ft_transfer");
|
|
1119
|
+
const amount = requireAmount(payload, "ft_transfer");
|
|
1120
|
+
const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier, "ft_transfer");
|
|
1121
|
+
return decodedRow(event, "ft_transfer", {
|
|
1122
|
+
asset_identifier: assetIdentifier,
|
|
1123
|
+
contract_id: event.contract_id ?? contract_id,
|
|
1124
|
+
token_name,
|
|
1125
|
+
sender,
|
|
1126
|
+
recipient,
|
|
1127
|
+
amount
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
// src/streams/nft-transfer.ts
|
|
1131
|
+
function isNftTransfer(event) {
|
|
1132
|
+
return event.event_type === "nft_transfer";
|
|
1133
|
+
}
|
|
1134
|
+
function decodeNftTransfer(event) {
|
|
1135
|
+
if (!isNftTransfer(event)) {
|
|
1136
|
+
throw new Error(`Expected nft_transfer event, got ${event.event_type}`);
|
|
1137
|
+
}
|
|
1138
|
+
const payload = event.payload;
|
|
1139
|
+
const assetIdentifier = requireString(payload, "asset_identifier", "nft_transfer");
|
|
1140
|
+
const sender = requireString(payload, "sender", "nft_transfer");
|
|
1141
|
+
const recipient = requireString(payload, "recipient", "nft_transfer");
|
|
1142
|
+
const value = requireHexValue(payload, "nft_transfer");
|
|
1143
|
+
const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier, "nft_transfer");
|
|
1144
|
+
return decodedRow(event, "nft_transfer", {
|
|
1145
|
+
asset_identifier: assetIdentifier,
|
|
1146
|
+
contract_id: event.contract_id ?? contract_id,
|
|
1147
|
+
token_name,
|
|
1148
|
+
sender,
|
|
1149
|
+
recipient,
|
|
1150
|
+
value
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1163
1153
|
// src/streams/stx-events.ts
|
|
1164
1154
|
function isStxTransfer(event) {
|
|
1165
1155
|
return event.event_type === "stx_transfer";
|
|
@@ -1170,8 +1160,8 @@ function decodeStxTransfer(event) {
|
|
|
1170
1160
|
}
|
|
1171
1161
|
const payload = event.payload;
|
|
1172
1162
|
return decodedRow(event, "stx_transfer", {
|
|
1173
|
-
sender:
|
|
1174
|
-
recipient:
|
|
1163
|
+
sender: requireString(payload, "sender", "stx_transfer"),
|
|
1164
|
+
recipient: requireString(payload, "recipient", "stx_transfer"),
|
|
1175
1165
|
amount: requireAmount(payload, "stx_transfer"),
|
|
1176
1166
|
memo: optionalString(payload.memo)
|
|
1177
1167
|
});
|
|
@@ -1185,7 +1175,7 @@ function decodeStxMint(event) {
|
|
|
1185
1175
|
}
|
|
1186
1176
|
const payload = event.payload;
|
|
1187
1177
|
return decodedRow(event, "stx_mint", {
|
|
1188
|
-
recipient:
|
|
1178
|
+
recipient: requireString(payload, "recipient", "stx_mint"),
|
|
1189
1179
|
amount: requireAmount(payload, "stx_mint")
|
|
1190
1180
|
});
|
|
1191
1181
|
}
|
|
@@ -1198,7 +1188,7 @@ function decodeStxBurn(event) {
|
|
|
1198
1188
|
}
|
|
1199
1189
|
const payload = event.payload;
|
|
1200
1190
|
return decodedRow(event, "stx_burn", {
|
|
1201
|
-
sender:
|
|
1191
|
+
sender: requireString(payload, "sender", "stx_burn"),
|
|
1202
1192
|
amount: requireAmount(payload, "stx_burn")
|
|
1203
1193
|
});
|
|
1204
1194
|
}
|
|
@@ -1211,15 +1201,15 @@ function decodeStxLock(event) {
|
|
|
1211
1201
|
}
|
|
1212
1202
|
const payload = event.payload;
|
|
1213
1203
|
return decodedRow(event, "stx_lock", {
|
|
1214
|
-
sender:
|
|
1204
|
+
sender: requireString(payload, "locked_address", "stx_lock"),
|
|
1215
1205
|
amount: requireAmountField(payload, "locked_amount", "stx_lock"),
|
|
1216
1206
|
payload: { unlock_height: optionalString(payload.unlock_height) }
|
|
1217
1207
|
});
|
|
1218
1208
|
}
|
|
1219
1209
|
// src/streams/token-mint-burn.ts
|
|
1220
1210
|
function assetFields(event, eventType) {
|
|
1221
|
-
const assetIdentifier =
|
|
1222
|
-
const { contract_id, token_name } =
|
|
1211
|
+
const assetIdentifier = requireString(event.payload, "asset_identifier", eventType);
|
|
1212
|
+
const { contract_id, token_name } = parseAssetIdentifier(assetIdentifier, eventType);
|
|
1223
1213
|
return {
|
|
1224
1214
|
asset_identifier: assetIdentifier,
|
|
1225
1215
|
contract_id: event.contract_id ?? contract_id,
|
|
@@ -1235,7 +1225,7 @@ function decodeFtMint(event) {
|
|
|
1235
1225
|
}
|
|
1236
1226
|
return decodedRow(event, "ft_mint", {
|
|
1237
1227
|
...assetFields(event, "ft_mint"),
|
|
1238
|
-
recipient:
|
|
1228
|
+
recipient: requireString(event.payload, "recipient", "ft_mint"),
|
|
1239
1229
|
amount: requireAmount(event.payload, "ft_mint")
|
|
1240
1230
|
});
|
|
1241
1231
|
}
|
|
@@ -1248,7 +1238,7 @@ function decodeFtBurn(event) {
|
|
|
1248
1238
|
}
|
|
1249
1239
|
return decodedRow(event, "ft_burn", {
|
|
1250
1240
|
...assetFields(event, "ft_burn"),
|
|
1251
|
-
sender:
|
|
1241
|
+
sender: requireString(event.payload, "sender", "ft_burn"),
|
|
1252
1242
|
amount: requireAmount(event.payload, "ft_burn")
|
|
1253
1243
|
});
|
|
1254
1244
|
}
|
|
@@ -1261,8 +1251,8 @@ function decodeNftMint(event) {
|
|
|
1261
1251
|
}
|
|
1262
1252
|
return decodedRow(event, "nft_mint", {
|
|
1263
1253
|
...assetFields(event, "nft_mint"),
|
|
1264
|
-
recipient:
|
|
1265
|
-
value:
|
|
1254
|
+
recipient: requireString(event.payload, "recipient", "nft_mint"),
|
|
1255
|
+
value: requireHexValue(event.payload, "nft_mint")
|
|
1266
1256
|
});
|
|
1267
1257
|
}
|
|
1268
1258
|
function isNftBurn(event) {
|
|
@@ -1274,8 +1264,8 @@ function decodeNftBurn(event) {
|
|
|
1274
1264
|
}
|
|
1275
1265
|
return decodedRow(event, "nft_burn", {
|
|
1276
1266
|
...assetFields(event, "nft_burn"),
|
|
1277
|
-
sender:
|
|
1278
|
-
value:
|
|
1267
|
+
sender: requireString(event.payload, "sender", "nft_burn"),
|
|
1268
|
+
value: requireHexValue(event.payload, "nft_burn")
|
|
1279
1269
|
});
|
|
1280
1270
|
}
|
|
1281
1271
|
// src/clarity.ts
|
|
@@ -1346,11 +1336,6 @@ var STREAMS_EVENT_TYPES = [
|
|
|
1346
1336
|
"print"
|
|
1347
1337
|
];
|
|
1348
1338
|
// src/datasets/client.ts
|
|
1349
|
-
function appendParam(params, name, value) {
|
|
1350
|
-
if (value === undefined || value === null)
|
|
1351
|
-
return;
|
|
1352
|
-
params.set(name, String(value));
|
|
1353
|
-
}
|
|
1354
1339
|
var PARAM_KEYS = {
|
|
1355
1340
|
fromBlock: "from_block",
|
|
1356
1341
|
toBlock: "to_block",
|
|
@@ -1391,7 +1376,7 @@ class Datasets extends BaseClient {
|
|
|
1391
1376
|
if (!d) {
|
|
1392
1377
|
throw new Error(`unknown cursor dataset "${slug}" (use one of: ${Object.keys(CURSOR_SLUGS).join(", ")})`);
|
|
1393
1378
|
}
|
|
1394
|
-
const env = await this.get(d.path, this.
|
|
1379
|
+
const env = await this.get(d.path, this.paramsToQuery(params));
|
|
1395
1380
|
return {
|
|
1396
1381
|
rows: env[d.rowKey] ?? [],
|
|
1397
1382
|
next_cursor: env.next_cursor ?? null,
|
|
@@ -1408,40 +1393,37 @@ class Datasets extends BaseClient {
|
|
|
1408
1393
|
bnsNamespaceEvents = this.cursorDataset("bns/namespace-events", "events");
|
|
1409
1394
|
bnsMarketplaceEvents = this.cursorDataset("bns/marketplace-events", "events");
|
|
1410
1395
|
bnsNames(params = {}) {
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1396
|
+
return this.get("bns/names", buildQuery({
|
|
1397
|
+
namespace: params.namespace,
|
|
1398
|
+
owner: params.owner,
|
|
1399
|
+
limit: params.limit,
|
|
1400
|
+
offset: params.offset
|
|
1401
|
+
}));
|
|
1417
1402
|
}
|
|
1418
1403
|
bnsNamespaces() {
|
|
1419
|
-
return this.get("bns/namespaces",
|
|
1404
|
+
return this.get("bns/namespaces", "");
|
|
1420
1405
|
}
|
|
1421
1406
|
bnsResolve(fqn) {
|
|
1422
|
-
|
|
1423
|
-
sp.set("fqn", fqn);
|
|
1424
|
-
return this.get("bns/resolve", sp);
|
|
1407
|
+
return this.get("bns/resolve", buildQuery({ fqn }));
|
|
1425
1408
|
}
|
|
1426
1409
|
networkHealth() {
|
|
1427
|
-
return this.get("network-health/summary",
|
|
1410
|
+
return this.get("network-health/summary", "");
|
|
1428
1411
|
}
|
|
1429
|
-
get(path,
|
|
1430
|
-
|
|
1431
|
-
return this.request("GET", `/v1/datasets/${path}${qs ? `?${qs}` : ""}`);
|
|
1412
|
+
get(path, query) {
|
|
1413
|
+
return this.request("GET", `/v1/datasets/${path}${query}`);
|
|
1432
1414
|
}
|
|
1433
|
-
|
|
1434
|
-
const
|
|
1415
|
+
paramsToQuery(params) {
|
|
1416
|
+
const mapped = {};
|
|
1435
1417
|
for (const [k, v] of Object.entries(params)) {
|
|
1436
1418
|
if (v === undefined || v === null || k === "batchSize" || k === "signal")
|
|
1437
1419
|
continue;
|
|
1438
|
-
|
|
1420
|
+
mapped[PARAM_KEYS[k] ?? k] = v;
|
|
1439
1421
|
}
|
|
1440
|
-
return
|
|
1422
|
+
return buildQuery(mapped);
|
|
1441
1423
|
}
|
|
1442
1424
|
cursorDataset(path, rowKey) {
|
|
1443
1425
|
const list = async (params = {}) => {
|
|
1444
|
-
const envelope = await this.get(path, this.
|
|
1426
|
+
const envelope = await this.get(path, this.paramsToQuery(params));
|
|
1445
1427
|
return {
|
|
1446
1428
|
rows: envelope[rowKey] ?? [],
|
|
1447
1429
|
next_cursor: envelope.next_cursor ?? null,
|
|
@@ -1553,10 +1535,11 @@ export {
|
|
|
1553
1535
|
RateLimitError,
|
|
1554
1536
|
Index,
|
|
1555
1537
|
Datasets,
|
|
1538
|
+
Cursor,
|
|
1556
1539
|
CURSOR_SLUGS,
|
|
1557
1540
|
AuthError,
|
|
1558
1541
|
ApiError
|
|
1559
1542
|
};
|
|
1560
1543
|
|
|
1561
|
-
//# debugId=
|
|
1544
|
+
//# debugId=DF9925BCF7B82FB964756E2164756E21
|
|
1562
1545
|
//# sourceMappingURL=index.js.map
|