@fleet-sdk/blockchain-providers 0.4.1 → 0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @fleet-sdk/blockchain-providers
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [8f14d37]
8
+ - @fleet-sdk/core@0.5.0
9
+
3
10
  ## 0.4.1
4
11
 
5
12
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -278,4 +278,4 @@ declare class ErgoGraphQLProvider implements IBlockchainProvider<BoxWhere> {
278
278
  reduceTransaction(): Promise<TransactionReductionResult>;
279
279
  }
280
280
 
281
- export { ErgoGraphQLProvider, ErgoGraphQLRequestOptions, GraphQLBoxQuery, GraphQLBoxWhere };
281
+ export { ErgoGraphQLProvider, type ErgoGraphQLRequestOptions, type GraphQLBoxQuery, type GraphQLBoxWhere };
package/dist/index.d.ts CHANGED
@@ -278,4 +278,4 @@ declare class ErgoGraphQLProvider implements IBlockchainProvider<BoxWhere> {
278
278
  reduceTransaction(): Promise<TransactionReductionResult>;
279
279
  }
280
280
 
281
- export { ErgoGraphQLProvider, ErgoGraphQLRequestOptions, GraphQLBoxQuery, GraphQLBoxWhere };
281
+ export { ErgoGraphQLProvider, type ErgoGraphQLRequestOptions, type GraphQLBoxQuery, type GraphQLBoxWhere };
package/dist/index.js CHANGED
@@ -22,9 +22,13 @@ function createGqlOperation(query, options) {
22
22
  })
23
23
  });
24
24
  const rawData = await response.text();
25
- const parsedData = (options.parser ?? JSON).parse(rawData);
25
+ const parsedData = (options.parser ?? JSON).parse(
26
+ rawData
27
+ );
26
28
  if (options.throwOnNonNetworkErrors && common.some(parsedData.errors) && common.isEmpty(parsedData.data)) {
27
- throw new common.BlockchainProviderError(parsedData.errors[0].message, { cause: parsedData.errors });
29
+ throw new common.BlockchainProviderError(parsedData.errors[0].message, {
30
+ cause: parsedData.errors
31
+ });
28
32
  }
29
33
  return parsedData;
30
34
  };
@@ -38,16 +42,16 @@ function isRequestParam(obj) {
38
42
 
39
43
  // src/ergo-graphql/queries.ts
40
44
  var B = [
41
- `query boxes($spent: Boolean! $boxIds: [String!] $ergoTrees: [String!] $ergoTreeTemplateHash: String $tokenId: String $skip: Int $take: Int)`,
42
- `boxIds: $boxIds ergoTrees: $ergoTrees ergoTreeTemplateHash: $ergoTreeTemplateHash tokenId: $tokenId skip: $skip take: $take`,
43
- `boxId transactionId index value creationHeight ergoTree assets { tokenId amount } additionalRegisters beingSpent`
45
+ "query boxes($spent: Boolean! $boxIds: [String!] $ergoTrees: [String!] $ergoTreeTemplateHash: String $tokenId: String $skip: Int $take: Int)",
46
+ "boxIds: $boxIds ergoTrees: $ergoTrees ergoTreeTemplateHash: $ergoTreeTemplateHash tokenId: $tokenId skip: $skip take: $take",
47
+ "boxId transactionId index value creationHeight ergoTree assets { tokenId amount } additionalRegisters beingSpent"
44
48
  ];
45
49
  var CONF_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } }`;
46
50
  var UNCONF_BOXES_QUERY = `${B[0]} { mempool { boxes(${B[1]}) { ${B[2]} } } }`;
47
51
  var ALL_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } mempool { boxes(${B[1]}) { ${B[2]} } } }`;
48
- var HEADERS_QUERY = `query blockHeaders($take: Int) { blockHeaders(take: $take) {headerId timestamp version adProofsRoot stateRoot transactionsRoot nBits extensionHash powSolutions height difficulty parentId votes } }`;
49
- var CHECK_TX_MUTATION = `mutation checkTransaction($signedTransaction: SignedTransaction!) { checkTransaction(signedTransaction: $signedTransaction) }`;
50
- var SEND_TX_MUTATION = `mutation submitTransaction($signedTransaction: SignedTransaction!) { submitTransaction(signedTransaction: $signedTransaction) }`;
52
+ var HEADERS_QUERY = "query blockHeaders($take: Int) { blockHeaders(take: $take) {headerId timestamp version adProofsRoot stateRoot transactionsRoot nBits extensionHash powSolutions height difficulty parentId votes } }";
53
+ var CHECK_TX_MUTATION = "mutation checkTransaction($signedTransaction: SignedTransaction!) { checkTransaction(signedTransaction: $signedTransaction) }";
54
+ var SEND_TX_MUTATION = "mutation submitTransaction($signedTransaction: SignedTransaction!) { submitTransaction(signedTransaction: $signedTransaction) }";
51
55
 
52
56
  // src/ergo-graphql/ergoGraphQLProvider.ts
53
57
  var PAGE_SIZE = 50;
@@ -72,13 +76,7 @@ var ErgoGraphQLProvider = class {
72
76
  this.#sendTx = this.createOperation(SEND_TX_MUTATION);
73
77
  }
74
78
  #fetchBoxes(args, inclConf, inclUnconf) {
75
- if (inclConf && inclUnconf) {
76
- return this.#getAllBoxes(args);
77
- } else if (inclUnconf) {
78
- return this.#getUnconfBoxes(args);
79
- } else {
80
- return this.#getConfBoxes(args);
81
- }
79
+ return inclConf && inclUnconf ? this.#getAllBoxes(args) : inclUnconf ? this.#getUnconfBoxes(args) : this.#getConfBoxes(args);
82
80
  }
