-
-
Notifications
You must be signed in to change notification settings - Fork 179
Description
Hi,
when using the .authField method, using the args variable in the function passed to authScopes causes type instantiation to go infinite. The docs seem to suggest such a thing should be possible, but the only example is on the t.exposeInt method, which results in the args being untyped. I am currently working around it by using the .withAuth method and manually casting the args to the desired type.
In most cases I would put the authScope requirement on the actual Type itself. However when it comes to mutations, I need to know ahead of time because the mutation will do many different things, and may not even return an object until after it has been modified.
Is there any way to automatically get the typing from the args of the field so that I can cast to it safely? If not, is it possible to use a shared type for both the args on the field and the args on authScopes/.withAuth? Could this be done by building the args separately to the authScopes? (if that is possible)
I have some example code showing the situation:
Builder:
// authScopes on my builder
export const builder = new SchemaBuilder<{
...
PrismaTypes: PrismaTypes;
AuthScopes: {
"organisation:staff": string
},
...
}>({
...
plugins: [ScopeAuthPlugin, PrismaPlugin],
prisma: {
client: prisma,
},
scopeAuth: {
authScopes: async (context) => ({
"organisation:staff": (organisationId) => context.permissionService.isOrganisationStaff({ userId: context.user.id, organisationId }),
})
},
...
});
builder.mutationType({});
builder.queryType({});Errors with 'Type instantiation is excessively deep and possibly infinite.':
// Errors with 'Type instantiation is excessively deep and possibly infinite.'
builder.mutationField("updateOrganisationDescription", (t) =>
t.authField({
type: "Organisation",
args: {
organisationId: t.input.string({ required: true }),
description: t.input.string({ required: true }),
},
authScopes: (parent, args) => ({
"organisation:staff": args.organisationId,
}),
resolve: async (_root, _args, _ctx, _info) => {
return prisma.organisation.update({
where: { id: _args.organisationId },
data: { description: _args.description },
});
},
})
);Examples using the .withAuth method instead:
//Examples using the `.withAuth` method instead:
t.withAuth((parent, args) => ({ //args: Record<string, unknown>
"organisation:staff": args.organisationId, // Error: Type 'unknown' is not assignable to type 'string | undefined'
}))
t.withAuth((parent, args: Record<string, string>) => ({ // Error: Type 'unknown' is not assignable to type 'string'
"organisation:staff": args.organisationId,
}))
t.withAuth((parent, args: { organisationId: string; description: string }) => ({ // Error: Types of parameters 'args' and 'args' are incompatible.
"organisation:staff": args.organisationId,
}))Current workaround is using .withAuth and then manually casting the args to go into the scopeloader:
builder.mutationField("updateOrganisationDescription", (t) =>
t.withAuth((parent, args) => ({ //args: Record<string, unknown>
"organisation:staff": args.organisationId as string, // Current workaround, have to manually cast to string to use this authScope.
}))
.prismaField({
type: "Organisation",
args: {
organisationId: t.input.string({ required: true }),
description: t.input.string({ required: true }),
},
resolve: async (_query, _root, _args, _ctx, _info) => {
return prisma.organisation.update({
..._query,
where: { id: _args.organisationId },
data: { description: _args.description },
});
},
})
);