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