Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce dev dash webhooks API #4884

Merged
merged 6 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bin/get-graphql-schemas.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ const schemas = [
repo: 'shopify',
pathToFile: 'areas/core/shopify/db/graphql/admin_schema_unstable_public.graphql',
localPath: './packages/cli-kit/src/cli/api/graphql/admin/admin_schema.graphql',
},
{
repo: 'shopify',
pathToFile: 'areas/core/shopify/db/graphql/webhooks_schema_unstable_public.graphql',
localPath: './packages/app/src/cli/api/graphql/webhooks/webhooks_schema.graphql',
branch: 'dd',
}
]

Expand Down
6 changes: 5 additions & 1 deletion graphql.config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
function projectFactory(name: string, schemaName: string, project: string = 'app') {
return {
schema: `./packages/${project}/src/cli/api/graphql/${name}/${schemaName}`,
documents: [`./packages/${project}/src/cli/api/graphql/${name}/queries/**/*.graphql`,`./packages/${project}/src/cli/api/graphql/${name}/mutations/**/*.graphql`],
documents: [
`./packages/${project}/src/cli/api/graphql/${name}/queries/**/*.graphql`,
`./packages/${project}/src/cli/api/graphql/${name}/mutations/**/*.graphql`,
],
extensions: {
codegen: {
generates: {
Expand Down Expand Up @@ -78,5 +81,6 @@ export default {
appDev: projectFactory('app-dev', 'app_dev_schema.graphql'),
appManagement: projectFactory('app-management', 'app_management_schema.graphql'),
admin: projectFactory('admin', 'admin_schema.graphql', 'cli-kit'),
webhooks: projectFactory('webhooks', 'webhooks_schema.graphql'),
},
}
1 change: 1 addition & 0 deletions nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"build:types",
"graphql-codegen:generate:business-platform",
"graphql-codegen:generate:partners",
"graphql-codegen:generate:webhooks",
"graphql-codegen:postfix",
"graphql-codegen:formatting"
],
Expand Down
26 changes: 21 additions & 5 deletions packages/app/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,17 @@
"{projectRoot}/src/cli/api/graphql/business-platform-destinations/generated/**/*.ts",
"{projectRoot}/src/cli/api/graphql/business-platform-organizations/generated/**/*.ts",
"{projectRoot}/src/cli/api/graphql/app-dev/generated/**/*.ts",
"{projectRoot}/src/cli/api/graphql/app-management/generated/**/*.ts"
"{projectRoot}/src/cli/api/graphql/app-management/generated/**/*.ts",
"{projectRoot}/src/cli/api/graphql/webhooks/generated/**/*.ts"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish we had a nicer way to do this but all the plumbing looks great 👌

],
"options": {
"commands": [
"pnpm eslint 'src/cli/api/graphql/partners/generated/**/*.{ts,tsx}' --fix",
"pnpm eslint 'src/cli/api/graphql/business-platform-destinations/generated/**/*.{ts,tsx}' --fix",
"pnpm eslint 'src/cli/api/graphql/business-platform-organizations/generated/**/*.{ts,tsx}' --fix",
"pnpm eslint 'src/cli/api/graphql/app-dev/generated/**/*.{ts,tsx}' --fix",
"pnpm eslint 'src/cli/api/graphql/app-management/generated/**/*.{ts,tsx}' --fix"
"pnpm eslint 'src/cli/api/graphql/app-management/generated/**/*.{ts,tsx}' --fix",
"pnpm eslint 'src/cli/api/graphql/webhooks/generated/**/*.{ts,tsx}' --fix"
],
"cwd": "packages/app"
}
Expand Down Expand Up @@ -137,6 +139,17 @@
"cwd": "{workspaceRoot}"
}
},
"graphql-codegen:generate:webhooks": {
"executor": "nx:run-commands",
"inputs": ["{workspaceRoot}/graphql.config.ts", "{projectRoot}/src/cli/api/graphql/webhooks/**/*.graphql"],
"outputs": ["{projectRoot}/src/cli/api/graphql/webhooks/generated/**/*.ts"],
"options": {
"commands": [
"pnpm exec graphql-codegen --project=webhooks"
],
"cwd": "{workspaceRoot}"
}
},
"graphql-codegen:generate:app-management": {
"executor": "nx:run-commands",
"inputs": ["{workspaceRoot}/graphql.config.ts", "{projectRoot}/src/cli/api/graphql/app-management/**/*.graphql"],
Expand All @@ -155,23 +168,26 @@
"graphql-codegen:generate:business-platform-destinations",
"graphql-codegen:generate:business-platform-organizations",
"graphql-codegen:generate:app-dev",
"graphql-codegen:generate:app-management"
"graphql-codegen:generate:app-management",
"graphql-codegen:generate:webhooks"
],
"inputs": [{ "dependentTasksOutputFiles": "**/*.ts" }],
"outputs": [
"{projectRoot}/src/cli/api/graphql/partners/generated/**/*.ts",
"{projectRoot}/src/cli/api/graphql/business-platform-destinations/generated/**/*.ts",
"{projectRoot}/src/cli/api/graphql/business-platform-organizations/generated/**/*.ts",
"{projectRoot}/src/cli/api/graphql/app-dev/generated/**/*.ts",
"{projectRoot}/src/cli/api/graphql/app-management/generated/**/*.ts"
"{projectRoot}/src/cli/api/graphql/app-management/generated/**/*.ts",
"{projectRoot}/src/cli/api/graphql/webhooks/generated/**/*.ts"
],
"options": {
"commands": [
"find ./packages/app/src/cli/api/graphql/partners/generated/ -type f -name '*.ts' -exec sh -c 'sed -i \"\" \"s|import \\* as Types from '\\''./types'\\'';|import \\* as Types from '\\''./types.js'\\'';|g; s|export const \\([A-Za-z0-9_]*\\)Document =|export const \\1 =|g\" \"$0\"' {} \\;",
"find ./packages/app/src/cli/api/graphql/business-platform-destinations/generated/ -type f -name '*.ts' -exec sh -c 'sed -i \"\" \"s|import \\* as Types from '\\''./types'\\'';|import \\* as Types from '\\''./types.js'\\'';|g; s|export const \\([A-Za-z0-9_]*\\)Document =|export const \\1 =|g\" \"$0\"' {} \\;",
"find ./packages/app/src/cli/api/graphql/business-platform-organizations/generated/ -type f -name '*.ts' -exec sh -c 'sed -i \"\" \"s|import \\* as Types from '\\''./types'\\'';|import \\* as Types from '\\''./types.js'\\'';|g; s|export const \\([A-Za-z0-9_]*\\)Document =|export const \\1 =|g\" \"$0\"' {} \\;",
"find ./packages/app/src/cli/api/graphql/app-dev/generated/ -type f -name '*.ts' -exec sh -c 'sed -i \"\" \"s|import \\* as Types from '\\''./types'\\'';|import \\* as Types from '\\''./types.js'\\'';|g; s|export const \\([A-Za-z0-9_]*\\)Document =|export const \\1 =|g\" \"$0\"' {} \\;",
"find ./packages/app/src/cli/api/graphql/app-management/generated/ -type f -name '*.ts' -exec sh -c 'sed -i \"\" \"s|import \\* as Types from '\\''./types'\\'';|import \\* as Types from '\\''./types.js'\\'';|g; s|export const \\([A-Za-z0-9_]*\\)Document =|export const \\1 =|g\" \"$0\"' {} \\;"
"find ./packages/app/src/cli/api/graphql/app-management/generated/ -type f -name '*.ts' -exec sh -c 'sed -i \"\" \"s|import \\* as Types from '\\''./types'\\'';|import \\* as Types from '\\''./types.js'\\'';|g; s|export const \\([A-Za-z0-9_]*\\)Document =|export const \\1 =|g\" \"$0\"' {} \\;",
"find ./packages/app/src/cli/api/graphql/webhooks/generated/ -type f -name '*.ts' -exec sh -c 'sed -i \"\" \"s|import \\* as Types from '\\''./types'\\'';|import \\* as Types from '\\''./types.js'\\'';|g; s|export const \\([A-Za-z0-9_]*\\)Document =|export const \\1 =|g\" \"$0\"' {} \\;"
],
"cwd": "{workspaceRoot}"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions */
import * as Types from './types.js'

import {TypedDocumentNode as DocumentNode} from '@graphql-typed-document-node/core'

export type AvailableTopicsQueryVariables = Types.Exact<{
apiVersion: Types.Scalars['String']['input']
}>

export type AvailableTopicsQuery = {availableTopics?: string[] | null}

export const AvailableTopics = {
kind: 'Document',
definitions: [
{
kind: 'OperationDefinition',
operation: 'query',
name: {kind: 'Name', value: 'availableTopics'},
variableDefinitions: [
{
kind: 'VariableDefinition',
variable: {kind: 'Variable', name: {kind: 'Name', value: 'apiVersion'}},
type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}}},
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
name: {kind: 'Name', value: 'availableTopics'},
arguments: [
{
kind: 'Argument',
name: {kind: 'Name', value: 'apiVersion'},
value: {kind: 'Variable', name: {kind: 'Name', value: 'apiVersion'}},
},
],
},
],
},
},
],
} as unknown as DocumentNode<AvailableTopicsQuery, AvailableTopicsQueryVariables>
111 changes: 111 additions & 0 deletions packages/app/src/cli/api/graphql/webhooks/generated/cli-testing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions */
import * as Types from './types.js'