83
81
  async *streamBoxes(query) {
84
82
  if (common.isEmpty(query.where)) {
@@ -88,26 +86,26 @@ var ErgoGraphQLProvider = class {
88
86
  const returnedBoxIds = /* @__PURE__ */ new Set();
89
87
  const { where, from } = query;
90
88
  const args = buildGqlBoxQueryArgs(where);
91
- let fetchFromChain = from !== "mempool";
92
- let fetchFromMempool = from !== "blockchain";
93
- const isMempoolAware = fetchFromMempool;
89
+ let inclChain = from !== "mempool";
90
+ let inclPool = from !== "blockchain";
91
+ const isMempoolAware = inclPool;
94
92
  do {
95
- const response = await this.#fetchBoxes(args, fetchFromChain, fetchFromMempool);
93
+ const response = await this.#fetchBoxes(args, inclChain, inclPool);
96
94
  const { data } = response;
97
95
  let boxes = [];
98
- if (fetchFromChain && hasConfirmed(data)) {
96
+ if (inclChain && hasConfirmed(data)) {
99
97
  if (common.some(data.boxes)) {
100
98
  const confirmedBoxes = (isMempoolAware ? data.boxes.filter(notBeingSpent) : data.boxes).map(asConfirmed(true));
101
99
  boxes = boxes.concat(confirmedBoxes);
102
100
  }
103
- fetchFromChain = data.boxes.length === PAGE_SIZE;
101
+ inclChain = data.boxes.length === PAGE_SIZE;
104
102
  }
105
103
  if (isMempoolAware && hasMempool(data)) {
106
104
  if (common.some(data.mempool.boxes)) {
107
105
  const mempoolBoxes = data.mempool.boxes.filter(notBeingSpent).map(asConfirmed(false));
108
106
  boxes = boxes.concat(mempoolBoxes);
109
107
  }
110
- fetchFromMempool = data.mempool.boxes.length === PAGE_SIZE;
108
+ inclPool = data.mempool.boxes.length === PAGE_SIZE;
111
109
  }
112
110
  if (common.some(boxes)) {
113
111
  if (boxes.some((box) => returnedBoxIds.has(box.boxId))) {
@@ -115,13 +113,12 @@ var ErgoGraphQLProvider = class {
115
113
  }
116
114
  if (common.some(boxes)) {
117
115
  boxes = common.uniqBy(boxes, (box) => box.boxId);
118
- boxes.forEach((box) => returnedBoxIds.add(box.boxId));
116
+ for (const box of boxes) returnedBoxIds.add(box.boxId);
119
117
  yield boxes;
120
118
  }
121
119
  }
122
- if (fetchFromChain || fetchFromMempool)
123
- args.skip += PAGE_SIZE;
124
- } while (fetchFromChain || fetchFromMempool);
120
+ if (inclChain || inclPool) args.skip += PAGE_SIZE;
121
+ } while (inclChain || inclPool);
125
122
  }
126
123
  async getBoxes(query) {
127
124
  let boxes = [];
@@ -162,7 +159,9 @@ var ErgoGraphQLProvider = class {
162
159
  }
163
160
  }
164
161
  reduceTransaction() {
165
- throw new common.NotSupportedError("Transaction reducing is not supported by ergo-graphql.");
162
+ throw new common.NotSupportedError(
163
+ "Transaction reducing is not supported by ergo-graphql."
164
+ );
166
165
  }
167
166
  };
168
167
  function buildGqlBoxQueryArgs(where) {
@@ -180,16 +179,16 @@ function buildGqlBoxQueryArgs(where) {
180
179
  const trees = addresses.map(
181
180
  (address) => typeof address === "string" ? core.ErgoAddress.fromBase58(address).ergoTree : address.ergoTree
182
181
  );
183
- args.ergoTrees = common.uniq(common.some(args.ergoTrees) ? args.ergoTrees.concat(trees) : trees);
182
+ args.ergoTrees = common.uniq(
183
+ common.some(args.ergoTrees) ? args.ergoTrees.concat(trees) : trees
184
+ );
184
185
  }
185
186
  return args;
186
187
  }
187
188
  function merge(array, el) {
188
- if (common.isEmpty(array) && common.isUndefined(el))
189
- return;
189
+ if (common.isEmpty(array) && common.isUndefined(el)) return;
190
190
  const set = new Set(array ?? []);
191
- if (!common.isUndefined(el))
192
- set.add(el);
191
+ if (!common.isUndefined(el)) set.add(el);
193
192
  return Array.from(set.values());
194
193
  }
195
194
  function hasMempool(data) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ergo-graphql/ergoGraphQLProvider.ts","../src/utils/graphql.ts","../src/ergo-graphql/queries.ts"],"names":["ensureDefaults","isEmpty","some"],"mappings":"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","sourcesContent":["import {\n Box,\n QueryBoxesArgs as BoxesArgs,\n Header,\n QueryBlockHeadersArgs as HeadersArgs\n} from \"@ergo-graphql/types\";\nimport {\n Base58String,\n BlockHeader,\n ensureDefaults,\n HexString,\n isEmpty,\n isUndefined,\n NotSupportedError,\n orderBy,\n SignedTransaction,\n some,\n uniq,\n uniqBy\n} from \"@fleet-sdk/common\";\nimport { ErgoAddress } from \"@fleet-sdk/core\";\nimport {\n BoxQuery,\n BoxWhere,\n ChainProviderBox,\n HeaderQuery,\n IBlockchainProvider,\n TransactionEvaluationResult,\n TransactionReductionResult\n} from \"../types\";\nimport {\n createGqlOperation,\n GraphQLOperation,\n GraphQLRequestOptions,\n GraphQLSuccessResponse,\n GraphQLThrowableOptions,\n GraphQLVariables,\n isRequestParam\n} from \"../utils\";\nimport {\n ALL_BOXES_QUERY,\n CHECK_TX_MUTATION,\n CONF_BOXES_QUERY,\n HEADERS_QUERY,\n SEND_TX_MUTATION,\n UNCONF_BOXES_QUERY\n} from \"./queries\";\n\nexport type GraphQLBoxWhere = BoxWhere & {\n /** Base16-encoded BoxIds */\n boxIds?: HexString[];\n\n /** Base16-encoded ErgoTrees */\n ergoTrees?: HexString[];\n\n /** Base58-encoded addresses or `ErgoAddress` objects */\n addresses?: (Base58String | ErgoAddress)[];\n};\n\nexport type GraphQLBoxQuery = BoxQuery<GraphQLBoxWhere>;\nexport type ErgoGraphQLRequestOptions = Omit<GraphQLRequestOptions, \"throwOnNonNetworkError\">;\n\ntype ConfBoxesResp = { boxes: Box[] };\ntype UnconfBoxesResp = { mempool: { boxes: Box[] } };\ntype AllBoxesResp = ConfBoxesResp & UnconfBoxesResp;\ntype HeadersResp = { blockHeaders: Header[] };\ntype CheckTxResp = { checkTransaction: string };\ntype SendTxResp = { submitTransaction: string };\ntype SignedTxArgsResp = { signedTransaction: SignedTransaction };\n\nconst PAGE_SIZE = 50;\n\nexport class ErgoGraphQLProvider implements IBlockchainProvider<BoxWhere> {\n #options: GraphQLThrowableOptions;\n\n #getConfBoxes;\n #getUnconfBoxes;\n #getAllBoxes;\n #getHeaders;\n #checkTx;\n #sendTx;\n\n constructor(url: string | URL);\n constructor(url: ErgoGraphQLRequestOptions);\n constructor(optOrUrl: ErgoGraphQLRequestOptions | string | URL) {\n this.#options = {\n ...(isRequestParam(optOrUrl) ? optOrUrl : { url: optOrUrl }),\n throwOnNonNetworkErrors: true\n };\n\n this.#getConfBoxes = this.createOperation<ConfBoxesResp, BoxesArgs>(CONF_BOXES_QUERY);\n this.#getUnconfBoxes = this.createOperation<UnconfBoxesResp, BoxesArgs>(UNCONF_BOXES_QUERY);\n this.#getAllBoxes = this.createOperation<AllBoxesResp, BoxesArgs>(ALL_BOXES_QUERY);\n this.#getHeaders = this.createOperation<HeadersResp, HeadersArgs>(HEADERS_QUERY);\n this.#checkTx = this.createOperation<CheckTxResp, SignedTxArgsResp>(CHECK_TX_MUTATION);\n this.#sendTx = this.createOperation<SendTxResp, SignedTxArgsResp>(SEND_TX_MUTATION);\n }\n\n #fetchBoxes(args: BoxesArgs, inclConf: boolean, inclUnconf: boolean) {\n if (inclConf && inclUnconf) {\n return this.#getAllBoxes(args);\n } else if (inclUnconf) {\n return this.#getUnconfBoxes(args);\n } else {\n return this.#getConfBoxes(args);\n }\n }\n\n async *streamBoxes(query: GraphQLBoxQuery): AsyncGenerator<ChainProviderBox[]> {\n if (isEmpty(query.where)) {\n throw new Error(\"Cannot fetch unspent boxes without a where clause.\");\n }\n\n const notBeingSpent = (box: Box) => !box.beingSpent;\n const returnedBoxIds = new Set<string>();\n const { where, from } = query;\n const args = buildGqlBoxQueryArgs(where);\n\n let fetchFromChain = from !== \"mempool\";\n let fetchFromMempool = from !== \"blockchain\";\n const isMempoolAware = fetchFromMempool;\n\n do {\n const response = await this.#fetchBoxes(args, fetchFromChain, fetchFromMempool);\n\n const { data } = response;\n let boxes: ChainProviderBox[] = [];\n\n if (fetchFromChain && hasConfirmed(data)) {\n if (some(data.boxes)) {\n const confirmedBoxes = (\n isMempoolAware ? data.boxes.filter(notBeingSpent) : data.boxes\n ).map(asConfirmed(true));\n\n boxes = boxes.concat(confirmedBoxes);\n }\n\n fetchFromChain = data.boxes.length === PAGE_SIZE;\n }\n\n if (isMempoolAware && hasMempool(data)) {\n if (some(data.mempool.boxes)) {\n const mempoolBoxes = data.mempool.boxes.filter(notBeingSpent).map(asConfirmed(false));\n boxes = boxes.concat(mempoolBoxes);\n }\n\n fetchFromMempool = data.mempool.boxes.length === PAGE_SIZE;\n }\n\n if (some(boxes)) {\n // boxes can be moved from the mempool to the blockchain while streaming,\n // so we need to filter out boxes that have already been returned.\n if (boxes.some((box) => returnedBoxIds.has(box.boxId))) {\n boxes = boxes.filter((b) => !returnedBoxIds.has(b.boxId));\n }\n\n if (some(boxes)) {\n boxes = uniqBy(boxes, (box) => box.boxId);\n boxes.forEach((box) => returnedBoxIds.add(box.boxId));\n\n yield boxes;\n }\n }\n\n if (fetchFromChain || fetchFromMempool) args.skip += PAGE_SIZE;\n } while (fetchFromChain || fetchFromMempool);\n }\n\n async getBoxes(query: GraphQLBoxQuery): Promise<ChainProviderBox[]> {\n let boxes: ChainProviderBox[] = [];\n for await (const chunk of this.streamBoxes(query)) {\n boxes = boxes.concat(chunk);\n }\n\n return orderBy(boxes, (box) => box.creationHeight);\n }\n\n async getHeaders(query: HeaderQuery): Promise<BlockHeader[]> {\n const response = await this.#getHeaders(query);\n\n return (\n response.data?.blockHeaders.map((header) => ({\n ...header,\n id: header.headerId,\n timestamp: Number(header.timestamp),\n nBits: Number(header.nBits),\n votes: header.votes.join(\"\")\n })) ?? []\n );\n }\n\n createOperation<R, V extends GraphQLVariables = GraphQLVariables>(\n query: string,\n options?: Partial<ErgoGraphQLRequestOptions>\n ): GraphQLOperation<GraphQLSuccessResponse<R>, V> {\n const opt = ensureDefaults(options, this.#options);\n opt.throwOnNonNetworkErrors = true;\n\n return createGqlOperation(query, opt);\n }\n\n async checkTransaction(\n signedTransaction: SignedTransaction\n ): Promise<TransactionEvaluationResult> {\n try {\n const response = await this.#checkTx({ signedTransaction });\n\n return { success: true, transactionId: response.data.checkTransaction };\n } catch (e) {\n return { success: false, message: (e as Error).message };\n }\n }\n\n async submitTransaction(\n signedTransaction: SignedTransaction\n ): Promise<TransactionEvaluationResult> {\n try {\n const response = await this.#sendTx({ signedTransaction });\n\n return { success: true, transactionId: response.data.submitTransaction };\n } catch (e) {\n return { success: false, message: (e as Error).message };\n }\n }\n\n reduceTransaction(): Promise<TransactionReductionResult> {\n throw new NotSupportedError(\"Transaction reducing is not supported by ergo-graphql.\");\n }\n}\n\nfunction buildGqlBoxQueryArgs(where: GraphQLBoxWhere) {\n const args = {\n spent: false,\n boxIds: merge(where.boxIds, where.boxId),\n ergoTrees: merge(where.ergoTrees, where.ergoTree),\n ergoTreeTemplateHash: where.templateHash,\n tokenId: where.tokenId,\n skip: 0,\n take: PAGE_SIZE\n } satisfies BoxesArgs;\n\n const addresses = merge(where.addresses, where.address);\n if (some(addresses)) {\n const trees = addresses.map((address) =>\n typeof address === \"string\" ? ErgoAddress.fromBase58(address).ergoTree : address.ergoTree\n );\n\n args.ergoTrees = uniq(some(args.ergoTrees) ? args.ergoTrees.concat(trees) : trees);\n }\n\n return args;\n}\n\nfunction merge<T>(array?: T[], el?: T) {\n if (isEmpty(array) && isUndefined(el)) return;\n\n const set = new Set<T>(array ?? []);\n if (!isUndefined(el)) set.add(el);\n return Array.from(set.values());\n}\n\nfunction hasMempool(data: AllBoxesResp | ConfBoxesResp | UnconfBoxesResp): data is UnconfBoxesResp {\n return !!(data as UnconfBoxesResp)?.mempool?.boxes;\n}\n\nfunction hasConfirmed(data: AllBoxesResp | ConfBoxesResp | UnconfBoxesResp): data is ConfBoxesResp {\n return !!(data as ConfBoxesResp)?.boxes;\n}\n\nfunction asConfirmed(confirmed: boolean) {\n return (box: Box): ChainProviderBox => ({\n ...box,\n value: BigInt(box.value),\n assets: box.assets.map((asset) => ({\n tokenId: asset.tokenId,\n amount: BigInt(asset.amount)\n })),\n confirmed\n });\n}\n","import {\n BlockchainProviderError,\n clearUndefined,\n ensureDefaults,\n isEmpty,\n some\n} from \"@fleet-sdk/common\";\n\nconst OP_NAME_REGEX = /(query|mutation)\\s?([\\w\\-_]+)?/;\nexport const DEFAULT_HEADERS: Headers = {\n \"content-type\": \"application/json; charset=utf-8\",\n accept: \"application/graphql-response+json, application/json\"\n};\n\ntype Credentials = RequestCredentials;\ntype Headers = HeadersInit;\ntype Fetcher = typeof fetch;\n\nexport type GraphQLVariables = Record<string, unknown> | null;\n\nexport interface GraphQLError {\n message: string;\n}\n\nexport interface GraphQLSuccessResponse<T = unknown> {\n data: T;\n errors: null;\n}\n\nexport interface GraphQLErrorResponse {\n data: null;\n errors: GraphQLError[];\n}\n\nexport type GraphQLResponse<T = unknown> = GraphQLSuccessResponse<T> | GraphQLErrorResponse;\n\nexport type GraphQLOperation<R extends GraphQLResponse, V extends GraphQLVariables> = (\n variables?: V\n) => Promise<R>;\n\nexport interface ResponseParser {\n parse<T>(text: string): T;\n stringify<T>(value: T): string;\n}\n\nexport interface RequestParams {\n operationName?: string | null;\n query: string;\n variables?: Record<string, unknown> | null;\n}\n\nexport interface GraphQLRequestOptions {\n url: URL | string;\n headers?: Headers;\n parser?: ResponseParser;\n fetcher?: Fetcher;\n credentials?: Credentials;\n throwOnNonNetworkErrors?: boolean;\n}\n\nexport interface GraphQLThrowableOptions extends GraphQLRequestOptions {\n throwOnNonNetworkErrors: true;\n}\n\nexport function createGqlOperation<R, V extends GraphQLVariables = GraphQLVariables>(\n query: string,\n options: GraphQLThrowableOptions\n): GraphQLOperation<GraphQLSuccessResponse<R>, V>;\nexport function createGqlOperation<R, V extends GraphQLVariables = GraphQLVariables>(\n query: string,\n options: GraphQLRequestOptions\n): GraphQLOperation<GraphQLResponse<R>, V>;\nexport function createGqlOperation<R, V extends GraphQLVariables = GraphQLVariables>(\n query: string,\n options: GraphQLRequestOptions\n): GraphQLOperation<GraphQLResponse<R>, V> {\n return async (variables?: V): Promise<GraphQLResponse<R>> => {\n const response = await (options.fetcher ?? fetch)(options.url, {\n method: \"POST\",\n headers: ensureDefaults(options.headers, DEFAULT_HEADERS),\n credentials: options.credentials,\n body: (options.parser ?? JSON).stringify({\n operationName: getOpName(query),\n query,\n variables: variables ? clearUndefined(variables) : undefined\n } as RequestParams)\n });\n\n const rawData = await response.text();\n const parsedData = (options.parser ?? JSON).parse(rawData) as GraphQLResponse<R>;\n\n if (options.throwOnNonNetworkErrors && some(parsedData.errors) && isEmpty(parsedData.data)) {\n throw new BlockchainProviderError(parsedData.errors[0].message, { cause: parsedData.errors });\n }\n\n return parsedData;\n };\n}\n\nexport function gql(query: TemplateStringsArray): string {\n return query[0];\n}\n\nexport function getOpName(query: string): string | undefined {\n return OP_NAME_REGEX.exec(query)?.at(2);\n}\n\nexport function isRequestParam(obj: unknown): obj is GraphQLRequestOptions {\n return typeof obj === \"object\" && (obj as GraphQLRequestOptions).url !== undefined;\n}\n","const B = [\n `query boxes($spent: Boolean! $boxIds: [String!] $ergoTrees: [String!] $ergoTreeTemplateHash: String $tokenId: String $skip: Int $take: Int)`,\n `boxIds: $boxIds ergoTrees: $ergoTrees ergoTreeTemplateHash: $ergoTreeTemplateHash tokenId: $tokenId skip: $skip take: $take`,\n `boxId transactionId index value creationHeight ergoTree assets { tokenId amount } additionalRegisters beingSpent`\n];\n\nexport const CONF_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } }`;\nexport const UNCONF_BOXES_QUERY = `${B[0]} { mempool { boxes(${B[1]}) { ${B[2]} } } }`;\nexport const ALL_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } mempool { boxes(${B[1]}) { ${B[2]} } } }`;\nexport const HEADERS_QUERY = `query blockHeaders($take: Int) { blockHeaders(take: $take) {headerId timestamp version adProofsRoot stateRoot transactionsRoot nBits extensionHash powSolutions height difficulty parentId votes } }`;\nexport const CHECK_TX_MUTATION = `mutation checkTransaction($signedTransaction: SignedTransaction!) { checkTransaction(signedTransaction: $signedTransaction) }`;\nexport const SEND_TX_MUTATION = `mutation submitTransaction($signedTransaction: SignedTransaction!) { submitTransaction(signedTransaction: $signedTransaction) }`;\n"]}
