@graphprotocol/graph-cli 0.54.0 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @graphprotocol/graph-cli
2
2
 
3
+ ## 0.55.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#1419](https://github.com/graphprotocol/graph-tooling/pull/1419)
8
+ [`e88ff02`](https://github.com/graphprotocol/graph-tooling/commit/e88ff02cd236f6c556afd99cecb00b6cffd738ed)
9
+ Thanks [@saihaj](https://github.com/saihaj)! - Introduce `--from-hosted-service` flag which will
10
+ make it easier to deploy subgraphs from hosted service to Studio.
11
+
12
+ - [#1418](https://github.com/graphprotocol/graph-tooling/pull/1418)
13
+ [`38c16be`](https://github.com/graphprotocol/graph-tooling/commit/38c16be4ed865bec12a4db63b219dba058f06e72)
14
+ Thanks [@uF4No](https://github.com/uF4No)! - feat: adds zksync era testnet
15
+
3
16
  ## 0.54.0
4
17
 
5
18
  ### Minor Changes
@@ -150,6 +150,8 @@ const getEtherscanLikeAPIUrl = (network) => {
150
150
  return `https://api-testnet.ftmscan.com/api`;
151
151
  case 'zksync-era':
152
152
  return `https://block-explorer-api.mainnet.zksync.io/api`;
153
+ case 'zksync-era-testnet':
154
+ return `https://block-explorer-api.testnets.zksync.dev/api`;
153
155
  case 'polygon-zkevm-testnet':
154
156
  return `https://testnet-zkevm.polygonscan.com/api`;
155
157
  case 'polygon-zkevm':
@@ -225,7 +227,9 @@ const getPublicRPCEndpoint = (network) => {
225
227
  case 'rinkeby':
226
228
  return 'https://rpc.ankr.com/eth_rinkeby';
227
229
  case 'zksync-era':
228
- return 'https://zksync2-mainnet.zksync.io';
230
+ return 'https://mainnet.era.zksync.io';
231
+ case 'zksync-era-testnet':
232
+ return 'https://testnet.era.zksync.dev';
229
233
  case 'sepolia':
230
234
  return 'https://rpc.ankr.com/eth_sepolia';
231
235
  default:
@@ -11,3 +11,10 @@ export declare function chooseNodeUrl({ product, studio, node, allowSimpleName,
11
11
  node: string | undefined;
12
12
  allowSimpleName: boolean | undefined;
13
13
  };
14
+ export declare function getHostedServiceSubgraphId({ subgraphName, }: {
15
+ subgraphName: string;
16
+ }): Promise<{
17
+ subgraph: string;
18
+ synced: boolean;
19
+ health: 'healthy' | 'unhealthy' | 'failed';
20
+ }>;
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.chooseNodeUrl = exports.normalizeNodeUrl = exports.validateNodeUrl = void 0;
3
+ exports.getHostedServiceSubgraphId = exports.chooseNodeUrl = exports.normalizeNodeUrl = exports.validateNodeUrl = void 0;
4
4
  const url_1 = require("url");
5
5
  const gluegun_1 = require("gluegun");
6
6
  const SUBGRAPH_STUDIO_URL = 'https://api.studio.thegraph.com/deploy/';
7
7
  const HOSTED_SERVICE_URL = 'https://api.thegraph.com/deploy/';
8
+ const HOSTED_SERVICE_INDEX_NODE_URL = 'https://api.thegraph.com/index-node/graphql';
8
9
  const validateNodeUrl = (node) => new url_1.URL(node);
9
10
  exports.validateNodeUrl = validateNodeUrl;
10
11
  const normalizeNodeUrl = (node) => new url_1.URL(node).toString();
@@ -38,3 +39,35 @@ function chooseNodeUrl({ product, studio, node, allowSimpleName, }) {
38
39
  return { node, allowSimpleName };
39
40
  }
40
41
  exports.chooseNodeUrl = chooseNodeUrl;
42
+ async function getHostedServiceSubgraphId({ subgraphName, }) {
43
+ const response = await fetch(HOSTED_SERVICE_INDEX_NODE_URL, {
44
+ method: 'POST',
45
+ body: JSON.stringify({
46
+ query: /* GraphQL */ `
47
+ query GraphCli_getSubgraphId($subgraphName: String!) {
48
+ indexingStatusForCurrentVersion(subgraphName: $subgraphName) {
49
+ subgraph
50
+ synced
51
+ health
52
+ }
53
+ }
54
+ `,
55
+ variables: {
56
+ subgraphName,
57
+ },
58
+ }),
59
+ headers: {
60
+ 'content-type': 'application/json',
61
+ 'User-Agent': '@graphprotocol/graph-cli',
62
+ },
63
+ });
64
+ const { data, errors } = await response.json();
65
+ if (errors) {
66
+ throw new Error(errors[0].message);
67
+ }
68
+ if (!data.indexingStatusForCurrentVersion) {
69
+ throw new Error(`Subgraph "${subgraphName}" not found on the hosted service`);
70
+ }
71
+ return data.indexingStatusForCurrentVersion;
72
+ }
73
+ exports.getHostedServiceSubgraphId = getHostedServiceSubgraphId;
@@ -1,4 +1,4 @@
1
- export declare const allowedStudioNetworks: readonly ["mainnet", "rinkeby", "goerli", "gnosis", "chapel", "optimism-goerli", "clover", "fantom", "matic", "fantom-testnet", "arbitrum-goerli", "fuji", "celo-alfajores", "mumbai", "aurora-testnet", "near-testnet", "optimism", "optimism-goerli", "theta-testnet-001", "osmo-test-4", "base-testnet", "base", "celo", "arbitrum-one", "avalanche", "zksync-era", "sepolia", "polygon-zkevm-testnet", "polygon-zkevm"];
1
+ export declare const allowedStudioNetworks: readonly ["mainnet", "rinkeby", "goerli", "gnosis", "chapel", "optimism-goerli", "clover", "fantom", "matic", "fantom-testnet", "arbitrum-goerli", "fuji", "celo-alfajores", "mumbai", "aurora-testnet", "near-testnet", "optimism", "optimism-goerli", "theta-testnet-001", "osmo-test-4", "base-testnet", "base", "celo", "arbitrum-one", "avalanche", "zksync-era", "zksync-era-testnet", "sepolia", "polygon-zkevm-testnet", "polygon-zkevm"];
2
2
  export declare const validateStudioNetwork: ({ studio, product, network, }: {
3
3
  studio?: string | boolean | undefined;
4
4
  product?: string | undefined;
@@ -28,6 +28,7 @@ exports.allowedStudioNetworks = [
28
28
  'arbitrum-one',
29
29
  'avalanche',
30
30
  'zksync-era',
31
+ 'zksync-era-testnet',
31
32
  'sepolia',
32
33
  'polygon-zkevm-testnet',
33
34
  'polygon-zkevm',
@@ -22,6 +22,7 @@ export default class DeployCommand extends Command {
22
22
  watch: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
23
23
  network: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
24
24
  'network-file': import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
25
+ 'from-hosted-service': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
25
26
  };
26
27
  run(): Promise<void>;
27
28
  }
@@ -50,7 +50,103 @@ const headersFlag = core_1.Flags.custom({
50
50
  const productOptions = ['subgraph-studio', 'hosted-service'];
51
51
  class DeployCommand extends core_1.Command {
52
52
  async run() {
53
- const { args: { 'subgraph-name': subgraphNameArg, 'subgraph-manifest': manifest }, flags: { product: productFlag, studio, 'deploy-key': deployKeyFlag, 'access-token': accessToken, 'version-label': versionLabelFlag, ipfs, headers, node: nodeFlag, 'output-dir': outputDir, 'skip-migrations': skipMigrations, watch, 'debug-fork': debugFork, network, 'network-file': networkFile, 'ipfs-hash': ipfsHash, }, } = await this.parse(DeployCommand);
53
+ const { args: { 'subgraph-name': subgraphNameArg, 'subgraph-manifest': manifest }, flags: { product: productFlag, studio, 'deploy-key': deployKeyFlag, 'access-token': accessToken, 'version-label': versionLabelFlag, ipfs, headers, node: nodeFlag, 'output-dir': outputDir, 'skip-migrations': skipMigrations, watch, 'debug-fork': debugFork, network, 'network-file': networkFile, 'ipfs-hash': ipfsHash, 'from-hosted-service': hostedServiceSubgraphName, }, } = await this.parse(DeployCommand);
54
+ if (hostedServiceSubgraphName) {
55
+ const { health, subgraph: subgraphIpfsHash } = await (0, node_1.getHostedServiceSubgraphId)({
56
+ subgraphName: hostedServiceSubgraphName,
57
+ });
58
+ const safeToDeployFailedSubgraph = health === 'failed'
59
+ ? await core_1.ux.confirm('This subgraph has failed indexing on hosted service. Do you wish to continue the deploy?')
60
+ : true;
61
+ if (!safeToDeployFailedSubgraph)
62
+ return;
63
+ const safeToDeployUnhealthySubgraph = health === 'unhealthy'
64
+ ? await core_1.ux.confirm('This subgraph is not healthy on hosted service. Do you wish to continue the deploy?')
65
+ : true;
66
+ if (!safeToDeployUnhealthySubgraph)
67
+ return;
68
+ const { node } = (0, node_1.chooseNodeUrl)({ studio: true, product: undefined });
69
+ // shouldn't happen, but we need to satisfy the compiler
70
+ if (!node) {
71
+ this.error('No node URL available');
72
+ }
73
+ const requestUrl = new url_1.URL(node);
74
+ const client = (0, jsonrpc_1.createJsonRpcClient)(requestUrl);
75
+ // Exit with an error code if the client couldn't be created
76
+ if (!client) {
77
+ this.error('Failed to create RPC client');
78
+ }
79
+ // Use the deploy key, if one is set
80
+ let deployKey = deployKeyFlag;
81
+ if (!deployKey && accessToken) {
82
+ deployKey = accessToken; // backwards compatibility
83
+ }
84
+ deployKey = await (0, auth_1.identifyDeployKey)(node, deployKey);
85
+ if (!deployKey) {
86
+ this.error('No deploy key available');
87
+ }
88
+ // @ts-expect-error options property seems to exist
89
+ client.options.headers = { Authorization: 'Bearer ' + deployKey };
90
+ const subgraphName = await core_1.ux.prompt('What is the name of the subgraph you want to deploy?', {
91
+ required: true,
92
+ });
93
+ // Ask for label if not on hosted service
94
+ const versionLabel = versionLabelFlag ||
95
+ (await core_1.ux.prompt('Which version label to use? (e.g. "v0.0.1")', {
96
+ required: true,
97
+ }));
98
+ const spinner = gluegun_1.print.spin(`Deploying to Graph node ${requestUrl}`);
99
+ client.request('subgraph_deploy', {
100
+ name: subgraphName,
101
+ ipfs_hash: subgraphIpfsHash,
102
+ version_label: versionLabel,
103
+ debug_fork: debugFork,
104
+ }, async (
105
+ // @ts-expect-error TODO: why are the arguments not typed?
106
+ requestError,
107
+ // @ts-expect-error TODO: why are the arguments not typed?
108
+ jsonRpcError,
109
+ // @ts-expect-error TODO: why are the arguments not typed?
110
+ res) => {
111
+ if (jsonRpcError) {
112
+ let errorMessage = `Failed to deploy to Graph node ${requestUrl}: ${jsonRpcError.message}`;
113
+ // Provide helpful advice when the subgraph has not been created yet
114
+ if (jsonRpcError.message.match(/subgraph name not found/)) {
115
+ errorMessage += `
116
+ Make sure to create the subgraph first by running the following command:
117
+ $ graph create --node ${node} ${subgraphName}`;
118
+ }
119
+ if (jsonRpcError.message.match(/auth failure/)) {
120
+ errorMessage += '\nYou may need to authenticate first.';
121
+ }
122
+ spinner.fail(errorMessage);
123
+ process.exit(1);
124
+ }
125
+ else if (requestError) {
126
+ spinner.fail(`HTTP error deploying the subgraph ${requestError.code}`);
127
+ process.exit(1);
128
+ }
129
+ else {
130
+ spinner.stop();
131
+ const base = requestUrl.protocol + '//' + requestUrl.hostname;
132
+ let playground = res.playground;
133
+ let queries = res.queries;
134
+ // Add a base URL if graph-node did not return the full URL
135
+ if (playground.charAt(0) === ':') {
136
+ playground = base + playground;
137
+ }
138
+ if (queries.charAt(0) === ':') {
139
+ queries = base + queries;
140
+ }
141
+ gluegun_1.print.success(`Deployed to ${playground}`);
142
+ gluegun_1.print.info('\nSubgraph endpoints:');
143
+ gluegun_1.print.info(`Queries (HTTP): ${queries}`);
144
+ gluegun_1.print.info(``);
145
+ process.exit(0);
146
+ }
147
+ });
148
+ return;
149
+ }
54
150
  const subgraphName = subgraphNameArg ||
55
151
  (await core_1.ux.prompt('What is the subgraph name?', {
56
152
  required: true,
@@ -329,5 +425,8 @@ DeployCommand.flags = {
329
425
  summary: 'Networks config file path.',
330
426
  default: 'networks.json',
331
427
  }),
428
+ 'from-hosted-service': core_1.Flags.string({
429
+ summary: 'Hosted service Subgraph Name to deploy to studio.',
430
+ }),
332
431
  };
333
432
  exports.default = DeployCommand;
@@ -121,6 +121,7 @@ class Protocol {
121
121
  'base-testnet',
122
122
  'base',
123
123
  'zksync-era',
124
+ 'zksync-era-testnet',
124
125
  'sepolia',
125
126
  'polygon-zkevm-testnet',
126
127
  'polygon-zkevm',
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.54.0",
2
+ "version": "0.55.0",
3
3
  "commands": {
4
4
  "add": {
5
5
  "id": "add",
@@ -451,6 +451,12 @@
451
451
  "summary": "Networks config file path.",
452
452
  "multiple": false,
453
453
  "default": "networks.json"
454
+ },
455
+ "from-hosted-service": {
456
+ "name": "from-hosted-service",
457
+ "type": "option",
458
+ "summary": "Hosted service Subgraph Name to deploy to studio.",
459
+ "multiple": false
454
460
  }
455
461
  },
456
462
  "args": {
@@ -628,6 +634,7 @@
628
634
  "base-testnet",
629
635
  "base",
630
636
  "zksync-era",
637
+ "zksync-era-testnet",
631
638
  "sepolia",
632
639
  "polygon-zkevm-testnet",
633
640
  "polygon-zkevm",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphprotocol/graph-cli",
3
- "version": "0.54.0",
3
+ "version": "0.55.0",
4
4
  "description": "CLI for building for and deploying to The Graph",
5
5
  "license": "(Apache-2.0 OR MIT)",
6
6
  "engines": {