@hashgraphonline/standards-sdk 0.1.170 → 0.1.171
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 +2 -2
- package/dist/es/standards-sdk.es121.js +1 -1
- package/dist/es/standards-sdk.es128.js +5 -5
- package/dist/es/standards-sdk.es138.js +1 -1
- package/dist/es/standards-sdk.es139.js +1 -1
- package/dist/es/standards-sdk.es140.js +5 -5
- package/dist/es/standards-sdk.es142.js +1 -1
- package/dist/es/standards-sdk.es148.js +1 -1
- package/dist/es/standards-sdk.es149.js +1 -1
- package/dist/es/standards-sdk.es161.js +542 -48
- package/dist/es/standards-sdk.es161.js.map +1 -1
- package/dist/es/standards-sdk.es162.js +59 -70
- package/dist/es/standards-sdk.es162.js.map +1 -1
- package/dist/es/standards-sdk.es163.js +48 -73
- package/dist/es/standards-sdk.es163.js.map +1 -1
- package/dist/es/standards-sdk.es164.js +64 -180
- package/dist/es/standards-sdk.es164.js.map +1 -1
- package/dist/es/standards-sdk.es165.js +79 -15
- package/dist/es/standards-sdk.es165.js.map +1 -1
- package/dist/es/standards-sdk.es166.js +187 -537
- package/dist/es/standards-sdk.es166.js.map +1 -1
- package/dist/es/standards-sdk.es167.js +13 -168
- package/dist/es/standards-sdk.es167.js.map +1 -1
- package/dist/es/standards-sdk.es168.js +139 -289
- package/dist/es/standards-sdk.es168.js.map +1 -1
- package/dist/es/standards-sdk.es169.js +274 -298
- package/dist/es/standards-sdk.es169.js.map +1 -1
- package/dist/es/standards-sdk.es170.js +262 -369
- package/dist/es/standards-sdk.es170.js.map +1 -1
- package/dist/es/standards-sdk.es171.js +316 -194
- package/dist/es/standards-sdk.es171.js.map +1 -1
- package/dist/es/standards-sdk.es172.js +319 -64
- package/dist/es/standards-sdk.es172.js.map +1 -1
- package/dist/es/standards-sdk.es173.js +66 -63
- package/dist/es/standards-sdk.es173.js.map +1 -1
- package/dist/es/standards-sdk.es174.js +1 -1
- package/dist/es/standards-sdk.es178.js +1 -1
- package/dist/es/standards-sdk.es56.js +1 -1
- package/dist/es/standards-sdk.es59.js +1 -1
- package/dist/es/standards-sdk.es60.js +1 -1
- package/dist/es/standards-sdk.es62.js +1 -1
- package/dist/es/standards-sdk.es63.js +2 -2
- package/dist/es/standards-sdk.es64.js +1 -1
- package/dist/es/standards-sdk.es65.js +1 -1
- package/dist/es/standards-sdk.es66.js +1 -1
- package/dist/es/standards-sdk.es69.js +1 -1
- package/dist/es/standards-sdk.es71.js +1 -1
- package/dist/es/standards-sdk.es72.js +1 -1
- package/package.json +1 -1
|
@@ -1,76 +1,79 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { proto } from "@hashgraph/proto";
|
|
2
|
+
import { ContractId } from "@hashgraph/sdk";
|
|
3
|
+
import { Buffer } from "buffer";
|
|
4
|
+
function parseKey(key) {
|
|
5
|
+
if (!key) {
|
|
6
|
+
return void 0;
|
|
6
7
|
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
function resolvePayerDebitTinybar(transfers, payerAccountId) {
|
|
15
|
-
if (!Array.isArray(transfers)) {
|
|
16
|
-
return null;
|
|
8
|
+
if (key.contractID) {
|
|
9
|
+
return `ContractID: ${new ContractId(
|
|
10
|
+
key.contractID.shardNum ?? 0,
|
|
11
|
+
key.contractID.realmNum ?? 0,
|
|
12
|
+
key.contractID.contractNum ?? 0
|
|
13
|
+
).toString()}`;
|
|
17
14
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
);
|
|
21
|
-
if (!payerDebit || typeof payerDebit.amount !== "number") {
|
|
22
|
-
return null;
|
|
15
|
+
if (key.ed25519) {
|
|
16
|
+
return `ED25519: ${Buffer.from(key.ed25519).toString("hex")}`;
|
|
23
17
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
function fallbackFeeTinybar(chargedTxFee) {
|
|
30
|
-
if (typeof chargedTxFee !== "number" || !Number.isFinite(chargedTxFee)) {
|
|
31
|
-
return null;
|
|
18
|
+
if (key.ECDSASecp256k1) {
|
|
19
|
+
return `ECDSA_secp256k1: ${Buffer.from(key.ECDSASecp256k1).toString(
|
|
20
|
+
"hex"
|
|
21
|
+
)}`;
|
|
32
22
|
}
|
|
33
|
-
if (
|
|
34
|
-
|
|
23
|
+
if (key?.keyList?.keys?.length > 0) {
|
|
24
|
+
const keys = key.keyList.keys.map((k) => parseKey(k)).filter(Boolean);
|
|
25
|
+
return `KeyList (${keys.length} keys): [${keys.join(", ")}]`;
|
|
35
26
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const { txn, payerAccountId } = params;
|
|
40
|
-
const positiveTransfers = safePositiveTransfers(txn.transfers);
|
|
41
|
-
const payerDebitTinybar = resolvePayerDebitTinybar(
|
|
42
|
-
txn.transfers,
|
|
43
|
-
payerAccountId
|
|
44
|
-
);
|
|
45
|
-
const transferOutflowTinybar = payerDebitTinybar ?? positiveTransfers.reduce((sum, t) => sum + t.amountTinybar, 0);
|
|
46
|
-
const chargedFeeTinybar = fallbackFeeTinybar(txn.charged_tx_fee);
|
|
47
|
-
const resolvedTotalTinybar = transferOutflowTinybar > 0 ? transferOutflowTinybar : chargedFeeTinybar;
|
|
48
|
-
if (!resolvedTotalTinybar || resolvedTotalTinybar <= 0) {
|
|
49
|
-
return null;
|
|
27
|
+
if (key?.thresholdKey?.keys?.keys?.length > 0) {
|
|
28
|
+
const keys = key.thresholdKey.keys.keys.map((k) => parseKey(k)).filter(Boolean);
|
|
29
|
+
return `ThresholdKey (${key.thresholdKey.threshold} of ${keys.length}): [${keys.join(", ")}]`;
|
|
50
30
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
31
|
+
if (key.delegatableContractId) {
|
|
32
|
+
return `DelegatableContractID: ${new ContractId(
|
|
33
|
+
key.delegatableContractId.shardNum ?? 0,
|
|
34
|
+
key.delegatableContractId.realmNum ?? 0,
|
|
35
|
+
key.delegatableContractId.contractNum ?? 0
|
|
36
|
+
).toString()}`;
|
|
37
|
+
}
|
|
38
|
+
if (Object.keys(key).length === 0) {
|
|
39
|
+
return "Empty Key Structure";
|
|
40
|
+
}
|
|
41
|
+
return "Unknown or Unset Key Type";
|
|
42
|
+
}
|
|
43
|
+
function extractTransactionBody(transaction) {
|
|
44
|
+
try {
|
|
45
|
+
const bytes = transaction.toBytes ? transaction.toBytes() : void 0;
|
|
46
|
+
if (!bytes) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const decoded = proto.TransactionList.decode(bytes);
|
|
50
|
+
if (!decoded.transactionList || decoded.transactionList.length === 0) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const tx = decoded.transactionList[0];
|
|
54
|
+
if (tx.bodyBytes && tx.bodyBytes.length > 0) {
|
|
55
|
+
return proto.TransactionBody.decode(tx.bodyBytes);
|
|
61
56
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
transfers: breakdownTransfers
|
|
57
|
+
if (tx.signedTransactionBytes && tx.signedTransactionBytes.length > 0) {
|
|
58
|
+
const signedTx = proto.SignedTransaction.decode(
|
|
59
|
+
tx.signedTransactionBytes
|
|
60
|
+
);
|
|
61
|
+
if (signedTx.bodyBytes) {
|
|
62
|
+
return proto.TransactionBody.decode(signedTx.bodyBytes);
|
|
69
63
|
}
|
|
70
64
|
}
|
|
71
|
-
|
|
65
|
+
return null;
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function hasTransactionType(transaction, transactionField) {
|
|
71
|
+
const txBody = extractTransactionBody(transaction);
|
|
72
|
+
return !!(txBody && txBody[transactionField]);
|
|
72
73
|
}
|
|
73
74
|
export {
|
|
74
|
-
|
|
75
|
+
extractTransactionBody,
|
|
76
|
+
hasTransactionType,
|
|
77
|
+
parseKey
|
|
75
78
|
};
|
|
76
79
|
//# sourceMappingURL=standards-sdk.es173.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"standards-sdk.es173.js","sources":["../../src/
|
|
1
|
+
{"version":3,"file":"standards-sdk.es173.js","sources":["../../src/utils/parsers/parser-utils.ts"],"sourcesContent":["import { proto } from '@hashgraph/proto';\nimport { ContractId, Transaction } from '@hashgraph/sdk';\nimport { Buffer } from 'buffer';\n\nexport function parseKey(\n key: proto.IKey | null | undefined,\n): string | undefined {\n if (!key) {\n return undefined;\n }\n\n if (key.contractID) {\n return `ContractID: ${new ContractId(\n key.contractID.shardNum ?? 0,\n key.contractID.realmNum ?? 0,\n key.contractID.contractNum ?? 0,\n ).toString()}`;\n }\n if (key.ed25519) {\n return `ED25519: ${Buffer.from(key.ed25519).toString('hex')}`;\n }\n if (key.ECDSASecp256k1) {\n return `ECDSA_secp256k1: ${Buffer.from(key.ECDSASecp256k1).toString(\n 'hex',\n )}`;\n }\n if (key?.keyList?.keys?.length > 0) {\n const keys = key.keyList.keys.map(k => parseKey(k)).filter(Boolean);\n return `KeyList (${keys.length} keys): [${keys.join(', ')}]`;\n }\n if (key?.thresholdKey?.keys?.keys?.length > 0) {\n const keys = key.thresholdKey.keys.keys\n .map(k => parseKey(k))\n .filter(Boolean);\n return `ThresholdKey (${key.thresholdKey.threshold} of ${\n keys.length\n }): [${keys.join(', ')}]`;\n }\n if (key.delegatableContractId) {\n return `DelegatableContractID: ${new ContractId(\n key.delegatableContractId.shardNum ?? 0,\n key.delegatableContractId.realmNum ?? 0,\n key.delegatableContractId.contractNum ?? 0,\n ).toString()}`;\n }\n if (Object.keys(key).length === 0) {\n return 'Empty Key Structure';\n }\n\n return 'Unknown or Unset Key Type';\n}\n\n/**\n * Extract TransactionBody from Transaction object using protobuf parsing\n * This replaces fragile constructor name checking with reliable protobuf data\n */\nexport function extractTransactionBody(\n transaction: Transaction,\n): proto.ITransactionBody | null {\n try {\n const bytes = transaction.toBytes ? transaction.toBytes() : undefined;\n if (!bytes) {\n return null;\n }\n\n const decoded = proto.TransactionList.decode(bytes);\n if (!decoded.transactionList || decoded.transactionList.length === 0) {\n return null;\n }\n\n const tx = decoded.transactionList[0];\n\n if (tx.bodyBytes && tx.bodyBytes.length > 0) {\n return proto.TransactionBody.decode(tx.bodyBytes);\n }\n\n if (tx.signedTransactionBytes && tx.signedTransactionBytes.length > 0) {\n const signedTx = proto.SignedTransaction.decode(\n tx.signedTransactionBytes,\n );\n if (signedTx.bodyBytes) {\n return proto.TransactionBody.decode(signedTx.bodyBytes);\n }\n }\n\n return null;\n } catch (error) {\n return null;\n }\n}\n\n/**\n * Check if transaction has specific transaction type using protobuf data\n * This replaces constructor name checking with reliable protobuf field detection\n */\nexport function hasTransactionType(\n transaction: Transaction,\n transactionField: keyof proto.ITransactionBody,\n): boolean {\n const txBody = extractTransactionBody(transaction);\n return !!(txBody && txBody[transactionField]);\n}\n"],"names":[],"mappings":";;;AAIO,SAAS,SACd,KACoB;AACpB,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AAEA,MAAI,IAAI,YAAY;AAClB,WAAO,eAAe,IAAI;AAAA,MACxB,IAAI,WAAW,YAAY;AAAA,MAC3B,IAAI,WAAW,YAAY;AAAA,MAC3B,IAAI,WAAW,eAAe;AAAA,IAAA,EAC9B,UAAU;AAAA,EACd;AACA,MAAI,IAAI,SAAS;AACf,WAAO,YAAY,OAAO,KAAK,IAAI,OAAO,EAAE,SAAS,KAAK,CAAC;AAAA,EAC7D;AACA,MAAI,IAAI,gBAAgB;AACtB,WAAO,oBAAoB,OAAO,KAAK,IAAI,cAAc,EAAE;AAAA,MACzD;AAAA,IAAA,CACD;AAAA,EACH;AACA,MAAI,KAAK,SAAS,MAAM,SAAS,GAAG;AAClC,UAAM,OAAO,IAAI,QAAQ,KAAK,IAAI,CAAA,MAAK,SAAS,CAAC,CAAC,EAAE,OAAO,OAAO;AAClE,WAAO,YAAY,KAAK,MAAM,YAAY,KAAK,KAAK,IAAI,CAAC;AAAA,EAC3D;AACA,MAAI,KAAK,cAAc,MAAM,MAAM,SAAS,GAAG;AAC7C,UAAM,OAAO,IAAI,aAAa,KAAK,KAChC,IAAI,CAAA,MAAK,SAAS,CAAC,CAAC,EACpB,OAAO,OAAO;AACjB,WAAO,iBAAiB,IAAI,aAAa,SAAS,OAChD,KAAK,MACP,OAAO,KAAK,KAAK,IAAI,CAAC;AAAA,EACxB;AACA,MAAI,IAAI,uBAAuB;AAC7B,WAAO,0BAA0B,IAAI;AAAA,MACnC,IAAI,sBAAsB,YAAY;AAAA,MACtC,IAAI,sBAAsB,YAAY;AAAA,MACtC,IAAI,sBAAsB,eAAe;AAAA,IAAA,EACzC,UAAU;AAAA,EACd;AACA,MAAI,OAAO,KAAK,GAAG,EAAE,WAAW,GAAG;AACjC,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAMO,SAAS,uBACd,aAC+B;AAC/B,MAAI;AACF,UAAM,QAAQ,YAAY,UAAU,YAAY,YAAY;AAC5D,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,MAAM,gBAAgB,OAAO,KAAK;AAClD,QAAI,CAAC,QAAQ,mBAAmB,QAAQ,gBAAgB,WAAW,GAAG;AACpE,aAAO;AAAA,IACT;AAEA,UAAM,KAAK,QAAQ,gBAAgB,CAAC;AAEpC,QAAI,GAAG,aAAa,GAAG,UAAU,SAAS,GAAG;AAC3C,aAAO,MAAM,gBAAgB,OAAO,GAAG,SAAS;AAAA,IAClD;AAEA,QAAI,GAAG,0BAA0B,GAAG,uBAAuB,SAAS,GAAG;AACrE,YAAM,WAAW,MAAM,kBAAkB;AAAA,QACvC,GAAG;AAAA,MAAA;AAEL,UAAI,SAAS,WAAW;AACtB,eAAO,MAAM,gBAAgB,OAAO,SAAS,SAAS;AAAA,MACxD;AAAA,IACF;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AAMO,SAAS,mBACd,aACA,kBACS;AACT,QAAM,SAAS,uBAAuB,WAAW;AACjD,SAAO,CAAC,EAAE,UAAU,OAAO,gBAAgB;AAC7C;"}
|
|
@@ -3,7 +3,7 @@ import { Buffer } from "buffer";
|
|
|
3
3
|
import { randomBytes } from "crypto";
|
|
4
4
|
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
5
5
|
import { registerEncryptionKeyResponseSchema } from "./standards-sdk.es145.js";
|
|
6
|
-
import { optionalImport } from "./standards-sdk.
|
|
6
|
+
import { optionalImport } from "./standards-sdk.es164.js";
|
|
7
7
|
const getFs = async () => {
|
|
8
8
|
const fsModule = await optionalImport("node:fs");
|
|
9
9
|
if (fsModule && typeof fsModule.existsSync === "function" && typeof fsModule.readFileSync === "function" && typeof fsModule.writeFileSync === "function" && typeof fsModule.appendFileSync === "function") {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { creditPurchaseResponseSchema, x402MinimumsResponseSchema, x402CreditPurchaseResponseSchema } from "./standards-sdk.es145.js";
|
|
2
2
|
import { normalizeHexPrivateKey } from "./standards-sdk.es176.js";
|
|
3
|
-
import { optionalImport } from "./standards-sdk.
|
|
3
|
+
import { optionalImport } from "./standards-sdk.es164.js";
|
|
4
4
|
async function loadX402Dependencies(client) {
|
|
5
5
|
const [{ default: axios }, x402Axios, x402Types] = await Promise.all([
|
|
6
6
|
import("axios"),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { getCryptoAdapter } from "./standards-sdk.es137.js";
|
|
2
|
-
import { base58Encode } from "./standards-sdk.
|
|
2
|
+
import { base58Encode } from "./standards-sdk.es163.js";
|
|
3
3
|
import { canonicalizeAgentData } from "./standards-sdk.es55.js";
|
|
4
4
|
function encodeMultibaseB58btc(input) {
|
|
5
5
|
const bytes = Buffer.from(input, "utf8");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isUaidProfileResolverAdapter, isDidProfileResolverAdapter, isDidResolverAdapter } from "./standards-sdk.es58.js";
|
|
2
2
|
import { HieroDidResolver } from "./standards-sdk.es60.js";
|
|
3
3
|
import { parseHcs14Did } from "./standards-sdk.es56.js";
|
|
4
|
-
import { multibaseB58btcDecode } from "./standards-sdk.
|
|
4
|
+
import { multibaseB58btcDecode } from "./standards-sdk.es163.js";
|
|
5
5
|
class ResolverRegistry {
|
|
6
6
|
constructor() {
|
|
7
7
|
this.resolvers = [];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { nodeDnsTxtLookup } from "./standards-sdk.es66.js";
|
|
2
|
-
import { isFqdn, normalizeDomain, parseSemicolonFields } from "./standards-sdk.
|
|
2
|
+
import { isFqdn, normalizeDomain, parseSemicolonFields } from "./standards-sdk.es165.js";
|
|
3
3
|
const AID_DNS_WEB_PROFILE_ID = "hcs-14.profile.aid-dns-web";
|
|
4
4
|
function buildErrorProfile(uaid, code, message, details) {
|
|
5
5
|
const error = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { nodeDnsTxtLookup } from "./standards-sdk.es66.js";
|
|
2
|
-
import { isFqdn, normalizeDomain } from "./standards-sdk.
|
|
3
|
-
import { normalizeAnsVersion, isValidAnsProfileVersion, parseAnsDnsTxtRecord, toErrorMessage, parseAnsAgentCard, extractEndpointCandidates, selectPreferredEndpoint } from "./standards-sdk.
|
|
2
|
+
import { isFqdn, normalizeDomain } from "./standards-sdk.es165.js";
|
|
3
|
+
import { normalizeAnsVersion, isValidAnsProfileVersion, parseAnsDnsTxtRecord, toErrorMessage, parseAnsAgentCard, extractEndpointCandidates, selectPreferredEndpoint } from "./standards-sdk.es166.js";
|
|
4
4
|
const ANS_DNS_WEB_PROFILE_ID = "hcs-14.profile.ans-dns-web";
|
|
5
5
|
const UAID_UNSPECIFIED_PARAM_VALUE = "0";
|
|
6
6
|
function buildErrorProfile(uaid, code, message, details) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { nodeDnsTxtLookup } from "./standards-sdk.es66.js";
|
|
2
|
-
import { uaidTargetFromParsed, isFqdn, normalizeDomain, buildCanonicalUaid, parseSemicolonFields } from "./standards-sdk.
|
|
2
|
+
import { uaidTargetFromParsed, isFqdn, normalizeDomain, buildCanonicalUaid, parseSemicolonFields } from "./standards-sdk.es165.js";
|
|
3
3
|
import { AID_DNS_WEB_PROFILE_ID } from "./standards-sdk.es62.js";
|
|
4
4
|
import { ANS_DNS_WEB_PROFILE_ID } from "./standards-sdk.es63.js";
|
|
5
5
|
import { UAID_DID_RESOLUTION_PROFILE_ID } from "./standards-sdk.es65.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HCS5BaseClient } from "./standards-sdk.
|
|
1
|
+
import { HCS5BaseClient } from "./standards-sdk.es167.js";
|
|
2
2
|
import { buildHcs1Hrl } from "./standards-sdk.es70.js";
|
|
3
3
|
import { PrivateKey } from "@hashgraph/sdk";
|
|
4
4
|
import { inscribeWithSigner } from "./standards-sdk.es142.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HCS5BaseClient } from "./standards-sdk.
|
|
1
|
+
import { HCS5BaseClient } from "./standards-sdk.es167.js";
|
|
2
2
|
import { buildHcs1Hrl } from "./standards-sdk.es70.js";
|
|
3
3
|
import { AccountId } from "@hashgraph/sdk";
|
|
4
4
|
import { inscribe } from "./standards-sdk.es142.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hashgraphonline/standards-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.171",
|
|
4
4
|
"description": "The Hashgraph Online Standards SDK provides a complete implementation of the Hiero Consensus Standards (HCS), giving developers all the tools needed to build wonderful decentralized applications on the Hashgraph network. https://hol.org",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|