1
+ {"version":3,"sources":["../src/ergo-graphql/ergoGraphQLProvider.ts","../src/utils/graphql.ts","../src/ergo-graphql/queries.ts"],"names":["ensureDefaults","isEmpty","some"],"mappings":"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","sourcesContent":["import type {\n Box,\n QueryBoxesArgs,\n Header,\n QueryBlockHeadersArgs\n} from \"@ergo-graphql/types\";\nimport {\n type Base58String,\n type BlockHeader,\n ensureDefaults,\n type HexString,\n isEmpty,\n isUndefined,\n NotSupportedError,\n orderBy,\n type SignedTransaction,\n some,\n uniq,\n uniqBy\n} from \"@fleet-sdk/common\";\nimport { ErgoAddress } from \"@fleet-sdk/core\";\nimport type {\n BoxQuery,\n BoxWhere,\n ChainProviderBox,\n HeaderQuery,\n IBlockchainProvider,\n TransactionEvaluationResult,\n TransactionReductionResult\n} from \"../types/blockchainProvider\";\nimport {\n createGqlOperation,\n type GraphQLOperation,\n type GraphQLRequestOptions,\n type GraphQLSuccessResponse,\n type GraphQLThrowableOptions,\n type GraphQLVariables,\n isRequestParam\n} from \"../utils\";\nimport {\n ALL_BOXES_QUERY,\n CHECK_TX_MUTATION,\n CONF_BOXES_QUERY,\n HEADERS_QUERY,\n SEND_TX_MUTATION,\n UNCONF_BOXES_QUERY\n} from \"./queries\";\n\nexport type GraphQLBoxWhere = BoxWhere & {\n /** Base16-encoded BoxIds */\n boxIds?: HexString[];\n\n /** Base16-encoded ErgoTrees */\n ergoTrees?: HexString[];\n\n /** Base58-encoded addresses or `ErgoAddress` objects */\n addresses?: (Base58String | ErgoAddress)[];\n};\n\nexport type GraphQLBoxQuery = BoxQuery<GraphQLBoxWhere>;\nexport type ErgoGraphQLRequestOptions = Omit<\n GraphQLRequestOptions,\n \"throwOnNonNetworkError\"\n>;\n\ntype ConfirmedBoxesResponse = { boxes: Box[] };\ntype UnconfirmedBoxesResponse = { mempool: { boxes: Box[] } };\ntype CombinedBoxesResponse = ConfirmedBoxesResponse & UnconfirmedBoxesResponse;\ntype BlockHeadersResponse = { blockHeaders: Header[] };\ntype CheckTransactionResponse = { checkTransaction: string };\ntype TransactionSubmissionResponse = { submitTransaction: string };\ntype SignedTxArgsResp = { signedTransaction: SignedTransaction };\n\nconst PAGE_SIZE = 50;\n\nexport class ErgoGraphQLProvider implements IBlockchainProvider<BoxWhere> {\n #options: GraphQLThrowableOptions;\n\n #getConfBoxes;\n #getUnconfBoxes;\n #getAllBoxes;\n #getHeaders;\n #checkTx;\n #sendTx;\n\n constructor(url: string | URL);\n constructor(url: ErgoGraphQLRequestOptions);\n constructor(optOrUrl: ErgoGraphQLRequestOptions | string | URL) {\n this.#options = {\n ...(isRequestParam(optOrUrl) ? optOrUrl : { url: optOrUrl }),\n throwOnNonNetworkErrors: true\n };\n\n this.#getConfBoxes = this.createOperation<\n ConfirmedBoxesResponse,\n QueryBoxesArgs\n >(CONF_BOXES_QUERY);\n\n this.#getUnconfBoxes = this.createOperation<\n UnconfirmedBoxesResponse,\n QueryBoxesArgs\n >(UNCONF_BOXES_QUERY);\n\n this.#getAllBoxes = this.createOperation<\n CombinedBoxesResponse,\n QueryBoxesArgs\n >(ALL_BOXES_QUERY);\n\n this.#getHeaders = this.createOperation<\n BlockHeadersResponse,\n QueryBlockHeadersArgs\n >(HEADERS_QUERY);\n\n this.#checkTx = this.createOperation<\n CheckTransactionResponse,\n SignedTxArgsResp\n >(CHECK_TX_MUTATION);\n\n this.#sendTx = this.createOperation<\n TransactionSubmissionResponse,\n SignedTxArgsResp\n >(SEND_TX_MUTATION);\n }\n\n #fetchBoxes(args: QueryBoxesArgs, inclConf: boolean, inclUnconf: boolean) {\n return inclConf && inclUnconf\n ? this.#getAllBoxes(args)\n : inclUnconf\n ? this.#getUnconfBoxes(args)\n : this.#getConfBoxes(args);\n }\n\n async *streamBoxes(\n query: GraphQLBoxQuery\n ): AsyncGenerator<ChainProviderBox[]> {\n if (isEmpty(query.where)) {\n throw new Error(\"Cannot fetch unspent boxes without a where clause.\");\n }\n\n const notBeingSpent = (box: Box) => !box.beingSpent;\n const returnedBoxIds = new Set<string>();\n const { where, from } = query;\n const args = buildGqlBoxQueryArgs(where);\n\n let inclChain = from !== \"mempool\";\n let inclPool = from !== \"blockchain\";\n const isMempoolAware = inclPool;\n\n do {\n const response = await this.#fetchBoxes(args, inclChain, inclPool);\n\n const { data } = response;\n let boxes: ChainProviderBox[] = [];\n\n if (inclChain && hasConfirmed(data)) {\n if (some(data.boxes)) {\n const confirmedBoxes = (\n isMempoolAware ? data.boxes.filter(notBeingSpent) : data.boxes\n ).map(asConfirmed(true));\n\n boxes = boxes.concat(confirmedBoxes);\n }\n\n inclChain = data.boxes.length === PAGE_SIZE;\n }\n\n if (isMempoolAware && hasMempool(data)) {\n if (some(data.mempool.boxes)) {\n const mempoolBoxes = data.mempool.boxes\n .filter(notBeingSpent)\n .map(asConfirmed(false));\n boxes = boxes.concat(mempoolBoxes);\n }\n\n inclPool = data.mempool.boxes.length === PAGE_SIZE;\n }\n\n if (some(boxes)) {\n // boxes can be moved from the mempool to the blockchain while streaming,\n // so we need to filter out boxes that have already been returned.\n if (boxes.some((box) => returnedBoxIds.has(box.boxId))) {\n boxes = boxes.filter((b) => !returnedBoxIds.has(b.boxId));\n }\n\n if (some(boxes)) {\n boxes = uniqBy(boxes, (box) => box.boxId);\n for (const box of boxes) returnedBoxIds.add(box.boxId);\n yield boxes;\n }\n }\n\n if (inclChain || inclPool) args.skip += PAGE_SIZE;\n } while (inclChain || inclPool);\n }\n\n async getBoxes(query: GraphQLBoxQuery): Promise<ChainProviderBox[]> {\n let boxes: ChainProviderBox[] = [];\n for await (const chunk of this.streamBoxes(query)) {\n boxes = boxes.concat(chunk);\n }\n\n return orderBy(boxes, (box) => box.creationHeight);\n }\n\n async getHeaders(query: HeaderQuery): Promise<BlockHeader[]> {\n const response = await this.#getHeaders(query);\n\n return (\n response.data?.blockHeaders.map((header) => ({\n ...header,\n id: header.headerId,\n timestamp: Number(header.timestamp),\n nBits: Number(header.nBits),\n votes: header.votes.join(\"\")\n })) ?? []\n );\n }\n\n createOperation<R, V extends GraphQLVariables = GraphQLVariables>(\n query: string,\n options?: Partial<ErgoGraphQLRequestOptions>\n ): GraphQLOperation<GraphQLSuccessResponse<R>, V> {\n const opt = ensureDefaults(options, this.#options);\n opt.throwOnNonNetworkErrors = true;\n\n return createGqlOperation(query, opt);\n }\n\n async checkTransaction(\n signedTransaction: SignedTransaction\n ): Promise<TransactionEvaluationResult> {\n try {\n const response = await this.#checkTx({ signedTransaction });\n\n return { success: true, transactionId: response.data.checkTransaction };\n } catch (e) {\n return { success: false, message: (e as Error).message };\n }\n }\n\n async submitTransaction(\n signedTransaction: SignedTransaction\n ): Promise<TransactionEvaluationResult> {\n try {\n const response = await this.#sendTx({ signedTransaction });\n\n return { success: true, transactionId: response.data.submitTransaction };\n } catch (e) {\n return { success: false, message: (e as Error).message };\n }\n }\n\n reduceTransaction(): Promise<TransactionReductionResult> {\n throw new NotSupportedError(\n \"Transaction reducing is not supported by ergo-graphql.\"\n );\n }\n}\n\nfunction buildGqlBoxQueryArgs(where: GraphQLBoxWhere) {\n const args = {\n spent: false,\n boxIds: merge(where.boxIds, where.boxId),\n ergoTrees: merge(where.ergoTrees, where.ergoTree),\n ergoTreeTemplateHash: where.templateHash,\n tokenId: where.tokenId,\n skip: 0,\n take: PAGE_SIZE\n } satisfies QueryBoxesArgs;\n\n const addresses = merge(where.addresses, where.address);\n if (some(addresses)) {\n const trees = addresses.map((address) =>\n typeof address === \"string\"\n ? ErgoAddress.fromBase58(address).ergoTree\n : address.ergoTree\n );\n\n args.ergoTrees = uniq(\n some(args.ergoTrees) ? args.ergoTrees.concat(trees) : trees\n );\n }\n\n return args;\n}\n\nfunction merge<T>(array?: T[], el?: T) {\n if (isEmpty(array) && isUndefined(el)) return;\n\n const set = new Set<T>(array ?? []);\n if (!isUndefined(el)) set.add(el);\n return Array.from(set.values());\n}\n\nfunction hasMempool(data: unknown): data is UnconfirmedBoxesResponse {\n return !!(data as UnconfirmedBoxesResponse)?.mempool?.boxes;\n}\n\nfunction hasConfirmed(data: unknown): data is ConfirmedBoxesResponse {\n return !!(data as ConfirmedBoxesResponse)?.boxes;\n}\n\nfunction asConfirmed(confirmed: boolean) {\n return (box: Box): ChainProviderBox => ({\n ...box,\n value: BigInt(box.value),\n assets: box.assets.map((asset) => ({\n tokenId: asset.tokenId,\n amount: BigInt(asset.amount)\n })),\n confirmed\n });\n}\n","import {\n BlockchainProviderError,\n clearUndefined,\n ensureDefaults,\n isEmpty,\n some\n} from \"@fleet-sdk/common\";\n\nconst OP_NAME_REGEX = /(query|mutation)\\s?([\\w\\-_]+)?/;\nexport const DEFAULT_HEADERS: Headers = {\n \"content-type\": \"application/json; charset=utf-8\",\n accept: \"application/graphql-response+json, application/json\"\n};\n\ntype Credentials = RequestCredentials;\ntype Headers = HeadersInit;\ntype Fetcher = typeof fetch;\n\nexport type GraphQLVariables = Record<string, unknown> | null;\n\nexport interface GraphQLError {\n message: string;\n}\n\nexport interface GraphQLSuccessResponse<T = unknown> {\n data: T;\n errors: null;\n}\n\nexport interface GraphQLErrorResponse {\n data: null;\n errors: GraphQLError[];\n}\n\nexport type GraphQLResponse<T = unknown> =\n | GraphQLSuccessResponse<T>\n | GraphQLErrorResponse;\n\nexport type GraphQLOperation<\n R extends GraphQLResponse,\n V extends GraphQLVariables\n> = (variables?: V) => Promise<R>;\n\nexport interface ResponseParser {\n parse<T>(text: string): T;\n stringify<T>(value: T): string;\n}\n\nexport interface RequestParams {\n operationName?: string | null;\n query: string;\n variables?: Record<string, unknown> | null;\n}\n\nexport interface GraphQLRequestOptions {\n url: URL | string;\n headers?: Headers;\n parser?: ResponseParser;\n fetcher?: Fetcher;\n credentials?: Credentials;\n throwOnNonNetworkErrors?: boolean;\n}\n\nexport interface GraphQLThrowableOptions extends GraphQLRequestOptions {\n throwOnNonNetworkErrors: true;\n}\n\nexport function createGqlOperation<\n R,\n V extends GraphQLVariables = GraphQLVariables\n>(\n query: string,\n options: GraphQLThrowableOptions\n): GraphQLOperation<GraphQLSuccessResponse<R>, V>;\nexport function createGqlOperation<\n R,\n V extends GraphQLVariables = GraphQLVariables\n>(\n query: string,\n options: GraphQLRequestOptions\n): GraphQLOperation<GraphQLResponse<R>, V>;\nexport function createGqlOperation<\n R,\n V extends GraphQLVariables = GraphQLVariables\n>(\n query: string,\n options: GraphQLRequestOptions\n): GraphQLOperation<GraphQLResponse<R>, V> {\n return async (variables?: V): Promise<GraphQLResponse<R>> => {\n const response = await (options.fetcher ?? fetch)(options.url, {\n method: \"POST\",\n headers: ensureDefaults(options.headers, DEFAULT_HEADERS),\n credentials: options.credentials,\n body: (options.parser ?? JSON).stringify({\n operationName: getOpName(query),\n query,\n variables: variables ? clearUndefined(variables) : undefined\n } as RequestParams)\n });\n\n const rawData = await response.text();\n const parsedData = (options.parser ?? JSON).parse(\n rawData\n ) as GraphQLResponse<R>;\n\n if (\n options.throwOnNonNetworkErrors &&\n some(parsedData.errors) &&\n isEmpty(parsedData.data)\n ) {\n throw new BlockchainProviderError(parsedData.errors[0].message, {\n cause: parsedData.errors\n });\n }\n\n return parsedData;\n };\n}\n\nexport function gql(query: TemplateStringsArray): string {\n return query[0];\n}\n\nexport function getOpName(query: string): string | undefined {\n return OP_NAME_REGEX.exec(query)?.at(2);\n}\n\nexport function isRequestParam(obj: unknown): obj is GraphQLRequestOptions {\n return (\n typeof obj === \"object\" && (obj as GraphQLRequestOptions).url !== undefined\n );\n}\n","const B = [\n \"query boxes($spent: Boolean! $boxIds: [String!] $ergoTrees: [String!] $ergoTreeTemplateHash: String $tokenId: String $skip: Int $take: Int)\",\n \"boxIds: $boxIds ergoTrees: $ergoTrees ergoTreeTemplateHash: $ergoTreeTemplateHash tokenId: $tokenId skip: $skip take: $take\",\n \"boxId transactionId index value creationHeight ergoTree assets { tokenId amount } additionalRegisters beingSpent\"\n];\n\nexport const CONF_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } }`;\nexport const UNCONF_BOXES_QUERY = `${B[0]} { mempool { boxes(${B[1]}) { ${B[2]} } } }`;\nexport const ALL_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } mempool { boxes(${B[1]}) { ${B[2]} } } }`;\nexport const HEADERS_QUERY =\n \"query blockHeaders($take: Int) { blockHeaders(take: $take) {headerId timestamp version adProofsRoot stateRoot transactionsRoot nBits extensionHash powSolutions height difficulty parentId votes } }\";\nexport const CHECK_TX_MUTATION =\n \"mutation checkTransaction($signedTransaction: SignedTransaction!) { checkTransaction(signedTransaction: $signedTransaction) }\";\nexport const SEND_TX_MUTATION =\n \"mutation submitTransaction($signedTransaction: SignedTransaction!) { submitTransaction(signedTransaction: $signedTransaction) }\";\n"]}
package/dist/index.mjs CHANGED
@@ -20,9 +20,13 @@ function createGqlOperation(query, options) {
20
20
  })
