@otskit/client 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +27 -5
- package/dist/index.cjs +32 -9
- package/dist/index.js +32 -9
- package/package.json +5 -7
package/dist/browser.js
CHANGED
|
@@ -500,7 +500,7 @@ function parseWhitelistPattern(raw) {
|
|
|
500
500
|
return void 0;
|
|
501
501
|
}
|
|
502
502
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
|
|
503
|
-
const hostname = parsed.hostname.toLowerCase();
|
|
503
|
+
const hostname = parsed.hostname.toLowerCase().replaceAll("%2a", "*");
|
|
504
504
|
const wildcardSuffix = hostname.startsWith("*.") ? hostname.slice(2) : void 0;
|
|
505
505
|
if (hostname.includes("*") && wildcardSuffix === void 0) return void 0;
|
|
506
506
|
if (wildcardSuffix !== void 0 && (wildcardSuffix.length === 0 || wildcardSuffix.includes("*"))) return void 0;
|
|
@@ -619,7 +619,29 @@ async function orchestrateStamp(hash, calendars, networkLayer, validateCalendarU
|
|
|
619
619
|
`minimumSuccessfulSubmissions (${minimumSuccessfulSubmissions}) cannot exceed the number of calendars (${calendars.length})`
|
|
620
620
|
);
|
|
621
621
|
}
|
|
622
|
-
await Promise.
|
|
622
|
+
const validations = await Promise.allSettled(calendars.map((url) => validateCalendarUrl(url)));
|
|
623
|
+
const usable = [];
|
|
624
|
+
const unusable = [];
|
|
625
|
+
validations.forEach((v, i) => {
|
|
626
|
+
const calendar = calendars[i];
|
|
627
|
+
if (v.status === "fulfilled") {
|
|
628
|
+
usable.push(calendar);
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
const error = v.reason instanceof Error ? v.reason : new Error(String(v.reason));
|
|
632
|
+
unusable.push({ calendar, error });
|
|
633
|
+
logger?.warn(`Skipping calendar ${calendar}: ${error.message}`);
|
|
634
|
+
});
|
|
635
|
+
if (usable.length === 0) {
|
|
636
|
+
throw unusable[0].error;
|
|
637
|
+
}
|
|
638
|
+
if (usable.length < minimumSuccessfulSubmissions) {
|
|
639
|
+
throw new StampError(
|
|
640
|
+
`Insufficient usable calendars (${usable.length}/${minimumSuccessfulSubmissions} required)`,
|
|
641
|
+
[],
|
|
642
|
+
unusable
|
|
643
|
+
);
|
|
644
|
+
}
|
|
623
645
|
const digest = validateHash(hash);
|
|
624
646
|
logger?.info(`Starting stamp for ${bytesToHex2(digest)}`);
|
|
625
647
|
const detached = DetachedTimestampFile.fromHash(new OpSHA256(), digest);
|
|
@@ -627,14 +649,14 @@ async function orchestrateStamp(hash, calendars, networkLayer, validateCalendarU
|
|
|
627
649
|
const merkleRoot = nonceAppended.add(new OpSHA256());
|
|
628
650
|
const merkleTip = makeMerkleTree([merkleRoot]);
|
|
629
651
|
const results = await Promise.allSettled(
|
|
630
|
-
|
|
652
|
+
usable.map(
|
|
631
653
|
(url) => new CalendarClient(url, networkLayer, logger).submit(merkleTip.getDigest(), signal)
|
|
632
654
|
)
|
|
633
655
|
);
|
|
634
656
|
const successful = [];
|
|
635
|
-
const failed = [];
|
|
657
|
+
const failed = [...unusable];
|
|
636
658
|
results.forEach((r, i) => {
|
|
637
|
-
const calendar =
|
|
659
|
+
const calendar = usable[i];
|
|
638
660
|
if (r.status === "fulfilled") {
|
|
639
661
|
merkleTip.merge(r.value);
|
|
640
662
|
successful.push({ calendar });
|
package/dist/index.cjs
CHANGED
|
@@ -583,7 +583,7 @@ function parseWhitelistPattern(raw) {
|
|
|
583
583
|
return void 0;
|
|
584
584
|
}
|
|
585
585
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
|
|
586
|
-
const hostname = parsed.hostname.toLowerCase();
|
|
586
|
+
const hostname = parsed.hostname.toLowerCase().replaceAll("%2a", "*");
|
|
587
587
|
const wildcardSuffix = hostname.startsWith("*.") ? hostname.slice(2) : void 0;
|
|
588
588
|
if (hostname.includes("*") && wildcardSuffix === void 0) return void 0;
|
|
589
589
|
if (wildcardSuffix !== void 0 && (wildcardSuffix.length === 0 || wildcardSuffix.includes("*"))) return void 0;
|
|
@@ -702,7 +702,29 @@ async function orchestrateStamp(hash, calendars, networkLayer, validateCalendarU
|
|
|
702
702
|
`minimumSuccessfulSubmissions (${minimumSuccessfulSubmissions}) cannot exceed the number of calendars (${calendars.length})`
|
|
703
703
|
);
|
|
704
704
|
}
|
|
705
|
-
await Promise.
|
|
705
|
+
const validations = await Promise.allSettled(calendars.map((url) => validateCalendarUrl(url)));
|
|
706
|
+
const usable = [];
|
|
707
|
+
const unusable = [];
|
|
708
|
+
validations.forEach((v, i) => {
|
|
709
|
+
const calendar = calendars[i];
|
|
710
|
+
if (v.status === "fulfilled") {
|
|
711
|
+
usable.push(calendar);
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
const error = v.reason instanceof Error ? v.reason : new Error(String(v.reason));
|
|
715
|
+
unusable.push({ calendar, error });
|
|
716
|
+
logger?.warn(`Skipping calendar ${calendar}: ${error.message}`);
|
|
717
|
+
});
|
|
718
|
+
if (usable.length === 0) {
|
|
719
|
+
throw unusable[0].error;
|
|
720
|
+
}
|
|
721
|
+
if (usable.length < minimumSuccessfulSubmissions) {
|
|
722
|
+
throw new StampError(
|
|
723
|
+
`Insufficient usable calendars (${usable.length}/${minimumSuccessfulSubmissions} required)`,
|
|
724
|
+
[],
|
|
725
|
+
unusable
|
|
726
|
+
);
|
|
727
|
+
}
|
|
706
728
|
const digest = validateHash(hash);
|
|
707
729
|
logger?.info(`Starting stamp for ${bytesToHex2(digest)}`);
|
|
708
730
|
const detached = import_core3.DetachedTimestampFile.fromHash(new import_core3.OpSHA256(), digest);
|
|
@@ -710,14 +732,14 @@ async function orchestrateStamp(hash, calendars, networkLayer, validateCalendarU
|
|
|
710
732
|
const merkleRoot = nonceAppended.add(new import_core3.OpSHA256());
|
|
711
733
|
const merkleTip = (0, import_core3.makeMerkleTree)([merkleRoot]);
|
|
712
734
|
const results = await Promise.allSettled(
|
|
713
|
-
|
|
735
|
+
usable.map(
|
|
714
736
|
(url) => new CalendarClient(url, networkLayer, logger).submit(merkleTip.getDigest(), signal)
|
|
715
737
|
)
|
|
716
738
|
);
|
|
717
739
|
const successful = [];
|
|
718
|
-
const failed = [];
|
|
740
|
+
const failed = [...unusable];
|
|
719
741
|
results.forEach((r, i) => {
|
|
720
|
-
const calendar =
|
|
742
|
+
const calendar = usable[i];
|
|
721
743
|
if (r.status === "fulfilled") {
|
|
722
744
|
merkleTip.merge(r.value);
|
|
723
745
|
successful.push({ calendar });
|
|
@@ -991,14 +1013,15 @@ async function orchestrateVerify(proof, networkLayer, originalDataHash, logger,
|
|
|
991
1013
|
}
|
|
992
1014
|
}
|
|
993
1015
|
const allBitcoin = detached.timestamp.allAttestations().filter(({ attestation }) => attestation.kind === "bitcoin");
|
|
994
|
-
const
|
|
995
|
-
const deduped = allBitcoin.filter(({ attestation }) => {
|
|
1016
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1017
|
+
const deduped = allBitcoin.filter(({ msg, attestation }) => {
|
|
996
1018
|
if (attestation.kind !== "bitcoin") return false;
|
|
997
|
-
|
|
1019
|
+
const key = `${attestation.height}:${bytesToHex2(msg)}`;
|
|
1020
|
+
if (seen.has(key)) {
|
|
998
1021
|
logger?.debug(`Skipping duplicate Bitcoin attestation at height ${attestation.height}`);
|
|
999
1022
|
return false;
|
|
1000
1023
|
}
|
|
1001
|
-
|
|
1024
|
+
seen.add(key);
|
|
1002
1025
|
return true;
|
|
1003
1026
|
});
|
|
1004
1027
|
const bitcoinAtts = deduped.slice(0, MAX_BITCOIN_ATTESTATIONS);
|
package/dist/index.js
CHANGED
|
@@ -533,7 +533,7 @@ function parseWhitelistPattern(raw) {
|
|
|
533
533
|
return void 0;
|
|
534
534
|
}
|
|
535
535
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
|
|
536
|
-
const hostname = parsed.hostname.toLowerCase();
|
|
536
|
+
const hostname = parsed.hostname.toLowerCase().replaceAll("%2a", "*");
|
|
537
537
|
const wildcardSuffix = hostname.startsWith("*.") ? hostname.slice(2) : void 0;
|
|
538
538
|
if (hostname.includes("*") && wildcardSuffix === void 0) return void 0;
|
|
539
539
|
if (wildcardSuffix !== void 0 && (wildcardSuffix.length === 0 || wildcardSuffix.includes("*"))) return void 0;
|
|
@@ -652,7 +652,29 @@ async function orchestrateStamp(hash, calendars, networkLayer, validateCalendarU
|
|
|
652
652
|
`minimumSuccessfulSubmissions (${minimumSuccessfulSubmissions}) cannot exceed the number of calendars (${calendars.length})`
|
|
653
653
|
);
|
|
654
654
|
}
|
|
655
|
-
await Promise.
|
|
655
|
+
const validations = await Promise.allSettled(calendars.map((url) => validateCalendarUrl(url)));
|
|
656
|
+
const usable = [];
|
|
657
|
+
const unusable = [];
|
|
658
|
+
validations.forEach((v, i) => {
|
|
659
|
+
const calendar = calendars[i];
|
|
660
|
+
if (v.status === "fulfilled") {
|
|
661
|
+
usable.push(calendar);
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
const error = v.reason instanceof Error ? v.reason : new Error(String(v.reason));
|
|
665
|
+
unusable.push({ calendar, error });
|
|
666
|
+
logger?.warn(`Skipping calendar ${calendar}: ${error.message}`);
|
|
667
|
+
});
|
|
668
|
+
if (usable.length === 0) {
|
|
669
|
+
throw unusable[0].error;
|
|
670
|
+
}
|
|
671
|
+
if (usable.length < minimumSuccessfulSubmissions) {
|
|
672
|
+
throw new StampError(
|
|
673
|
+
`Insufficient usable calendars (${usable.length}/${minimumSuccessfulSubmissions} required)`,
|
|
674
|
+
[],
|
|
675
|
+
unusable
|
|
676
|
+
);
|
|
677
|
+
}
|
|
656
678
|
const digest = validateHash(hash);
|
|
657
679
|
logger?.info(`Starting stamp for ${bytesToHex2(digest)}`);
|
|
658
680
|
const detached = DetachedTimestampFile.fromHash(new OpSHA256(), digest);
|
|
@@ -660,14 +682,14 @@ async function orchestrateStamp(hash, calendars, networkLayer, validateCalendarU
|
|
|
660
682
|
const merkleRoot = nonceAppended.add(new OpSHA256());
|
|
661
683
|
const merkleTip = makeMerkleTree([merkleRoot]);
|
|
662
684
|
const results = await Promise.allSettled(
|
|
663
|
-
|
|
685
|
+
usable.map(
|
|
664
686
|
(url) => new CalendarClient(url, networkLayer, logger).submit(merkleTip.getDigest(), signal)
|
|
665
687
|
)
|
|
666
688
|
);
|
|
667
689
|
const successful = [];
|
|
668
|
-
const failed = [];
|
|
690
|
+
const failed = [...unusable];
|
|
669
691
|
results.forEach((r, i) => {
|
|
670
|
-
const calendar =
|
|
692
|
+
const calendar = usable[i];
|
|
671
693
|
if (r.status === "fulfilled") {
|
|
672
694
|
merkleTip.merge(r.value);
|
|
673
695
|
successful.push({ calendar });
|
|
@@ -941,14 +963,15 @@ async function orchestrateVerify(proof, networkLayer, originalDataHash, logger,
|
|
|
941
963
|
}
|
|
942
964
|
}
|
|
943
965
|
const allBitcoin = detached.timestamp.allAttestations().filter(({ attestation }) => attestation.kind === "bitcoin");
|
|
944
|
-
const
|
|
945
|
-
const deduped = allBitcoin.filter(({ attestation }) => {
|
|
966
|
+
const seen = /* @__PURE__ */ new Set();
|
|
967
|
+
const deduped = allBitcoin.filter(({ msg, attestation }) => {
|
|
946
968
|
if (attestation.kind !== "bitcoin") return false;
|
|
947
|
-
|
|
969
|
+
const key = `${attestation.height}:${bytesToHex2(msg)}`;
|
|
970
|
+
if (seen.has(key)) {
|
|
948
971
|
logger?.debug(`Skipping duplicate Bitcoin attestation at height ${attestation.height}`);
|
|
949
972
|
return false;
|
|
950
973
|
}
|
|
951
|
-
|
|
974
|
+
seen.add(key);
|
|
952
975
|
return true;
|
|
953
976
|
});
|
|
954
977
|
const bitcoinAtts = deduped.slice(0, MAX_BITCOIN_ATTESTATIONS);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otskit/client",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Official client SDK for OpenTimestamps calendars with resilience patterns",
|
|
5
5
|
"author": "alexalves87",
|
|
6
6
|
"license": "MIT",
|
|
@@ -67,21 +67,19 @@
|
|
|
67
67
|
"@otskit/core": "^0.2.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
+
"@eslint/js": "^10.0.1",
|
|
70
71
|
"@semantic-release/changelog": "^7.0.0",
|
|
71
72
|
"@semantic-release/git": "^11.0.0",
|
|
72
73
|
"@types/node": "^26.1.1",
|
|
73
|
-
"@vitest/
|
|
74
|
-
"@vitest/coverage-v8": "^4.1.8",
|
|
75
|
-
"@eslint/js": "^10.0.1",
|
|
74
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
76
75
|
"eslint": "^10.0.1",
|
|
77
|
-
"typescript-eslint": "^8.0.0",
|
|
78
76
|
"fast-check": "^4.3.0",
|
|
79
77
|
"msw": "^2.11.6",
|
|
80
|
-
"playwright": "^1.56.1",
|
|
81
78
|
"prettier": "^3.3.3",
|
|
82
79
|
"semantic-release": "^25.0.3",
|
|
83
80
|
"tsup": "^8.3.5",
|
|
84
81
|
"typescript": "^6.0.3",
|
|
85
|
-
"
|
|
82
|
+
"typescript-eslint": "^8.0.0",
|
|
83
|
+
"vitest": "^5.0.0"
|
|
86
84
|
}
|
|
87
85
|
}
|