import {TypedDocumentNode as DocumentNode} from '@graphql-typed-document-node/core'

export type CliTestingMutationVariables = Types.Exact<{
address: Types.Scalars['String']['input']
apiKey?: Types.InputMaybe<Types.Scalars['String']['input']>
apiVersion: Types.Scalars['String']['input']
deliveryMethod: Types.Scalars['String']['input']
sharedSecret: Types.Scalars['String']['input']
topic: Types.Scalars['String']['input']
}>

export type CliTestingMutation = {
cliTesting?: {headers?: string | null; samplePayload?: string | null; success: boolean; errors: string[]} | null
}

export const CliTesting = {
kind: 'Document',
definitions: [
{
kind: 'OperationDefinition',
operation: 'mutation',
name: {kind: 'Name', value: 'CliTesting'},
variableDefinitions: [
{
kind: 'VariableDefinition',
variable: {kind: 'Variable', name: {kind: 'Name', value: 'address'}},
type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}}},
},
{
kind: 'VariableDefinition',
variable: {kind: 'Variable', name: {kind: 'Name', value: 'apiKey'}},
type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}},
},
{
kind: 'VariableDefinition',
variable: {kind: 'Variable', name: {kind: 'Name', value: 'apiVersion'}},
type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}}},
},
{
kind: 'VariableDefinition',
variable: {kind: 'Variable', name: {kind: 'Name', value: 'deliveryMethod'}},
type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}}},
},
{
kind: 'VariableDefinition',
variable: {kind: 'Variable', name: {kind: 'Name', value: 'sharedSecret'}},
type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}}},
},
{
kind: 'VariableDefinition',
variable: {kind: 'Variable', name: {kind: 'Name', value: 'topic'}},
type: {kind: 'NonNullType', type: {kind: 'NamedType', name: {kind: 'Name', value: 'String'}}},
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
name: {kind: 'Name', value: 'cliTesting'},
arguments: [
{
kind: 'Argument',
name: {kind: 'Name', value: 'address'},
value: {kind: 'Variable', name: {kind: 'Name', value: 'address'}},
},
{
kind: 'Argument',
name: {kind: 'Name', value: 'apiKey'},
value: {kind: 'Variable', name: {kind: 'Name', value: 'apiKey'}},
},
{
kind: 'Argument',
name: {kind: 'Name', value: 'apiVersion'},
value: {kind: 'Variable', name: {kind: 'Name', value: 'apiVersion'}},
},
{
kind: 'Argument',
name: {kind: 'Name', value: 'deliveryMethod'},
value: {kind: 'Variable', name: {kind: 'Name', value: 'deliveryMethod'}},
},
{
kind: 'Argument',
name: {kind: 'Name', value: 'sharedSecret'},
value: {kind: 'Variable', name: {kind: 'Name', value: 'sharedSecret'}},
},
{
kind: 'Argument',
name: {kind: 'Name', value: 'topic'},
value: {kind: 'Variable', name: {kind: 'Name', value: 'topic'}},
},
],
selectionSet: {
kind: 'SelectionSet',
selections: [
{kind: 'Field', name: {kind: 'Name', value: 'headers'}},
{kind: 'Field', name: {kind: 'Name', value: 'samplePayload'}},
{kind: 'Field', name: {kind: 'Name', value: 'success'}},
{kind: 'Field', name: {kind: 'Name', value: 'errors'}},
{kind: 'Field', name: {kind: 'Name', value: '__typename'}},
],
},
},
],
},
},
],
} as unknown as DocumentNode<CliTestingMutation, CliTestingMutationVariables>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions */
import * as Types from './types.js'