21
21
  });
22
22
  const rawData = await response.text();
23
- const parsedData = (options.parser ?? JSON).parse(rawData);
23
+ const parsedData = (options.parser ?? JSON).parse(
24
+ rawData
25
+ );
24
26
  if (options.throwOnNonNetworkErrors && some(parsedData.errors) && isEmpty(parsedData.data)) {
25
- throw new BlockchainProviderError(parsedData.errors[0].message, { cause: parsedData.errors });
27
+ throw new BlockchainProviderError(parsedData.errors[0].message, {
28
+ cause: parsedData.errors
29
+ });
26
30
  }
27
31
  return parsedData;
28
32
  };
@@ -36,16 +40,16 @@ function isRequestParam(obj) {
36
40
 
37
41
  // src/ergo-graphql/queries.ts
38
42
  var B = [
39
- `query boxes($spent: Boolean! $boxIds: [String!] $ergoTrees: [String!] $ergoTreeTemplateHash: String $tokenId: String $skip: Int $take: Int)`,
40
- `boxIds: $boxIds ergoTrees: $ergoTrees ergoTreeTemplateHash: $ergoTreeTemplateHash tokenId: $tokenId skip: $skip take: $take`,
41
- `boxId transactionId index value creationHeight ergoTree assets { tokenId amount } additionalRegisters beingSpent`
43
+ "query boxes($spent: Boolean! $boxIds: [String!] $ergoTrees: [String!] $ergoTreeTemplateHash: String $tokenId: String $skip: Int $take: Int)",
44
+ "boxIds: $boxIds ergoTrees: $ergoTrees ergoTreeTemplateHash: $ergoTreeTemplateHash tokenId: $tokenId skip: $skip take: $take",
45
+ "boxId transactionId index value creationHeight ergoTree assets { tokenId amount } additionalRegisters beingSpent"
42
46
  ];
43
47
  var CONF_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } }`;
44
48
  var UNCONF_BOXES_QUERY = `${B[0]} { mempool { boxes(${B[1]}) { ${B[2]} } } }`;
45
49
  var ALL_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } mempool { boxes(${B[1]}) { ${B[2]} } } }`;
46
- var HEADERS_QUERY = `query blockHeaders($take: Int) { blockHeaders(take: $take) {headerId timestamp version adProofsRoot stateRoot transactionsRoot nBits extensionHash powSolutions height difficulty parentId votes } }`;
47
- var CHECK_TX_MUTATION = `mutation checkTransaction($signedTransaction: SignedTransaction!) { checkTransaction(signedTransaction: $signedTransaction) }`;
48
- var SEND_TX_MUTATION = `mutation submitTransaction($signedTransaction: SignedTransaction!) { submitTransaction(signedTransaction: $signedTransaction) }`;
50
+ var HEADERS_QUERY = "query blockHeaders($take: Int) { blockHeaders(take: $take) {headerId timestamp version adProofsRoot stateRoot transactionsRoot nBits extensionHash powSolutions height difficulty parentId votes } }";
51
+ var CHECK_TX_MUTATION = "mutation checkTransaction($signedTransaction: SignedTransaction!) { checkTransaction(signedTransaction: $signedTransaction) }";
52
+ var SEND_TX_MUTATION = "mutation submitTransaction($signedTransaction: SignedTransaction!) { submitTransaction(signedTransaction: $signedTransaction) }";
49
53
 
50
54
  // src/ergo-graphql/ergoGraphQLProvider.ts
51
55
  var PAGE_SIZE = 50;
@@ -70,13 +74,7 @@ var ErgoGraphQLProvider = class {
70
74
  this.#sendTx = this.createOperation(SEND_TX_MUTATION);
71
75
  }
72
76
  #fetchBoxes(args, inclConf, inclUnconf) {
73
- if (inclConf && inclUnconf) {
74
- return this.#getAllBoxes(args);
75
- } else if (inclUnconf) {
76
- return this.#getUnconfBoxes(args);
77
- } else {
78
- return this.#getConfBoxes(args);
79
- }
77
+ return inclConf && inclUnconf ? this.#getAllBoxes(args) : inclUnconf ? this.#getUnconfBoxes(args) : this.#getConfBoxes(args);
80
78
  }
