diff --git a/packages/cli/src/commands/experimental/templates/liveQueries/auctions/auctions.sdl.ts.template b/packages/cli/src/commands/experimental/templates/liveQueries/auctions/auctions.sdl.ts.template index f68d689eb9b9..791ed36e3d49 100644 --- a/packages/cli/src/commands/experimental/templates/liveQueries/auctions/auctions.sdl.ts.template +++ b/packages/cli/src/commands/experimental/templates/liveQueries/auctions/auctions.sdl.ts.template @@ -2,7 +2,7 @@ export const schema = gql` type Query { - auction(id: ID!): Auction @skipAuth + auction(id: ID!): Auction @requireAuth } type Auction { @@ -17,7 +17,7 @@ export const schema = gql` } type Mutation { - bid(input: BidInput!): Bid @skipAuth + bid(input: BidInput!): Bid @requireAuth } input BidInput { diff --git a/packages/cli/src/commands/experimental/templates/liveQueries/auctions/auctions.ts.template b/packages/cli/src/commands/experimental/templates/liveQueries/auctions/auctions.ts.template index 5b9c70c8b2a8..88e6ae7c56e1 100644 --- a/packages/cli/src/commands/experimental/templates/liveQueries/auctions/auctions.ts.template +++ b/packages/cli/src/commands/experimental/templates/liveQueries/auctions/auctions.ts.template @@ -1,4 +1,5 @@ // api/src/services/auctions/auctions.ts +import type { LiveQueryStorageMechanism } from '@redwoodjs/graphql-server' import { logger } from 'src/lib/logger' @@ -40,7 +41,10 @@ export const auction = async ({ id }) => { return foundAuction } -export const bid = async ({ input }, { context }) => { +export const bid = async ( + { input }, + { context }: { context: { liveQueryStore: LiveQueryStorageMechanism } } +) => { const { auctionId, amount } = input const index = auctions.findIndex((a) => a.id === auctionId) diff --git a/packages/cli/src/commands/experimental/templates/liveQueries/blank/blank.sdl.ts.template b/packages/cli/src/commands/experimental/templates/liveQueries/blank/blank.sdl.ts.template index 4c6e8ae7e023..a373de5f7d77 100644 --- a/packages/cli/src/commands/experimental/templates/liveQueries/blank/blank.sdl.ts.template +++ b/packages/cli/src/commands/experimental/templates/liveQueries/blank/blank.sdl.ts.template @@ -2,7 +2,7 @@ export const schema = gql` type Query { - ${liveQueryName}(id: ID!): ${typeName} @skipAuth + ${liveQueryName}(id: ID!): ${typeName} @requireAuth } type ${typeName} { @@ -17,7 +17,7 @@ export const schema = gql` } type Mutation { - create${typeName}Item(input: ${typeName}ItemInput!): ${typeName}Item @skipAuth + create${typeName}Item(input: ${typeName}ItemInput!): ${typeName}Item @requireAuth } input ${typeName}ItemInput { diff --git a/packages/cli/src/commands/experimental/templates/liveQueries/blank/blank.service.ts.template b/packages/cli/src/commands/experimental/templates/liveQueries/blank/blank.service.ts.template index c5b502b2f23d..7c25504efdb5 100644 --- a/packages/cli/src/commands/experimental/templates/liveQueries/blank/blank.service.ts.template +++ b/packages/cli/src/commands/experimental/templates/liveQueries/blank/blank.service.ts.template @@ -1,4 +1,5 @@ // api/src/services/${name}s/${name}s.ts +import type { LiveQueryStorageMechanism } from '@redwoodjs/graphql-server' import { logger } from 'src/lib/logger' @@ -40,7 +41,10 @@ export const ${liveQueryName} = async ({ id }) => { return found${modelName} } -export const create${typeName}Item = async ({ input }, { context }) => { +export const create${typeName}Item = async ( + { input }, + { context }: { context: { liveQueryStore: LiveQueryStorageMechanism } } +) => { const { ${camelName}Id, amount } = input const index = ${collectionName}.findIndex((a) => a.id === ${camelName}Id) diff --git a/packages/cli/src/commands/experimental/templates/subscriptions/blank/blank.ts.template b/packages/cli/src/commands/experimental/templates/subscriptions/blank/blank.ts.template index 233b9cf54843..341f9752d2de 100644 --- a/packages/cli/src/commands/experimental/templates/subscriptions/blank/blank.ts.template +++ b/packages/cli/src/commands/experimental/templates/subscriptions/blank/blank.ts.template @@ -6,7 +6,7 @@ import { logger } from 'src/lib/logger' export const schema = gql` type Subscription { - ${subscriptionName}(id: ID!): ${typeName}! + ${subscriptionName}(id: ID!): ${typeName}! @requireAuth } ` diff --git a/packages/cli/src/commands/experimental/templates/subscriptions/countdown/countdown.ts.template b/packages/cli/src/commands/experimental/templates/subscriptions/countdown/countdown.ts.template index eb563135d3aa..ff46abf1fdd0 100644 --- a/packages/cli/src/commands/experimental/templates/subscriptions/countdown/countdown.ts.template +++ b/packages/cli/src/commands/experimental/templates/subscriptions/countdown/countdown.ts.template @@ -2,7 +2,7 @@ import gql from 'graphql-tag' export const schema = gql` type Subscription { - countdown(from: Int!, interval: Int!): Int! + countdown(from: Int!, interval: Int!): Int! @requireAuth } ` diff --git a/packages/cli/src/commands/experimental/templates/subscriptions/newMessage/newMessage.ts.template b/packages/cli/src/commands/experimental/templates/subscriptions/newMessage/newMessage.ts.template index 4641159d0b90..5799226ba01e 100644 --- a/packages/cli/src/commands/experimental/templates/subscriptions/newMessage/newMessage.ts.template +++ b/packages/cli/src/commands/experimental/templates/subscriptions/newMessage/newMessage.ts.template @@ -6,7 +6,7 @@ import { logger } from 'src/lib/logger' export const schema = gql` type Subscription { - newMessage(roomId: ID!): Message! + newMessage(roomId: ID!): Message! @requireAuth } ` export type NewMessageChannel = { diff --git a/packages/graphql-server/src/index.ts b/packages/graphql-server/src/index.ts index 27dd921170ec..34c4b8f5487e 100644 --- a/packages/graphql-server/src/index.ts +++ b/packages/graphql-server/src/index.ts @@ -34,8 +34,9 @@ export { export { useRedwoodRealtime, createPubSub, - InMemoryLiveQueryStore, liveDirectiveTypeDefs, + InMemoryLiveQueryStore, + LiveQueryStorageMechanism, RedisLiveQueryStore, RedwoodRealtimeOptions, PublishClientType, diff --git a/packages/graphql-server/src/plugins/useRedwoodDirective.ts b/packages/graphql-server/src/plugins/useRedwoodDirective.ts index dbf150b60fc2..bf8bcfbc67cf 100644 --- a/packages/graphql-server/src/plugins/useRedwoodDirective.ts +++ b/packages/graphql-server/src/plugins/useRedwoodDirective.ts @@ -154,7 +154,11 @@ function wrapAffectedResolvers( if (directiveNode && directive) { const directiveArgs = getDirectiveValues(directive, { directives: [directiveNode] }) || {} + const originalResolve = fieldConfig.resolve ?? defaultFieldResolver + // Only validator directives handle a subscribe function + const originalSubscribe = fieldConfig.subscribe ?? defaultFieldResolver + if (_isValidator(options)) { return { ...fieldConfig, @@ -180,6 +184,28 @@ function wrapAffectedResolvers( } return originalResolve(root, args, context, info) }, + subscribe: function useRedwoodDirectiveValidatorResolver( + root, + args, + context, + info + ) { + const result = options.onResolvedValue({ + root, + args, + context, + info, + directiveNode, + directiveArgs, + }) + + if (isPromise(result)) { + return result.then(() => + originalSubscribe(root, args, context, info) + ) + } + return originalSubscribe(root, args, context, info) + }, } } if (_isTransformer(options)) { diff --git a/packages/internal/src/validateSchema.ts b/packages/internal/src/validateSchema.ts index 2d60ec72f982..613ccf2ee437 100644 --- a/packages/internal/src/validateSchema.ts +++ b/packages/internal/src/validateSchema.ts @@ -13,7 +13,7 @@ export const DIRECTIVE_INVALID_ROLE_TYPES_ERROR_MESSAGE = 'Please check that the requireAuth roles is a string or an array of strings.' export function validateSchemaForDirectives( schemaDocumentNode: DocumentNode, - typesToCheck: string[] = ['Query', 'Mutation'] + typesToCheck: string[] = ['Query', 'Mutation', 'Subscription'] ) { const validationOutput: string[] = [] const directiveRoleValidationOutput: Record = [] @@ -106,7 +106,11 @@ export function validateSchemaForDirectives( export const loadAndValidateSdls = async () => { const projectTypeSrc = await loadTypedefs( - ['graphql/**/*.sdl.{js,ts}', 'directives/**/*.{js,ts}'], + [ + 'graphql/**/*.sdl.{js,ts}', + 'directives/**/*.{js,ts}', + 'subscriptions/**/*.{js,ts}', + ], { loaders: [ new CodeFileLoader({