From 92b03902d7a3e06fa3582fe5efac5579a6122ac1 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 6 Nov 2024 11:32:11 +0100 Subject: [PATCH 1/5] update NETWORK_SUBGRAPH_MAINNET & add `api-key` to CLI --- packages/cli/src/commands/publish.ts | 13 +++++++- packages/cli/src/validation/schema.ts | 2 +- website/src/lib/graphql.ts | 28 ++++++---------- website/src/routes/publish.lazy.tsx | 46 +++++++++++++++++---------- website/src/routes/publish.tsx | 3 +- 5 files changed, 53 insertions(+), 39 deletions(-) diff --git a/packages/cli/src/commands/publish.ts b/packages/cli/src/commands/publish.ts index df4a183a..e0a5822f 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,12 @@ export default class PublishCommand extends Command { ipfs, 'subgraph-id': subgraphId, 'protocol-network': protocolNetwork, + 'api-key': apiKey, }, } = await this.parse(PublishCommand); if (ipfsHash) { - await this.publishWithBrowser({ ipfsHash, webapp: webUiUrl, subgraphId, protocolNetwork }); + await this.publishWithBrowser({ ipfsHash, webapp: webUiUrl, subgraphId, protocolNetwork, apiKey }); return; } @@ -146,6 +156,7 @@ export default class PublishCommand extends Command { webapp: webUiUrl, subgraphId, protocolNetwork, + apiKey, }); return; } diff --git a/packages/cli/src/validation/schema.ts b/packages/cli/src/validation/schema.ts index 8f83df3f..4d50c465 100644 --- a/packages/cli/src/validation/schema.ts +++ b/packages/cli/src/validation/schema.ts @@ -227,7 +227,7 @@ const gatherLocalTypes = (defs: readonly graphql.DefinitionNode[]) => { ) .map( def => - // @ts-expect-error TODO: name field does not exist on definition, really? + // TODO: name field does not exist on definition, really? def.name.value, ); }; diff --git a/website/src/lib/graphql.ts b/website/src/lib/graphql.ts index 0f112874..4aad974b 100644 --- a/website/src/lib/graphql.ts +++ b/website/src/lib/graphql.ts @@ -1,25 +1,15 @@ -import { print } from 'graphql'; -import { TypedDocumentNode } from '@graphql-typed-document-node/core'; +export const NETWORK_SUBGRAPH_MAINNET = 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/DZz4kDTdmzWLWsV373w2bSmoar3umKKH9y82SUKr5qmp'; +export const NETWORK_SUBGRAPH_SEPOLIA = 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/3xQHhMudr1oh69ut36G2mbzpYmYxwqCeU6wwqyCDCnqV'; -export const NETWORK_SUBGRAPH_MAINNET = - 'https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-arbitrum'; -export const NETWORK_SUBGRAPH_SEPOLIA = - 'https://api.thegraph.com/subgraphs/name/graphprotocol/graph-network-arbitrum-sepolia'; - -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..198b0448 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,31 @@ 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; @@ -264,7 +276,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 +292,7 @@ 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 +387,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 +577,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 +593,7 @@ 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(), }), }); From ae781bf709024bd13c4911b82fb09d7529953119 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 6 Nov 2024 18:03:39 +0100 Subject: [PATCH 2/5] fix lint --- packages/cli/src/commands/publish.ts | 8 +++++++- website/src/lib/graphql.ts | 14 ++++++-------- website/src/routes/publish.lazy.tsx | 18 +++++++++++++----- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/packages/cli/src/commands/publish.ts b/packages/cli/src/commands/publish.ts index e0a5822f..c178baf8 100644 --- a/packages/cli/src/commands/publish.ts +++ b/packages/cli/src/commands/publish.ts @@ -119,7 +119,13 @@ export default class PublishCommand extends Command { } = await this.parse(PublishCommand); if (ipfsHash) { - await this.publishWithBrowser({ ipfsHash, webapp: webUiUrl, subgraphId, protocolNetwork, apiKey }); + await this.publishWithBrowser({ + ipfsHash, + webapp: webUiUrl, + subgraphId, + protocolNetwork, + apiKey, + }); return; } diff --git a/website/src/lib/graphql.ts b/website/src/lib/graphql.ts index 4aad974b..850829bb 100644 --- a/website/src/lib/graphql.ts +++ b/website/src/lib/graphql.ts @@ -1,12 +1,10 @@ -export const NETWORK_SUBGRAPH_MAINNET = 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/DZz4kDTdmzWLWsV373w2bSmoar3umKKH9y82SUKr5qmp'; -export const NETWORK_SUBGRAPH_SEPOLIA = 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/3xQHhMudr1oh69ut36G2mbzpYmYxwqCeU6wwqyCDCnqV'; +export const NETWORK_SUBGRAPH_MAINNET = + 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/DZz4kDTdmzWLWsV373w2bSmoar3umKKH9y82SUKr5qmp'; +export const NETWORK_SUBGRAPH_SEPOLIA = + 'https://gateway.thegraph.com/api/{api-key}/subgraphs/id/3xQHhMudr1oh69ut36G2mbzpYmYxwqCeU6wwqyCDCnqV'; -export async function networkSubgraphExecute( - query: string, - endpoint: string, - apiKey: string, -) { - const response = await fetch(endpoint.replace("{api-key}", apiKey), { +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, diff --git a/website/src/routes/publish.lazy.tsx b/website/src/routes/publish.lazy.tsx index 198b0448..aa3d1326 100644 --- a/website/src/routes/publish.lazy.tsx +++ b/website/src/routes/publish.lazy.tsx @@ -171,7 +171,7 @@ function DeploySubgraph({ deploymentId, subgraphId, network, - apiKey + apiKey, }: { deploymentId: string; subgraphId: string | undefined; @@ -226,7 +226,8 @@ function DeploySubgraph({ } if (!apiKey) { toast({ - description: "apiKey is missing in URL params. Please add it to the URL params and try again.", + description: + 'apiKey is missing in URL params. Please add it to the URL params and try again.', variant: 'destructive', }); return; @@ -239,7 +240,7 @@ function DeploySubgraph({ const data = await networkSubgraphExecute( GetSubgraphInfo(subgraphId), subgraphEndpoint, - apiKey + apiKey, ); const metadata = data.subgraph?.metadata; @@ -292,7 +293,9 @@ function DeploySubgraph({ const version = form.watch('versionLabel'); - return !subgraphInfo.subgraph?.versions.some(({ metadata }: { metadata: { label: string } }) => metadata?.label === version); + return !subgraphInfo.subgraph?.versions.some( + ({ metadata }: { metadata: { label: string } }) => metadata?.label === version, + ); } function isOwner() { @@ -593,7 +596,12 @@ function Page() { {id ? ( - + ) : (
Unable to find the Deployment ID. Go back to CLI From b620cd18fa48c75a7c7dafc543abfb29218cca56 Mon Sep 17 00:00:00 2001 From: Etienne Donneger Date: Thu, 7 Nov 2024 12:09:03 -0500 Subject: [PATCH 3/5] Fix build --- packages/cli/src/validation/schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/validation/schema.ts b/packages/cli/src/validation/schema.ts index 4d50c465..8f83df3f 100644 --- a/packages/cli/src/validation/schema.ts +++ b/packages/cli/src/validation/schema.ts @@ -227,7 +227,7 @@ const gatherLocalTypes = (defs: readonly graphql.DefinitionNode[]) => { ) .map( def => - // TODO: name field does not exist on definition, really? + // @ts-expect-error TODO: name field does not exist on definition, really? def.name.value, ); }; From 5888e509762c329508b25187c8b6b03ad138f297 Mon Sep 17 00:00:00 2001 From: Etienne Donneger Date: Wed, 20 Nov 2024 15:29:37 -0500 Subject: [PATCH 4/5] Fail publish if missing API key with Subgraph ID --- packages/cli/src/commands/publish.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/cli/src/commands/publish.ts b/packages/cli/src/commands/publish.ts index c178baf8..fe37d00f 100644 --- a/packages/cli/src/commands/publish.ts +++ b/packages/cli/src/commands/publish.ts @@ -118,6 +118,13 @@ export default class PublishCommand extends Command { }, } = 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, From 78a4a90b4d7a5bce52cde98728fa8999a54d2cad Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Wed, 20 Nov 2024 17:21:41 -0500 Subject: [PATCH 5/5] get version from network subgraph --- website/src/routes/publish.lazy.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/src/routes/publish.lazy.tsx b/website/src/routes/publish.lazy.tsx index aa3d1326..a8c9b2aa 100644 --- a/website/src/routes/publish.lazy.tsx +++ b/website/src/routes/publish.lazy.tsx @@ -264,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;