81
79
  async *streamBoxes(query) {
82
80
  if (isEmpty(query.where)) {
@@ -86,26 +84,26 @@ var ErgoGraphQLProvider = class {
86
84
  const returnedBoxIds = /* @__PURE__ */ new Set();
87
85
  const { where, from } = query;
88
86
  const args = buildGqlBoxQueryArgs(where);
89
- let fetchFromChain = from !== "mempool";
90
- let fetchFromMempool = from !== "blockchain";
91
- const isMempoolAware = fetchFromMempool;
87
+ let inclChain = from !== "mempool";
88
+ let inclPool = from !== "blockchain";
89
+ const isMempoolAware = inclPool;
92
90
  do {
93
- const response = await this.#fetchBoxes(args, fetchFromChain, fetchFromMempool);
91
+ const response = await this.#fetchBoxes(args, inclChain, inclPool);
94
92
  const { data } = response;
95
93
  let boxes = [];
96
- if (fetchFromChain && hasConfirmed(data)) {
94
+ if (inclChain && hasConfirmed(data)) {
97
95
  if (some(data.boxes)) {
98
96
  const confirmedBoxes = (isMempoolAware ? data.boxes.filter(notBeingSpent) : data.boxes).map(asConfirmed(true));
99
97
  boxes = boxes.concat(confirmedBoxes);
100
98
  }
101
- fetchFromChain = data.boxes.length === PAGE_SIZE;
99
+ inclChain = data.boxes.length === PAGE_SIZE;
102
100
  }
103
101
  if (isMempoolAware && hasMempool(data)) {
104
102
  if (some(data.mempool.boxes)) {
105
103
  const mempoolBoxes = data.mempool.boxes.filter(notBeingSpent).map(asConfirmed(false));
106
104
  boxes = boxes.concat(mempoolBoxes);
107
105
  }
108
- fetchFromMempool = data.mempool.boxes.length === PAGE_SIZE;
106
+ inclPool = data.mempool.boxes.length === PAGE_SIZE;
109
107
  }
110
108
  if (some(boxes)) {
111
109
  if (boxes.some((box) => returnedBoxIds.has(box.boxId))) {
@@ -113,13 +111,12 @@ var ErgoGraphQLProvider = class {
113
111
  }
114
112
  if (some(boxes)) {
115
113
  boxes = uniqBy(boxes, (box) => box.boxId);
116
- boxes.forEach((box) => returnedBoxIds.add(box.boxId));
114
+ for (const box of boxes) returnedBoxIds.add(box.boxId);
117
115
  yield boxes;
118
116
  }
119
117
  }
120
- if (fetchFromChain || fetchFromMempool)
121
- args.skip += PAGE_SIZE;
122
- } while (fetchFromChain || fetchFromMempool);
118
+ if (inclChain || inclPool) args.skip += PAGE_SIZE;
119
+ } while (inclChain || inclPool);
123
120
  }
124
121
  async getBoxes(query) {
125
122
  let boxes = [];
@@ -160,7 +157,9 @@ var ErgoGraphQLProvider = class {
160
157
  }
161
158
  }
162
159
  reduceTransaction() {
163
- throw new NotSupportedError("Transaction reducing is not supported by ergo-graphql.");
160
+ throw new NotSupportedError(
161
+ "Transaction reducing is not supported by ergo-graphql."
162
+ );
164
163
  }
165
164
  };
166
165
  function buildGqlBoxQueryArgs(where) {
@@ -178,16 +177,16 @@ function buildGqlBoxQueryArgs(where) {
178
177
  const trees = addresses.map(
179
178
  (address) => typeof address === "string" ? ErgoAddress.fromBase58(address).ergoTree : address.ergoTree
180
179
  );
181
- args.ergoTrees = uniq(some(args.ergoTrees) ? args.ergoTrees.concat(trees) : trees);
180
+ args.ergoTrees = uniq(
181
+ some(args.ergoTrees) ? args.ergoTrees.concat(trees) : trees
182
+ );
182
183
  }
183
184
  return args;
184
185
  }
185
186
  function merge(array, el) {
186
- if (isEmpty(array) && isUndefined(el))
187
- return;
187
+ if (isEmpty(array) && isUndefined(el)) return;
188
188
  const set = new Set(array ?? []);
189
- if (!isUndefined(el))
190
- set.add(el);
189
+ if (!isUndefined(el)) set.add(el);
191
190
  return Array.from(set.values());
192
191
  }
193
192
  function hasMempool(data) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ergo-graphql/ergoGraphQLProvider.ts","../src/utils/graphql.ts","../src/ergo-graphql/queries.ts"],"names":["ensureDefaults","isEmpty","some"],"mappings":"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","sourcesContent":["import {\n Box,\n QueryBoxesArgs as BoxesArgs,\n Header,\n QueryBlockHeadersArgs as HeadersArgs\n} from \"@ergo-graphql/types\";\nimport {\n Base58String,\n BlockHeader,\n ensureDefaults,\n HexString,\n isEmpty,\n isUndefined,\n NotSupportedError,\n orderBy,\n SignedTransaction,\n some,\n uniq,\n uniqBy\n} from \"@fleet-sdk/common\";\nimport { ErgoAddress } from \"@fleet-sdk/core\";\nimport {\n BoxQuery,\n BoxWhere,\n ChainProviderBox,\n HeaderQuery,\n IBlockchainProvider,\n TransactionEvaluationResult,\n TransactionReductionResult\n} from \"../types\";\nimport {\n createGqlOperation,\n GraphQLOperation,\n GraphQLRequestOptions,\n GraphQLSuccessResponse,\n GraphQLThrowableOptions,\n GraphQLVariables,\n isRequestParam\n} from \"../utils\";\nimport {\n ALL_BOXES_QUERY,\n CHECK_TX_MUTATION,\n CONF_BOXES_QUERY,\n HEADERS_QUERY,\n SEND_TX_MUTATION,\n UNCONF_BOXES_QUERY\n} from \"./queries\";\n\nexport type GraphQLBoxWhere = BoxWhere & {\n /** Base16-encoded BoxIds */\n boxIds?: HexString[];\n\n /** Base16-encoded ErgoTrees */\n ergoTrees?: HexString[];\n\n /** Base58-encoded addresses or `ErgoAddress` objects */\n addresses?: (Base58String | ErgoAddress)[];\n};\n\nexport type GraphQLBoxQuery = BoxQuery<GraphQLBoxWhere>;\nexport type ErgoGraphQLRequestOptions = Omit<GraphQLRequestOptions, \"throwOnNonNetworkError\">;\n\ntype ConfBoxesResp = { boxes: Box[] };\ntype UnconfBoxesResp = { mempool: { boxes: Box[] } };\ntype AllBoxesResp = ConfBoxesResp & UnconfBoxesResp;\ntype HeadersResp = { blockHeaders: Header[] };\ntype CheckTxResp = { checkTransaction: string };\ntype SendTxResp = { submitTransaction: string };\ntype SignedTxArgsResp = { signedTransaction: SignedTransaction };\n\nconst PAGE_SIZE = 50;\n\nexport class ErgoGraphQLProvider implements IBlockchainProvider<BoxWhere> {\n #options: GraphQLThrowableOptions;\n\n #getConfBoxes;\n #getUnconfBoxes;\n #getAllBoxes;\n #getHeaders;\n #checkTx;\n #sendTx;\n\n constructor(url: string | URL);\n constructor(url: ErgoGraphQLRequestOptions);\n constructor(optOrUrl: ErgoGraphQLRequestOptions | string | URL) {\n this.#options = {\n ...(isRequestParam(optOrUrl) ? optOrUrl : { url: optOrUrl }),\n throwOnNonNetworkErrors: true\n };\n\n this.#getConfBoxes = this.createOperation<ConfBoxesResp, BoxesArgs>(CONF_BOXES_QUERY);\n this.#getUnconfBoxes = this.createOperation<UnconfBoxesResp, BoxesArgs>(UNCONF_BOXES_QUERY);\n this.#getAllBoxes = this.createOperation<AllBoxesResp, BoxesArgs>(ALL_BOXES_QUERY);\n this.#getHeaders = this.createOperation<HeadersResp, HeadersArgs>(HEADERS_QUERY);\n this.#checkTx = this.createOperation<CheckTxResp, SignedTxArgsResp>(CHECK_TX_MUTATION);\n this.#sendTx = this.createOperation<SendTxResp, SignedTxArgsResp>(SEND_TX_MUTATION);\n }\n\n #fetchBoxes(args: BoxesArgs, inclConf: boolean, inclUnconf: boolean) {\n if (inclConf && inclUnconf) {\n return this.#getAllBoxes(args);\n } else if (inclUnconf) {\n return this.#getUnconfBoxes(args);\n } else {\n return this.#getConfBoxes(args);\n }\n }\n\n async *streamBoxes(query: GraphQLBoxQuery): AsyncGenerator<ChainProviderBox[]> {\n if (isEmpty(query.where)) {\n throw new Error(\"Cannot fetch unspent boxes without a where clause.\");\n }\n\n const notBeingSpent = (box: Box) => !box.beingSpent;\n const returnedBoxIds = new Set<string>();\n const { where, from } = query;\n const args = buildGqlBoxQueryArgs(where);\n\n let fetchFromChain = from !== \"mempool\";\n let fetchFromMempool = from !== \"blockchain\";\n const isMempoolAware = fetchFromMempool;\n\n do {\n const response = await this.#fetchBoxes(args, fetchFromChain, fetchFromMempool);\n\n const { data } = response;\n let boxes: ChainProviderBox[] = [];\n\n if (fetchFromChain && hasConfirmed(data)) {\n if (some(data.boxes)) {\n const confirmedBoxes = (\n isMempoolAware ? data.boxes.filter(notBeingSpent) : data.boxes\n ).map(asConfirmed(true));\n\n boxes = boxes.concat(confirmedBoxes);\n }\n\n fetchFromChain = data.boxes.length === PAGE_SIZE;\n }\n\n if (isMempoolAware && hasMempool(data)) {\n if (some(data.mempool.boxes)) {\n const mempoolBoxes = data.mempool.boxes.filter(notBeingSpent).map(asConfirmed(false));\n boxes = boxes.concat(mempoolBoxes);\n }\n\n fetchFromMempool = data.mempool.boxes.length === PAGE_SIZE;\n }\n\n if (some(boxes)) {\n // boxes can be moved from the mempool to the blockchain while streaming,\n // so we need to filter out boxes that have already been returned.\n if (boxes.some((box) => returnedBoxIds.has(box.boxId))) {\n boxes = boxes.filter((b) => !returnedBoxIds.has(b.boxId));\n }\n\n if (some(boxes)) {\n boxes = uniqBy(boxes, (box) => box.boxId);\n boxes.forEach((box) => returnedBoxIds.add(box.boxId));\n\n yield boxes;\n }\n }\n\n if (fetchFromChain || fetchFromMempool) args.skip += PAGE_SIZE;\n } while (fetchFromChain || fetchFromMempool);\n }\n\n async getBoxes(query: GraphQLBoxQuery): Promise<ChainProviderBox[]> {\n let boxes: ChainProviderBox[] = [];\n for await (const chunk of this.streamBoxes(query)) {\n boxes = boxes.concat(chunk);\n }\n\n return orderBy(boxes, (box) => box.creationHeight);\n }\n\n async getHeaders(query: HeaderQuery): Promise<BlockHeader[]> {\n const response = await this.#getHeaders(query);\n\n return (\n response.data?.blockHeaders.map((header) => ({\n ...header,\n id: header.headerId,\n timestamp: Number(header.timestamp),\n nBits: Number(header.nBits),\n votes: header.votes.join(\"\")\n })) ?? []\n );\n }\n\n createOperation<R, V extends GraphQLVariables = GraphQLVariables>(\n query: string,\n options?: Partial<ErgoGraphQLRequestOptions>\n ): GraphQLOperation<GraphQLSuccessResponse<R>, V> {\n const opt = ensureDefaults(options, this.#options);\n opt.throwOnNonNetworkErrors = true;\n\n return createGqlOperation(query, opt);\n }\n\n async checkTransaction(\n signedTransaction: SignedTransaction\n ): Promise<TransactionEvaluationResult> {\n try {\n const response = await this.#checkTx({ signedTransaction });\n\n return { success: true, transactionId: response.data.checkTransaction };\n } catch (e) {\n return { success: false, message: (e as Error).message };\n }\n }\n\n async submitTransaction(\n signedTransaction: SignedTransaction\n ): Promise<TransactionEvaluationResult> {\n try {\n const response = await this.#sendTx({ signedTransaction });\n\n return { success: true, transactionId: response.data.submitTransaction };\n } catch (e) {\n return { success: false, message: (e as Error).message };\n }\n }\n\n reduceTransaction(): Promise<TransactionReductionResult> {\n throw new NotSupportedError(\"Transaction reducing is not supported by ergo-graphql.\");\n }\n}\n\nfunction buildGqlBoxQueryArgs(where: GraphQLBoxWhere) {\n const args = {\n spent: false,\n boxIds: merge(where.boxIds, where.boxId),\n ergoTrees: merge(where.ergoTrees, where.ergoTree),\n ergoTreeTemplateHash: where.templateHash,\n tokenId: where.tokenId,\n skip: 0,\n take: PAGE_SIZE\n } satisfies BoxesArgs;\n\n const addresses = merge(where.addresses, where.address);\n if (some(addresses)) {\n const trees = addresses.map((address) =>\n typeof address === \"string\" ? ErgoAddress.fromBase58(address).ergoTree : address.ergoTree\n );\n\n args.ergoTrees = uniq(some(args.ergoTrees) ? args.ergoTrees.concat(trees) : trees);\n }\n\n return args;\n}\n\nfunction merge<T>(array?: T[], el?: T) {\n if (isEmpty(array) && isUndefined(el)) return;\n\n const set = new Set<T>(array ?? []);\n if (!isUndefined(el)) set.add(el);\n return Array.from(set.values());\n}\n\nfunction hasMempool(data: AllBoxesResp | ConfBoxesResp | UnconfBoxesResp): data is UnconfBoxesResp {\n return !!(data as UnconfBoxesResp)?.mempool?.boxes;\n}\n\nfunction hasConfirmed(data: AllBoxesResp | ConfBoxesResp | UnconfBoxesResp): data is ConfBoxesResp {\n return !!(data as ConfBoxesResp)?.boxes;\n}\n\nfunction asConfirmed(confirmed: boolean) {\n return (box: Box): ChainProviderBox => ({\n ...box,\n value: BigInt(box.value),\n assets: box.assets.map((asset) => ({\n tokenId: asset.tokenId,\n amount: BigInt(asset.amount)\n })),\n confirmed\n });\n}\n","import {\n BlockchainProviderError,\n clearUndefined,\n ensureDefaults,\n isEmpty,\n some\n} from \"@fleet-sdk/common\";\n\nconst OP_NAME_REGEX = /(query|mutation)\\s?([\\w\\-_]+)?/;\nexport const DEFAULT_HEADERS: Headers = {\n \"content-type\": \"application/json; charset=utf-8\",\n accept: \"application/graphql-response+json, application/json\"\n};\n\ntype Credentials = RequestCredentials;\ntype Headers = HeadersInit;\ntype Fetcher = typeof fetch;\n\nexport type GraphQLVariables = Record<string, unknown> | null;\n\nexport interface GraphQLError {\n message: string;\n}\n\nexport interface GraphQLSuccessResponse<T = unknown> {\n data: T;\n errors: null;\n}\n\nexport interface GraphQLErrorResponse {\n data: null;\n errors: GraphQLError[];\n}\n\nexport type GraphQLResponse<T = unknown> = GraphQLSuccessResponse<T> | GraphQLErrorResponse;\n\nexport type GraphQLOperation<R extends GraphQLResponse, V extends GraphQLVariables> = (\n variables?: V\n) => Promise<R>;\n\nexport interface ResponseParser {\n parse<T>(text: string): T;\n stringify<T>(value: T): string;\n}\n\nexport interface RequestParams {\n operationName?: string | null;\n query: string;\n variables?: Record<string, unknown> | null;\n}\n\nexport interface GraphQLRequestOptions {\n url: URL | string;\n headers?: Headers;\n parser?: ResponseParser;\n fetcher?: Fetcher;\n credentials?: Credentials;\n throwOnNonNetworkErrors?: boolean;\n}\n\nexport interface GraphQLThrowableOptions extends GraphQLRequestOptions {\n throwOnNonNetworkErrors: true;\n}\n\nexport function createGqlOperation<R, V extends GraphQLVariables = GraphQLVariables>(\n query: string,\n options: GraphQLThrowableOptions\n): GraphQLOperation<GraphQLSuccessResponse<R>, V>;\nexport function createGqlOperation<R, V extends GraphQLVariables = GraphQLVariables>(\n query: string,\n options: GraphQLRequestOptions\n): GraphQLOperation<GraphQLResponse<R>, V>;\nexport function createGqlOperation<R, V extends GraphQLVariables = GraphQLVariables>(\n query: string,\n options: GraphQLRequestOptions\n): GraphQLOperation<GraphQLResponse<R>, V> {\n return async (variables?: V): Promise<GraphQLResponse<R>> => {\n const response = await (options.fetcher ?? fetch)(options.url, {\n method: \"POST\",\n headers: ensureDefaults(options.headers, DEFAULT_HEADERS),\n credentials: options.credentials,\n body: (options.parser ?? JSON).stringify({\n operationName: getOpName(query),\n query,\n variables: variables ? clearUndefined(variables) : undefined\n } as RequestParams)\n });\n\n const rawData = await response.text();\n const parsedData = (options.parser ?? JSON).parse(rawData) as GraphQLResponse<R>;\n\n if (options.throwOnNonNetworkErrors && some(parsedData.errors) && isEmpty(parsedData.data)) {\n throw new BlockchainProviderError(parsedData.errors[0].message, { cause: parsedData.errors });\n }\n\n return parsedData;\n };\n}\n\nexport function gql(query: TemplateStringsArray): string {\n return query[0];\n}\n\nexport function getOpName(query: string): string | undefined {\n return OP_NAME_REGEX.exec(query)?.at(2);\n}\n\nexport function isRequestParam(obj: unknown): obj is GraphQLRequestOptions {\n return typeof obj === \"object\" && (obj as GraphQLRequestOptions).url !== undefined;\n}\n","const B = [\n `query boxes($spent: Boolean! $boxIds: [String!] $ergoTrees: [String!] $ergoTreeTemplateHash: String $tokenId: String $skip: Int $take: Int)`,\n `boxIds: $boxIds ergoTrees: $ergoTrees ergoTreeTemplateHash: $ergoTreeTemplateHash tokenId: $tokenId skip: $skip take: $take`,\n `boxId transactionId index value creationHeight ergoTree assets { tokenId amount } additionalRegisters beingSpent`\n];\n\nexport const CONF_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } }`;\nexport const UNCONF_BOXES_QUERY = `${B[0]} { mempool { boxes(${B[1]}) { ${B[2]} } } }`;\nexport const ALL_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } mempool { boxes(${B[1]}) { ${B[2]} } } }`;\nexport const HEADERS_QUERY = `query blockHeaders($take: Int) { blockHeaders(take: $take) {headerId timestamp version adProofsRoot stateRoot transactionsRoot nBits extensionHash powSolutions height difficulty parentId votes } }`;\nexport const CHECK_TX_MUTATION = `mutation checkTransaction($signedTransaction: SignedTransaction!) { checkTransaction(signedTransaction: $signedTransaction) }`;\nexport const SEND_TX_MUTATION = `mutation submitTransaction($signedTransaction: SignedTransaction!) { submitTransaction(signedTransaction: $signedTransaction) }`;\n"]}
