@graphprotocol/graph-cli 0.90.1 → 0.91.0-alpha-20241202202221-345552f

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,14 @@
1
1
  # @graphprotocol/graph-cli
2
2
 
3
+ ## 0.91.0-alpha-20241202202221-345552f
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1754](https://github.com/graphprotocol/graph-tooling/pull/1754)
8
+ [`2050bf6`](https://github.com/graphprotocol/graph-tooling/commit/2050bf6259c19bd86a7446410c7e124dfaddf4cd)
9
+ Thanks [@incrypto32](https://github.com/incrypto32)! - Add support for subgraph datasource and
10
+ associated types.
11
+
3
12
  ## 0.90.1
4
13
 
5
14
  ### Patch Changes
@@ -20,12 +20,12 @@ export default class SchemaCodeGenerator {
20
20
  private schema;
21
21
  constructor(schema: Schema);
22
22
  generateModuleImports(): tsCodegen.ModuleImports[];
23
- generateTypes(): Array<tsCodegen.Class>;
23
+ generateTypes(generateStoreMethods?: boolean): Array<tsCodegen.Class>;
24
24
  generateDerivedLoaders(): any[];
25
25
  _isEntityTypeDefinition(def: DefinitionNode): def is ObjectTypeDefinitionNode;
26
26
  _isDerivedField(field: FieldDefinitionNode | undefined): boolean;
27
27
  _isInterfaceDefinition(def: DefinitionNode): def is InterfaceTypeDefinitionNode;
28
- _generateEntityType(def: ObjectTypeDefinitionNode): tsCodegen.Class;
28
+ _generateEntityType(def: ObjectTypeDefinitionNode, generateStoreMethods?: boolean): tsCodegen.Class;
29
29
  _generateDerivedLoader(typeName: string): any;
30
30
  _getTypeNameForField(gqlType: TypeNode): string;
31
31
  _generateConstructor(_entityName: string, fields: readonly FieldDefinitionNode[] | undefined): tsCodegen.Method;
@@ -94,12 +94,12 @@ class SchemaCodeGenerator {
94
94
  ], '@graphprotocol/graph-ts'),
95
95
  ];
96
96
  }
97
- generateTypes() {
97
+ generateTypes(generateStoreMethods = true) {
98
98
  return this.schema.ast.definitions
99
99
  .map(def => {
100
100
  if (this._isEntityTypeDefinition(def)) {
101
101
  schemaCodeGeneratorDebug.extend('generateTypes')(`Generating entity type for ${def.name.value}`);
102
- return this._generateEntityType(def);
102
+ return this._generateEntityType(def, generateStoreMethods);
103
103
  }
104
104
  })
105
105
  .filter(Boolean);
@@ -132,15 +132,17 @@ class SchemaCodeGenerator {
132
132
  _isInterfaceDefinition(def) {
133
133
  return def.kind === 'InterfaceTypeDefinition';
134
134
  }
135
- _generateEntityType(def) {
135
+ _generateEntityType(def, generateStoreMethods = true) {
136
136
  const name = def.name.value;
137
137
  const klass = tsCodegen.klass(name, { export: true, extends: 'Entity' });
138
138
  const fields = def.fields;
139
139
  const idField = IdField.fromFields(fields);
140
140
  // Generate and add a constructor
141
141
  klass.addMethod(this._generateConstructor(name, fields));
142
- // Generate and add save() and getById() methods
143
- this._generateStoreMethods(name, idField).forEach(method => klass.addMethod(method));
142
+ if (generateStoreMethods) {
143
+ // Generate and add save() and getById() methods
144
+ this._generateStoreMethods(name, idField).forEach(method => klass.addMethod(method));
145
+ }
144
146
  // Generate and add entity field getters and setters
145
147
  def.fields
146
148
  ?.reduce((methods, field) => methods.concat(this._generateEntityFieldMethods(def, field)), [])
@@ -34,7 +34,7 @@ const schema_1 = __importDefault(require("../schema"));
34
34
  const schema_2 = __importDefault(require("./schema"));
35
35
  const typescript_1 = require("./typescript");
36
36
  const formatTS = async (code) => await prettier_1.default.format(code, { parser: 'typescript', semi: false });
37
- const createSchemaCodeGen = (schema) => new schema_2.default(new schema_1.default('', schema, graphql.parse(schema)));
37
+ const createSchemaCodeGen = (schema) => new schema_2.default(new schema_1.default(schema, graphql.parse(schema), ''));
38
38
  const testEntity = async (generatedTypes, expectedEntity) => {
39
39
  const entity = generatedTypes.find(type => type.name === expectedEntity.name);
40
40
  (0, vitest_1.expect)(entity instanceof typescript_1.Class).toBe(true);
@@ -282,6 +282,8 @@ const getEtherscanLikeAPIUrl = (network) => {
282
282
  return 'https://maizenet-explorer.usecorn.com/api';
283
283
  case 'corn-testnet':
284
284
  return 'https://testnet-explorer.usecorn.com/api';
285
+ case 'botanix-testnet':
286
+ return 'https://api.routescan.io/v2/network/testnet/evm/3636/etherscan/api';
285
287
  default:
286
288
  return `https://api-${network}.etherscan.io/api`;
287
289
  }
@@ -446,6 +448,8 @@ const getPublicRPCEndpoint = (network) => {
446
448
  return 'https://maizenet-rpc.usecorn.com';
447
449
  case 'corn-testnet':
448
450
  return 'https://testnet-rpc.usecorn.com';
451
+ case 'botanix-testnet':
452
+ return 'https://node.botanixlabs.dev';
449
453
  default:
450
454
  throw new Error(`Unknown network: ${network}`);
451
455
  }
@@ -3,10 +3,10 @@ import Protocol from '../protocols';
3
3
  import ABI from '../protocols/ethereum/abi';
4
4
  import { Spinner } from './spinner';
5
5
  export declare const generateDataSource: (protocol: Protocol, contractName: string, network: string, contractAddress: string, abi: ABI, startBlock?: string) => Promise<Map<unknown, unknown>>;
6
- export declare const generateScaffold: ({ protocolInstance, abi, contract, network, subgraphName, indexEvents, contractName, startBlock, node, spkgPath, }: {
6
+ export declare const generateScaffold: ({ protocolInstance, abi, source, network, subgraphName, indexEvents, contractName, startBlock, node, spkgPath, entities, }: {
7
7
  protocolInstance: Protocol;
8
8
  abi: ABI;
9
- contract: string;
9
+ source: string;
10
10
  network: string;
11
11
  subgraphName: string;
12
12
  indexEvents: boolean;
@@ -14,6 +14,7 @@ export declare const generateScaffold: ({ protocolInstance, abi, contract, netwo
14
14
  startBlock?: string | undefined;
15
15
  node?: string | undefined;
16
16
  spkgPath?: string | undefined;
17
+ entities?: string[] | undefined;
17
18
  }, spinner: Spinner) => Promise<{
18
19
  'subgraph.yaml': string;
19
20
  'schema.graphql': string;
@@ -28,19 +28,20 @@ const generateDataSource = async (protocol, contractName, network, contractAddre
28
28
  }))).asMutable();
29
29
  };
30
30
  exports.generateDataSource = generateDataSource;
31
- const generateScaffold = async ({ protocolInstance, abi, contract, network, subgraphName, indexEvents, contractName = 'Contract', startBlock, node, spkgPath, }, spinner) => {
31
+ const generateScaffold = async ({ protocolInstance, abi, source, network, subgraphName, indexEvents, contractName = 'Contract', startBlock, node, spkgPath, entities, }, spinner) => {
32
32
  (0, spinner_1.step)(spinner, 'Generate subgraph');
33
33
  const scaffold = new scaffold_1.default({
34
34
  protocol: protocolInstance,
35
35
  abi,
36
36
  indexEvents,
37
- contract,
37
+ contract: source,
38
38
  network,
39
39
  contractName,
40
40
  startBlock,
41
41
  subgraphName,
42
42
  node,
43
43
  spkgPath,
44
+ entities,
44
45
  });
45
46
  return await scaffold.generate();
46
47
  };
@@ -10,6 +10,7 @@ export default class CodegenCommand extends Command {
10
10
  'skip-migrations': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
11
11
  watch: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
12
  uncrashable: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
+ ipfs: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
13
14
  'uncrashable-config': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
15
  };
15
16
  run(): Promise<void>;
@@ -29,6 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const path_1 = __importDefault(require("path"));
30
30
  const core_1 = require("@oclif/core");
31
31
  const DataSourcesExtractor = __importStar(require("../command-helpers/data-sources"));
32
+ const ipfs_1 = require("../command-helpers/ipfs");
32
33
  const version_1 = require("../command-helpers/version");
33
34
  const debug_1 = __importDefault(require("../debug"));
34
35
  const protocols_1 = __importDefault(require("../protocols"));
@@ -36,9 +37,10 @@ const type_generator_1 = __importDefault(require("../type-generator"));
36
37
  const codegenDebug = (0, debug_1.default)('graph-cli:codegen');
37
38
  class CodegenCommand extends core_1.Command {
38
39
  async run() {
39
- const { args: { 'subgraph-manifest': manifest }, flags: { 'output-dir': outputDir, 'skip-migrations': skipMigrations, watch, uncrashable, 'uncrashable-config': uncrashableConfig, }, } = await this.parse(CodegenCommand);
40
+ const { args: { 'subgraph-manifest': manifest }, flags: { 'output-dir': outputDir, 'skip-migrations': skipMigrations, watch, ipfs, uncrashable, 'uncrashable-config': uncrashableConfig, }, } = await this.parse(CodegenCommand);
40
41
  codegenDebug('Initialized codegen manifest: %o', manifest);
41
42
  let protocol;
43
+ let subgraphSources;
42
44
  try {
43
45
  // Checks to make sure codegen doesn't run against
44
46
  // older subgraphs (both apiVersion and graph-ts version).
@@ -50,6 +52,9 @@ class CodegenCommand extends core_1.Command {
50
52
  await (0, version_1.assertGraphTsVersion)(path_1.default.dirname(manifest), '0.25.0');
51
53
  const dataSourcesAndTemplates = await DataSourcesExtractor.fromFilePath(manifest);
52
54
  protocol = protocols_1.default.fromDataSources(dataSourcesAndTemplates);
55
+ subgraphSources = dataSourcesAndTemplates
56
+ .filter((ds) => ds.kind == 'subgraph')
57
+ .map((ds) => ds.source.address);
53
58
  }
54
59
  catch (e) {
55
60
  this.error(e, { exit: 1 });
@@ -60,7 +65,9 @@ class CodegenCommand extends core_1.Command {
60
65
  skipMigrations,
61
66
  protocol,
62
67
  uncrashable,
68
+ subgraphSources,
63
69
  uncrashableConfig: uncrashableConfig || 'uncrashable-config.yaml',
70
+ ipfsUrl: ipfs,
64
71
  });
65
72
  // Watch working directory for file updates or additions, trigger
66
73
  // type generation (if watch argument specified)
@@ -98,6 +105,11 @@ CodegenCommand.flags = {
98
105
  summary: 'Generate Float Subgraph Uncrashable helper file.',
99
106
  char: 'u',
100
107
  }),
108
+ ipfs: core_1.Flags.string({
109
+ summary: 'IPFS node to use for fetching subgraph data.',
110
+ char: 'i',
111
+ default: ipfs_1.DEFAULT_IPFS_URL,
112
+ }),
101
113
  'uncrashable-config': core_1.Flags.file({
102
114
  summary: 'Directory for uncrashable config.',
103
115
  aliases: ['uc'],
@@ -19,6 +19,7 @@ export default class InitCommand extends Command {
19
19
  abi: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
20
20
  spkg: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
21
21
  network: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
22
+ ipfs: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
22
23
  };
23
24
  run(): Promise<void>;
24
25
  }
@@ -31,8 +31,11 @@ const os_1 = __importDefault(require("os"));
31
31
  const path_1 = __importDefault(require("path"));
32
32
  const toolbox = __importStar(require("gluegun"));
33
33
  const gluegun_1 = require("gluegun");
34
+ const ipfs_http_client_1 = require("ipfs-http-client");
34
35
  const core_1 = require("@oclif/core");
35
36
  const abi_1 = require("../command-helpers/abi");
37
+ const compiler_1 = require("../command-helpers/compiler");
38
+ const ipfs_1 = require("../command-helpers/ipfs");
36
39
  const network_1 = require("../command-helpers/network");
37
40
  const node_1 = require("../command-helpers/node");
38
41
  const scaffold_1 = require("../command-helpers/scaffold");
@@ -43,6 +46,8 @@ const constants_1 = require("../constants");
43
46
  const debug_1 = __importDefault(require("../debug"));
44
47
  const protocols_1 = __importDefault(require("../protocols"));
45
48
  const schema_1 = require("../scaffold/schema");
49
+ const schema_2 = __importDefault(require("../schema"));
50
+ const utils_1 = __importDefault(require("../utils"));
46
51
  const validation_1 = require("../validation");
47
52
  const add_1 = __importDefault(require("./add"));
48
53
  const protocolChoices = Array.from(protocols_1.default.availableProtocols().keys());
@@ -88,7 +93,7 @@ const DEFAULT_EXAMPLE_SUBGRAPH = 'ethereum-gravatar';
88
93
  class InitCommand extends core_1.Command {
89
94
  async run() {
90
95
  const { args: { subgraphName, directory }, flags, } = await this.parse(InitCommand);
91
- const { protocol, node: nodeFlag, 'from-contract': fromContract, 'contract-name': contractName, 'from-example': fromExample, 'index-events': indexEvents, 'skip-install': skipInstall, 'skip-git': skipGit, network, abi: abiPath, 'start-block': startBlock, spkg: spkgPath, } = flags;
96
+ const { protocol, node: nodeFlag, 'from-contract': fromContract, 'contract-name': contractName, 'from-example': fromExample, 'index-events': indexEvents, 'skip-install': skipInstall, 'skip-git': skipGit, ipfs, network, abi: abiPath, 'start-block': startBlock, spkg: spkgPath, } = flags;
92
97
  initDebugger('Flags: %O', flags);
93
98
  let { node } = (0, node_1.chooseNodeUrl)({
94
99
  node: nodeFlag,
@@ -170,7 +175,7 @@ class InitCommand extends core_1.Command {
170
175
  protocolInstance,
171
176
  abi,
172
177
  directory,
173
- contract: fromContract,
178
+ source: fromContract,
174
179
  indexEvents,
175
180
  network,
176
181
  subgraphName,
@@ -180,6 +185,7 @@ class InitCommand extends core_1.Command {
180
185
  spkgPath,
181
186
  skipInstall,
182
187
  skipGit,
188
+ ipfsUrl: ipfs,
183
189
  }, { commands, addContract: false });
184
190
  // Exit with success
185
191
  return this.exit(0);
@@ -208,7 +214,7 @@ class InitCommand extends core_1.Command {
208
214
  abi,
209
215
  abiPath,
210
216
  directory,
211
- contract: fromContract,
217
+ source: fromContract,
212
218
  indexEvents,
213
219
  fromExample,
214
220
  network,
@@ -216,6 +222,7 @@ class InitCommand extends core_1.Command {
216
222
  contractName,
217
223
  startBlock,
218
224
  spkgPath,
225
+ ipfsUrl: ipfs,
219
226
  });
220
227
  if (!answers) {
221
228
  this.exit(1);
@@ -230,7 +237,7 @@ class InitCommand extends core_1.Command {
230
237
  directory: answers.directory,
231
238
  abi: answers.abi,
232
239
  network: answers.network,
233
- contract: answers.contract,
240
+ source: answers.source,
234
241
  indexEvents: answers.indexEvents,
235
242
  contractName: answers.contractName,
236
243
  node,
@@ -238,6 +245,7 @@ class InitCommand extends core_1.Command {
238
245
  spkgPath: answers.spkgPath,
239
246
  skipInstall,
240
247
  skipGit,
248
+ ipfsUrl: answers.ipfs,
241
249
  }, { commands, addContract: true });
242
250
  }
243
251
  // Exit with success
@@ -312,6 +320,11 @@ InitCommand.flags = {
312
320
  description: 'Check https://thegraph.com/docs/en/developing/supported-networks/ for supported networks',
313
321
  dependsOn: ['from-contract'],
314
322
  }),
323
+ ipfs: core_1.Flags.string({
324
+ summary: 'IPFS node to use for fetching subgraph data.',
325
+ char: 'i',
326
+ default: ipfs_1.DEFAULT_IPFS_URL,
327
+ }),
315
328
  };
316
329
  exports.default = InitCommand;
317
330
  async function processFromExampleInitForm({ directory: initDirectory, subgraphName: initSubgraphName, }) {
@@ -360,7 +373,7 @@ async function retryWithPrompt(func) {
360
373
  }
361
374
  return undefined;
362
375
  }
363
- async function processInitForm({ protocol: initProtocol, abi: initAbi, abiPath: initAbiPath, directory: initDirectory, contract: initContract, indexEvents: initIndexEvents, fromExample: initFromExample, network: initNetwork, subgraphName: initSubgraphName, contractName: initContractName, startBlock: initStartBlock, spkgPath: initSpkgPath, }) {
376
+ async function processInitForm({ protocol: initProtocol, abi: initAbi, abiPath: initAbiPath, directory: initDirectory, source: initContract, indexEvents: initIndexEvents, fromExample: initFromExample, network: initNetwork, subgraphName: initSubgraphName, contractName: initContractName, startBlock: initStartBlock, spkgPath: initSpkgPath, ipfsUrl, }) {
364
377
  let abiFromEtherscan = undefined;
365
378
  let startBlockFromEtherscan = undefined;
366
379
  let contractNameFromEtherscan = undefined;
@@ -381,6 +394,7 @@ async function processInitForm({ protocol: initProtocol, abi: initAbi, abiPath:
381
394
  },
382
395
  });
383
396
  const protocolInstance = new protocols_1.default(protocol);
397
+ const isComposedSubgraph = protocolInstance.isComposedSubgraph();
384
398
  const isSubstreams = protocol === 'substreams';
385
399
  initDebugger.extend('processInitForm')('isSubstreams: %O', isSubstreams);
386
400
  const { subgraphName } = await gluegun_1.prompt.ask([
@@ -421,18 +435,20 @@ async function processInitForm({ protocol: initProtocol, abi: initAbi, abiPath:
421
435
  },
422
436
  },
423
437
  ]);
424
- const { contract } = await gluegun_1.prompt.ask([
425
- // TODO:
426
- // protocols that don't support contract
427
- // - arweave
428
- // - cosmos
438
+ const sourceMessage = isComposedSubgraph
439
+ ? 'Source subgraph identifier'
440
+ : `Contract ${protocolInstance.getContract()?.identifierName()}`;
441
+ const { source } = await gluegun_1.prompt.ask([
429
442
  {
430
443
  type: 'input',
431
- name: 'contract',
432
- message: `Contract ${protocolInstance.getContract()?.identifierName()}`,
433
- skip: () => initFromExample !== undefined || !protocolInstance.hasContract() || isSubstreams,
444
+ name: 'source',
445
+ message: sourceMessage,
446
+ skip: () => !isComposedSubgraph,
434
447
  initial: initContract,
435
448
  validate: async (value) => {
449
+ if (isComposedSubgraph) {
450
+ return true;
451
+ }
436
452
  if (initFromExample !== undefined || !protocolInstance.hasContract()) {
437
453
  return true;
438
454
  }
@@ -445,7 +461,8 @@ async function processInitForm({ protocol: initProtocol, abi: initAbi, abiPath:
445
461
  return valid ? true : error;
446
462
  },
447
463
  result: async (value) => {
448
- if (initFromExample !== undefined || isSubstreams || initAbiPath) {
464
+ if (initFromExample !== undefined || isSubstreams || initAbiPath || isComposedSubgraph) {
465
+ initDebugger("value: '%s'", value);
449
466
  return value;
450
467
  }
451
468
  const ABI = protocolInstance.getABI();
@@ -478,6 +495,15 @@ async function processInitForm({ protocol: initProtocol, abi: initAbi, abiPath:
478
495
  },
479
496
  },
480
497
  ]);
498
+ const { ipfs } = await gluegun_1.prompt.ask([
499
+ {
500
+ type: 'input',
501
+ name: 'ipfs',
502
+ message: `IPFS node to use for fetching subgraph manifest`,
503
+ initial: ipfsUrl,
504
+ skip: () => !isComposedSubgraph,
505
+ },
506
+ ]);
481
507
  const { spkg } = await gluegun_1.prompt.ask([
482
508
  {
483
509
  type: 'input',
@@ -497,9 +523,14 @@ async function processInitForm({ protocol: initProtocol, abi: initAbi, abiPath:
497
523
  skip: () => !protocolInstance.hasABIs() ||
498
524
  initFromExample !== undefined ||
499
525
  abiFromEtherscan !== undefined ||
500
- isSubstreams,
526
+ isSubstreams ||
527
+ !!initAbiPath ||
528
+ isComposedSubgraph,
501
529
  validate: async (value) => {
502
- if (initFromExample || abiFromEtherscan || !protocolInstance.hasABIs()) {
530
+ if (initFromExample ||
531
+ abiFromEtherscan ||
532
+ !protocolInstance.hasABIs() ||
533
+ isComposedSubgraph) {
503
534
  return true;
504
535
  }
505
536
  const ABI = protocolInstance.getABI();
@@ -514,7 +545,10 @@ async function processInitForm({ protocol: initProtocol, abi: initAbi, abiPath:
514
545
  }
515
546
  },
516
547
  result: async (value) => {
517
- if (initFromExample || abiFromEtherscan || !protocolInstance.hasABIs()) {
548
+ if (initFromExample ||
549
+ abiFromEtherscan ||
550
+ !protocolInstance.hasABIs() ||
551
+ isComposedSubgraph) {
518
552
  return null;
519
553
  }
520
554
  const ABI = protocolInstance.getABI();
@@ -555,7 +589,7 @@ async function processInitForm({ protocol: initProtocol, abi: initAbi, abiPath:
555
589
  name: 'indexEvents',
556
590
  message: 'Index contract events as entities',
557
591
  initial: true,
558
- skip: () => !!initIndexEvents || isSubstreams,
592
+ skip: () => !!initIndexEvents || isSubstreams || isComposedSubgraph,
559
593
  },
560
594
  ]);
561
595
  return {
@@ -567,9 +601,10 @@ async function processInitForm({ protocol: initProtocol, abi: initAbi, abiPath:
567
601
  fromExample: !!initFromExample,
568
602
  network,
569
603
  contractName,
570
- contract,
604
+ source,
571
605
  indexEvents,
572
606
  spkgPath: spkg,
607
+ ipfs,
573
608
  };
574
609
  }
575
610
  catch (e) {
@@ -753,14 +788,33 @@ async function initSubgraphFromExample({ fromExample, subgraphName, directory, s
753
788
  }
754
789
  printNextSteps.bind(this)({ subgraphName, directory }, { commands });
755
790
  }
756
- async function initSubgraphFromContract({ protocolInstance, subgraphName, directory, abi, network, contract, indexEvents, contractName, node, startBlock, spkgPath, skipInstall, skipGit, }, { commands, addContract, }) {
791
+ async function initSubgraphFromContract({ protocolInstance, subgraphName, directory, abi, network, source, indexEvents, contractName, node, startBlock, spkgPath, skipInstall, skipGit, ipfsUrl, }, { commands, addContract, }) {
757
792
  const isSubstreams = protocolInstance.name === 'substreams';
793
+ const isComposedSubgraph = protocolInstance.isComposedSubgraph();
758
794
  if (gluegun_1.filesystem.exists(directory) &&
759
795
  !(await gluegun_1.prompt.confirm('Directory already exists, do you want to initialize the subgraph here (files will be overwritten) ?', false))) {
760
796
  this.exit(1);
761
797
  return;
762
798
  }
763
- if (protocolInstance.hasABIs() &&
799
+ let entities;
800
+ if (isComposedSubgraph) {
801
+ try {
802
+ const ipfsClient = (0, ipfs_http_client_1.create)({
803
+ url: (0, compiler_1.appendApiVersionForGraph)(ipfsUrl),
804
+ headers: {
805
+ ...constants_1.GRAPH_CLI_SHARED_HEADERS,
806
+ },
807
+ });
808
+ const schemaString = await (0, utils_1.default)(ipfsClient, source);
809
+ const schema = await schema_2.default.loadFromString(schemaString);
810
+ entities = schema.getEntityNames();
811
+ }
812
+ catch (e) {
813
+ this.error(`Failed to load and parse subgraph schema: ${e.message}`, { exit: 1 });
814
+ }
815
+ }
816
+ if (!protocolInstance.isComposedSubgraph() &&
817
+ protocolInstance.hasABIs() &&
764
818
  ((0, schema_1.abiEvents)(abi).size === 0 ||
765
819
  // @ts-expect-error TODO: the abiEvents result is expected to be a List, how's it an array?
766
820
  (0, schema_1.abiEvents)(abi).length === 0)) {
@@ -774,12 +828,13 @@ async function initSubgraphFromContract({ protocolInstance, subgraphName, direct
774
828
  subgraphName,
775
829
  abi,
776
830
  network,
777
- contract,
831
+ source,
778
832
  indexEvents,
779
833
  contractName,
780
834
  startBlock,
781
835
  node,
782
836
  spkgPath,
837
+ entities,
783
838
  }, spinner);
784
839
  await (0, scaffold_1.writeScaffold)(scaffold, directory, spinner);
785
840
  return true;
@@ -7,6 +7,7 @@ export default class EthereumTypeGenerator {
7
7
  private outputDir;
8
8
  constructor(options: TypeGeneratorOptions);
9
9
  loadABIs(subgraph: immutable.Map<any, any>): Promise<any>;
10
+ isValidAbiConfig(abiConfig: any): boolean;
10
11
  _loadABI(dataSource: any, name: string, maybeRelativePath: string, spinner: Spinner): {
11
12
  dataSource: any;
12
13
  abi: ABI;
@@ -17,19 +17,36 @@ class EthereumTypeGenerator {
17
17
  this.outputDir = options.outputDir;
18
18
  }
19
19
  async loadABIs(subgraph) {
20
- return await (0, spinner_1.withSpinner)('Load contract ABIs', 'Failed to load contract ABIs', `Warnings while loading contract ABIs`, async (spinner) => {
20
+ return await (0, spinner_1.withSpinner)('Load contract ABIs', 'Failed to load contract ABIs', 'Warnings while loading contract ABIs', async (spinner) => {
21
21
  try {
22
- return subgraph
23
- .get('dataSources')
24
- .reduce((abis, dataSource) => dataSource
25
- .getIn(['mapping', 'abis'])
26
- .reduce((abis, abi) => abis.push(this._loadABI(dataSource, abi.get('name'), abi.get('file'), spinner)), abis), immutable_1.default.List());
22
+ const dataSources = subgraph.get('dataSources');
23
+ if (!dataSources)
24
+ return immutable_1.default.List();
25
+ return dataSources.reduce((accumulatedAbis, dataSource) => {
26
+ // Get ABIs from the current data source's mapping
27
+ const sourceAbis = dataSource.getIn(['mapping', 'abis']);
28
+ if (!sourceAbis)
29
+ return accumulatedAbis;
30
+ // Process each ABI in the current data source
31
+ return sourceAbis.reduce((currentAbis, abiConfig) => {
32
+ // Skip invalid ABI configurations
33
+ if (!this.isValidAbiConfig(abiConfig)) {
34
+ return currentAbis;
35
+ }
36
+ // Load and add the ABI to our list
37
+ const loadedAbi = this._loadABI(dataSource, abiConfig.get('name'), abiConfig.get('file'), spinner);
38
+ return currentAbis.push(loadedAbi);
39
+ }, accumulatedAbis);
40
+ }, immutable_1.default.List());
27
41
  }
28
42
  catch (e) {
29
43
  throw Error(`Failed to load contract ABIs: ${e.message}`);
30
44
  }
31
45
  });
32
46
  }
47
+ isValidAbiConfig(abiConfig) {
48
+ return !!(abiConfig?.get('name') && abiConfig?.get('file'));
49
+ }
33
50
  _loadABI(dataSource, name, maybeRelativePath, spinner) {
34
51
  try {
35
52
  if (this.sourceDir) {
@@ -8,7 +8,7 @@ export default class Protocol {
8
8
  config: ProtocolConfig;
9
9
  constructor(datasource: any);
10
10
  static availableProtocols(): immutable.Collection<ProtocolName, string[]>;
11
- static availableNetworks(): immutable.Map<"ethereum" | "arweave" | "near" | "cosmos" | "substreams" | "substreams/triggers", immutable.List<string>>;
11
+ static availableNetworks(): immutable.Map<"ethereum" | "arweave" | "near" | "cosmos" | "substreams" | "substreams/triggers" | "subgraph", immutable.List<string>>;
12
12
  static normalizeName(name: ProtocolName): ProtocolName;
13
13
  displayName(): string;
14
14
  isValidKindName(kind: string): boolean;
@@ -24,8 +24,9 @@ export default class Protocol {
24
24
  getContract(): ContractCtor | undefined;
25
25
  getManifestScaffold(): any;
26
26
  getMappingScaffold(): any;
27
+ isComposedSubgraph(): boolean;
27
28
  }
28
- export type ProtocolName = 'arweave' | 'ethereum' | 'near' | 'cosmos' | 'substreams' | 'substreams/triggers';
29
+ export type ProtocolName = 'arweave' | 'ethereum' | 'near' | 'cosmos' | 'substreams' | 'substreams/triggers' | 'subgraph';
29
30
  export interface ProtocolConfig {
30
31
  displayName: string;
31
32
  abi?: any;
@@ -45,8 +45,11 @@ const contract_2 = __importDefault(require("./near/contract"));
45
45
  const NearManifestScaffold = __importStar(require("./near/scaffold/manifest"));
46
46
  const NearMappingScaffold = __importStar(require("./near/scaffold/mapping"));
47
47
  const subgraph_4 = __importDefault(require("./near/subgraph"));
48
+ const SubgraphDataSourceManifestScaffold = __importStar(require("./subgraph/scaffold/manifest"));
49
+ const SubgraphMappingScaffold = __importStar(require("./subgraph/scaffold/mapping"));
50
+ const subgraph_5 = __importDefault(require("./subgraph/subgraph"));
48
51
  const SubstreamsManifestScaffold = __importStar(require("./substreams/scaffold/manifest"));
49
- const subgraph_5 = __importDefault(require("./substreams/subgraph"));
52
+ const subgraph_6 = __importDefault(require("./substreams/subgraph"));
50
53
  const protocolDebug = (0, debug_1.default)('graph-cli:protocol');
51
54
  class Protocol {
52
55
  static fromDataSources(dataSourcesAndTemplates) {
@@ -60,6 +63,7 @@ class Protocol {
60
63
  * some other places use datasource object
61
64
  */
62
65
  const name = typeof datasource === 'string' ? datasource : datasource.kind;
66
+ protocolDebug('Initializing protocol with datasource %O', datasource);
63
67
  this.name = Protocol.normalizeName(name);
64
68
  protocolDebug('Initializing protocol %s', this.name);
65
69
  switch (this.name) {
@@ -75,6 +79,9 @@ class Protocol {
75
79
  case 'near':
76
80
  this.config = nearProtocol;
77
81
  break;
82
+ case 'subgraph':
83
+ this.config = subgraphProtocol;
84
+ break;
78
85
  case 'substreams':
79
86
  this.config = substreamsProtocol;
80
87
  /**
@@ -99,6 +106,7 @@ class Protocol {
99
106
  near: ['near'],
100
107
  cosmos: ['cosmos'],
101
108
  substreams: ['substreams'],
109
+ subgraph: ['subgraph'],
102
110
  });
103
111
  }
104
112
  static availableNetworks() {
@@ -153,6 +161,7 @@ class Protocol {
153
161
  'uni-3', // Juno testnet
154
162
  ],
155
163
  substreams: ['mainnet'],
164
+ subgraph: ['mainnet'],
156
165
  });
157
166
  }
158
167
  static normalizeName(name) {
@@ -178,7 +187,7 @@ class Protocol {
178
187
  // A problem with hasEvents usage in the codebase is that it's almost every where
179
188
  // where used, the ABI data is actually use after the conditional, so it seems
180
189
  // both concept are related. So internally, we map to this condition.
181
- return this.hasABIs();
190
+ return this.hasABIs() && !this.isComposedSubgraph();
182
191
  }
183
192
  hasTemplates() {
184
193
  return this.config.getTemplateCodeGen != null;
@@ -213,6 +222,9 @@ class Protocol {
213
222
  getMappingScaffold() {
214
223
  return this.config.mappingScaffold;
215
224
  }
225
+ isComposedSubgraph() {
226
+ return this.name === 'subgraph';
227
+ }
216
228
  }
217
229
  exports.default = Protocol;
218
230
  const arweaveProtocol = {
@@ -255,6 +267,20 @@ const ethereumProtocol = {
255
267
  manifestScaffold: EthereumManifestScaffold,
256
268
  mappingScaffold: EthereumMappingScaffold,
257
269
  };
270
+ const subgraphProtocol = {
271
+ displayName: 'Subgraph',
272
+ abi: abi_1.default,
273
+ contract: undefined,
274
+ getTemplateCodeGen: undefined,
275
+ getTypeGenerator(options) {
276
+ return new type_generator_1.default(options);
277
+ },
278
+ getSubgraph(options) {
279
+ return new subgraph_5.default(options);
280
+ },
281
+ manifestScaffold: SubgraphDataSourceManifestScaffold,
282
+ mappingScaffold: SubgraphMappingScaffold,
283
+ };
258
284
  const nearProtocol = {
259
285
  displayName: 'NEAR',
260
286
  abi: undefined,
@@ -274,7 +300,7 @@ const substreamsProtocol = {
274
300
  getTypeGenerator: undefined,
275
301
  getTemplateCodeGen: undefined,
276
302
  getSubgraph(options) {
277
- return new subgraph_5.default(options);
303
+ return new subgraph_6.default(options);
278
304
  },
279
305
  manifestScaffold: SubstreamsManifestScaffold,
280
306
  mappingScaffold: undefined,
@@ -0,0 +1,71 @@
1
+ # Each referenced type's in any of the types below must be listed
2
+ # here either as `scalar` or `type` for the validation code to work
3
+ # properly.
4
+ #
5
+ # That's why `String` is listed as a scalar even though it's built-in
6
+ # GraphQL basic types.
7
+ scalar String
8
+ scalar File
9
+ scalar BigInt
10
+ scalar Boolean
11
+ scalar JSON
12
+
13
+ union StringOrBigInt = String | BigInt
14
+
15
+ type SubgraphManifest {
16
+ specVersion: String!
17
+ features: [String!]
18
+ schema: Schema!
19
+ description: String
20
+ repository: String
21
+ graft: Graft
22
+ dataSources: [DataSource!]!
23
+ indexerHints: IndexerHints
24
+ }
25
+
26
+ type Schema {
27
+ file: File!
28
+ }
29
+
30
+ type IndexerHints {
31
+ prune: StringOrBigInt
32
+ }
33
+
34
+ type DataSource {
35
+ kind: String!
36
+ name: String!
37
+ network: String
38
+ context: JSON
39
+ source: ContractSource!
40
+ mapping: ContractMapping!
41
+ }
42
+
43
+ type ContractSource {
44
+ address: String!
45
+ startBlock: BigInt
46
+ }
47
+
48
+ type ContractMapping {
49
+ kind: String
50
+ apiVersion: String!
51
+ language: String!
52
+ file: File!
53
+ abis: [ContractABI!]
54
+ entities: [String!]!
55
+ handlers: [EntityHandler!]
56
+ }
57
+
58
+ type ContractABI {
59
+ name: String!
60
+ file: File!
61
+ }
62
+
63
+ type EntityHandler {
64
+ handler: String!
65
+ entity: String!
66
+ }
67
+
68
+ type Graft {
69
+ base: String!
70
+ block: BigInt!
71
+ }
@@ -0,0 +1,9 @@
1
+ export declare const source: ({ contract, startBlock, }: {
2
+ contract: string;
3
+ contractName: string;
4
+ startBlock: string;
5
+ }) => string;
6
+ export declare const mapping: ({ entities, contractName, }: {
7
+ entities: string[];
8
+ contractName: string;
9
+ }) => string;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mapping = exports.source = void 0;
4
+ const source = ({ contract, startBlock, }) => `
5
+ address: '${contract}'
6
+ startBlock: ${startBlock}`;
7
+ exports.source = source;
8
+ const mapping = ({ entities, contractName, }) => `
9
+ kind: ethereum/events
10
+ apiVersion: 0.0.7
11
+ language: wasm/assemblyscript
12
+ entities:
13
+ - ExampleEntity
14
+ handlers:
15
+ ${entities
16
+ .map(entity => `
17
+ - handler: handle${entity}
18
+ entity: ${entity}`)
19
+ .join(' ')}
20
+ file: ./src/${contractName}.ts
21
+ `;
22
+ exports.mapping = mapping;
@@ -0,0 +1,4 @@
1
+ export declare const generatePlaceholderHandlers: ({ entities, contract, }: {
2
+ entities: string[];
3
+ contract: string;
4
+ }) => string;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generatePlaceholderHandlers = void 0;
4
+ const generatePlaceholderHandlers = ({ entities, contract, }) => `
5
+ import { ExampleEntity } from '../generated/schema'
6
+ import {${entities.join(', ')}} from '../generated/subgraph-${contract}'
7
+ import { EntityTrigger } from '@graphprotocol/graph-ts'
8
+
9
+ ${entities
10
+ .map(entityName => `
11
+ export function handle${entityName}(entity: EntityTrigger<${entityName}>): void {
12
+ // Empty handler for ${entityName}
13
+ }`)
14
+ .join('\n')}
15
+ `;
16
+ exports.generatePlaceholderHandlers = generatePlaceholderHandlers;
@@ -0,0 +1,10 @@
1
+ import immutable from 'immutable';
2
+ import { Subgraph, SubgraphOptions } from '../subgraph';
3
+ export default class SubgraphDataSource implements Subgraph {
4
+ manifest: SubgraphOptions['manifest'];
5
+ resolveFile: SubgraphOptions['resolveFile'];
6
+ protocol: SubgraphOptions['protocol'];
7
+ constructor(options: SubgraphOptions);
8
+ validateManifest(): immutable.List<unknown>;
9
+ handlerTypes(): immutable.List<never>;
10
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const immutable_1 = __importDefault(require("immutable"));
7
+ class SubgraphDataSource {
8
+ constructor(options) {
9
+ this.manifest = options.manifest;
10
+ this.resolveFile = options.resolveFile;
11
+ this.protocol = options.protocol;
12
+ }
13
+ validateManifest() {
14
+ return immutable_1.default.List();
15
+ }
16
+ handlerTypes() {
17
+ return immutable_1.default.List([]);
18
+ }
19
+ }
20
+ exports.default = SubgraphDataSource;
@@ -11,6 +11,7 @@ export interface ScaffoldOptions {
11
11
  subgraphName?: string;
12
12
  node?: string;
13
13
  spkgPath?: string;
14
+ entities?: string[];
14
15
  }
15
16
  export default class Scaffold {
16
17
  protocol: Protocol;
@@ -23,6 +24,7 @@ export default class Scaffold {
23
24
  node?: string;
24
25
  startBlock?: string;
25
26
  spkgPath?: string;
27
+ entities?: string[];
26
28
  constructor(options: ScaffoldOptions);
27
29
  generatePackageJson(): Promise<string>;
28
30
  generatePackageJsonForSubstreams(): Promise<string>;
@@ -30,6 +30,7 @@ class Scaffold {
30
30
  this.startBlock = options.startBlock;
31
31
  this.node = options.node;
32
32
  this.spkgPath = options.spkgPath;
33
+ this.entities = options.entities;
33
34
  }
34
35
  async generatePackageJson() {
35
36
  return await prettier_1.default.format(JSON.stringify({
package/dist/schema.d.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import type { DocumentNode } from 'graphql/language';
2
2
  import SchemaCodeGenerator from './codegen/schema';
3
3
  export default class Schema {
4
- filename: string;
5
4
  document: string;
6
5
  ast: DocumentNode;
7
- constructor(filename: string, document: string, ast: DocumentNode);
6
+ filename?: string | undefined;
7
+ constructor(document: string, ast: DocumentNode, filename?: string | undefined);
8
8
  codeGenerator(): SchemaCodeGenerator;
9
9
  static load(filename: string): Promise<Schema>;
10
+ static loadFromString(document: string): Promise<Schema>;
11
+ getEntityNames(): string[];
10
12
  }
package/dist/schema.js CHANGED
@@ -30,11 +30,11 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
30
30
  const graphql = __importStar(require("graphql/language"));
31
31
  const schema_1 = __importDefault(require("./codegen/schema"));
32
32
  class Schema {
33
- constructor(filename, document, ast) {
34
- this.filename = filename;
33
+ constructor(document, ast, filename) {
35
34
  this.document = document;
36
35
  this.ast = ast;
37
36
  this.filename = filename;
37
+ this.filename = filename;
38
38
  this.document = document;
39
39
  this.ast = ast;
40
40
  }
@@ -44,7 +44,22 @@ class Schema {
44
44
  static async load(filename) {
45
45
  const document = await fs_extra_1.default.readFile(filename, 'utf-8');
46
46
  const ast = graphql.parse(document);
47
- return new Schema(filename, document, ast);
47
+ return new Schema(document, ast, filename);
48
+ }
49
+ static async loadFromString(document) {
50
+ try {
51
+ const ast = graphql.parse(document);
52
+ return new Schema(document, ast);
53
+ }
54
+ catch (e) {
55
+ throw new Error(`Failed to load schema from string: ${e.message}`);
56
+ }
57
+ }
58
+ getEntityNames() {
59
+ return this.ast.definitions
60
+ .filter(def => def.kind === 'ObjectTypeDefinition' &&
61
+ def.directives?.find(directive => directive.name.value === 'entity') !== undefined)
62
+ .map(entity => entity.name.value);
48
63
  }
49
64
  }
50
65
  exports.default = Schema;
@@ -9,6 +9,8 @@ export interface TypeGeneratorOptions {
9
9
  skipMigrations?: boolean;
10
10
  uncrashable: boolean;
11
11
  uncrashableConfig: string;
12
+ subgraphSources: string[];
13
+ ipfsUrl: string;
12
14
  }
13
15
  export default class TypeGenerator {
14
16
  private sourceDir;
@@ -22,7 +24,14 @@ export default class TypeGenerator {
22
24
  quiet: boolean;
23
25
  }): Promise<any>;
24
26
  loadSchema(subgraph: immutable.Map<any, any>): Promise<any>;
25
- generateTypesForSchema(schema: any): Promise<any>;
27
+ generateTypesForSchema({ schema, fileName, // Default file name
28
+ outputDir, // Default output directory
29
+ generateStoreMethods, }: {
30
+ schema: any;
31
+ fileName?: string;
32
+ outputDir?: string;
33
+ generateStoreMethods?: boolean;
34
+ }): Promise<any>;
26
35
  generateTypesForDataSourceTemplates(subgraph: immutable.Map<any, any>): Promise<any>;
27
36
  getFilesToWatch(): Promise<string[]>;
28
37
  watchAndGenerateTypes(): Promise<void>;
@@ -31,17 +31,21 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
31
31
  const toolbox = __importStar(require("gluegun"));
32
32
  const graphql = __importStar(require("graphql/language"));
33
33
  const immutable_1 = __importDefault(require("immutable"));
34
+ const ipfs_http_client_1 = require("ipfs-http-client");
34
35
  const prettier_1 = __importDefault(require("prettier"));
35
36
  // @ts-expect-error TODO: type out if necessary
36
37
  const Index_bs_js_1 = __importDefault(require("@float-capital/float-subgraph-uncrashable/src/Index.bs.js"));
37
38
  const template_1 = __importDefault(require("./codegen/template"));
38
39
  const typescript_1 = require("./codegen/typescript");
40
+ const compiler_1 = require("./command-helpers/compiler");
39
41
  const fs_1 = require("./command-helpers/fs");
40
42
  const spinner_1 = require("./command-helpers/spinner");
43
+ const constants_1 = require("./constants");
41
44
  const debug_1 = __importDefault(require("./debug"));
42
45
  const migrations_1 = require("./migrations");
43
46
  const schema_1 = __importDefault(require("./schema"));
44
47
  const subgraph_1 = __importDefault(require("./subgraph"));
48
+ const utils_1 = __importDefault(require("./utils"));
45
49
  const watcher_1 = __importDefault(require("./watcher"));
46
50
  const typeGenDebug = (0, debug_1.default)('graph-cli:type-generator');
47
51
  class TypeGenerator {
@@ -66,6 +70,10 @@ class TypeGenerator {
66
70
  process.exit(0);
67
71
  return;
68
72
  }
73
+ if (this.options.subgraphSources.length > 0) {
74
+ typeGenDebug.extend('generateTypes')('Subgraph uses subgraph datasources.');
75
+ toolbox.print.success('Subgraph uses subgraph datasources.');
76
+ }
69
77
  try {
70
78
  if (!this.options.skipMigrations && this.options.subgraphManifest) {
71
79
  await (0, migrations_1.applyMigrations)({
@@ -89,7 +97,25 @@ class TypeGenerator {
89
97
  }
90
98
  const schema = await this.loadSchema(subgraph);
91
99
  typeGenDebug.extend('generateTypes')('Generating types for schema');
92
- await this.generateTypesForSchema(schema);
100
+ await this.generateTypesForSchema({ schema });
101
+ if (this.options.subgraphSources.length > 0) {
102
+ const ipfsClient = (0, ipfs_http_client_1.create)({
103
+ url: (0, compiler_1.appendApiVersionForGraph)(this.options.ipfsUrl.toString()),
104
+ headers: {
105
+ ...constants_1.GRAPH_CLI_SHARED_HEADERS,
106
+ },
107
+ });
108
+ await Promise.all(this.options.subgraphSources.map(async (manifest) => {
109
+ const subgraphSchemaFile = await (0, utils_1.default)(ipfsClient, manifest);
110
+ const subgraphSchema = await schema_1.default.loadFromString(subgraphSchemaFile);
111
+ typeGenDebug.extend('generateTypes')(`Generating types for subgraph datasource ${manifest}`);
112
+ await this.generateTypesForSchema({
113
+ schema: subgraphSchema,
114
+ fileName: `subgraph-${manifest}.ts`,
115
+ generateStoreMethods: false,
116
+ });
117
+ }));
118
+ }
93
119
  toolbox.print.success('\nTypes generated successfully\n');
94
120
  if (this.options.uncrashable && this.options.uncrashableConfig) {
95
121
  await this.generateUncrashableEntities(schema);
@@ -132,19 +158,21 @@ class TypeGenerator {
132
158
  return schema_1.default.load(absolutePath);
133
159
  });
134
160
  }
135
- async generateTypesForSchema(schema) {
161
+ async generateTypesForSchema({ schema, fileName = 'schema.ts', // Default file name
162
+ outputDir = this.options.outputDir, // Default output directory
163
+ generateStoreMethods = true, }) {
136
164
  return await (0, spinner_1.withSpinner)(`Generate types for GraphQL schema`, `Failed to generate types for GraphQL schema`, `Warnings while generating types for GraphQL schema`, async (spinner) => {
137
165
  // Generate TypeScript module from schema
138
166
  const codeGenerator = schema.codeGenerator();
139
167
  const code = await prettier_1.default.format([
140
168
  typescript_1.GENERATED_FILE_NOTE,
141
169
  ...codeGenerator.generateModuleImports(),
142
- ...codeGenerator.generateTypes(),
170
+ ...codeGenerator.generateTypes(generateStoreMethods),
143
171
  ...codeGenerator.generateDerivedLoaders(),
144
172
  ].join('\n'), {
145
173
  parser: 'typescript',
146
174
  });
147
- const outputFile = path_1.default.join(this.options.outputDir, 'schema.ts');
175
+ const outputFile = path_1.default.join(outputDir, fileName); // Use provided outputDir and fileName
148
176
  (0, spinner_1.step)(spinner, 'Write types to', (0, fs_1.displayPath)(outputFile));
149
177
  await fs_extra_1.default.mkdirs(path_1.default.dirname(outputFile));
150
178
  await fs_extra_1.default.writeFile(outputFile, code);
@@ -0,0 +1 @@
1
+ export default function loadSubgraphSchemaFromIPFS(ipfsClient: any, manifest: string): Promise<string>;
package/dist/utils.js ADDED
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const js_yaml_1 = __importDefault(require("js-yaml"));
7
+ const debug_1 = __importDefault(require("./debug"));
8
+ const utilsDebug = (0, debug_1.default)('graph-cli:utils');
9
+ async function loadSubgraphSchemaFromIPFS(ipfsClient, manifest) {
10
+ try {
11
+ const manifestBuffer = ipfsClient.cat(manifest);
12
+ let manifestFile = '';
13
+ for await (const chunk of manifestBuffer) {
14
+ manifestFile += Buffer.from(chunk).toString('utf8'); // Explicitly convert each chunk to UTF-8
15
+ }
16
+ const manifestYaml = js_yaml_1.default.safeLoad(manifestFile);
17
+ let schema = manifestYaml.schema.file['/'];
18
+ if (schema.startsWith('/ipfs/')) {
19
+ schema = schema.slice(6);
20
+ }
21
+ const schemaBuffer = ipfsClient.cat(schema);
22
+ let schemaFile = '';
23
+ for await (const chunk of schemaBuffer) {
24
+ schemaFile += Buffer.from(chunk).toString('utf8'); // Explicitly convert each chunk to UTF-8
25
+ }
26
+ return schemaFile;
27
+ }
28
+ catch (e) {
29
+ utilsDebug.extend('loadSubgraphSchemaFromIPFS')(`Failed to load schema from IPFS ${manifest}`);
30
+ utilsDebug.extend('loadSubgraphSchemaFromIPFS')(e);
31
+ throw Error(`Failed to load schema from IPFS ${manifest}`);
32
+ }
33
+ }
34
+ exports.default = loadSubgraphSchemaFromIPFS;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.90.1",
2
+ "version": "0.91.0-alpha-20241202202221-345552f",
3
3
  "commands": {
4
4
  "add": {
5
5
  "id": "add",
@@ -239,6 +239,14 @@
239
239
  "summary": "Generate Float Subgraph Uncrashable helper file.",
240
240
  "allowNo": false
241
241
  },
242
+ "ipfs": {
243
+ "name": "ipfs",
244
+ "type": "option",
245
+ "char": "i",
246
+ "summary": "IPFS node to use for fetching subgraph data.",
247
+ "multiple": false,
248
+ "default": "https://api.thegraph.com/ipfs/api/v0"
249
+ },
242
250
  "uncrashable-config": {
243
251
  "name": "uncrashable-config",
244
252
  "type": "option",
@@ -453,7 +461,8 @@
453
461
  "ethereum",
454
462
  "near",
455
463
  "cosmos",
456
- "substreams"
464
+ "substreams",
465
+ "subgraph"
457
466
  ]
458
467
  },
459
468
  "node": {
@@ -550,6 +559,14 @@
550
559
  "dependsOn": [
551
560
  "from-contract"
552
561
  ]
562
+ },
563
+ "ipfs": {
564
+ "name": "ipfs",
565
+ "type": "option",
566
+ "char": "i",
567
+ "summary": "IPFS node to use for fetching subgraph data.",
568
+ "multiple": false,
569
+ "default": "https://api.thegraph.com/ipfs/api/v0"
553
570
  }
554
571
  },
555
572
  "args": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphprotocol/graph-cli",
3
- "version": "0.90.1",
3
+ "version": "0.91.0-alpha-20241202202221-345552f",
4
4
  "description": "CLI for building for and deploying to The Graph",
5
5
  "license": "(Apache-2.0 OR MIT)",
6
6
  "engines": {