@graphprotocol/graph-cli 0.95.0-alpha-20250127115813-55c1f2bf474a247489f48edfcdcf9ccbb48a00ee → 0.95.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,23 +1,44 @@
1
1
  # @graphprotocol/graph-cli
2
2
 
3
- ## 0.95.0-alpha-20250127115813-55c1f2bf474a247489f48edfcdcf9ccbb48a00ee
3
+ ## 0.95.0
4
4
 
5
5
  ### Minor Changes
6
6
 
7
- - [#1920](https://github.com/graphprotocol/graph-tooling/pull/1920)
8
- [`0f5ced8`](https://github.com/graphprotocol/graph-tooling/commit/0f5ced8919ec85dde027bfb63cc3121c7bb3eeb3)
9
- Thanks [@incrypto32](https://github.com/incrypto32)! - Add support for subgraph datasource in
10
- `graph init`
7
+ - [#1899](https://github.com/graphprotocol/graph-tooling/pull/1899)
8
+ [`8cdaf31`](https://github.com/graphprotocol/graph-tooling/commit/8cdaf31e78c7fb7bf7ef4f5380d0c72b2a05b08d)
9
+ Thanks [@0237h](https://github.com/0237h)! - Add support for Sourcify contract information lookup
11
10
 
12
11
  ### Patch Changes
13
12
 
14
- - [#1920](https://github.com/graphprotocol/graph-tooling/pull/1920)
15
- [`55c1f2b`](https://github.com/graphprotocol/graph-tooling/commit/55c1f2bf474a247489f48edfcdcf9ccbb48a00ee)
16
- Thanks [@incrypto32](https://github.com/incrypto32)! - dependencies updates:
13
+ - [#1910](https://github.com/graphprotocol/graph-tooling/pull/1910)
14
+ [`15384e6`](https://github.com/graphprotocol/graph-tooling/commit/15384e6bd8af6ba2ad07e9eb5a637d148fb39867)
15
+ Thanks [@renovate](https://github.com/apps/renovate)! - dependencies updates:
16
+
17
+ - Updated dependency [`undici@7.2.3` ↗︎](https://www.npmjs.com/package/undici/v/7.2.3) (from
18
+ `7.1.1`, in `dependencies`)
19
+
20
+ - [#1914](https://github.com/graphprotocol/graph-tooling/pull/1914)
21
+ [`e63b483`](https://github.com/graphprotocol/graph-tooling/commit/e63b483612e74587b3d33b7ce6d5f3264096820f)
22
+ Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - dependencies updates:
23
+
17
24
  - Removed dependency
18
25
  [`binary-install@^1.1.0` ↗︎](https://www.npmjs.com/package/binary-install/v/1.1.0) (from
19
26
  `dependencies`)
20
27
 
28
+ - [#1914](https://github.com/graphprotocol/graph-tooling/pull/1914)
29
+ [`e63b483`](https://github.com/graphprotocol/graph-tooling/commit/e63b483612e74587b3d33b7ce6d5f3264096820f)
30
+ Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - fix bug with graph test #1904
31
+
32
+ - [#1903](https://github.com/graphprotocol/graph-tooling/pull/1903)
33
+ [`bcaad5e`](https://github.com/graphprotocol/graph-tooling/commit/bcaad5e077e485224c06842491145d05215f4c0e)
34
+ Thanks [@0237h](https://github.com/0237h)! - Fix `import.meta.url` not being parsed as path
35
+ properly
36
+
37
+ - [#1918](https://github.com/graphprotocol/graph-tooling/pull/1918)
38
+ [`14ac25c`](https://github.com/graphprotocol/graph-tooling/commit/14ac25c1f08134d15410dad215cad8a9e941a105)
39
+ Thanks [@YaroShkvorets](https://github.com/YaroShkvorets)! - fix bug with loud errors in
40
+ `graph test`
41
+
21
42
  ## 0.94.0
22
43
 
23
44
  ### Minor Changes
@@ -10,5 +10,10 @@ export declare class ContractService {
10
10
  getABI(ABICtor: typeof ABI, networkId: string, address: string): Promise<ABI>;
11
11
  getStartBlock(networkId: string, address: string): Promise<string>;
12
12
  getContractName(networkId: string, address: string): Promise<string>;
13
+ getFromSourcify(ABICtor: typeof ABI, networkId: string, address: string): Promise<{
14
+ abi: ABI;
15
+ startBlock: string;
16
+ name: string;
17
+ } | null>;
13
18
  private fetchTransactionByHash;
14
19
  }
@@ -122,6 +122,45 @@ export class ContractService {
122
122
  }
123
123
  throw new Error(`Failed to fetch contract name for ${address}`);
124
124
  }
125
+ async getFromSourcify(ABICtor, networkId, address) {
126
+ try {
127
+ const network = this.registry.getNetworkById(networkId);
128
+ if (!network)
129
+ throw new Error(`Invalid network ${networkId}`);
130
+ if (!network.caip2Id.startsWith('eip155'))
131
+ throw new Error(`Invalid chainId, Sourcify API only supports EVM chains`);
132
+ const chainId = network.caip2Id.split(':')[1];
133
+ const url = `https://sourcify.dev/server/files/any/${chainId}/${address}`;
134
+ const json = await (await fetch(url).catch(error => {
135
+ throw new Error(`Sourcify API is unreachable: ${error}`);
136
+ })).json();
137
+ if (json) {
138
+ if ('error' in json)
139
+ throw new Error(`Sourcify API error: ${json.error}`);
140
+ let metadata = json.files.find(e => e.name === 'metadata.json')?.content;
141
+ if (!metadata)
142
+ throw new Error('Contract is missing metadata');
143
+ const tx_hash = json.files.find(e => e.name === 'creator-tx-hash.txt')?.content;
144
+ if (!tx_hash)
145
+ throw new Error('Contract is missing tx creation hash');
146
+ const tx = await this.fetchTransactionByHash(networkId, tx_hash);
147
+ if (!tx?.blockNumber)
148
+ throw new Error(`Can't fetch blockNumber from tx: ${JSON.stringify(tx)}`);
149
+ metadata = JSON.parse(metadata);
150
+ const contractName = Object.values(metadata.settings.compilationTarget)[0];
151
+ return {
152
+ abi: new ABICtor(contractName, undefined, immutable.fromJS(metadata.output.abi)),
153
+ startBlock: Number(tx.blockNumber).toString(),
154
+ name: contractName,
155
+ };
156
+ }
157
+ throw new Error(`No result: ${JSON.stringify(json)}`);
158
+ }
159
+ catch (error) {
160
+ logger(`Failed to fetch from Sourcify: ${error}`);
161
+ }
162
+ return null;
163
+ }
125
164
  async fetchTransactionByHash(networkId, txHash) {
126
165
  const urls = this.getRpcUrls(networkId);
127
166
  if (!urls.length) {
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, test } from 'vitest';
2
+ import EthereumABI from '../protocols/ethereum/abi.js';
2
3
  import { ContractService } from './contracts.js';
3
4
  import { loadRegistry } from './registry.js';
4
5
  // An object with some test cases for contract deployment block numbers
@@ -79,16 +80,76 @@ const TEST_CONTRACT_START_BLOCKS = {
79
80
  // clover: {
80
81
  // },
81
82
  };
82
- describe('getStartBlockForContract', { sequential: true }, async () => {
83
+ const TEST_SOURCIFY_CONTRACT_INFO = {
84
+ mainnet: {
85
+ '0xc2EdaD668740f1aA35E4D8f227fB8E17dcA888Cd': {
86
+ name: 'MasterChef',
87
+ startBlock: 10_736_242,
88
+ },
89
+ },
90
+ optimism: {
91
+ '0xc35DADB65012eC5796536bD9864eD8773aBc74C4': {
92
+ name: 'BentoBoxV1',
93
+ startBlock: 7_019_815,
94
+ },
95
+ },
96
+ wax: {
97
+ account: {
98
+ name: null,
99
+ startBlock: null,
100
+ },
101
+ },
102
+ 'non-existing chain': {
103
+ '0x0000000000000000000000000000000000000000': {
104
+ name: null,
105
+ startBlock: null,
106
+ },
107
+ },
108
+ };
109
+ // Retry helper with configurable number of retries
110
+ async function retry(operation, maxRetries = 3, sleepMs = 5000) {
111
+ let lastError;
112
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
113
+ try {
114
+ return await operation();
115
+ }
116
+ catch (error) {
117
+ lastError = error;
118
+ if (attempt < maxRetries - 1) {
119
+ await new Promise(resolve => setTimeout(resolve, sleepMs));
120
+ }
121
+ }
122
+ }
123
+ throw lastError;
124
+ }
125
+ describe('getStartBlockForContract', { concurrent: true }, async () => {
83
126
  const registry = await loadRegistry();
84
127
  const contractService = new ContractService(registry);
85
128
  for (const [network, contracts] of Object.entries(TEST_CONTRACT_START_BLOCKS)) {
86
129
  for (const [contract, startBlockExp] of Object.entries(contracts)) {
87
- test(`Returns the start block ${network} ${contract} ${startBlockExp}`, async () => {
88
- //loop through the TEST_CONTRACT_START_BLOCKS object and test each network
89
- const startBlock = await contractService.getStartBlock(network, contract);
130
+ test(`Returns the start block ${network} ${contract} ${startBlockExp}`, { timeout: 50_000 }, async ({ expect }) => {
131
+ const startBlock = await retry(() => contractService.getStartBlock(network, contract), 10);
90
132
  expect(parseInt(startBlock)).toBe(startBlockExp);
91
- }, { timeout: 10_000 });
133
+ });
134
+ }
135
+ }
136
+ });
137
+ describe('getFromSourcifyForContract', { concurrent: true }, async () => {
138
+ const registry = await loadRegistry();
139
+ const contractService = new ContractService(registry);
140
+ for (const [networkId, contractInfo] of Object.entries(TEST_SOURCIFY_CONTRACT_INFO)) {
141
+ for (const [contract, t] of Object.entries(contractInfo)) {
142
+ test(`Returns contract information ${networkId} ${contract} ${t.name} ${t.startBlock}`, { timeout: 50_000 }, async () => {
143
+ const result = await retry(() => contractService.getFromSourcify(EthereumABI, networkId, contract));
144
+ if (t.name === null && t.startBlock === null) {
145
+ expect(result).toBeNull();
146
+ }
147
+ else {
148
+ // Only check name and startBlock, omit API property from Sourcify results
149
+ const { name, startBlock } = result;
150
+ expect(t).toEqual({ name, startBlock: parseInt(startBlock) });
151
+ }
152
+ });
92
153
  }
93
154
  }
94
155
  });
@@ -1,9 +1,10 @@
1
1
  import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
2
3
  import * as toolbox from 'gluegun';
3
4
  import { afterAll, beforeAll, describe, expect, test } from 'vitest';
4
5
  import yaml from 'yaml';
5
6
  import { initNetworksConfig, updateSubgraphNetwork } from './network.js';
6
- const SUBGRAPH_PATH_BASE = path.join(`${process.platform === 'win32' ? '' : '/'}${/file:\/{2,3}(.+)\/[^/]/.exec(import.meta.url)[1]}`, '..', '..', '..', '..', 'examples', 'example-subgraph');
7
+ const SUBGRAPH_PATH_BASE = path.join(fileURLToPath(import.meta.url), '..', '..', '..', '..', '..', 'examples', 'example-subgraph');
7
8
  describe('initNetworksConfig', () => {
8
9
  beforeAll(async () => {
9
10
  await initNetworksConfig(SUBGRAPH_PATH_BASE, 'address');
@@ -58,10 +58,17 @@ export default class AddCommand extends Command {
58
58
  this.warn('`localhost` network detected, prompting user for inputs');
59
59
  const registry = await loadRegistry();
60
60
  const contractService = new ContractService(registry);
61
+ const sourcifyContractInfo = await contractService.getFromSourcify(EthereumABI, network, address);
61
62
  let startBlock = startBlockFlag ? parseInt(startBlockFlag).toString() : startBlockFlag;
62
63
  let contractName = contractNameFlag || DEFAULT_CONTRACT_NAME;
63
64
  let ethabi = null;
64
- if (abi) {
65
+ if (sourcifyContractInfo) {
66
+ startBlock ??= sourcifyContractInfo.startBlock;
67
+ contractName =
68
+ contractName == DEFAULT_CONTRACT_NAME ? sourcifyContractInfo.name : contractName;
69
+ ethabi ??= sourcifyContractInfo.abi;
70
+ }
71
+ if (!ethabi && abi) {
65
72
  ethabi = EthereumABI.load(contractName, abi);
66
73
  }
67
74
  else {
@@ -18,10 +18,11 @@ import { withSpinner } from '../command-helpers/spinner.js';
18
18
  import { getSubgraphBasename } from '../command-helpers/subgraph.js';
19
19
  import { GRAPH_CLI_SHARED_HEADERS } from '../constants.js';
20
20
  import debugFactory from '../debug.js';
21
+ import EthereumABI from '../protocols/ethereum/abi.js';
21
22
  import Protocol from '../protocols/index.js';
22
23
  import { abiEvents } from '../scaffold/schema.js';
23
24
  import Schema from '../schema.js';
24
- import { createIpfsClient, loadSubgraphSchemaFromIPFS, validateSubgraphNetworkMatch, } from '../utils.js';
25
+ import { createIpfsClient, loadSubgraphSchemaFromIPFS } from '../utils.js';
25
26
  import { validateContract } from '../validation/index.js';
26
27
  import AddCommand from './add.js';
27
28
  const protocolChoices = Array.from(Protocol.availableProtocols().keys());
@@ -154,6 +155,7 @@ export default class InitCommand extends Command {
154
155
  if ((fromContract || spkgPath) && protocol && subgraphName && directory && network && node) {
155
156
  const registry = await loadRegistry();
156
157
  const contractService = new ContractService(registry);
158
+ const sourcifyContractInfo = await contractService.getFromSourcify(EthereumABI, network, fromContract);
157
159
  if (!protocolChoices.includes(protocol)) {
158
160
  this.error(`Protocol '${protocol}' is not supported, choose from these options: ${protocolChoices.join(', ')}`, { exit: 1 });
159
161
  }
@@ -170,7 +172,9 @@ export default class InitCommand extends Command {
170
172
  }
171
173
  else {
172
174
  try {
173
- abi = await contractService.getABI(ABI, network, fromContract);
175
+ abi = sourcifyContractInfo
176
+ ? sourcifyContractInfo.abi
177
+ : await contractService.getABI(ABI, network, fromContract);
174
178
  }
175
179
  catch (e) {
176
180
  this.exit(1);
@@ -369,7 +373,7 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
369
373
  value: 'contract',
370
374
  },
371
375
  { message: 'Substreams', name: 'substreams', value: 'substreams' },
372
- { message: 'Subgraph', name: 'subgraph', value: 'subgraph' },
376
+ // { message: 'Subgraph', name: 'subgraph', value: 'subgraph' },
373
377
  ].filter(({ name }) => name),
374
378
  });
375
379
  return value;
@@ -433,18 +437,6 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
433
437
  return value;
434
438
  },
435
439
  });
436
- promptManager.addStep({
437
- type: 'input',
438
- name: 'ipfs',
439
- message: `IPFS node to use for fetching subgraph manifest`,
440
- initial: ipfsUrl,
441
- skip: () => !isComposedSubgraph,
442
- result: value => {
443
- ipfsNode = value;
444
- initDebugger.extend('processInitForm')('ipfs: %O', value);
445
- return value;
446
- },
447
- });
448
440
  promptManager.addStep({
449
441
  type: 'input',
450
442
  name: 'source',
@@ -457,15 +449,7 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
457
449
  initial: initContract,
458
450
  validate: async (value) => {
459
451
  if (isComposedSubgraph) {
460
- if (!ipfsNode) {
461
- return true;
462
- }
463
- const ipfs = createIpfsClient(ipfsNode);
464
- const { valid, error } = await validateSubgraphNetworkMatch(ipfs, value, network.id);
465
- if (!valid) {
466
- return error || 'Invalid subgraph network match';
467
- }
468
- return true;
452
+ return value.startsWith('Qm') ? true : 'Subgraph deployment ID must start with Qm';
469
453
  }
470
454
  if (initFromExample !== undefined || !protocolInstance.hasContract()) {
471
455
  return true;
@@ -482,11 +466,21 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
482
466
  source = address;
483
467
  return address;
484
468
  }
469
+ const sourcifyContractInfo = await contractService.getFromSourcify(EthereumABI, network.id, address);
470
+ if (sourcifyContractInfo) {
471
+ initStartBlock ??= sourcifyContractInfo.startBlock;
472
+ initContractName ??= sourcifyContractInfo.name;
473
+ initAbi ??= sourcifyContractInfo.abi;
474
+ initDebugger.extend('processInitForm')("infoFromSourcify: '%s'/'%s'", initStartBlock, initContractName);
475
+ }
485
476
  // If ABI is not provided, try to fetch it from Etherscan API
486
477
  if (protocolInstance.hasABIs() && !initAbi) {
487
478
  abiFromApi = await retryWithPrompt(() => withSpinner('Fetching ABI from contract API...', 'Failed to fetch ABI', 'Warning fetching ABI', () => contractService.getABI(protocolInstance.getABI(), network.id, address)));
488
479
  initDebugger.extend('processInitForm')("abiFromEtherscan len: '%s'", abiFromApi?.name);
489
480
  }
481
+ else {
482
+ abiFromApi = initAbi;
483
+ }
490
484
  // If startBlock is not provided, try to fetch it from Etherscan API
491
485
  if (!initStartBlock) {
492
486
  startBlock = await retryWithPrompt(() => withSpinner('Fetching start block from contract API...', 'Failed to fetch start block', 'Warning fetching start block', () => contractService.getStartBlock(network.id, address)));
@@ -501,6 +495,18 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
501
495
  return address;
502
496
  },
503
497
  });
498
+ promptManager.addStep({
499
+ type: 'input',
500
+ name: 'ipfs',
501
+ message: `IPFS node to use for fetching subgraph manifest`,
502
+ initial: ipfsUrl,
503
+ skip: () => !isComposedSubgraph,
504
+ result: value => {
505
+ ipfsNode = value;
506
+ initDebugger.extend('processInitForm')('ipfs: %O', value);
507
+ return value;
508
+ },
509
+ });
504
510
  promptManager.addStep({
505
511
  type: 'input',
506
512
  name: 'spkg',
@@ -617,22 +623,6 @@ async function processInitForm({ abi: initAbi, abiPath: initAbiPath, directory:
617
623
  },
618
624
  });
619
625
  await promptManager.executeInteractive();
620
- // Validate network matches if loading from IPFS
621
- if (ipfsNode && source && source.startsWith('Qm')) {
622
- const ipfs = createIpfsClient(ipfsNode);
623
- try {
624
- const { valid, error } = await validateSubgraphNetworkMatch(ipfs, source, network.id);
625
- if (!valid) {
626
- throw new Error(error || 'Invalid subgraph network match');
627
- }
628
- }
629
- catch (e) {
630
- if (e instanceof Error) {
631
- print.error(`Failed to validate subgraph network: ${e.message}`);
632
- }
633
- throw e;
634
- }
635
- }
636
626
  return {
637
627
  abi: (abiFromApi || abiFromFile),
638
628
  protocolInstance,
@@ -851,9 +841,8 @@ async function initSubgraphFromContract({ protocolInstance, subgraphName, direct
851
841
  this.error(`Failed to load and parse subgraph schema: ${e.message}`, { exit: 1 });
852
842
  }
853
843
  }
854
- if (!isComposedSubgraph &&
844
+ if (!protocolInstance.isComposedSubgraph() &&
855
845
  protocolInstance.hasABIs() &&
856
- abi && // Add check for abi existence
857
846
  (abiEvents(abi).size === 0 ||
858
847
  // @ts-expect-error TODO: the abiEvents result is expected to be a List, how's it an array?
859
848
  abiEvents(abi).length === 0)) {
@@ -862,11 +851,6 @@ async function initSubgraphFromContract({ protocolInstance, subgraphName, direct
862
851
  }
863
852
  // Scaffold subgraph
864
853
  const scaffold = await withSpinner(`Create subgraph scaffold`, `Failed to create subgraph scaffold`, `Warnings while creating subgraph scaffold`, async (spinner) => {
865
- initDebugger('Generating scaffold with ABI:', abi);
866
- initDebugger('ABI data:', abi?.data);
867
- if (abi) {
868
- initDebugger('ABI events:', abiEvents(abi));
869
- }
870
854
  const scaffold = await generateScaffold({
871
855
  protocolInstance,
872
856
  subgraphName,
@@ -2,6 +2,7 @@ import { spawn } from 'node:child_process';
2
2
  import http from 'node:http';
3
3
  import net from 'node:net';
4
4
  import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
5
6
  import compose from 'docker-compose';
6
7
  import { filesystem, patching } from 'gluegun';
7
8
  import stripAnsi from 'strip-ansi';
@@ -67,7 +68,7 @@ export default class LocalCommand extends Command {
67
68
  const skipWaitForEthereum = skipWaitForEthereumTypo || skipWaitForEthereumGood;
68
69
  // Obtain the Docker Compose file for services that the tests run against
69
70
  const composeFile = composeFileFlag ||
70
- path.join(`${process.platform === 'win32' ? '' : '/'}${/file:\/{2,3}(.+)\/[^/]/.exec(import.meta.url)[1]}`, '..', '..', 'resources', 'test', standaloneNode ? 'docker-compose-standalone-node.yml' : 'docker-compose.yml');
71
+ path.join(fileURLToPath(import.meta.url), '..', '..', '..', 'resources', 'test', standaloneNode ? 'docker-compose-standalone-node.yml' : 'docker-compose.yml');
71
72
  if (!filesystem.exists(composeFile)) {
72
73
  this.error(`Docker Compose file "${composeFile}" not found`, { exit: 1 });
73
74
  }
@@ -1,13 +1,15 @@
1
1
  import { exec, spawn } from 'node:child_process';
2
+ import events from 'node:events';
3
+ import fs from 'node:fs';
2
4
  import os from 'node:os';
3
5
  import path from 'node:path';
4
- import { Binary } from 'binary-install';
6
+ import { pipeline } from 'node:stream/promises';
7
+ import { fileURLToPath } from 'node:url';
5
8
  import { filesystem, patching, print, system } from 'gluegun';
6
9
  import yaml from 'js-yaml';
7
10
  import semver from 'semver';
8
11
  import { Args, Command, Flags } from '@oclif/core';
9
12
  import { GRAPH_CLI_SHARED_HEADERS } from '../constants.js';
10
- import fetch from '../fetch.js';
11
13
  export default class TestCommand extends Command {
12
14
  static description = 'Runs rust binary for subgraph testing.';
13
15
  static args = {
@@ -92,10 +94,10 @@ export default class TestCommand extends Command {
92
94
  });
93
95
  }
94
96
  if (opts.docker) {
95
- runDocker.bind(this)(datasource, opts);
97
+ await runDocker.bind(this)(datasource, opts);
96
98
  }
97
99
  else {
98
- runBinary.bind(this)(datasource, opts);
100
+ await runBinary.bind(this)(datasource, opts);
99
101
  }
100
102
  }
101
103
  }
@@ -113,19 +115,36 @@ function getLatestVersionFromCache(cachePath) {
113
115
  }
114
116
  async function runBinary(datasource, opts) {
115
117
  const coverageOpt = opts.coverage;
116
- const forceOpt = opts.force;
117
118
  const logsOpt = opts.logs;
118
119
  const versionOpt = opts.version;
119
120
  const latestVersion = opts.latestVersion;
120
121
  const recompileOpt = opts.recompile;
121
- const platform = await getPlatform.bind(this)(versionOpt || latestVersion, logsOpt);
122
- const url = `https://github.com/LimeChain/matchstick/releases/download/${versionOpt || latestVersion}/${platform}`;
123
- if (logsOpt) {
124
- this.log(`Download link: ${url}`);
122
+ let binPath = '';
123
+ try {
124
+ const platform = await getPlatform.bind(this)(versionOpt || latestVersion, logsOpt);
125
+ const url = `https://github.com/LimeChain/matchstick/releases/download/${versionOpt || latestVersion}/${platform}`;
126
+ const binDir = path.join(path.dirname(fileURLToPath(import.meta.url)), 'node_modules', '.bin');
127
+ binPath = path.join(binDir, `matchstick-${platform}`);
128
+ if (logsOpt) {
129
+ this.log(`Download link: ${url}`);
130
+ this.log(`Binary path: ${binPath}`);
131
+ }
132
+ if (!fs.existsSync(binPath)) {
133
+ this.log(`Downloading matchstick binary: ${url}`);
134
+ await fs.promises.mkdir(binDir, { recursive: true });
135
+ const response = await fetch(url);
136
+ if (!response.ok)
137
+ throw new Error(`Status: ${response.statusText}`);
138
+ if (!response.body)
139
+ throw new Error('No response body received');
140
+ const fileStream = fs.createWriteStream(binPath);
141
+ await pipeline(response.body, fileStream);
142
+ await fs.promises.chmod(binPath, '755');
143
+ }
144
+ }
145
+ catch (e) {
146
+ this.error(`Failed to get matchstick binary: ${e.message}\nConsider using -d flag to run it in Docker instead:\n graph test -d`, { exit: 1 });
125
147
  }
126
- const binary = new Binary(platform, url, versionOpt || latestVersion);
127
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
128
- forceOpt ? await binary.install(true) : await binary.install(false);
129
148
  const args = [];
130
149
  if (coverageOpt)
131
150
  args.push('-c');
@@ -133,14 +152,17 @@ async function runBinary(datasource, opts) {
133
152
  args.push('-r');
134
153
  if (datasource)
135
154
  args.push(datasource);
136
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
137
- args.length > 0 ? binary.run(...args) : binary.run();
155
+ const child = spawn(binPath, args, { stdio: 'inherit' });
156
+ const [code] = await events.once(child, 'exit');
157
+ if (code !== 0) {
158
+ this.error('Matchstick exited with an error', { exit: 1 });
159
+ }
138
160
  }
139
161
  async function getPlatform(matchstickVersion, logsOpt) {
140
162
  const type = os.type();
141
163
  const arch = os.arch();
142
164
  const cpuCore = os.cpus()[0];
143
- const isAppleSilicon = arch === 'arm64' && /Apple (M1|M2|M3|M4|processor)/.test(cpuCore.model);
165
+ const isAppleSilicon = arch === 'arm64' && /Apple (M[0-9]|processor)/.test(cpuCore.model);
144
166
  const linuxInfo = type === 'Linux' ? await getLinuxInfo.bind(this)() : {};
145
167
  const linuxDistro = linuxInfo.name;
146
168
  const release = linuxInfo.version || os.release();
@@ -156,7 +178,7 @@ async function getPlatform(matchstickVersion, logsOpt) {
156
178
  }
157
179
  return 'binary-macos-12';
158
180
  }
159
- if (type === 'Linux' && majorVersion === 22) {
181
+ if (type === 'Linux' && (majorVersion === 22 || majorVersion === 24)) {
160
182
  return 'binary-linux-22';
161
183
  }
162
184
  }
@@ -206,9 +228,6 @@ async function runDocker(datasource, opts) {
206
228
  const versionOpt = opts.version;
207
229
  const latestVersion = opts.latestVersion;
208
230
  const recompileOpt = opts.recompile;
209
- // Remove binary-install binaries, because docker has permission issues
210
- // when building the docker images
211
- filesystem.remove('./node_modules/binary-install/bin');
212
231
  // Get current working directory
213
232
  const current_folder = filesystem.cwd();
214
233
  // Declate dockerfilePath with default location
@@ -336,8 +336,6 @@ export default class Compiler {
336
336
  // ensure that the output directory exists
337
337
  fs.mkdirsSync(this.options.outputDir);
338
338
  return await withSpinner(`Write compiled subgraph to ${displayDir}`, `Failed to write compiled subgraph to ${displayDir}`, `Warnings while writing compiled subgraph to ${displayDir}`, async (spinner) => {
339
- // Add debug log for initial subgraph state
340
- compilerDebug('Initial subgraph state:', subgraph.toJS());
341
339
  // Copy schema and update its path
342
340
  subgraph = subgraph.updateIn(['schema', 'file'], schemaFile => {
343
341
  const schemaFilePath = path.resolve(this.sourceDir, schemaFile);
@@ -347,28 +345,17 @@ export default class Compiler {
347
345
  fs.copyFileSync(schemaFilePath, targetFile);
348
346
  return path.relative(this.options.outputDir, targetFile);
349
347
  });
350
- // Add debug log before processing data sources
351
- compilerDebug('Processing dataSources:', subgraph.get('dataSources').toJS());
352
348
  // Copy data source files and update their paths
353
349
  subgraph = subgraph.update('dataSources', (dataSources) => dataSources.map(dataSource => {
354
- // Add debug log for each data source
355
- compilerDebug('Processing dataSource:', dataSource.toJS());
356
350
  let updatedDataSource = dataSource;
357
351
  if (this.protocol.hasABIs()) {
358
- // Add debug log for ABIs
359
- compilerDebug('Processing ABIs for dataSource:', dataSource.getIn(['mapping', 'abis'])?.toJS() || 'undefined');
360
- updatedDataSource = updatedDataSource.updateIn(['mapping', 'abis'], (abis) => {
361
- compilerDebug('ABIs value:', Array.isArray(abis) ? abis : 'undefined');
362
- if (!abis) {
363
- compilerDebug('No ABIs found for dataSource');
364
- return immutable.List();
365
- }
366
- return abis.map((abi) => abi.update('file', (abiFile) => {
367
- abiFile = path.resolve(this.sourceDir, abiFile);
368
- const abiData = this.ABI.load(abi.get('name'), abiFile);
369
- return path.relative(this.options.outputDir, this._writeSubgraphFile(abiFile, JSON.stringify(abiData.data.toJS(), null, 2), this.sourceDir, this.subgraphDir(this.options.outputDir, dataSource), spinner));
370
- }));
371
- });
352
+ updatedDataSource = updatedDataSource
353
+ // Write data source ABIs to the output directory
354
+ .updateIn(['mapping', 'abis'], (abis) => abis.map((abi) => abi.update('file', (abiFile) => {
355
+ abiFile = path.resolve(this.sourceDir, abiFile);
356
+ const abiData = this.ABI.load(abi.get('name'), abiFile);
357
+ return path.relative(this.options.outputDir, this._writeSubgraphFile(abiFile, JSON.stringify(abiData.data.toJS(), null, 2), this.sourceDir, this.subgraphDir(this.options.outputDir, dataSource), spinner));
358
+ })));
372
359
  }
373
360
  if (protocol.name == 'substreams' || protocol.name == 'substreams/triggers') {
374
361
  updatedDataSource = updatedDataSource
@@ -63,7 +63,6 @@ type ContractABI {
63
63
  type EntityHandler {
64
64
  handler: String!
65
65
  entity: String!
66
- calls: JSON
67
66
  }
68
67
 
69
68
  type Graft {
@@ -25,7 +25,7 @@ export default class Scaffold {
25
25
  startBlock?: string;
26
26
  spkgPath?: string;
27
27
  entities?: string[];
28
- constructor({ protocol, abi, contract, network, contractName, startBlock, subgraphName, node, spkgPath, indexEvents, entities, }: ScaffoldOptions);
28
+ constructor(options: ScaffoldOptions);
29
29
  generatePackageJson(): Promise<string>;
30
30
  generatePackageJsonForSubstreams(): Promise<string>;
31
31
  generateManifest(): Promise<string>;
@@ -1,4 +1,3 @@
1
- import debugFactory from 'debug';
2
1
  import fs from 'fs-extra';
3
2
  import { strings } from 'gluegun';
4
3
  import prettier from 'prettier';
@@ -9,7 +8,6 @@ import { getGitIgnore } from './get-git-ignore.js';
9
8
  import { generateEventIndexingHandlers } from './mapping.js';
10
9
  import { abiEvents, generateEventType, generateExampleEntityType } from './schema.js';
11
10
  import { generateTestsFiles } from './tests.js';
12
- const scaffoldDebugger = debugFactory('graph-cli:scaffold');
13
11
  const GRAPH_CLI_VERSION = process.env.GRAPH_CLI_TESTS
14
12
  ? // JSON.stringify should remove this key, we will install the local
15
13
  // graph-cli for the tests using `npm link` instead of fetching from npm.
@@ -30,21 +28,18 @@ export default class Scaffold {
30
28
  startBlock;
31
29
  spkgPath;
32
30
  entities;
33
- constructor({ protocol, abi, contract, network, contractName, startBlock, subgraphName, node, spkgPath, indexEvents, entities, }) {
34
- this.protocol = protocol;
35
- this.abi = abi;
36
- this.contract = contract;
37
- this.network = network;
38
- this.contractName = contractName;
39
- this.startBlock = startBlock;
40
- this.subgraphName = subgraphName;
41
- this.node = node;
42
- this.spkgPath = spkgPath;
43
- this.indexEvents = indexEvents;
44
- this.entities = entities;
45
- scaffoldDebugger('Scaffold constructor called with ABI:', abi);
46
- scaffoldDebugger('ABI data:', abi?.data);
47
- scaffoldDebugger('ABI file:', abi?.file);
31
+ constructor(options) {
32
+ this.protocol = options.protocol;
33
+ this.abi = options.abi;
34
+ this.indexEvents = options.indexEvents;
35
+ this.contract = options.contract;
36
+ this.network = options.network;
37
+ this.contractName = options.contractName;
38
+ this.subgraphName = options.subgraphName;
39
+ this.startBlock = options.startBlock;
40
+ this.node = options.node;
41
+ this.spkgPath = options.spkgPath;
42
+ this.entities = options.entities;
48
43
  }
49
44
  async generatePackageJson() {
50
45
  return await prettier.format(JSON.stringify({
@@ -155,21 +150,9 @@ dataSources:
155
150
  }), { parser: 'typescript', semi: false, trailingComma: 'none' });
156
151
  }
157
152
  async generateABIs() {
158
- scaffoldDebugger('Generating ABIs...');
159
- scaffoldDebugger('Protocol has ABIs:', this.protocol.hasABIs());
160
- scaffoldDebugger('ABI data:', this.abi?.data);
161
- scaffoldDebugger('ABI file:', this.abi?.file);
162
- if (!this.protocol.hasABIs()) {
163
- scaffoldDebugger('Protocol does not have ABIs, skipping ABI generation');
164
- return;
165
- }
166
- if (!this.abi?.data) {
167
- scaffoldDebugger('ABI data is undefined, skipping ABI generation');
168
- return;
169
- }
170
153
  return this.protocol.hasABIs()
171
154
  ? {
172
- [`${this.contractName}.json`]: await prettier.format(JSON.stringify(this.abi.data), {
155
+ [`${this.contractName}.json`]: await prettier.format(JSON.stringify(this.abi?.data), {
173
156
  parser: 'json',
174
157
  }),
175
158
  }
package/dist/subgraph.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
2
3
  import fs from 'fs-extra';
3
4
  import * as graphql from 'graphql/language/index.js';
4
5
  import immutable from 'immutable';
@@ -31,7 +32,7 @@ export default class Subgraph {
31
32
  ]);
32
33
  }
33
34
  // Parse the default subgraph schema
34
- const schema = graphql.parse(await fs.readFile(path.join(`${process.platform === 'win32' ? '' : '/'}${/file:\/{2,3}(.+)\/[^/]/.exec(import.meta.url)[1]}`, 'protocols',
35
+ const schema = graphql.parse(await fs.readFile(path.join(fileURLToPath(import.meta.url), '..', 'protocols',
35
36
  // TODO: substreams/triggers is a special case, should be handled better
36
37
  protocol.name === 'substreams/triggers' ? 'substreams' : protocol.name, `manifest.graphql`), 'utf-8'));
37
38
  // Obtain the root `SubgraphManifest` type from the schema
@@ -1 +1 @@
1
- {"root":["../src/constants.ts","../src/debug.ts","../src/fetch.ts","../src/index.ts","../src/migrations.ts","../src/schema.ts","../src/subgraph.ts","../src/type-generator.ts","../src/utils.ts","../src/version.ts","../src/watcher.ts","../src/codegen/schema.test.ts","../src/codegen/schema.ts","../src/codegen/template.ts","../src/codegen/typescript.ts","../src/codegen/util.test.ts","../src/codegen/util.ts","../src/codegen/types/conversions.ts","../src/codegen/types/index.test.ts","../src/codegen/types/index.ts","../src/command-helpers/auth.ts","../src/command-helpers/compiler.test.ts","../src/command-helpers/compiler.ts","../src/command-helpers/contracts.test.ts","../src/command-helpers/contracts.ts","../src/command-helpers/data-sources.ts","../src/command-helpers/file-resolver.test.ts","../src/command-helpers/file-resolver.ts","../src/command-helpers/fs.ts","../src/command-helpers/ipfs.ts","../src/command-helpers/jsonrpc.ts","../src/command-helpers/network.test.ts","../src/command-helpers/network.ts","../src/command-helpers/node.ts","../src/command-helpers/prompt-manager.ts","../src/command-helpers/registry.ts","../src/command-helpers/retry.ts","../src/command-helpers/scaffold.ts","../src/command-helpers/sort.test.ts","../src/command-helpers/sort.ts","../src/command-helpers/spinner.ts","../src/command-helpers/subgraph.ts","../src/command-helpers/version.test.ts","../src/command-helpers/version.ts","../src/commands/add.ts","../src/commands/auth.ts","../src/commands/binary-install.d.ts","../src/commands/build.ts","../src/commands/clean.ts","../src/commands/codegen.ts","../src/commands/create.ts","../src/commands/deploy.ts","../src/commands/init.ts","../src/commands/local.ts","../src/commands/publish.ts","../src/commands/remove.ts","../src/commands/test.ts","../src/compiler/asc.ts","../src/compiler/index.ts","../src/migrations/mapping_api_version_0_0_1.ts","../src/migrations/mapping_api_version_0_0_2.ts","../src/migrations/mapping_api_version_0_0_3.ts","../src/migrations/mapping_api_version_0_0_4.ts","../src/migrations/mapping_api_version_0_0_5.ts","../src/migrations/spec_version_0_0_2.ts","../src/migrations/spec_version_0_0_3.ts","../src/migrations/util/load-manifest.ts","../src/migrations/util/versions.ts","../src/protocols/contract.ts","../src/protocols/file_template.ts","../src/protocols/index.ts","../src/protocols/subgraph.ts","../src/protocols/arweave/subgraph.ts","../src/protocols/arweave/scaffold/manifest.ts","../src/protocols/arweave/scaffold/mapping.ts","../src/protocols/cosmos/subgraph.ts","../src/protocols/cosmos/scaffold/manifest.ts","../src/protocols/cosmos/scaffold/mapping.ts","../src/protocols/ethereum/abi.ts","../src/protocols/ethereum/contract.ts","../src/protocols/ethereum/subgraph.ts","../src/protocols/ethereum/type-generator.ts","../src/protocols/ethereum/codegen/abi.test.ts","../src/protocols/ethereum/codegen/abi.ts","../src/protocols/ethereum/codegen/template.ts","../src/protocols/ethereum/scaffold/manifest.ts","../src/protocols/ethereum/scaffold/mapping.ts","../src/protocols/near/contract.ts","../src/protocols/near/subgraph.ts","../src/protocols/near/scaffold/manifest.ts","../src/protocols/near/scaffold/mapping.ts","../src/protocols/subgraph/subgraph.ts","../src/protocols/subgraph/scaffold/manifest.ts","../src/protocols/subgraph/scaffold/mapping.ts","../src/protocols/substreams/subgraph.ts","../src/protocols/substreams/scaffold/manifest.ts","../src/scaffold/cosmos.test.ts","../src/scaffold/ethereum.test.ts","../src/scaffold/get-docker-file.ts","../src/scaffold/get-git-ignore.ts","../src/scaffold/index.ts","../src/scaffold/mapping.ts","../src/scaffold/near.test.ts","../src/scaffold/schema.ts","../src/scaffold/tests.ts","../src/validation/contract.ts","../src/validation/index.ts","../src/validation/manifest.ts","../src/validation/schema.test.ts","../src/validation/schema.ts"],"version":"5.7.2"}
1
+ {"root":["../src/constants.ts","../src/debug.ts","../src/fetch.ts","../src/index.ts","../src/migrations.ts","../src/schema.ts","../src/subgraph.ts","../src/type-generator.ts","../src/utils.ts","../src/version.ts","../src/watcher.ts","../src/codegen/schema.test.ts","../src/codegen/schema.ts","../src/codegen/template.ts","../src/codegen/typescript.ts","../src/codegen/util.test.ts","../src/codegen/util.ts","../src/codegen/types/conversions.ts","../src/codegen/types/index.test.ts","../src/codegen/types/index.ts","../src/command-helpers/auth.ts","../src/command-helpers/compiler.test.ts","../src/command-helpers/compiler.ts","../src/command-helpers/contracts.test.ts","../src/command-helpers/contracts.ts","../src/command-helpers/data-sources.ts","../src/command-helpers/file-resolver.test.ts","../src/command-helpers/file-resolver.ts","../src/command-helpers/fs.ts","../src/command-helpers/ipfs.ts","../src/command-helpers/jsonrpc.ts","../src/command-helpers/network.test.ts","../src/command-helpers/network.ts","../src/command-helpers/node.ts","../src/command-helpers/prompt-manager.ts","../src/command-helpers/registry.ts","../src/command-helpers/retry.ts","../src/command-helpers/scaffold.ts","../src/command-helpers/sort.test.ts","../src/command-helpers/sort.ts","../src/command-helpers/spinner.ts","../src/command-helpers/subgraph.ts","../src/command-helpers/version.test.ts","../src/command-helpers/version.ts","../src/commands/add.ts","../src/commands/auth.ts","../src/commands/build.ts","../src/commands/clean.ts","../src/commands/codegen.ts","../src/commands/create.ts","../src/commands/deploy.ts","../src/commands/init.ts","../src/commands/local.ts","../src/commands/publish.ts","../src/commands/remove.ts","../src/commands/test.ts","../src/compiler/asc.ts","../src/compiler/index.ts","../src/migrations/mapping_api_version_0_0_1.ts","../src/migrations/mapping_api_version_0_0_2.ts","../src/migrations/mapping_api_version_0_0_3.ts","../src/migrations/mapping_api_version_0_0_4.ts","../src/migrations/mapping_api_version_0_0_5.ts","../src/migrations/spec_version_0_0_2.ts","../src/migrations/spec_version_0_0_3.ts","../src/migrations/util/load-manifest.ts","../src/migrations/util/versions.ts","../src/protocols/contract.ts","../src/protocols/file_template.ts","../src/protocols/index.ts","../src/protocols/subgraph.ts","../src/protocols/arweave/subgraph.ts","../src/protocols/arweave/scaffold/manifest.ts","../src/protocols/arweave/scaffold/mapping.ts","../src/protocols/cosmos/subgraph.ts","../src/protocols/cosmos/scaffold/manifest.ts","../src/protocols/cosmos/scaffold/mapping.ts","../src/protocols/ethereum/abi.ts","../src/protocols/ethereum/contract.ts","../src/protocols/ethereum/subgraph.ts","../src/protocols/ethereum/type-generator.ts","../src/protocols/ethereum/codegen/abi.test.ts","../src/protocols/ethereum/codegen/abi.ts","../src/protocols/ethereum/codegen/template.ts","../src/protocols/ethereum/scaffold/manifest.ts","../src/protocols/ethereum/scaffold/mapping.ts","../src/protocols/near/contract.ts","../src/protocols/near/subgraph.ts","../src/protocols/near/scaffold/manifest.ts","../src/protocols/near/scaffold/mapping.ts","../src/protocols/subgraph/subgraph.ts","../src/protocols/subgraph/scaffold/manifest.ts","../src/protocols/subgraph/scaffold/mapping.ts","../src/protocols/substreams/subgraph.ts","../src/protocols/substreams/scaffold/manifest.ts","../src/scaffold/cosmos.test.ts","../src/scaffold/ethereum.test.ts","../src/scaffold/get-docker-file.ts","../src/scaffold/get-git-ignore.ts","../src/scaffold/index.ts","../src/scaffold/mapping.ts","../src/scaffold/near.test.ts","../src/scaffold/schema.ts","../src/scaffold/tests.ts","../src/validation/contract.ts","../src/validation/index.ts","../src/validation/manifest.ts","../src/validation/schema.test.ts","../src/validation/schema.ts"],"version":"5.7.2"}
package/dist/utils.d.ts CHANGED
@@ -1,14 +1,2 @@
1
1
  export declare const createIpfsClient: typeof import("kubo-rpc-client").create;
2
2
  export declare function loadSubgraphSchemaFromIPFS(ipfsClient: any, manifest: string): Promise<string>;
3
- export declare function loadManifestFromIPFS(ipfsClient: any, manifest: string): Promise<string>;
4
- /**
5
- * Validates that the network of a source subgraph matches the target network
6
- * @param ipfsClient IPFS client instance
7
- * @param sourceSubgraphId IPFS hash of the source subgraph
8
- * @param targetNetwork Network of the target subgraph being created
9
- * @returns Object containing validation result and error message if any
10
- */
11
- export declare function validateSubgraphNetworkMatch(ipfsClient: any, sourceSubgraphId: string, targetNetwork: string): Promise<{
12
- valid: boolean;
13
- error?: string;
14
- }>;
package/dist/utils.js CHANGED
@@ -27,59 +27,3 @@ export async function loadSubgraphSchemaFromIPFS(ipfsClient, manifest) {
27
27
  throw Error(`Failed to load schema from IPFS ${manifest}`);
28
28
  }
29
29
  }
30
- export async function loadManifestFromIPFS(ipfsClient, manifest) {
31
- try {
32
- const manifestBuffer = ipfsClient.cat(manifest);
33
- let manifestFile = '';
34
- for await (const chunk of manifestBuffer) {
35
- manifestFile += Buffer.from(chunk).toString('utf8');
36
- }
37
- return manifestFile;
38
- }
39
- catch (e) {
40
- utilsDebug.extend('loadManifestFromIPFS')(`Failed to load manifest from IPFS ${manifest}`);
41
- utilsDebug.extend('loadManifestFromIPFS')(e);
42
- throw Error(`Failed to load manifest from IPFS ${manifest}`);
43
- }
44
- }
45
- /**
46
- * Validates that the network of a source subgraph matches the target network
47
- * @param ipfsClient IPFS client instance
48
- * @param sourceSubgraphId IPFS hash of the source subgraph
49
- * @param targetNetwork Network of the target subgraph being created
50
- * @returns Object containing validation result and error message if any
51
- */
52
- export async function validateSubgraphNetworkMatch(ipfsClient, sourceSubgraphId, targetNetwork) {
53
- try {
54
- const manifestFile = await loadManifestFromIPFS(ipfsClient, sourceSubgraphId);
55
- const manifestYaml = yaml.load(manifestFile);
56
- // Extract network from data sources
57
- const dataSources = manifestYaml.dataSources || [];
58
- const templates = manifestYaml.templates || [];
59
- const allSources = [...dataSources, ...templates];
60
- if (allSources.length === 0) {
61
- return { valid: true }; // No data sources to validate
62
- }
63
- // Get network from first data source
64
- const sourceNetwork = allSources[0].network;
65
- if (!sourceNetwork) {
66
- return { valid: true }; // Network not specified in source, skip validation
67
- }
68
- const normalizedSourceNetwork = sourceNetwork.toLowerCase();
69
- const normalizedTargetNetwork = targetNetwork.toLowerCase();
70
- if (normalizedSourceNetwork !== normalizedTargetNetwork) {
71
- return {
72
- valid: false,
73
- error: `Network mismatch: The source subgraph is indexing the '${sourceNetwork}' network, but you're creating a subgraph for '${targetNetwork}' network. When composing subgraphs, they must index the same network.`,
74
- };
75
- }
76
- return { valid: true };
77
- }
78
- catch (e) {
79
- utilsDebug.extend('validateSubgraphNetworkMatch')(`Failed to validate network match: ${e}`);
80
- return {
81
- valid: false,
82
- error: e instanceof Error ? e.message : 'Failed to validate subgraph network',
83
- };
84
- }
85
- }
package/dist/version.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
3
4
  const packageJson = JSON.parse(fs
4
5
  .readFileSync(
5
6
  // works even when bundled/built because the path to package.json is the same
6
- path.join(`${process.platform === 'win32' ? '' : '/'}${/file:\/{2,3}(.+)\/[^/]/.exec(import.meta.url)[1]}`, '..', 'package.json'))
7
+ path.join(fileURLToPath(import.meta.url), '..', '..', 'package.json'))
7
8
  .toString());
8
9
  export const version = packageJson.version;
9
10
  export const nodeVersion = (packageJson.engines?.node ?? '');
@@ -1011,5 +1011,5 @@
1011
1011
  ]
1012
1012
  }
1013
1013
  },
1014
- "version": "0.95.0-alpha-20250127115813-55c1f2bf474a247489f48edfcdcf9ccbb48a00ee"
1014
+ "version": "0.95.0"
1015
1015
  }
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@graphprotocol/graph-cli",
3
- "version": "0.95.0-alpha-20250127115813-55c1f2bf474a247489f48edfcdcf9ccbb48a00ee",
3
+ "version": "0.95.0",
4
4
  "type": "module",
5
5
  "description": "CLI for building for and deploying to The Graph",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/graphprotocol/graph-tooling.git",
9
+ "directory": "packages/cli"
10
+ },
6
11
  "license": "(Apache-2.0 OR MIT)",
7
12
  "engines": {
8
13
  "node": ">=20.18.1"
@@ -29,7 +34,6 @@
29
34
  "@pinax/graph-networks-registry": "^0.6.5",
30
35
  "@whatwg-node/fetch": "^0.10.1",
31
36
  "assemblyscript": "0.19.23",
32
- "binary-install": "^1.1.0",
33
37
  "chokidar": "4.0.1",
34
38
  "debug": "4.3.7",
35
39
  "docker-compose": "1.1.0",
@@ -45,7 +49,7 @@
45
49
  "prettier": "3.4.2",
46
50
  "semver": "7.6.3",
47
51
  "tmp-promise": "3.0.3",
48
- "undici": "7.1.1",
52
+ "undici": "7.2.3",
49
53
  "web3-eth-abi": "4.4.1",
50
54
  "yaml": "2.6.1"
51
55
  },
@@ -63,7 +67,8 @@
63
67
  "vitest": "^2.1.8"
64
68
  },
65
69
  "publishConfig": {
66
- "access": "public"
70
+ "access": "public",
71
+ "provenance": true
67
72
  },
68
73
  "oclif": {
69
74
  "bin": "graph",