1
+ {"version":3,"sources":["../src/ergo-graphql/ergoGraphQLProvider.ts","../src/utils/graphql.ts","../src/ergo-graphql/queries.ts"],"names":["ensureDefaults","isEmpty","some"],"mappings":"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","sourcesContent":["import type {\n Box,\n QueryBoxesArgs,\n Header,\n QueryBlockHeadersArgs\n} from \"@ergo-graphql/types\";\nimport {\n type Base58String,\n type BlockHeader,\n ensureDefaults,\n type HexString,\n isEmpty,\n isUndefined,\n NotSupportedError,\n orderBy,\n type SignedTransaction,\n some,\n uniq,\n uniqBy\n} from \"@fleet-sdk/common\";\nimport { ErgoAddress } from \"@fleet-sdk/core\";\nimport type {\n BoxQuery,\n BoxWhere,\n ChainProviderBox,\n HeaderQuery,\n IBlockchainProvider,\n TransactionEvaluationResult,\n TransactionReductionResult\n} from \"../types/blockchainProvider\";\nimport {\n createGqlOperation,\n type GraphQLOperation,\n type GraphQLRequestOptions,\n type GraphQLSuccessResponse,\n type GraphQLThrowableOptions,\n type GraphQLVariables,\n isRequestParam\n} from \"../utils\";\nimport {\n ALL_BOXES_QUERY,\n CHECK_TX_MUTATION,\n CONF_BOXES_QUERY,\n HEADERS_QUERY,\n SEND_TX_MUTATION,\n UNCONF_BOXES_QUERY\n} from \"./queries\";\n\nexport type GraphQLBoxWhere = BoxWhere & {\n /** Base16-encoded BoxIds */\n boxIds?: HexString[];\n\n /** Base16-encoded ErgoTrees */\n ergoTrees?: HexString[];\n\n /** Base58-encoded addresses or `ErgoAddress` objects */\n addresses?: (Base58String | ErgoAddress)[];\n};\n\nexport type GraphQLBoxQuery = BoxQuery<GraphQLBoxWhere>;\nexport type ErgoGraphQLRequestOptions = Omit<\n GraphQLRequestOptions,\n \"throwOnNonNetworkError\"\n>;\n\ntype ConfirmedBoxesResponse = { boxes: Box[] };\ntype UnconfirmedBoxesResponse = { mempool: { boxes: Box[] } };\ntype CombinedBoxesResponse = ConfirmedBoxesResponse & UnconfirmedBoxesResponse;\ntype BlockHeadersResponse = { blockHeaders: Header[] };\ntype CheckTransactionResponse = { checkTransaction: string };\ntype TransactionSubmissionResponse = { submitTransaction: string };\ntype SignedTxArgsResp = { signedTransaction: SignedTransaction };\n\nconst PAGE_SIZE = 50;\n\nexport class ErgoGraphQLProvider implements IBlockchainProvider<BoxWhere> {\n #options: GraphQLThrowableOptions;\n\n #getConfBoxes;\n #getUnconfBoxes;\n #getAllBoxes;\n #getHeaders;\n #checkTx;\n #sendTx;\n\n constructor(url: string | URL);\n constructor(url: ErgoGraphQLRequestOptions);\n constructor(optOrUrl: ErgoGraphQLRequestOptions | string | URL) {\n this.#options = {\n ...(isRequestParam(optOrUrl) ? optOrUrl : { url: optOrUrl }),\n throwOnNonNetworkErrors: true\n };\n\n this.#getConfBoxes = this.createOperation<\n ConfirmedBoxesResponse,\n QueryBoxesArgs\n >(CONF_BOXES_QUERY);\n\n this.#getUnconfBoxes = this.createOperation<\n UnconfirmedBoxesResponse,\n QueryBoxesArgs\n >(UNCONF_BOXES_QUERY);\n\n this.#getAllBoxes = this.createOperation<\n CombinedBoxesResponse,\n QueryBoxesArgs\n >(ALL_BOXES_QUERY);\n\n this.#getHeaders = this.createOperation<\n BlockHeadersResponse,\n QueryBlockHeadersArgs\n >(HEADERS_QUERY);\n\n this.#checkTx = this.createOperation<\n CheckTransactionResponse,\n SignedTxArgsResp\n >(CHECK_TX_MUTATION);\n\n this.#sendTx = this.createOperation<\n TransactionSubmissionResponse,\n SignedTxArgsResp\n >(SEND_TX_MUTATION);\n }\n\n #fetchBoxes(args: QueryBoxesArgs, inclConf: boolean, inclUnconf: boolean) {\n return inclConf && inclUnconf\n ? this.#getAllBoxes(args)\n : inclUnconf\n ? this.#getUnconfBoxes(args)\n : this.#getConfBoxes(args);\n }\n\n async *streamBoxes(\n query: GraphQLBoxQuery\n ): AsyncGenerator<ChainProviderBox[]> {\n if (isEmpty(query.where)) {\n throw new Error(\"Cannot fetch unspent boxes without a where clause.\");\n }\n\n const notBeingSpent = (box: Box) => !box.beingSpent;\n const returnedBoxIds = new Set<string>();\n const { where, from } = query;\n const args = buildGqlBoxQueryArgs(where);\n\n let inclChain = from !== \"mempool\";\n let inclPool = from !== \"blockchain\";\n const isMempoolAware = inclPool;\n\n do {\n const response = await this.#fetchBoxes(args, inclChain, inclPool);\n\n const { data } = response;\n let boxes: ChainProviderBox[] = [];\n\n if (inclChain && hasConfirmed(data)) {\n if (some(data.boxes)) {\n const confirmedBoxes = (\n isMempoolAware ? data.boxes.filter(notBeingSpent) : data.boxes\n ).map(asConfirmed(true));\n\n boxes = boxes.concat(confirmedBoxes);\n }\n\n inclChain = data.boxes.length === PAGE_SIZE;\n }\n\n if (isMempoolAware && hasMempool(data)) {\n if (some(data.mempool.boxes)) {\n const mempoolBoxes = data.mempool.boxes\n .filter(notBeingSpent)\n .map(asConfirmed(false));\n boxes = boxes.concat(mempoolBoxes);\n }\n\n inclPool = data.mempool.boxes.length === PAGE_SIZE;\n }\n\n if (some(boxes)) {\n // boxes can be moved from the mempool to the blockchain while streaming,\n // so we need to filter out boxes that have already been returned.\n if (boxes.some((box) => returnedBoxIds.has(box.boxId))) {\n boxes = boxes.filter((b) => !returnedBoxIds.has(b.boxId));\n }\n\n if (some(boxes)) {\n boxes = uniqBy(boxes, (box) => box.boxId);\n for (const box of boxes) returnedBoxIds.add(box.boxId);\n yield boxes;\n }\n }\n\n if (inclChain || inclPool) args.skip += PAGE_SIZE;\n } while (inclChain || inclPool);\n }\n\n async getBoxes(query: GraphQLBoxQuery): Promise<ChainProviderBox[]> {\n let boxes: ChainProviderBox[] = [];\n for await (const chunk of this.streamBoxes(query)) {\n boxes = boxes.concat(chunk);\n }\n\n return orderBy(boxes, (box) => box.creationHeight);\n }\n\n async getHeaders(query: HeaderQuery): Promise<BlockHeader[]> {\n const response = await this.#getHeaders(query);\n\n return (\n response.data?.blockHeaders.map((header) => ({\n ...header,\n id: header.headerId,\n timestamp: Number(header.timestamp),\n nBits: Number(header.nBits),\n votes: header.votes.join(\"\")\n })) ?? []\n );\n }\n\n createOperation<R, V extends GraphQLVariables = GraphQLVariables>(\n query: string,\n options?: Partial<ErgoGraphQLRequestOptions>\n ): GraphQLOperation<GraphQLSuccessResponse<R>, V> {\n const opt = ensureDefaults(options, this.#options);\n opt.throwOnNonNetworkErrors = true;\n\n return createGqlOperation(query, opt);\n }\n\n async checkTransaction(\n signedTransaction: SignedTransaction\n ): Promise<TransactionEvaluationResult> {\n try {\n const response = await this.#checkTx({ signedTransaction });\n\n return { success: true, transactionId: response.data.checkTransaction };\n } catch (e) {\n return { success: false, message: (e as Error).message };\n }\n }\n\n async submitTransaction(\n signedTransaction: SignedTransaction\n ): Promise<TransactionEvaluationResult> {\n try {\n const response = await this.#sendTx({ signedTransaction });\n\n return { success: true, transactionId: response.data.submitTransaction };\n } catch (e) {\n return { success: false, message: (e as Error).message };\n }\n }\n\n reduceTransaction(): Promise<TransactionReductionResult> {\n throw new NotSupportedError(\n \"Transaction reducing is not supported by ergo-graphql.\"\n );\n }\n}\n\nfunction buildGqlBoxQueryArgs(where: GraphQLBoxWhere) {\n const args = {\n spent: false,\n boxIds: merge(where.boxIds, where.boxId),\n ergoTrees: merge(where.ergoTrees, where.ergoTree),\n ergoTreeTemplateHash: where.templateHash,\n tokenId: where.tokenId,\n skip: 0,\n take: PAGE_SIZE\n } satisfies QueryBoxesArgs;\n\n const addresses = merge(where.addresses, where.address);\n if (some(addresses)) {\n const trees = addresses.map((address) =>\n typeof address === \"string\"\n ? ErgoAddress.fromBase58(address).ergoTree\n : address.ergoTree\n );\n\n args.ergoTrees = uniq(\n some(args.ergoTrees) ? args.ergoTrees.concat(trees) : trees\n );\n }\n\n return args;\n}\n\nfunction merge<T>(array?: T[], el?: T) {\n if (isEmpty(array) && isUndefined(el)) return;\n\n const set = new Set<T>(array ?? []);\n if (!isUndefined(el)) set.add(el);\n return Array.from(set.values());\n}\n\nfunction hasMempool(data: unknown): data is UnconfirmedBoxesResponse {\n return !!(data as UnconfirmedBoxesResponse)?.mempool?.boxes;\n}\n\nfunction hasConfirmed(data: unknown): data is ConfirmedBoxesResponse {\n return !!(data as ConfirmedBoxesResponse)?.boxes;\n}\n\nfunction asConfirmed(confirmed: boolean) {\n return (box: Box): ChainProviderBox => ({\n ...box,\n value: BigInt(box.value),\n assets: box.assets.map((asset) => ({\n tokenId: asset.tokenId,\n amount: BigInt(asset.amount)\n })),\n confirmed\n });\n}\n","import {\n BlockchainProviderError,\n clearUndefined,\n ensureDefaults,\n isEmpty,\n some\n} from \"@fleet-sdk/common\";\n\nconst OP_NAME_REGEX = /(query|mutation)\\s?([\\w\\-_]+)?/;\nexport const DEFAULT_HEADERS: Headers = {\n \"content-type\": \"application/json; charset=utf-8\",\n accept: \"application/graphql-response+json, application/json\"\n};\n\ntype Credentials = RequestCredentials;\ntype Headers = HeadersInit;\ntype Fetcher = typeof fetch;\n\nexport type GraphQLVariables = Record<string, unknown> | null;\n\nexport interface GraphQLError {\n message: string;\n}\n\nexport interface GraphQLSuccessResponse<T = unknown> {\n data: T;\n errors: null;\n}\n\nexport interface GraphQLErrorResponse {\n data: null;\n errors: GraphQLError[];\n}\n\nexport type GraphQLResponse<T = unknown> =\n | GraphQLSuccessResponse<T>\n | GraphQLErrorResponse;\n\nexport type GraphQLOperation<\n R extends GraphQLResponse,\n V extends GraphQLVariables\n> = (variables?: V) => Promise<R>;\n\nexport interface ResponseParser {\n parse<T>(text: string): T;\n stringify<T>(value: T): string;\n}\n\nexport interface RequestParams {\n operationName?: string | null;\n query: string;\n variables?: Record<string, unknown> | null;\n}\n\nexport interface GraphQLRequestOptions {\n url: URL | string;\n headers?: Headers;\n parser?: ResponseParser;\n fetcher?: Fetcher;\n credentials?: Credentials;\n throwOnNonNetworkErrors?: boolean;\n}\n\nexport interface GraphQLThrowableOptions extends GraphQLRequestOptions {\n throwOnNonNetworkErrors: true;\n}\n\nexport function createGqlOperation<\n R,\n V extends GraphQLVariables = GraphQLVariables\n>(\n query: string,\n options: GraphQLThrowableOptions\n): GraphQLOperation<GraphQLSuccessResponse<R>, V>;\nexport function createGqlOperation<\n R,\n V extends GraphQLVariables = GraphQLVariables\n>(\n query: string,\n options: GraphQLRequestOptions\n): GraphQLOperation<GraphQLResponse<R>, V>;\nexport function createGqlOperation<\n R,\n V extends GraphQLVariables = GraphQLVariables\n>(\n query: string,\n options: GraphQLRequestOptions\n): GraphQLOperation<GraphQLResponse<R>, V> {\n return async (variables?: V): Promise<GraphQLResponse<R>> => {\n const response = await (options.fetcher ?? fetch)(options.url, {\n method: \"POST\",\n headers: ensureDefaults(options.headers, DEFAULT_HEADERS),\n credentials: options.credentials,\n body: (options.parser ?? JSON).stringify({\n operationName: getOpName(query),\n query,\n variables: variables ? clearUndefined(variables) : undefined\n } as RequestParams)\n });\n\n const rawData = await response.text();\n const parsedData = (options.parser ?? JSON).parse(\n rawData\n ) as GraphQLResponse<R>;\n\n if (\n options.throwOnNonNetworkErrors &&\n some(parsedData.errors) &&\n isEmpty(parsedData.data)\n ) {\n throw new BlockchainProviderError(parsedData.errors[0].message, {\n cause: parsedData.errors\n });\n }\n\n return parsedData;\n };\n}\n\nexport function gql(query: TemplateStringsArray): string {\n return query[0];\n}\n\nexport function getOpName(query: string): string | undefined {\n return OP_NAME_REGEX.exec(query)?.at(2);\n}\n\nexport function isRequestParam(obj: unknown): obj is GraphQLRequestOptions {\n return (\n typeof obj === \"object\" && (obj as GraphQLRequestOptions).url !== undefined\n );\n}\n","const B = [\n \"query boxes($spent: Boolean! $boxIds: [String!] $ergoTrees: [String!] $ergoTreeTemplateHash: String $tokenId: String $skip: Int $take: Int)\",\n \"boxIds: $boxIds ergoTrees: $ergoTrees ergoTreeTemplateHash: $ergoTreeTemplateHash tokenId: $tokenId skip: $skip take: $take\",\n \"boxId transactionId index value creationHeight ergoTree assets { tokenId amount } additionalRegisters beingSpent\"\n];\n\nexport const CONF_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } }`;\nexport const UNCONF_BOXES_QUERY = `${B[0]} { mempool { boxes(${B[1]}) { ${B[2]} } } }`;\nexport const ALL_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } mempool { boxes(${B[1]}) { ${B[2]} } } }`;\nexport const HEADERS_QUERY =\n \"query blockHeaders($take: Int) { blockHeaders(take: $take) {headerId timestamp version adProofsRoot stateRoot transactionsRoot nBits extensionHash powSolutions height difficulty parentId votes } }\";\nexport const CHECK_TX_MUTATION =\n \"mutation checkTransaction($signedTransaction: SignedTransaction!) { checkTransaction(signedTransaction: $signedTransaction) }\";\nexport const SEND_TX_MUTATION =\n \"mutation submitTransaction($signedTransaction: SignedTransaction!) { submitTransaction(signedTransaction: $signedTransaction) }\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fleet-sdk/blockchain-providers",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Blockchain data providers",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -30,11 +30,11 @@
30
30
  "crypto"
31
31
  ],
32
32
  "engines": {
33
- "node": ">=14"
33
+ "node": ">=18"
34
34
  },
35
35
  "dependencies": {
36
36
  "@fleet-sdk/common": "^0.4.1",
37
- "@fleet-sdk/core": "^0.4.1"
37
+ "@fleet-sdk/core": "^0.5.0"
38
38
  },
39
39
  "files": [
40
40
  "src",
@@ -1,25 +1,25 @@
1
- import {
1
+ import type {
2
2
  Box,
3
- QueryBoxesArgs as BoxesArgs,
3
+ QueryBoxesArgs,
4
4
  Header,
5
- QueryBlockHeadersArgs as HeadersArgs
5
+ QueryBlockHeadersArgs
6
6
  } from "@ergo-graphql/types";
7
7
  import {
8
- Base58String,
9
- BlockHeader,
8
+ type Base58String,
9
+ type BlockHeader,
10
10
  ensureDefaults,
11
- HexString,
11
+ type HexString,
12
12
  isEmpty,
13
13
  isUndefined,
14
14
  NotSupportedError,
15
15
  orderBy,
16
- SignedTransaction,
16
+ type SignedTransaction,
17
17
  some,
18
18
  uniq,
19
19
  uniqBy
20
20
  } from "@fleet-sdk/common";
21
21
  import { ErgoAddress } from "@fleet-sdk/core";
22
- import {
22
+ import type {
23
23
  BoxQuery,
24
24
  BoxWhere,
25
25
  ChainProviderBox,
@@ -27,14 +27,14 @@ import {
27
27
  IBlockchainProvider,
28
28
  TransactionEvaluationResult,
29
29
  TransactionReductionResult
30
- } from "../types";
30
+ } from "../types/blockchainProvider";
31
31
  import {
32
32
  createGqlOperation,
33
- GraphQLOperation,
34
- GraphQLRequestOptions,
35
- GraphQLSuccessResponse,
36
- GraphQLThrowableOptions,
37
- GraphQLVariables,
33
+ type GraphQLOperation,
34
+ type GraphQLRequestOptions,
35
+ type GraphQLSuccessResponse,
36
+ type GraphQLThrowableOptions,
37
+ type GraphQLVariables,
38
38
  isRequestParam
39
39
  } from "../utils";
40
40
  import {
@@ -58,14 +58,17 @@ export type GraphQLBoxWhere = BoxWhere & {
58
58
  };
59
59
 
60
60
  export type GraphQLBoxQuery = BoxQuery<GraphQLBoxWhere>;
61
- export type ErgoGraphQLRequestOptions = Omit<GraphQLRequestOptions, "throwOnNonNetworkError">;
62
-
63
- type ConfBoxesResp = { boxes: Box[] };
64
- type UnconfBoxesResp = { mempool: { boxes: Box[] } };
65
- type AllBoxesResp = ConfBoxesResp & UnconfBoxesResp;
66
- type HeadersResp = { blockHeaders: Header[] };
67
- type CheckTxResp = { checkTransaction: string };
68
- type SendTxResp = { submitTransaction: string };
61
+ export type ErgoGraphQLRequestOptions = Omit<
62
+ GraphQLRequestOptions,
63
+ "throwOnNonNetworkError"
64
+ >;
65
+
66
+ type ConfirmedBoxesResponse = { boxes: Box[] };
67
+ type UnconfirmedBoxesResponse = { mempool: { boxes: Box[] } };
68
+ type CombinedBoxesResponse = ConfirmedBoxesResponse & UnconfirmedBoxesResponse;
69
+ type BlockHeadersResponse = { blockHeaders: Header[] };
70
+ type CheckTransactionResponse = { checkTransaction: string };
71
+ type TransactionSubmissionResponse = { submitTransaction: string };
69
72
  type SignedTxArgsResp = { signedTransaction: SignedTransaction };
70
73
 
71
74
  const PAGE_SIZE = 50;
@@ -88,25 +91,48 @@ export class ErgoGraphQLProvider implements IBlockchainProvider<BoxWhere> {
88
91
  throwOnNonNetworkErrors: true
89
92
  };
90
93
 
91
- this.#getConfBoxes = this.createOperation<ConfBoxesResp, BoxesArgs>(CONF_BOXES_QUERY);
92
- this.#getUnconfBoxes = this.createOperation<UnconfBoxesResp, BoxesArgs>(UNCONF_BOXES_QUERY);
93
- this.#getAllBoxes = this.createOperation<AllBoxesResp, BoxesArgs>(ALL_BOXES_QUERY);
94
- this.#getHeaders = this.createOperation<HeadersResp, HeadersArgs>(HEADERS_QUERY);
95
- this.#checkTx = this.createOperation<CheckTxResp, SignedTxArgsResp>(CHECK_TX_MUTATION);
96
- this.#sendTx = this.createOperation<SendTxResp, SignedTxArgsResp>(SEND_TX_MUTATION);
94
+ this.#getConfBoxes = this.createOperation<
95
+ ConfirmedBoxesResponse,
96
+ QueryBoxesArgs
97
+ >(CONF_BOXES_QUERY);
98
+
99
+ this.#getUnconfBoxes = this.createOperation<
100
+ UnconfirmedBoxesResponse,
101
+ QueryBoxesArgs
102
+ >(UNCONF_BOXES_QUERY);
103
+
104
+ this.#getAllBoxes = this.createOperation<
105
+ CombinedBoxesResponse,
106
+ QueryBoxesArgs
107
+ >(ALL_BOXES_QUERY);
108
+
109
+ this.#getHeaders = this.createOperation<
110
+ BlockHeadersResponse,
111
+ QueryBlockHeadersArgs
112
+ >(HEADERS_QUERY);
113
+
114
+ this.#checkTx = this.createOperation<
115
+ CheckTransactionResponse,
116
+ SignedTxArgsResp
117
+ >(CHECK_TX_MUTATION);
118
+
119
+ this.#sendTx = this.createOperation<
120
+ TransactionSubmissionResponse,
121
+ SignedTxArgsResp
122
+ >(SEND_TX_MUTATION);
97
123
  }
98
124
 
99
- #fetchBoxes(args: BoxesArgs, inclConf: boolean, inclUnconf: boolean) {
100
- if (inclConf && inclUnconf) {
101
- return this.#getAllBoxes(args);
102
- } else if (inclUnconf) {
103
- return this.#getUnconfBoxes(args);
104
- } else {
105
- return this.#getConfBoxes(args);
106
- }
125
+ #fetchBoxes(args: QueryBoxesArgs, inclConf: boolean, inclUnconf: boolean) {
126
+ return inclConf && inclUnconf
127
+ ? this.#getAllBoxes(args)
128
+ : inclUnconf
129
+ ? this.#getUnconfBoxes(args)
130
+ : this.#getConfBoxes(args);
107
131
  }
108
132
 
109
- async *streamBoxes(query: GraphQLBoxQuery): AsyncGenerator<ChainProviderBox[]> {
133
+ async *streamBoxes(
134
+ query: GraphQLBoxQuery
135
+ ): AsyncGenerator<ChainProviderBox[]> {
110
136
  if (isEmpty(query.where)) {
111
137
  throw new Error("Cannot fetch unspent boxes without a where clause.");
112
138
  }
@@ -116,17 +142,17 @@ export class ErgoGraphQLProvider implements IBlockchainProvider<BoxWhere> {
116
142
  const { where, from } = query;
117
143
  const args = buildGqlBoxQueryArgs(where);
118
144
 
119
- let fetchFromChain = from !== "mempool";
120
- let fetchFromMempool = from !== "blockchain";
121
- const isMempoolAware = fetchFromMempool;
145
+ let inclChain = from !== "mempool";
146
+ let inclPool = from !== "blockchain";
147
+ const isMempoolAware = inclPool;
122
148
 
123
149
  do {
124
- const response = await this.#fetchBoxes(args, fetchFromChain, fetchFromMempool);
150
+ const response = await this.#fetchBoxes(args, inclChain, inclPool);
125
151
 
126
152
  const { data } = response;
127
153
  let boxes: ChainProviderBox[] = [];
128
154
 
129
- if (fetchFromChain && hasConfirmed(data)) {
155
+ if (inclChain && hasConfirmed(data)) {
130
156
  if (some(data.boxes)) {
131
157
  const confirmedBoxes = (
132
158
  isMempoolAware ? data.boxes.filter(notBeingSpent) : data.boxes
@@ -135,16 +161,18 @@ export class ErgoGraphQLProvider implements IBlockchainProvider<BoxWhere> {
135
161
  boxes = boxes.concat(confirmedBoxes);
136
162
  }
137
163
 
138
- fetchFromChain = data.boxes.length === PAGE_SIZE;
164
+ inclChain = data.boxes.length === PAGE_SIZE;
139
165
  }
140
166
 
141
167
  if (isMempoolAware && hasMempool(data)) {
142
168
  if (some(data.mempool.boxes)) {
143
- const mempoolBoxes = data.mempool.boxes.filter(notBeingSpent).map(asConfirmed(false));
169
+ const mempoolBoxes = data.mempool.boxes
170
+ .filter(notBeingSpent)
171
+ .map(asConfirmed(false));
144
172
  boxes = boxes.concat(mempoolBoxes);
145
173
  }
146
174
 
147
- fetchFromMempool = data.mempool.boxes.length === PAGE_SIZE;
175
+ inclPool = data.mempool.boxes.length === PAGE_SIZE;
148
176
  }
149
177
 
150
178
  if (some(boxes)) {
@@ -156,14 +184,13 @@ export class ErgoGraphQLProvider implements IBlockchainProvider<BoxWhere> {
156
184
 
157
185
  if (some(boxes)) {
158
186
  boxes = uniqBy(boxes, (box) => box.boxId);
159
- boxes.forEach((box) => returnedBoxIds.add(box.boxId));
160
-
187
+ for (const box of boxes) returnedBoxIds.add(box.boxId);
161
188
  yield boxes;
162
189
  }
163
190
  }
164
191
 
165
- if (fetchFromChain || fetchFromMempool) args.skip += PAGE_SIZE;
166
- } while (fetchFromChain || fetchFromMempool);
192
+ if (inclChain || inclPool) args.skip += PAGE_SIZE;
193
+ } while (inclChain || inclPool);
167
194
  }
168
195
 
169
196
  async getBoxes(query: GraphQLBoxQuery): Promise<ChainProviderBox[]> {
@@ -224,7 +251,9 @@ export class ErgoGraphQLProvider implements IBlockchainProvider<BoxWhere> {
224
251
  }
225
252
 
226
253
  reduceTransaction(): Promise<TransactionReductionResult> {
227
- throw new NotSupportedError("Transaction reducing is not supported by ergo-graphql.");
254
+ throw new NotSupportedError(
255
+ "Transaction reducing is not supported by ergo-graphql."
256
+ );
228
257
  }
229
258
  }
230
259
 
@@ -237,15 +266,19 @@ function buildGqlBoxQueryArgs(where: GraphQLBoxWhere) {
237
266
  tokenId: where.tokenId,
238
267
  skip: 0,
239
268
  take: PAGE_SIZE
240
- } satisfies BoxesArgs;
269
+ } satisfies QueryBoxesArgs;
241
270
 
242
271
  const addresses = merge(where.addresses, where.address);
243
272
  if (some(addresses)) {
244
273
  const trees = addresses.map((address) =>
245
- typeof address === "string" ? ErgoAddress.fromBase58(address).ergoTree : address.ergoTree
274
+ typeof address === "string"
275
+ ? ErgoAddress.fromBase58(address).ergoTree
276
+ : address.ergoTree
246
277
  );
247
278
 
248
- args.ergoTrees = uniq(some(args.ergoTrees) ? args.ergoTrees.concat(trees) : trees);
279
+ args.ergoTrees = uniq(
280
+ some(args.ergoTrees) ? args.ergoTrees.concat(trees) : trees
281
+ );
249
282
  }
250
283
 
251
284
  return args;
@@ -259,12 +292,12 @@ function merge<T>(array?: T[], el?: T) {
259
292
  return Array.from(set.values());
260
293
  }
261
294
 
262
- function hasMempool(data: AllBoxesResp | ConfBoxesResp | UnconfBoxesResp): data is UnconfBoxesResp {
263
- return !!(data as UnconfBoxesResp)?.mempool?.boxes;
295
+ function hasMempool(data: unknown): data is UnconfirmedBoxesResponse {
296
+ return !!(data as UnconfirmedBoxesResponse)?.mempool?.boxes;
264
297
  }
265
298
 
266
- function hasConfirmed(data: AllBoxesResp | ConfBoxesResp | UnconfBoxesResp): data is ConfBoxesResp {
267
- return !!(data as ConfBoxesResp)?.boxes;
299
+ function hasConfirmed(data: unknown): data is ConfirmedBoxesResponse {
300
+ return !!(data as ConfirmedBoxesResponse)?.boxes;
268
301
  }
269
302
 
270
303
  function asConfirmed(confirmed: boolean) {
@@ -1,12 +1,15 @@
1
1
  const B = [
2
- `query boxes($spent: Boolean! $boxIds: [String!] $ergoTrees: [String!] $ergoTreeTemplateHash: String $tokenId: String $skip: Int $take: Int)`,
3
- `boxIds: $boxIds ergoTrees: $ergoTrees ergoTreeTemplateHash: $ergoTreeTemplateHash tokenId: $tokenId skip: $skip take: $take`,
4
- `boxId transactionId index value creationHeight ergoTree assets { tokenId amount } additionalRegisters beingSpent`
2
+ "query boxes($spent: Boolean! $boxIds: [String!] $ergoTrees: [String!] $ergoTreeTemplateHash: String $tokenId: String $skip: Int $take: Int)",
3
+ "boxIds: $boxIds ergoTrees: $ergoTrees ergoTreeTemplateHash: $ergoTreeTemplateHash tokenId: $tokenId skip: $skip take: $take",
4
+ "boxId transactionId index value creationHeight ergoTree assets { tokenId amount } additionalRegisters beingSpent"
5
5
  ];
6
6
 
7
7
  export const CONF_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } }`;
8
8
  export const UNCONF_BOXES_QUERY = `${B[0]} { mempool { boxes(${B[1]}) { ${B[2]} } } }`;
9
9
  export const ALL_BOXES_QUERY = `${B[0]} { boxes(spent: $spent ${B[1]}) { ${B[2]} } mempool { boxes(${B[1]}) { ${B[2]} } } }`;
10
- export const HEADERS_QUERY = `query blockHeaders($take: Int) { blockHeaders(take: $take) {headerId timestamp version adProofsRoot stateRoot transactionsRoot nBits extensionHash powSolutions height difficulty parentId votes } }`;
11
- export const CHECK_TX_MUTATION = `mutation checkTransaction($signedTransaction: SignedTransaction!) { checkTransaction(signedTransaction: $signedTransaction) }`;
12
- export const SEND_TX_MUTATION = `mutation submitTransaction($signedTransaction: SignedTransaction!) { submitTransaction(signedTransaction: $signedTransaction) }`;
10
+ export const HEADERS_QUERY =
11
+ "query blockHeaders($take: Int) { blockHeaders(take: $take) {headerId timestamp version adProofsRoot stateRoot transactionsRoot nBits extensionHash powSolutions height difficulty parentId votes } }";
12
+ export const CHECK_TX_MUTATION =
13
+ "mutation checkTransaction($signedTransaction: SignedTransaction!) { checkTransaction(signedTransaction: $signedTransaction) }";
14
+ export const SEND_TX_MUTATION =
15
+ "mutation submitTransaction($signedTransaction: SignedTransaction!) { submitTransaction(signedTransaction: $signedTransaction) }";
package/src/index.ts CHANGED
@@ -1 +1 @@
1
- export * from "./ergo-graphql";
1
+ export * from "./ergo-graphql/ergoGraphQLProvider";
@@ -1,4 +1,4 @@
1
- import {
1
+ import type {
2
2
  Base58String,
3
3
  BlockHeader,
4
4
  Box,
@@ -9,8 +9,8 @@ import {
9
9
  TransactionId,
10
10
  UnsignedTransaction
11
11
  } from "@fleet-sdk/common";
12
- import { ErgoAddress } from "@fleet-sdk/core";
13
- import { RequireAtLeastOne } from "type-fest";
12
+ import type { ErgoAddress } from "@fleet-sdk/core";
13
+ import type { RequireAtLeastOne } from "type-fest";
14
14
 
15
15
  export type BoxSource = "blockchain" | "mempool" | "blockchain+mempool";
16
16
 
@@ -63,8 +63,12 @@ export type TransactionReductionSuccess = {
63
63
  reducedTransaction: HexString;
64
64
  };
65
65
 
66
- export type TransactionEvaluationResult = TransactionEvaluationError | TransactionEvaluationSuccess;
67
- export type TransactionReductionResult = TransactionEvaluationError | TransactionReductionSuccess;
66
+ export type TransactionEvaluationResult =
67
+ | TransactionEvaluationError
68
+ | TransactionEvaluationSuccess;
69
+ export type TransactionReductionResult =
70
+ | TransactionEvaluationError
71
+ | TransactionReductionSuccess;
68
72
 
69
73
  /**
70
74
  * Represents a blockchain provider that can interact with the blockchain.
@@ -89,15 +93,21 @@ export interface IBlockchainProvider<B extends BoxWhere> {
89
93
  /**
90
94
  * Check for transaction validity without broadcasting it to the network.
91
95
  */
92
- checkTransaction(transaction: SignedTransaction): Promise<TransactionEvaluationResult>;
96
+ checkTransaction(
97
+ transaction: SignedTransaction
98
+ ): Promise<TransactionEvaluationResult>;
93
99
 
94
100
  /**
95
101
  * Broadcast a transaction to the network.
96
102
  */
97
- submitTransaction(transaction: SignedTransaction): Promise<TransactionEvaluationResult>;
103
+ submitTransaction(
104
+ transaction: SignedTransaction
105
+ ): Promise<TransactionEvaluationResult>;
98
106
 
99
107
  /**
100
108
  * Evaluate a transaction and return Base16-encoded evaluation result.
101
109
  */
102
- reduceTransaction(transaction: UnsignedTransaction): Promise<TransactionReductionResult>;
110
+ reduceTransaction(
111
+ transaction: UnsignedTransaction
112
+ ): Promise<TransactionReductionResult>;
103
113
  }
@@ -1,8 +1,12 @@
1
1
  export const mockResponse = (data: string) => {
2
- return { text: () => new Promise((resolve) => resolve(data)) } as unknown as Response;
2
+ return {
3
+ text: () => new Promise((resolve) => resolve(data))
4
+ } as unknown as Response;
3
5
  };
4
6
 
5
7
  export const mockChunkedResponse = (chunks: string[]) => {
6
8
  let i = 0;
7
- return { text: () => new Promise((resolve) => resolve(chunks[i++])) } as unknown as Response;
9
+ return {
10
+ text: () => new Promise((resolve) => resolve(chunks[i++]))
11
+ } as unknown as Response;
8
12
  };
@@ -1,10 +1,10 @@
1
1
  import { describe, expectTypeOf, it } from "vitest";
2
2
  import {
3
3
  createGqlOperation,
4
- GraphQLOperation,
5
- GraphQLResponse,
6
- GraphQLSuccessResponse,
7
- GraphQLVariables
4
+ type GraphQLOperation,
5
+ type GraphQLResponse,
6
+ type GraphQLSuccessResponse,
7
+ type GraphQLVariables
8
8
  } from "./graphql";
9
9
 
10
10
  describe("createGqlOperation() types", () => {
@@ -12,12 +12,20 @@ describe("createGqlOperation() types", () => {
12
12
  const url = "https://gql.example.com/";
13
13
 
14
14
  it("Should infer the correct type when throwOnNonNetworkErrors is set to true", () => {
15
- const throwable = createGqlOperation(query, { throwOnNonNetworkErrors: true, url });
15
+ const throwable = createGqlOperation(query, {
16
+ throwOnNonNetworkErrors: true,
17
+ url
18
+ });
16
19
  expectTypeOf(throwable).toMatchTypeOf<
17
20
  GraphQLOperation<GraphQLSuccessResponse, GraphQLVariables>
18
21
  >();
19
22
 
20
- const notThrowable = createGqlOperation(query, { throwOnNonNetworkErrors: false, url });
21
- expectTypeOf(notThrowable).toMatchTypeOf<GraphQLOperation<GraphQLResponse, GraphQLVariables>>();
23
+ const notThrowable = createGqlOperation(query, {
24
+ throwOnNonNetworkErrors: false,
25
+ url
26
+ });
27
+ expectTypeOf(notThrowable).toMatchTypeOf<
28
+ GraphQLOperation<GraphQLResponse, GraphQLVariables>
29
+ >();
22
30
  });
23
31
  });
@@ -32,11 +32,14 @@ export interface GraphQLErrorResponse {
32
32
  errors: GraphQLError[];
33
33
  }
34
34
 
35
- export type GraphQLResponse<T = unknown> = GraphQLSuccessResponse<T> | GraphQLErrorResponse;
35
+ export type GraphQLResponse<T = unknown> =
36
+ | GraphQLSuccessResponse<T>
37
+ | GraphQLErrorResponse;
36
38
 
37
- export type GraphQLOperation<R extends GraphQLResponse, V extends GraphQLVariables> = (
38
- variables?: V
39
- ) => Promise<R>;
39
+ export type GraphQLOperation<
40
+ R extends GraphQLResponse,
41
+ V extends GraphQLVariables
42
+ > = (variables?: V) => Promise<R>;
40
43
 
41
44
  export interface ResponseParser {
42
45
  parse<T>(text: string): T;
@@ -62,15 +65,24 @@ export interface GraphQLThrowableOptions extends GraphQLRequestOptions {
62
65
  throwOnNonNetworkErrors: true;
63
66
  }
64
67
 
65
- export function createGqlOperation<R, V extends GraphQLVariables = GraphQLVariables>(
68
+ export function createGqlOperation<
69
+ R,
70
+ V extends GraphQLVariables = GraphQLVariables
71
+ >(
66
72
  query: string,
67
73
  options: GraphQLThrowableOptions
68
74
  ): GraphQLOperation<GraphQLSuccessResponse<R>, V>;
69
- export function createGqlOperation<R, V extends GraphQLVariables = GraphQLVariables>(
75
+ export function createGqlOperation<
76
+ R,
77
+ V extends GraphQLVariables = GraphQLVariables
78
+ >(
70
79
  query: string,
71
80
  options: GraphQLRequestOptions
72
81
  ): GraphQLOperation<GraphQLResponse<R>, V>;
73
- export function createGqlOperation<R, V extends GraphQLVariables = GraphQLVariables>(
82
+ export function createGqlOperation<
83
+ R,
84
+ V extends GraphQLVariables = GraphQLVariables
85
+ >(
74
86
  query: string,
75
87
  options: GraphQLRequestOptions
76
88
  ): GraphQLOperation<GraphQLResponse<R>, V> {
@@ -87,10 +99,18 @@ export function createGqlOperation<R, V extends GraphQLVariables = GraphQLVariab
87
99
  });
88
100
 
89
101
  const rawData = await response.text();
90
- const parsedData = (options.parser ?? JSON).parse(rawData) as GraphQLResponse<R>;
91
-
92
- if (options.throwOnNonNetworkErrors && some(parsedData.errors) && isEmpty(parsedData.data)) {
93
- throw new BlockchainProviderError(parsedData.errors[0].message, { cause: parsedData.errors });
102
+ const parsedData = (options.parser ?? JSON).parse(
103
+ rawData
104
+ ) as GraphQLResponse<R>;
105
+
106
+ if (
107
+ options.throwOnNonNetworkErrors &&
108
+ some(parsedData.errors) &&
109
+ isEmpty(parsedData.data)
110
+ ) {
111
+ throw new BlockchainProviderError(parsedData.errors[0].message, {
112
+ cause: parsedData.errors
113
+ });
94
114
  }
95
115
 
96
116
  return parsedData;
@@ -106,5 +126,7 @@ export function getOpName(query: string): string | undefined {
106
126
  }
107
127
 
108
128
  export function isRequestParam(obj: unknown): obj is GraphQLRequestOptions {
109
- return typeof obj === "object" && (obj as GraphQLRequestOptions).url !== undefined;
129
+ return (
130
+ typeof obj === "object" && (obj as GraphQLRequestOptions).url !== undefined
131
+ );
110
132
  }
@@ -1 +0,0 @@
1
- export * from "./ergoGraphQLProvider";
@@ -1 +0,0 @@
1
- export * from "./blockchainProvider";