@solana/rpc-graphql 2.0.0-experimental.b153bb7 → 2.0.0-experimental.b419cd0

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.
@@ -1,8 +1,15 @@
1
1
  'use strict';
2
2
 
3
3
  var graphql = require('graphql');
4
+ var DataLoader = require('dataloader');
5
+ var fastStableStringify = require('fast-stable-stringify');
4
6
  var schema = require('@graphql-tools/schema');
5
7
 
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var DataLoader__default = /*#__PURE__*/_interopDefault(DataLoader);
11
+ var fastStableStringify__default = /*#__PURE__*/_interopDefault(fastStableStringify);
12
+
6
13
  // src/rpc.ts
7
14
 
8
15
  // src/cache.ts
@@ -40,8 +47,8 @@ function createGraphQLCache() {
40
47
  } ;
41
48
  }
42
49
 
43
- // src/loaders/account.ts
44
- function onlyAddressRequested(info) {
50
+ // src/loaders/common/resolve-info.ts
51
+ function onlyPresentFieldRequested(fieldName, info) {
45
52
  if (info && info.fieldNodes[0].selectionSet) {
46
53
  const selectionSet = info.fieldNodes[0].selectionSet;
47
54
  const requestedFields = selectionSet.selections.map((field) => {
@@ -50,12 +57,24 @@ function onlyAddressRequested(info) {
50
57
  }
51
58
  return null;
52
59
  });
53
- if (requestedFields && requestedFields.length === 1 && requestedFields[0] === "address") {
60
+ if (requestedFields && requestedFields.length === 1 && requestedFields[0] === fieldName) {
54
61
  return true;
55
62
  }
56
63
  }
57
64
  return false;
58
65
  }
66
+
67
+ // src/loaders/account.ts
68
+ function normalizeArgs(args) {
69
+ const { address, commitment, dataSlice, encoding, minContextSlot } = args;
70
+ return {
71
+ address,
72
+ commitment: commitment ?? "confirmed",
73
+ dataSlice,
74
+ encoding: encoding ?? "jsonParsed",
75
+ minContextSlot
76
+ };
77
+ }
59
78
  function refineJsonParsedAccountData(jsonParsedAccountData) {
60
79
  const meta = {
61
80
  program: jsonParsedAccountData.program,
@@ -81,86 +100,44 @@ function processQueryResponse({ address, account, encoding }) {
81
100
  data: refinedData
82
101
  };
83
102
  }
84
- async function loadAccount({ address, encoding = "jsonParsed", ...config }, cache, rpc, info) {
85
- if (onlyAddressRequested(info)) {
86
- return { address };
87
- }
88
- const requestConfig = { encoding, ...config };
89
- const cached = cache.get(address, requestConfig);
90
- if (cached !== null) {
91
- return cached;
92
- }
93
- const account = await rpc.getAccountInfo(address, requestConfig).send().then((res) => res.value).catch((e) => {
103
+ async function loadAccount(rpc, { address, ...config }) {
104
+ const { encoding } = config;
105
+ const account = await rpc.getAccountInfo(address, config).send().then((res) => res.value).catch((e) => {
94
106
  throw e;
95
107
  });
96
108
  if (account === null) {
97
109
  return { address };
98
110
  }
99
- const queryResponse = processQueryResponse({ account, address, encoding });
100
- cache.insert(address, requestConfig, queryResponse);
101
- return queryResponse;
111
+ return processQueryResponse({ account, address, encoding });
102
112
  }
103
-
104
- // src/loaders/block.ts
105
- async function loadBlock({ slot, encoding = "jsonParsed", ...config }, cache, rpc, _info) {
106
- const requestConfig = {
107
- encoding,
108
- ...config,
109
- // Always use 0 to avoid silly errors
110
- maxSupportedTransactionVersion: 0
113
+ function createAccountBatchLoadFn(rpc) {
114
+ const resolveAccountUsingRpc = loadAccount.bind(null, rpc);
115
+ return async (accountQueryArgs) => {
116
+ return await Promise.all(accountQueryArgs.map(async (args) => await resolveAccountUsingRpc(args)));
111
117
  };
112
- const cached = cache.get(slot, config);
113
- if (cached !== null) {
114
- return cached;
115
- }
116
- const block = await rpc.getBlock(slot, requestConfig).send();
117
- if (block === null) {
118
- return null;
119
- }
120
- cache.insert(slot, config, block);
121
- return block;
122
- }
123
-
124
- // src/loaders/program-accounts.ts
125
- function processQueryResponse2({ encoding, programAccounts }) {
126
- return programAccounts.map((programAccount) => {
127
- const [refinedData, responseEncoding] = Array.isArray(programAccount.account.data) ? encoding === "jsonParsed" ? [programAccount.account.data[0], "base64"] : [programAccount.account.data[0], encoding] : [refineJsonParsedAccountData(programAccount.account.data), "jsonParsed"];
128
- const pubkey = programAccount.pubkey;
129
- const responseBase = {
130
- ...programAccount.account,
131
- address: pubkey,
132
- encoding: responseEncoding
133
- };
134
- return typeof refinedData === "object" && "meta" in refinedData ? {
135
- ...responseBase,
136
- data: refinedData.data,
137
- meta: refinedData.meta
138
- } : {
139
- ...responseBase,
140
- data: refinedData
141
- };
142
- });
143
118
  }
144
- async function loadProgramAccounts({ programAddress, encoding = "jsonParsed", ...config }, cache, rpc, _info) {
145
- const requestConfig = { encoding, ...config };
146
- const cached = cache.get(programAddress, requestConfig);
147
- if (cached !== null) {
148
- return cached;
149
- }
150
- const programAccounts = await rpc.getProgramAccounts(programAddress, requestConfig).send().then((res) => {
151
- if ("value" in res) {
152
- return res.value;
119
+ function createAccountLoader(rpc) {
120
+ const loader = new DataLoader__default.default(createAccountBatchLoadFn(rpc), { cacheKeyFn: fastStableStringify__default.default });
121
+ return {
122
+ load: async (args, info) => {
123
+ if (onlyPresentFieldRequested("address", info)) {
124
+ return { address: args.address };
125
+ }
126
+ return loader.load(normalizeArgs(args));
153
127
  }
154
- return res;
155
- }).catch((e) => {
156
- throw e;
157
- });
158
- const queryResponse = processQueryResponse2({ encoding, programAccounts });
159
- cache.insert(programAddress, requestConfig, queryResponse);
160
- return queryResponse;
128
+ };
161
129
  }
162
130
 
163
131
  // src/loaders/transaction.ts
132
+ function normalizeArgs2(args) {
133
+ const { commitment, encoding } = args;
134
+ return {
135
+ commitment: commitment ?? "confirmed",
136
+ encoding: encoding ?? "jsonParsed",
137
+ // Always use 0 to avoid silly errors
138
+ maxSupportedTransactionVersion: 0
139
+ };
140
+ }
164
141
  function refineJsonParsedInstructionData(jsonParsedInstructionData) {
165
142
  if ("parsed" in jsonParsedInstructionData) {
166
143
  const meta = {
@@ -198,36 +175,36 @@ function refineJsonParsedTransactionMeta(jsonParsedTransactionMeta) {
198
175
  innerInstructions: refinedInnerInstructions
199
176
  };
200
177
  }
201
- function processQueryResponse3({ encoding, transaction }) {
202
- const [transactionData, transactionMeta, responseEncoding] = Array.isArray(transaction.transaction) ? [transaction.transaction[0], transaction.meta, encoding] : [
203
- refineJsonParsedTransactionData(transaction.transaction),
204
- refineJsonParsedTransactionMeta(transaction.meta),
205
- encoding
206
- ];
178
+ function refineJsonParsedTransaction({ encoding, transaction }) {
179
+ const [transactionData, transactionMeta] = Array.isArray(transaction.transaction) ? [transaction.transaction[0], transaction.meta] : [refineJsonParsedTransactionData(transaction.transaction), refineJsonParsedTransactionMeta(transaction.meta)];
207
180
  return {
208
- ...transaction,
209
181
  data: transactionData,
210
- encoding: responseEncoding,
211
- meta: transactionMeta
212
- };
213
- }
214
- async function loadTransaction({ signature, encoding = "jsonParsed", ...config }, cache, rpc, _info) {
215
- const requestConfig = {
216
182
  encoding,
217
- ...config,
218
- // Always use 0 to avoid silly errors
219
- maxSupportedTransactionVersion: 0
183
+ meta: transactionMeta,
184
+ slot: transaction.slot,
185
+ version: transaction.version
220
186
  };
187
+ }
188
+ function processQueryResponse2({ encoding, transaction }) {
189
+ return refineJsonParsedTransaction({ encoding, transaction });
190
+ }
191
+ async function loadTransaction({ signature, ...config }, cache, rpc, _info) {
192
+ const requestConfig = normalizeArgs2(config);
193
+ const { encoding } = requestConfig;
221
194
  const cached = cache.get(signature, requestConfig);
222
195
  if (cached !== null) {
223
196
  return cached;
224
197
  }
225
- let transaction = await rpc.getTransaction(signature, requestConfig).send();
198
+ let transaction = await rpc.getTransaction(signature, requestConfig).send().catch((e) => {
199
+ throw e;
200
+ });
226
201
  if (transaction === null) {
227
202
  return null;
228
203
  }
229
204
  if (encoding !== "jsonParsed") {
230
- const transactionJsonParsed = await rpc.getTransaction(signature, requestConfig).send();
205
+ const transactionJsonParsed = await rpc.getTransaction(signature, requestConfig).send().catch((e) => {
206
+ throw e;
207
+ });
231
208
  if (transactionJsonParsed === null) {
232
209
  return null;
233
210
  }
@@ -237,22 +214,140 @@ async function loadTransaction({ signature, encoding = "jsonParsed", ...config }
237
214
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
238
215
  };
239
216
  }
240
- const queryResponse = processQueryResponse3({ encoding, transaction });
217
+ const queryResponse = processQueryResponse2({ encoding, transaction });
241
218
  cache.insert(signature, requestConfig, queryResponse);
242
219
  return queryResponse;
243
220
  }
244
221
 
222
+ // src/loaders/block.ts
223
+ function normalizeArgs3(args) {
224
+ const { commitment, encoding, slot, transactionDetails } = args;
225
+ return {
226
+ commitment: commitment ?? "confirmed",
227
+ encoding: encoding ?? "jsonParsed",
228
+ // Always use 0 to avoid silly errors
229
+ maxSupportedTransactionVersion: 0,
230
+ slot,
231
+ transactionDetails: transactionDetails ?? "full"
232
+ };
233
+ }
234
+ function refineJsonParsedTransactionForAccounts({ transaction }) {
235
+ return {
236
+ data: transaction.transaction,
237
+ meta: transaction.meta,
238
+ version: transaction.version
239
+ };
240
+ }
241
+ function processQueryResponse3({
242
+ encoding,
243
+ block,
244
+ transactionDetails
245
+ }) {
246
+ if (typeof block === "object" && "transactions" in block) {
247
+ const refinedBlock = {
248
+ ...block,
249
+ transactions: block.transactions.map((transaction) => {
250
+ if (transactionDetails === "accounts") {
251
+ return refineJsonParsedTransactionForAccounts({ transaction });
252
+ } else {
253
+ return refineJsonParsedTransaction({ encoding, transaction });
254
+ }
255
+ })
256
+ };
257
+ block = refinedBlock;
258
+ }
259
+ return {
260
+ ...block,
261
+ encoding,
262
+ transactionDetails
263
+ };
264
+ }
265
+ async function loadBlock(rpc, { slot, ...config }) {
266
+ const { encoding, transactionDetails } = config;
267
+ const block = await rpc.getBlock(slot, config).send().catch((e) => {
268
+ throw e;
269
+ });
270
+ if (block === null) {
271
+ return { slot };
272
+ }
273
+ const queryResponse = processQueryResponse3({ block, encoding, transactionDetails });
274
+ return queryResponse;
275
+ }
276
+ function createBlockBatchLoadFn(rpc) {
277
+ const resolveBlockUsingRpc = loadBlock.bind(null, rpc);
278
+ return async (blockQueryArgs) => {
279
+ return await Promise.all(blockQueryArgs.map(async (args) => await resolveBlockUsingRpc(args)));
280
+ };
281
+ }
282
+ function createBlockLoader(rpc) {
283
+ const loader = new DataLoader__default.default(createBlockBatchLoadFn(rpc), { cacheKeyFn: fastStableStringify__default.default });
284
+ return {
285
+ load: async (args, info) => {
286
+ if (onlyPresentFieldRequested("slot", info)) {
287
+ return { slot: args.slot };
288
+ }
289
+ return loader.load(normalizeArgs3(args));
290
+ }
291
+ };
292
+ }
293
+
294
+ // src/loaders/program-accounts.ts
295
+ function normalizeArgs4(args) {
296
+ const { commitment, dataSlice, encoding, filters, minContextSlot } = args;
297
+ return {
298
+ commitment: commitment ?? "confirmed",
299
+ dataSlice,
300
+ encoding: encoding ?? "jsonParsed",
301
+ filters,
302
+ minContextSlot
303
+ };
304
+ }
305
+ function processQueryResponse4({ encoding, programAccounts }) {
306
+ return programAccounts.map((programAccount) => {
307
+ const [refinedData, responseEncoding] = Array.isArray(programAccount.account.data) ? encoding === "jsonParsed" ? [programAccount.account.data[0], "base64"] : [programAccount.account.data[0], encoding] : [refineJsonParsedAccountData(programAccount.account.data), "jsonParsed"];
308
+ const pubkey = programAccount.pubkey;
309
+ const responseBase = {
310
+ ...programAccount.account,
311
+ address: pubkey,
312
+ encoding: responseEncoding
313
+ };
314
+ return typeof refinedData === "object" && "meta" in refinedData ? {
315
+ ...responseBase,
316
+ data: refinedData.data,
317
+ meta: refinedData.meta
318
+ } : {
319
+ ...responseBase,
320
+ data: refinedData
321
+ };
322
+ });
323
+ }
324
+ async function loadProgramAccounts({ programAddress, ...config }, cache, rpc, _info) {
325
+ const requestConfig = normalizeArgs4(config);
326
+ const { encoding } = requestConfig;
327
+ const cached = cache.get(programAddress, requestConfig);
328
+ if (cached !== null) {
329
+ return cached;
330
+ }
331
+ const programAccounts = await rpc.getProgramAccounts(programAddress, requestConfig).send().then((res) => {
332
+ if ("value" in res) {
333
+ return res.value;
334
+ }
335
+ return res;
336
+ }).catch((e) => {
337
+ throw e;
338
+ });
339
+ const queryResponse = processQueryResponse4({ encoding, programAccounts });
340
+ cache.insert(programAddress, requestConfig, queryResponse);
341
+ return queryResponse;
342
+ }
343
+
245
344
  // src/context.ts
246
345
  function createSolanaGraphQLContext(rpc) {
247
346
  const cache = createGraphQLCache();
248
347
  return {
348
+ accountLoader: createAccountLoader(rpc),
349
+ blockLoader: createBlockLoader(rpc),
249
350
  cache,
250
- loadAccount(args, info) {
251
- return loadAccount(args, this.cache, this.rpc, info);
252
- },
253
- loadBlock(args, info) {
254
- return loadBlock(args, this.cache, this.rpc);
255
- },
256
351
  loadProgramAccounts(args, info) {
257
352
  return loadProgramAccounts(args, this.cache, this.rpc);
258
353
  },
@@ -265,7 +360,7 @@ function createSolanaGraphQLContext(rpc) {
265
360
 
266
361
  // src/resolvers/account.ts
267
362
  var resolveAccount = (fieldName) => {
268
- return (parent, args, context, info) => parent[fieldName] === null ? null : context.loadAccount({ ...args, address: parent[fieldName] }, info);
363
+ return (parent, args, context, info) => parent[fieldName] === null ? null : context.accountLoader.load({ ...args, address: parent[fieldName] }, info);
269
364
  };
270
365
 
271
366
  // src/schema/account.ts
@@ -606,59 +701,79 @@ var blockTypeDefs = (
606
701
 
607
702
  # Block interface
608
703
  interface Block {
609
- blockHeight: BigInt
610
- blockTime: BigInt
611
704
  blockhash: String
705
+ blockHeight: BigInt
706
+ blockTime: Int
612
707
  parentSlot: BigInt
613
708
  previousBlockhash: String
614
709
  rewards: [Reward]
710
+ transactionDetails: String
615
711
  }
616
712
 
617
713
  # A block with account transaction details
618
- type BlockWithAccounts {
619
- blockHeight: BigInt
620
- blockTime: BigInt
714
+ type BlockWithAccounts implements Block {
621
715
  blockhash: String
716
+ blockHeight: BigInt
717
+ blockTime: Int
622
718
  parentSlot: BigInt
623
719
  previousBlockhash: String
624
720
  rewards: [Reward]
625
721
  transactions: [BlockTransactionAccounts]
722
+ transactionDetails: String
626
723
  }
627
724
 
628
725
  # A block with full transaction details
629
- type BlockFull {
630
- blockHeight: BigInt
631
- blockTime: BigInt
726
+ type BlockWithFull implements Block {
632
727
  blockhash: String
728
+ blockHeight: BigInt
729
+ blockTime: Int
633
730
  parentSlot: BigInt
634
731
  previousBlockhash: String
635
732
  rewards: [Reward]
636
733
  transactions: [Transaction]
734
+ transactionDetails: String
637
735
  }
638
736
 
639
737
  # A block with none transaction details
640
- type BlockWithNone {
641
- blockHeight: BigInt
642
- blockTime: BigInt
738
+ type BlockWithNone implements Block {
643
739
  blockhash: String
740
+ blockHeight: BigInt
741
+ blockTime: Int
644
742
  parentSlot: BigInt
645
743
  previousBlockhash: String
646
744
  rewards: [Reward]
745
+ transactionDetails: String
647
746
  }
648
747
 
649
748
  # A block with signature transaction details
650
- type BlockWithSignatures {
651
- blockHeight: BigInt
652
- blockTime: BigInt
749
+ type BlockWithSignatures implements Block {
653
750
  blockhash: String
751
+ blockHeight: BigInt
752
+ blockTime: Int
654
753
  parentSlot: BigInt
655
754
  previousBlockhash: String
656
755
  rewards: [Reward]
657
756
  signatures: [String]
757
+ transactionDetails: String
658
758
  }
659
759
  `
660
760
  );
661
- var blockResolvers = {};
761
+ var blockResolvers = {
762
+ Block: {
763
+ __resolveType(block) {
764
+ switch (block.transactionDetails) {
765
+ case "accounts":
766
+ return "BlockWithAccounts";
767
+ case "none":
768
+ return "BlockWithNone";
769
+ case "signatures":
770
+ return "BlockWithSignatures";
771
+ default:
772
+ return "BlockWithFull";
773
+ }
774
+ }
775
+ }
776
+ };
662
777
 
663
778
  // src/schema/common/inputs.ts
664
779
  var inputTypeDefs = (
@@ -2879,10 +2994,10 @@ var schemaTypeDefs = (
2879
2994
  var schemaResolvers = {
2880
2995
  Query: {
2881
2996
  account(_, args, context, info) {
2882
- return context.loadAccount(args, info);
2997
+ return context.accountLoader.load(args, info);
2883
2998
  },
2884
2999
  block(_, args, context, info) {
2885
- return context.loadBlock(args, info);
3000
+ return context.blockLoader.load(args, info);
2886
3001
  },
2887
3002
  programAccounts(_, args, context, info) {
2888
3003
  return context.loadProgramAccounts(args, info);