From 098b433815390e5aff2e0e52f22ab0ee44b9c206 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 21 Nov 2024 16:01:58 +0100 Subject: [PATCH] update NETWORK_SUBGRAPH_MAINNET & add `api-key` to CLI (#1760) * update NETWORK_SUBGRAPH_MAINNET & add `api-key` to CLI * Fail publish if missing API key with Subgraph ID * get version from network subgraph --------- Co-authored-by: Etienne Donneger Co-authored-by: YaroShkvorets --- .changeset/breezy-eels-sniff.md | 5 +++ packages/cli/src/commands/publish.ts | 26 +++++++++++- website/src/lib/graphql.ts | 22 +++-------- website/src/routes/publish.lazy.tsx | 59 ++++++++++++++++++++-------- website/src/routes/publish.tsx | 3 +- 5 files changed, 79 insertions(+), 36 deletions(-) create mode 100644 .changeset/breezy-eels-sniff.md diff --git a/.changeset/breezy-eels-sniff.md b/.changeset/breezy-eels-sniff.md new file mode 100644 index 00000000..694a5c8e --- /dev/null +++ b/.changeset/breezy-eels-sniff.md @@ -0,0 +1,5 @@ +--- +'@graphprotocol/graph-cli': minor +--- + +Update deprecated endpoints and support API key for updating published subgraphs diff --git a/packages/cli/src/commands/publish.ts b/packages/cli/src/commands/publish.ts index df4a183a..fe37d00f 100644 --- a/packages/cli/src/commands/publish.ts +++ b/packages/cli/src/commands/publish.ts @@ -46,6 +46,10 @@ export default class PublishCommand extends Command { required: false, default: 'https://cli.thegraph.com/publish', }), + 'api-key': Flags.string({ + summary: 'The API key to use for the Subgraph queries.', + required: false, + }), }; /** @@ -56,11 +60,13 @@ export default class PublishCommand extends Command { webapp, subgraphId, protocolNetwork, + apiKey, }: { ipfsHash: string; webapp: string; subgraphId: string | undefined; protocolNetwork: string | undefined; + apiKey: string | undefined; }) { const answer = await ux.prompt( `Press ${chalk.green( @@ -84,6 +90,9 @@ export default class PublishCommand extends Command { if (protocolNetwork) { searchParams.set('network', protocolNetwork); } + if (apiKey) { + searchParams.set('apiKey', apiKey); + } url.search = searchParams.toString(); @@ -105,11 +114,25 @@ export default class PublishCommand extends Command { ipfs, 'subgraph-id': subgraphId, 'protocol-network': protocolNetwork, + 'api-key': apiKey, }, } = await this.parse(PublishCommand); + if (subgraphId && !apiKey) { + ux.error( + 'API key is required to publish to an existing subgraph (`--api-key`).\nSee https://thegraph.com/docs/en/deploying/subgraph-studio-faqs/#2-how-do-i-create-an-api-key', + { exit: 1 }, + ); + } + if (ipfsHash) { - await this.publishWithBrowser({ ipfsHash, webapp: webUiUrl, subgraphId, protocolNetwork }); + await this.publishWithBrowser({ + ipfsHash, + webapp: webUiUrl, + subgraphId, + protocolNetwork, + apiKey, + }); return; } @@ -146,6 +169,7 @@ export default class PublishCommand extends Command { webapp: webUiUrl, subgraphId, protocolNetwork, + apiKey, }); return; } diff --git a/website/src/lib/graphql.ts b/website/src/lib/graphql.ts index 0f112874..850829bb 100644 --- a/website/src/lib/graphql.ts +++ b/website/src/lib/graphql.ts @@ -1,25 +1,13 @@ -import { print } from 'graphql'; -import { TypedDocumentNode } from '@graphql-typed-document-node/core'; - export const NETWORK_SUBGRAPH_MAINNET = - 'https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-arbitrum'; + 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/DZz4kDTdmzWLWsV373w2bSmoar3umKKH9y82SUKr5qmp'; export const NETWORK_SUBGRAPH_SEPOLIA = - 'https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-arbitrum-sepolia'; + 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/3xQHhMudr1oh69ut36G2mbzpYmYxwqCeU6wwqyCDCnqV'; -export async function networkSubgraphExecute( - query: TypedDocumentNode, - variables: Variables, - { - endpoint, - }: { - endpoint: string; - }, -): Promise { - const response = await fetch(endpoint, { +export async function networkSubgraphExecute(query: string, endpoint: string, apiKey: string) { + const response = await fetch(endpoint.replace('{api-key}', apiKey), { method: 'POST', body: JSON.stringify({ - query: print(query), - variables, + query, }), }); return (await response.json()).data; diff --git a/website/src/routes/publish.lazy.tsx b/website/src/routes/publish.lazy.tsx index 69f6480a..a8c9b2aa 100644 --- a/website/src/routes/publish.lazy.tsx +++ b/website/src/routes/publish.lazy.tsx @@ -1,6 +1,5 @@ import { useState } from 'react'; import { ConnectKitButton, useModal } from 'connectkit'; -import { graphql } from 'gql.tada'; import { useForm } from 'react-hook-form'; import semver from 'semver'; import { Address } from 'viem'; @@ -129,9 +128,9 @@ const Manifest = z.object({ repository: z.string().describe('An optional link to where the subgraph lives.').optional(), }); -const GetSubgraphInfo = graphql(/* GraphQL */ ` - query GetSubgraphInfo($subgraphId: ID!) { - subgraph(id: $subgraphId) { +const GetSubgraphInfo = (subgraphId: string) => ` + { + subgraph(id: "${subgraphId}") { id owner { id @@ -155,7 +154,7 @@ const GetSubgraphInfo = graphql(/* GraphQL */ ` } } } -`); +`; function getEtherscanUrl({ chainId, hash }: { chainId: number; hash: string }) { switch (chainId) { @@ -172,10 +171,12 @@ function DeploySubgraph({ deploymentId, subgraphId, network, + apiKey, }: { deploymentId: string; subgraphId: string | undefined; network: (typeof CHAINS)[number] | undefined; + apiKey: string | undefined; }) { const { writeContractAsync, isPending, error: contractError } = useWriteContract({}); const { setOpen } = useModal(); @@ -214,20 +215,32 @@ function DeploySubgraph({ const chain = form.watch('chain'); const { data: subgraphInfo } = useQuery({ - queryKey: ['subgraph-info', subgraphId, chain, chainId], + queryKey: ['subgraph-info', subgraphId, chain, chainId, apiKey], queryFn: async () => { - if (!subgraphId) return; + if (!subgraphId) { + toast({ + description: 'Subgraph ID is missing. Please add it to the URL params and try again.', + variant: 'destructive', + }); + return; + } + if (!apiKey) { + toast({ + description: + 'apiKey is missing in URL params. Please add it to the URL params and try again.', + variant: 'destructive', + }); + return; + } const subgraphEndpoint = chain ? getChainInfo(chain)?.subgraph : null; if (!subgraphEndpoint) return; const data = await networkSubgraphExecute( - GetSubgraphInfo, - { subgraphId }, - { - endpoint: subgraphEndpoint, - }, + GetSubgraphInfo(subgraphId), + subgraphEndpoint, + apiKey, ); const metadata = data.subgraph?.metadata; @@ -251,6 +264,11 @@ function DeploySubgraph({ if (metadata.displayName) { form.setValue('displayName', metadata.displayName); } + + if (data.subgraph.versions?.length > 0) { + const version = data.subgraph.versions[data.subgraph.versions.length - 1]; + form.setValue('versionLabel', version.metadata?.label ?? ''); + } } return data; @@ -264,7 +282,7 @@ function DeploySubgraph({ const version = form.watch('versionLabel'); const versionInfo = subgraphInfo.subgraph?.versions.find( - ({ metadata }) => metadata?.label === version, + ({ metadata }: { metadata: { label: string } }) => metadata?.label === version, ); if (!versionInfo) return false; @@ -280,7 +298,9 @@ function DeploySubgraph({ const version = form.watch('versionLabel'); - return !subgraphInfo.subgraph?.versions.some(({ metadata }) => metadata?.label === version); + return !subgraphInfo.subgraph?.versions.some( + ({ metadata }: { metadata: { label: string } }) => metadata?.label === version, + ); } function isOwner() { @@ -375,7 +395,7 @@ function DeploySubgraph({ if (e?.name === 'ContractFunctionExecutionError') { if (e.cause.name === 'ContractFunctionRevertedError') { toast({ - description: e.cause.reason, + description: e.cause.message, variant: 'destructive', }); return; @@ -565,7 +585,7 @@ function DeploySubgraph({ } function Page() { - const { id, subgraphId, network } = Route.useSearch(); + const { id, subgraphId, network, apiKey } = Route.useSearch(); const protocolNetwork = network ? // @ts-expect-error we want to compare if it is a string or not @@ -581,7 +601,12 @@ function Page() { {id ? ( - + ) : (
Unable to find the Deployment ID. Go back to CLI diff --git a/website/src/routes/publish.tsx b/website/src/routes/publish.tsx index 8ed600e8..1c28480d 100644 --- a/website/src/routes/publish.tsx +++ b/website/src/routes/publish.tsx @@ -6,6 +6,7 @@ export const Route = createFileRoute('/publish')({ subgraphId: z.string().optional(), // Transforming string to enum here doesn't actually work network: z.string().optional(), - id: z.string(), + id: z.string().optional(), + apiKey: z.string().optional(), }), });