import {TypedDocumentNode as DocumentNode} from '@graphql-typed-document-node/core'

export type PublicApiVersionsQueryVariables = Types.Exact<{[key: string]: never}>

export type PublicApiVersionsQuery = {publicApiVersions: {handle: string}[]}

export const PublicApiVersions = {
kind: 'Document',
definitions: [
{
kind: 'OperationDefinition',
operation: 'query',
name: {kind: 'Name', value: 'publicApiVersions'},
selectionSet: {
kind: 'SelectionSet',
selections: [
{
kind: 'Field',
name: {kind: 'Name', value: 'publicApiVersions'},
selectionSet: {
kind: 'SelectionSet',
selections: [
{kind: 'Field', name: {kind: 'Name', value: 'handle'}},
{kind: 'Field', name: {kind: 'Name', value: '__typename'}},
],
},
},
],
},
},
],
} as unknown as DocumentNode<PublicApiVersionsQuery, PublicApiVersionsQueryVariables>
16 changes: 16 additions & 0 deletions packages/app/src/cli/api/graphql/webhooks/generated/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* eslint-disable @typescript-eslint/consistent-type-definitions, @typescript-eslint/naming-convention */
export type Maybe<T> = T | null
export type InputMaybe<T> = Maybe<T>
export type Exact<T extends {[key: string]: unknown}> = {[K in keyof T]: T[K]}
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & {[SubKey in K]?: Maybe<T[SubKey]>}
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & {[SubKey in K]: Maybe<T[SubKey]>}
export type MakeEmpty<T extends {[key: string]: unknown}, K extends keyof T> = {[_ in K]?: never}
export type Incremental<T> = T | {[P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never}
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars = {
ID: {input: string; output: string}
String: {input: string; output: string}
Boolean: {input: boolean; output: boolean}
Int: {input: number; output: number}
Float: {input: number; output: number}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
query availableTopics($apiVersion: String!) {
availableTopics(apiVersion: $apiVersion)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mutation CliTesting($address: String!, $apiKey: String, $apiVersion: String!, $deliveryMethod: String!, $sharedSecret: String!, $topic: String!) {
cliTesting(address: $address, apiKey: $apiKey, apiVersion: $apiVersion, deliveryMethod: $deliveryMethod, sharedSecret: $sharedSecret, topic: $topic) {
headers
samplePayload
success
errors
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
query publicApiVersions {
publicApiVersions {
handle
cdarne marked this conversation as resolved.
Show resolved Hide resolved
}
}
1 change: 1 addition & 0 deletions packages/app/src/cli/commands/app/webhook/trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export default class WebhookTrigger extends AppCommand {
clientSecret: flags['client-secret'] || flags['shared-secret'],
path: flags.path,
config: flags.config,
organizationId: appContextResult.organization.id,
}

await webhookTriggerService(usedFlags)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export async function setupDevProcesses({
webs: reloadedApp.webs,
backendPort: network.backendPort,
frontendPort: network.frontendPort,
organizationId: remoteApp.organizationId,
developerPlatformClient,
storeFqdn,
apiSecret,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface SendWebhookOptions {
storeFqdn: string
apiSecret: string
webhooksPath: string
organizationId: string
}

export interface SendWebhookProcess extends BaseProcess<SendWebhookOptions> {
Expand All @@ -23,6 +24,7 @@ export const sendWebhook: DevProcessFunction<SendWebhookOptions> = async ({stdou
address: `http://localhost:${options.deliveryPort}${options.webhooksPath}`,
sharedSecret: options.apiSecret,
storeFqdn: options.storeFqdn,
organizationId: options.organizationId,
})
}

Expand All @@ -31,12 +33,14 @@ export function setupSendUninstallWebhookProcess({
remoteAppUpdated,
backendPort,
frontendPort,
organizationId,
...options
}: Pick<SendWebhookOptions, 'developerPlatformClient' | 'storeFqdn' | 'apiSecret'> & {
remoteAppUpdated: boolean
backendPort: number
frontendPort: number
webs: Web[]
organizationId: string
}): SendWebhookProcess | undefined {
const {backendConfig, frontendConfig} = frontAndBackendConfig(webs)
const webhooksPath =
Expand All @@ -52,6 +56,7 @@ export function setupSendUninstallWebhookProcess({
options: {
deliveryPort: backendConfig ? backendPort : frontendPort,
webhooksPath,
organizationId,
...options,
},
}
Expand Down
Loading