Skip to content

Conversation

@kingston
Copy link
Collaborator

@kingston kingston commented Nov 20, 2025

Summary by CodeRabbit

  • New Features

    • GraphQL now includes Pothos validation plugin support for runtime input validation.
    • Data operations and field APIs expose runtime Zod schemas ($dataSchema) for richer validation and tooling.
  • Improvements

    • Input validation moved into schema builders, simplifying mutation payload handling.
    • Field definitions gained schema-aware typings and optional input transformation support.
    • Removed custom null-restriction utilities in favor of schema-driven validation.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Nov 20, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
baseplate-project-builder-web Error Error Nov 20, 2025 3:25pm

@changeset-bot
Copy link

changeset-bot bot commented Nov 20, 2025

🦋 Changeset detected

Latest commit: fb435cc

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 18 packages
Name Type
@baseplate-dev/fastify-generators Patch
@baseplate-dev/project-builder-server Patch
@baseplate-dev/plugin-auth Patch
@baseplate-dev/plugin-queue Patch
@baseplate-dev/plugin-storage Patch
@baseplate-dev/project-builder-cli Patch
@baseplate-dev/project-builder-common Patch
@baseplate-dev/project-builder-test Patch
@baseplate-dev/project-builder-web Patch
@baseplate-dev/create-project Patch
@baseplate-dev/code-morph Patch
@baseplate-dev/core-generators Patch
@baseplate-dev/project-builder-lib Patch
@baseplate-dev/react-generators Patch
@baseplate-dev/sync Patch
@baseplate-dev/tools Patch
@baseplate-dev/ui-components Patch
@baseplate-dev/utils Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link

coderabbitai bot commented Nov 20, 2025

Walkthrough

Integrates Pothos ValidationPlugin and replaces runtime restrictObjectNulls with Zod-based schemas attached to create/update operation functions; updates field definitions, Pothos plugin types, generator templates, writers, and example projects to propagate and use $dataSchema and skipValidation flags.

Changes

Cohort / File(s) Summary
Changesets
​.changeset/flat-buckets-make.md, ​.changeset/twelve-readers-fail.md
Two patch changesets documenting validation plugin support and schema-related fixes.
Examples — removed utils & tests
examples/*/apps/backend/src/utils/nulls.ts, examples/*/apps/backend/src/utils/normalize-types.ts, examples/*/apps/backend/src/utils/nulls.unit.test.ts, examples/*/apps/backend/baseplate/file-id-map.json, examples/*/apps/backend/src/utils/.templates-info.json
Deleted restrictObjectNulls, NormalizeTypes, associated test, and removed corresponding file-id-map/.templates entries.
Example deps & builder
examples/*/apps/backend/package.json, examples/*/apps/backend/src/plugins/graphql/builder.ts
Added @pothos/[email protected] and registered ValidationPlugin in SchemaBuilder plugins.
Generators — add ValidationPlugin & FASTIFY_PACKAGES
packages/fastify-generators/src/constants/fastify-packages.ts, packages/fastify-generators/src/generators/pothos/pothos/pothos.generator.ts
Added @pothos/plugin-validation to FASTIFY_PACKAGES and generator default plugins/nodePackages.
Data operations — types & define-operations
examples/*/apps/backend/src/utils/data-operations/types.ts, .../define-operations.ts, packages/.../define-operations.ts
Reworked FieldDefinition to accept Zod schema (TInputSchema), added schema member, introduced InferInputSchema, generateCreateSchema, Create/UpdateOperationFunction types with $dataSchema, and skipValidation handling; operations now validate via generated Zod schemas.
Field definitions
examples/*/apps/backend/src/utils/data-operations/field-definitions.ts, packages/.../field-definitions.ts
scalarField gains optional transform generic/arg and schema property; nestedOneToOne/Many types changed to Zod-based schemas and expose schema.
File field updates
examples/todo-with-auth0/.../file-field.ts, plugins/plugin-storage/.../file-field.ts
Introduced fileInputSchema and FileInput = z.infer<typeof fileInputSchema>; updated fileField types to expose conditional Zod schema and accept zod-inferred input.
Mutations — input validation wiring
examples/*/apps/backend/src/modules/**/schema/*mutations.ts
Replaced restrictObjectNulls sanitization with direct data passing; input types now chain .validate(operation.$dataSchema); resolvers pass skipValidation: true.
FieldWithInputPayloadPlugin types
examples/*/apps/backend/src/plugins/graphql/FieldWithInputPayloadPlugin/types.ts, packages/.../types.ts
Added exported PayloadFieldRef<Types,T> (Omit of FieldRef without validate) and updated PayloadFields generic usage to use PayloadFieldRef.
FieldWithInputPayloadPlugin builder/global types
examples/*/apps/backend/src/plugins/graphql/FieldWithInputPayloadPlugin/{global-types.ts,schema-builder.ts}, packages/.../templates/.../{global-types.ts,schema-builder.ts}
Imported PayloadFieldRef, changed PayloadFields constraint, updated nullability to Types['DefaultFieldNullability'], tightened resolve guard and fieldRef casting, and added eslint-safe handlers.
Generator extractor config
packages/fastify-generators/src/generators/pothos/pothos/extractor.json
Added referencedGeneratorTemplates to field-with-input-schema-builder config.
Prisma data generators
packages/fastify-generators/src/generators/prisma/prisma-data-create/*.ts, prisma-data-update/*.ts
Added methodFragment usage, injected skipValidation arg, and threaded zodSchemaFragment referencing ${methodFragment}.$dataSchema into nested DTOs.
Service output types
packages/fastify-generators/src/types/service-output.ts
Added optional zodSchemaFragment?: TsCodeFragment to ServiceOutputDtoNestedFieldWithoutPrisma.
Pothos writers — input-types & resolvers
packages/fastify-generators/src/writers/pothos/input-types.ts, packages/.../resolvers.ts
writePothosInputDefinitionFromDtoFields gained optional suffix?: TsCodeFragment; writers now pass zod-schema suffix when present. Added NestedArgContext with isValidatedField, threaded through nested arg conversion to avoid restrictObjectNulls for validated fields.
Prisma templates — data-utils & templates
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/*
Template variants of the data-operations/types, define-operations, and field-definitions updated to match Zod-based APIs and expose $dataSchema on generated operation functions.
Injected arg kinds & pocked handlers
packages/fastify-generators/src/types/service-dto-kinds.ts, packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/*.ts
Added skipValidationKind (createServiceDtoKind('skip-validation')) and handling in injected-arg dispatcher to emit a literal true fragment for skipValidation.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant GraphQL as Pothos InputType
    participant PothosVal as Validation Plugin
    participant Operation as Create/Update Operation
    participant Service as Application Service

    Client->>GraphQL: submit mutation with data
    GraphQL->>PothosVal: .validate(operation.$dataSchema)
    PothosVal->>PothosVal: Zod parse/check
    alt validation succeeds
        PothosVal->>Operation: pass validatedData
        Operation->>Operation: apply transforms / prepareComputedFields (uses validatedData)
        Operation->>Service: call service with skipValidation flag (if upstream validated)
        Service->>Client: return result
    else validation fails
        PothosVal->>Client: return validation errors
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Heterogeneous, cross-cutting changes across examples, generator templates, type definitions, and writers.
  • Areas needing focused review:
    • Zod-based type redesign in data-operations/types.ts and consistency of InferInputSchema usage.
    • Generator wiring for $dataSchema exposure (prisma create/update generators) and injected skipValidation handling.
    • Pothos writers/resolvers changes (NestedArgContext, bypass logic for validated fields).
    • FieldWithInputPayloadPlugin typing/nullability adjustments and PayloadFieldRef correctness.
    • Example mutation changes to ensure runtime behavior (skipValidation and removed restrictObjectNulls) remain correct.

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: replacing restrictObjectNulls with Zod schema-based validation in mutations for cleaner code.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch kingston/eng-673-optimize-nullundefined-in-pothos

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@socket-security
Copy link

socket-security bot commented Nov 20, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​pothos/​plugin-validation@​4.2.0100100100100100

View full report

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts (2)

192-245: FieldDefinition docs/example are out of sync with the interface (schema + validated input)

Two mismatches here:

  • The interface exposes a schema: TInputSchema, but the example still uses zodSchema.
  • processInput now receives value: z.output<TInputSchema>, i.e. an already‑validated value, yet the example re‑parses with a fresh z.string().min(1).parse(value) and ignores schema.

To keep the docs aligned with the actual contract, consider something like:

- * - Validate the input value using a Zod schema
+ * - Define the Zod schema used to validate this field's input
...
- * const nameField: FieldDefinition<z.ZodString, string, string> = {
- *   zodSchema: z.string().min(1),
- *   processInput: (value, ctx) => {
- *     const validated = z.string().min(1).parse(value);
- *
- *     return {
- *       data: {
- *         create: validated,
- *         update: validated,
- *       },
- *     };
- *   },
- * };
+ * const nameField: FieldDefinition<z.ZodString, string, string> = {
+ *   schema: z.string().min(1),
+ *   processInput: (value) => ({
+ *     data: {
+ *       create: value,
+ *       update: value,
+ *     },
+ *   }),
+ * };

This makes it clear that the pipeline handles validation using schema, and processInput works with the already‑validated value.


295-318: Update InferInput docs to describe Zod output types instead of “schema types”

InferInput is now defined as:

export type InferInput<TFields extends Record<string, AnyFieldDefinition>> =
  z.output<InferInputSchema<TFields>>;

So each property is the Zod output type (e.g. string), not “the field's Zod schema type” as stated in the bullet:

 * - Each value type is the field's Zod schema type

It would be clearer to rephrase to something like:

 * - Each value type is the Zod output type for that field's schema

The example { name: string; email?: string | undefined } then matches both the implementation and the description.

examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts (1)

193-245: FieldDefinition JSDoc example is out of sync with the new schema property

The interface now exposes schema: TInputSchema, but the example in the JSDoc still shows a zodSchema property and manually reparses value. To avoid confusion for consumers, I’d align the example with the current API and the new type of value:

- * const nameField: FieldDefinition<z.ZodString, string, string> = {
- *   zodSchema: z.string().min(1),
- *   processInput: (value, ctx) => {
- *     const validated = z.string().min(1).parse(value);
- *
- *     return {
- *       data: {
- *         create: validated,
- *         update: validated,
- *       },
- *     };
- *   },
- * };
+ * const nameField: FieldDefinition<z.ZodString, string, string> = {
+ *   schema: z.string().min(1),
+ *   processInput: (value, ctx) => {
+ *     // `value` is already typed as the schema's output
+ *     return {
+ *       data: {
+ *         create: value,
+ *         update: value,
+ *       },
+ *     };
+ *   },
+ * };

As per coding guidelines

examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts (2)

295-317: Correct documentation for InferInput type to accurately describe runtime types produced by z.output

The review comment is accurate. Line 300's bullet describes "the field's Zod schema type," but InferInput uses z.output<InferInputSchema<TFields>> which produces runtime output types, not schema types. The example comment at line 313 already correctly shows runtime types ({ name: string; email?: string | undefined }), but the descriptive bullet contradicts this.

Update line 300 from:

  • "Each value type is the field's Zod schema type"

To:

  • "Each value type is the field's runtime type inferred from its Zod schema"

This aligns the documentation with the actual behavior of z.output.


192-245: Update FieldDefinition example to match the schema property and current patterns

The example at lines 206-217 uses zodSchema but the interface defines schema (line 230). Additionally, the example unnecessarily re-parses the value, contradicting the interface signature where value: z.output<TInputSchema> is already validated output.

Update the example to:

  • Replace zodSchema with schema
  • Simplify processInput to work with the pre-validated value
  • Optionally show how ctx.skipValidation can be checked if needed
-const nameField: FieldDefinition<z.ZodString, string, string> = {
-  zodSchema: z.string().min(1),
-  processInput: (value, ctx) => {
-    const validated = z.string().min(1).parse(value);
+const nameField: FieldDefinition<z.ZodString, string, string> = {
+  schema: z.string().min(1),
+  processInput: (value, ctx) => {
+    const validated = value;
     return {
       data: {
         create: validated,
         update: validated,
       },
     };
🧹 Nitpick comments (10)
packages/fastify-generators/src/writers/pothos/resolvers.ts (2)

18-23: Export the NestedArgContext interface.

As per coding guidelines, interfaces and types should be exported. This also improves reusability and allows other modules to reference this type if needed.

Apply this diff:

-interface NestedArgContext {
+export interface NestedArgContext {
   /**
    * If the field is validated, we can skip the restrictObjectNulls call.
    */
   isValidatedField?: boolean;
 }

Based on coding guidelines.


100-100: Prefer explicit boolean conversion for clarity.

The current expression could result in isValidatedField being undefined when both arg.zodSchemaFragment is falsy and context.isValidatedField is undefined. While this works correctly in the boolean context on line 110, explicit boolean conversion improves clarity and aligns with the coding guideline to prefer ?? over ||.

Consider one of these alternatives:

-  const isValidatedField = !!arg.zodSchemaFragment || context.isValidatedField;
+  const isValidatedField = !!arg.zodSchemaFragment || (context.isValidatedField ?? false);

Or:

-  const isValidatedField = !!arg.zodSchemaFragment || context.isValidatedField;
+  const isValidatedField = !!arg.zodSchemaFragment || !!context.isValidatedField;

Based on coding guidelines.

plugins/plugin-storage/src/generators/fastify/storage-module/templates/module/services/file-field.ts (1)

3-10: Move external library import to the top of the import block.

The zod import should be placed before local imports, per the coding guidelines.

As per coding guidelines.

Apply this diff to fix the import ordering:

+import z from 'zod';
+
 import type { FileCategory } from '$typesFileCategory';
 import type { FieldDefinition } from '%dataUtilsImports';
 import type { Prisma } from '%prismaGeneratedImports';
 
 import { STORAGE_ADAPTERS } from '$configAdapters';
 import { BadRequestError } from '%errorHandlerServiceImports';
 import { prisma } from '%prismaImports';
-import z from 'zod';
examples/blog-with-auth/apps/backend/src/modules/accounts/schema/user.mutations.ts (2)

22-38: Consider adding JSDoc and explicit return type per coding guidelines.

Per the coding guidelines, exported functions should include JSDoc documentation and explicit return types. While Pothos infers types for mutation fields, consider adding JSDoc above the mutation definition to document its purpose, parameters, and return value.

Based on coding guidelines.


50-68: Consider adding JSDoc and explicit return type per coding guidelines.

Per the coding guidelines, exported functions should include JSDoc documentation and explicit return types. Consider adding JSDoc above the mutation definition to document its purpose, parameters, and return value.

Based on coding guidelines.

examples/todo-with-auth0/apps/backend/src/modules/accounts/users/schema/user.mutations.ts (2)

63-79: Consider adding JSDoc and explicit return type per coding guidelines.

Per the coding guidelines for this path (examples/todo-with-auth0/apps/backend/src/**/*.{ts,tsx}), all exported functions should include JSDoc documenting purpose, parameters, returns, and fields. Consider adding documentation above the mutation definition.

Based on coding guidelines.


94-112: Consider adding JSDoc and explicit return type per coding guidelines.

Per the coding guidelines for this path, exported functions should include JSDoc documenting purpose, parameters, returns, and fields. Consider adding documentation above the mutation definition.

Based on coding guidelines.

examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts (1)

86-103: Align schema’s runtime value with its conditional Zod type

The new conditional type for the first FieldDefinition generic and the schema property is good in principle, but right now both branches share the same runtime instance (fileInputSchema), and only the type changes via as. If anything downstream relies on Zod’s runtime optional/nullable behavior (e.g., schema.parse(null) succeeding for optional fields), this will not work as expected.

Consider constructing an actual optional/nullable schema when config.optional is set, and keep the conditional type for TS:

   return {
-    schema: fileInputSchema as TOptional extends true
-      ? z.ZodOptional<z.ZodNullable<typeof fileInputSchema>>
-      : typeof fileInputSchema,
+    schema: (config.optional
+      ? fileInputSchema.nullable().optional()
+      : fileInputSchema) as TOptional extends true
+      ? z.ZodOptional<z.ZodNullable<typeof fileInputSchema>>
+      : typeof fileInputSchema,
     processInput: async (
       value: z.infer<typeof fileInputSchema> | null | undefined,
       processCtx,
     ) => {

This keeps the generic typing you introduced but also makes the runtime schema genuinely accept null/undefined for the optional case.

packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts (1)

256-262: Consider exporting Identity to align with the “export all types” guideline

Per the coding guidelines, interfaces and types in *.ts files should be exported. Identity<T> is currently internal; if it’s intended for consumers (and it is already used in public utility types), it would be clearer to mark it as exported:

-type Identity<T> = T extends object
+export type Identity<T> = T extends object

If you prefer to keep it internal, we might want to revisit the guideline or rename it to signal non‑exported/private usage.

packages/fastify-generators/src/writers/pothos/input-types.ts (1)

56-75: Consider adding an explicit return type to match TS style guidelines

Since this exported helper is widely used, it would be nice to explicitly annotate its return type as PothosTypeDefinitionWithVariableName rather than relying on inference:

-export function writePothosInputDefinitionFromDtoFields(
+export function writePothosInputDefinitionFromDtoFields(
   name: string,
   fields: ServiceOutputDtoField[],
   options: PothosWriterOptions,
   shouldExport?: boolean,
   suffix?: TsCodeFragment,
-): PothosTypeDefinitionWithVariableName {
+): PothosTypeDefinitionWithVariableName {

As per coding guidelines

Comment on lines +345 to +352
type CreateOperationFunction<
TModelName extends ModelPropName,
TFields extends Record<string, AnyFieldDefinition>,
> = (<TQueryArgs extends ModelQuery<TModelName>>(
input: CreateOperationInput<TModelName, TFields, TQueryArgs>,
) => Promise<GetPayload<TModelName, TQueryArgs>>) & {
$dataSchema: InferInputSchema<TFields>;
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Export CreateOperationFunction and type createOperation so $dataSchema is type-checked

Two points here:

  1. CreateOperationFunction is currently file-local. Given the intent to expose this as part of the public API and the guideline to export interfaces/types, it should be exported.

  2. createOperation is inferred as a bare generic function, so createOperation.$dataSchema = … won’t type-check (property $dataSchema doesn’t exist on the inferred function type). Either annotate createOperation with CreateOperationFunction or cast before attaching the property.

A minimal fix:

-export interface CreateOperationInput<
+export interface CreateOperationInput<
@@
-}
-
-type CreateOperationFunction<
+}
+
+export type CreateOperationFunction<
@@
->: (<TQueryArgs extends ModelQuery<TModelName>>(
+> = (<TQueryArgs extends ModelQuery<TModelName>>(
   input: CreateOperationInput<TModelName, TFields, TQueryArgs>,
 ) => Promise<GetPayload<TModelName, TQueryArgs>>) & {
   $dataSchema: InferInputSchema<TFields>;
 };
@@
 export function defineCreateOperation<
@@
 >(
   config: CreateOperationConfig<TModelName, TFields, TPrepareResult>,
-): CreateOperationFunction<TModelName, TFields> {
-  const createOperation = async <TQueryArgs extends ModelQuery<TModelName>>({
+): CreateOperationFunction<TModelName, TFields> {
+  const createOperation: CreateOperationFunction<TModelName, TFields> =
+    async <TQueryArgs extends ModelQuery<TModelName>>({
@@
-  }: CreateOperationInput<TModelName, TFields, TQueryArgs>): Promise<
-    GetPayload<TModelName, TQueryArgs>
-  > => {
+    }: CreateOperationInput<TModelName, TFields, TQueryArgs>): Promise<
+      GetPayload<TModelName, TQueryArgs>
+    > => {
@@
-  };
+    };
   createOperation.$dataSchema = generateCreateSchema(config.fields);
   return createOperation;
 }

This keeps runtime behavior while making the $dataSchema contract explicit.

Also applies to: 398-415, 509-510


I'll verify the review comment by examining the file content at the specified locations.


🏁 Script executed:

#!/bin/bash
# Examine the primary location (lines 345-352)
echo "=== PRIMARY LOCATION (lines 345-352) ==="
sed -n '340,360p' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

# Examine secondary locations (lines 398-415 and 509-510)
echo -e "\n=== SECONDARY LOCATION (lines 398-415) ==="
sed -n '395,420p' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

echo -e "\n=== SECONDARY LOCATION (lines 509-510) ==="
sed -n '505,515p' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

# Check if CreateOperationFunction is exported anywhere in the file
echo -e "\n=== SEARCHING FOR CreateOperationFunction EXPORT ==="
rg -n 'export.*CreateOperationFunction' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

Length of output: 2008


The output confirms the review comment. Let me verify the similar patterns in the other operation types:


🏁 Script executed:

#!/bin/bash
# Check for UpdateOperationFunction
echo "=== SEARCHING FOR UpdateOperationFunction ==="
rg -n -B2 'type UpdateOperationFunction' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

# Check for DeleteOperationFunction
echo -e "\n=== SEARCHING FOR DeleteOperationFunction ==="
rg -n -B2 'type DeleteOperationFunction' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

# Check for any exported operation function types
echo -e "\n=== SEARCHING FOR ALL OPERATION FUNCTION TYPES ==="
rg -n 'type.*OperationFunction' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

# Check defineUpdateOperation and defineDeleteOperation similar patterns
echo -e "\n=== CHECKING defineUpdateOperation ==="
rg -n -A20 'export function defineUpdateOperation' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts | head -30

echo -e "\n=== CHECKING defineDeleteOperation ==="
rg -n -A20 'export function defineDeleteOperation' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts | head -30

Length of output: 2119



🏁 Script executed:

#!/bin/bash
# Get full UpdateOperationFunction definition
echo "=== UpdateOperationFunction DEFINITION ==="
sed -n '611,630p' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

# Get full context around updateOperation assignment
echo -e "\n=== updateOperation ASSIGNMENT IN defineUpdateOperation ==="
sed -n '675,685p' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

# Check where updateOperation.$dataSchema is assigned
echo -e "\n=== updateOperation.\$dataSchema ASSIGNMENT ==="
rg -n 'updateOperation\.\$dataSchema' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

# Check line 509-510 more precisely to see context
echo -e "\n=== CONTEXT FOR 509-510 ==="
sed -n '505,512p' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

# Get line numbers for updateOperation.$dataSchema assignment
echo -e "\n=== ALL DATASCHEMA ASSIGNMENTS ==="
rg -n '\$dataSchema' examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts

Length of output: 1931


Export CreateOperationFunction and UpdateOperationFunction, and add explicit type annotations to the operation variables

Two related issues affecting the create and update operations:

  1. CreateOperationFunction (line 345) and UpdateOperationFunction (line 611) are not exported. Given the intent to expose these as part of the public API and the guideline to export types, both should be exported.

  2. createOperation (lines ~412) and updateOperation (line 676) are inferred as bare async functions, so assigning $dataSchema won't type-check (property doesn't exist on the inferred function type). Annotate both with their respective types before attaching the property.

Minimal fix pattern:

  • Export both operation function types
  • Add type annotation: const createOperation: CreateOperationFunction<TModelName, TFields> = async ...
  • Add type annotation: const updateOperation: UpdateOperationFunction<TModelName, TFields> = async ...

This makes the $dataSchema contract explicit and enables proper type-checking.

🤖 Prompt for AI Agents
In
examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts
around lines 345-352 and 611-676, the type aliases CreateOperationFunction and
UpdateOperationFunction must be exported and the createOperation and
updateOperation variables must be explicitly typed so attaching $dataSchema
typechecks: export both CreateOperationFunction and UpdateOperationFunction,
then annotate the functions like const createOperation:
CreateOperationFunction<TModelName, TFields> = async (...) => { ... } and const
updateOperation: UpdateOperationFunction<TModelName, TFields> = async (...) => {
... } before assigning createOperation.$dataSchema and
updateOperation.$dataSchema.

Comment on lines +263 to +294
/**
* Infers the input schema from a record of field definitions.
*
* Creates an object type where:
* - Each key corresponds to a field name
* - Each value type is the field's Zod schema type
*
* @template TFields - Record of field definitions
*
* @example
* ```typescript
* const fields = {
* name: scalarField(z.string()),
* email: scalarField(z.string().email().optional()),
* };
*
* type InputSchema = InferInputSchema<typeof fields>;
* // { name: z.ZodString; email?: z.ZodString | undefined }
* ```
*/
export type InferInputSchema<
TFields extends Record<string, AnyFieldDefinition>,
> = z.ZodObject<{
[K in keyof TFields]: TFields[K] extends FieldDefinition<
infer TInputSchema,
any,
any
>
? TInputSchema
: never;
}>;

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clarify JSDoc for InferInput to reflect that it returns schema output types

InferInputSchema correctly documents that each property is the field’s Zod schema type. However, InferInput now returns z.output<InferInputSchema<TFields>>, i.e., the output TypeScript type of each schema, not the schema objects themselves. I’d tweak the description accordingly:

- * - Each value type is the field's Zod schema type
+ * - Each value type is the output type of the field's Zod schema

This keeps the prose consistent with the example showing { name: string; email?: string | undefined }.

Also applies to: 295-317

🤖 Prompt for AI Agents
In examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts
around lines 263 to 294 (and similarly for 295 to 317), the JSDoc for
InferInputSchema incorrectly states it returns the field's Zod schema types; in
reality the exported InferInput type uses z.output<InferInputSchema<TFields>>
and therefore represents the schemas' output TypeScript types. Update the JSDoc
to clarify that the resulting type represents the output (parsed) TypeScript
values produced by each Zod schema (e.g., string, optional string), and adjust
the example description to say the inferred type is { name: string; email?:
string | undefined } rather than Zod schema objects.

Comment on lines +263 to +294
/**
* Infers the input schema from a record of field definitions.
*
* Creates an object type where:
* - Each key corresponds to a field name
* - Each value type is the field's Zod schema type
*
* @template TFields - Record of field definitions
*
* @example
* ```typescript
* const fields = {
* name: scalarField(z.string()),
* email: scalarField(z.string().email().optional()),
* };
*
* type InputSchema = InferInputSchema<typeof fields>;
* // { name: z.ZodString; email?: z.ZodString | undefined }
* ```
*/
export type InferInputSchema<
TFields extends Record<string, AnyFieldDefinition>,
> = z.ZodObject<{
[K in keyof TFields]: TFields[K] extends FieldDefinition<
infer TInputSchema,
any,
any
>
? TInputSchema
: never;
}>;

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

InferInputSchema doc comment doesn’t match the actual type

InferInputSchema is defined as a z.ZodObject<…>, but the example comment suggests it’s a plain object type of field schemas. You might want to tweak the wording and example:

  • Say “returns a z.ZodObject whose shape maps field names to their input schemas”.
  • Example type should be z.ZodObject<{ name: z.ZodString; email: z.ZodOptional<z.ZodString> }> (or similar), not a plain object type.

Only the docs are off; the implementation itself looks correct and mirrors the blog/fastify templates.
Based on learnings


🏁 Script executed:

#!/bin/bash
# Inspect the InferInputSchema type definition and surrounding context
cat examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts | sed -n '250,300p'

Length of output: 1256


🏁 Script executed:

#!/bin/bash
# Check imports and FieldDefinition type to understand the structure
head -100 examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts | tail -50

Length of output: 1841


🏁 Script executed:

#!/bin/bash
# Search for InferInputSchema usage in the codebase to understand how it's consumed
rg -n 'InferInputSchema' examples/todo-with-auth0/apps/backend/src/ -A 2 -B 2

Length of output: 5018


Update JSDoc example to reflect that InferInputSchema returns a z.ZodObject, not a plain object type

The JSDoc comment at lines 263–294 is misleading. The type definition correctly returns z.ZodObject<{ ... }>, but the example shows a plain object type. Update the comment to:

  • Clarify that it returns a z.ZodObject whose shape maps field names to their input schemas
  • Change the example type annotation to reflect the actual type, e.g., z.ZodObject<{ name: z.ZodString; email: z.ZodOptional<z.ZodString> }> (or similar Zod-wrapped representation)
🤖 Prompt for AI Agents
In examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
around lines 263 to 294, the JSDoc example incorrectly shows a plain object type
but the exported InferInputSchema returns a z.ZodObject; update the comment to
state clearly that the type returns a z.ZodObject whose shape maps each field
name to its Zod input schema, and replace the example type annotation with a
Zod-wrapped representation (for example show z.ZodObject<{ name: z.ZodString;
email: z.ZodOptional<z.ZodString> }> or similar) so the docs match the actual
return type.

Comment on lines +267 to 274
z.ZodOptional<z.ZodNullable<InferInputSchema<TFields>>>,
undefined,
undefined | { delete: true }
> {
return {
schema: generateCreateSchema(config.fields).nullish(),
processInput: async (value, processCtx) => {
// Handle null - delete the relation
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix schema generic to match .nullish() output

.nullish() returns ZodNullable<ZodOptional<T>>, so the function currently promises callers a ZodOptional<ZodNullable<T>> but actually hands them a different wrapper. That leaks an incorrect method surface to generated code and can break downstream schema operations. Please swap the generic to reflect the real shape. (nuxt-sidebase-parse.sidebase.io)

-): FieldDefinition<
-  z.ZodOptional<z.ZodNullable<InferInputSchema<TFields>>>,
+): FieldDefinition<
+  z.ZodNullable<z.ZodOptional<InferInputSchema<TFields>>>,
🤖 Prompt for AI Agents
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts
around lines 267 to 274: the function return type currently declares
ZodOptional<ZodNullable<InferInputSchema<TFields>>> but .nullish() actually
produces ZodNullable<ZodOptional<InferInputSchema<TFields>>>; update the generic
to ZodNullable<ZodOptional<InferInputSchema<TFields>>> so the declared schema
type matches the runtime .nullish() wrapper, leaving processInput and other
logic unchanged.

Comment on lines +263 to +294
/**
* Infers the input schema from a record of field definitions.
*
* Creates an object type where:
* - Each key corresponds to a field name
* - Each value type is the field's Zod schema type
*
* @template TFields - Record of field definitions
*
* @example
* ```typescript
* const fields = {
* name: scalarField(z.string()),
* email: scalarField(z.string().email().optional()),
* };
*
* type InputSchema = InferInputSchema<typeof fields>;
* // { name: z.ZodString; email?: z.ZodString | undefined }
* ```
*/
export type InferInputSchema<
TFields extends Record<string, AnyFieldDefinition>,
> = z.ZodObject<{
[K in keyof TFields]: TFields[K] extends FieldDefinition<
infer TInputSchema,
any,
any
>
? TInputSchema
: never;
}>;

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

InferInputSchema JSDoc example doesn’t match the actual type it produces

InferInputSchema returns a z.ZodObject<...>, where each value is the field’s Zod schema type. The example comment:

// { name: z.ZodString; email?: z.ZodString | undefined }

suggests a plain object type with an optional email property, which is not what the alias actually returns, nor how Zod encodes optionality (it would be z.ZodOptional<z.ZodString> in the shape).

To avoid confusion, consider updating the example to something closer to:

// z.ZodObject<{
//   name: z.ZodString;
//   email: z.ZodOptional<z.ZodString>;
// }>

or simply drop the inline example type and keep the textual description.

🤖 Prompt for AI Agents
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts
lines 263-294: the JSDoc example for InferInputSchema is misleading because the
type is a z.ZodObject whose values are Zod schema types (e.g., z.ZodString or
z.ZodOptional<z.ZodString>), not a plain TS object with optional properties;
update the example to reflect the actual returned type (for example show
z.ZodObject<{ name: z.ZodString; email: z.ZodOptional<z.ZodString> }>) or remove
the inline example entirely and keep the textual description so the docs
accurately match the implemented type.

@kingston kingston merged commit e79df28 into main Nov 20, 2025
14 of 16 checks passed
@kingston kingston deleted the kingston/eng-673-optimize-nullundefined-in-pothos branch November 20, 2025 15:29
@github-actions github-actions bot mentioned this pull request Nov 19, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts (1)

25-43: Export FileFieldConfig to comply with TypeScript export guideline

Current FileFieldConfig is internal. Given the repo rule that interfaces/types should be exported, consider:

-interface FileFieldConfig<
+export interface FileFieldConfig<
   TFileCategory extends FileCategory,
   TOptional extends boolean = false,
 > {

This keeps the existing JSDoc valid while aligning with the shared TS guidelines.
As per coding guidelines

♻️ Duplicate comments (8)
examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts (1)

264-294: Update JSDoc example to reflect that InferInputSchema returns a z.ZodObject, not a plain object type

The example comment at line 281 shows // { name: z.ZodString; email?: z.ZodString | undefined }, but the actual type definition returns z.ZodObject<{ [K in keyof TFields]: ... }>. Update the example to show the correct Zod-wrapped representation, e.g., z.ZodObject<{ name: z.ZodString; email: z.ZodOptional<z.ZodString> }>.

examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts (1)

32-92: Update docstring to clarify validation happens at GraphQL layer, not within scalarField

The docstring at line 35 states "validates input using a Zod schema," but scalarField itself doesn't call schema.parse(). Validation occurs at the GraphQL input type level via .validate(operation.$dataSchema). For standalone use outside GraphQL, callers must validate using generateCreateSchema(fields).parse(input) before passing data to these helpers.

Update the docstring to clarify when and where validation occurs.

examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts (1)

1-1: Zod import is now NodeNext/ESM‑safe

Using import { z } from 'zod'; is correct here and fixes the earlier default‑import issue under NodeNext/ESM.

packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts (1)

190-201: Align FieldDefinition and Infer JSDoc/examples with the new schema‑driven model*

The types now correctly model a schema‑centric pipeline:

  • FieldDefinition is parameterized by TInputSchema extends z.ZodSchema and exposes a schema: TInputSchema.
  • processInput receives value: z.output<TInputSchema>, which implies validation has already happened upstream.
  • InferInputSchema builds a z.ZodObject<...> from field schemas, and InferInput returns z.output<InferInputSchema<TFields>> (parsed values, e.g. string, not Zod schema objects).

However, the JSDoc and example code are still based on the old design:

  • Summary bullets still say “Validate the input value using a Zod schema”, and the example uses zodSchema plus z.string().min(1).parse(value).
  • The InferInputSchema and InferInput comments claim “Each value type is the field’s Zod schema type” and show a plain object type with schema‑shaped properties.

To avoid confusing consumers of this template, I’d recommend:

  • Updating the FieldDefinition doc/example to show schema as the stored Zod schema and processInput operating on an already‑validated value without calling parse() again.
  • Tweaking the InferInputSchema/InferInput comments to say that:
    • InferInputSchema yields a z.ZodObject whose properties are the field schemas.
    • InferInput yields the output TS types from those schemas (e.g. { name: string; email?: string | undefined }).

This keeps the public docs in sync with the actual generic signatures used by generators.

Also applies to: 202-216, 218-246, 264-295, 296-303, 317-318

examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts (1)

190-201: Bring FieldDefinition and Infer docs in line with schema/output types*

The runtime and types have moved to a schema‑centric, operation‑level validation model:

  • FieldDefinition is parameterized by TInputSchema extends z.ZodSchema, exposes schema: TInputSchema, and processInput receives a z.output<TInputSchema> (already‑validated input).
  • InferInputSchema builds a z.ZodObject of field schemas.
  • InferInput is the parsed output type: z.output<InferInputSchema<TFields>>.

But the documentation still reflects the old model:

  • FieldDefinition’s summary bullet and example talk about validating via schema.parse() and reference a zodSchema property that no longer exists.
  • InferInputSchema’s example shows a plain object of schema types ({ name: z.ZodString; ... }) rather than a z.ZodObject<...>.
  • InferInput’s comment says “Each value type is the field’s Zod schema type” even though the example correctly shows { name: string; email?: string | undefined }.

To avoid confusion for app developers reading this file, I’d suggest:

  • Updating the FieldDefinition comment/example to show schema and a processInput that trusts the already‑validated value (no extra parse()).
  • Updating the InferInputSchema example to show the z.ZodObject<{ ... }> form.
  • Changing the InferInput description to say “Each value type is the output type of the field’s Zod schema”.

The types are solid; this is purely a documentation refresh to match the new design.

Also applies to: 202-216, 218-246, 264-295, 296-303, 317-318

packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts (1)

70-79: Fix nestedOneToOneField schema generic to match .nullish() output and clarify scalarField docs

Two points here:

  1. Type vs runtime schema mismatch in nestedOneToOneField

generateCreateSchema(config.fields).nullish() returns ZodNullable<ZodOptional<InferInputSchema<TFields>>>, but the declared FieldDefinition schema type is z.ZodOptional<z.ZodNullable<InferInputSchema<TFields>>>. This inverts the wrapper order and exposes an inaccurate schema surface to generated code.

You can fix the generic without changing runtime behaviour by swapping the wrappers:

 export function nestedOneToOneField<...>(
   config: NestedOneToOneFieldConfig<...>,
-): FieldDefinition<
-  z.ZodOptional<z.ZodNullable<InferInputSchema<TFields>>>,
-  undefined,
-  undefined | { delete: true }
-> {
+): FieldDefinition<
+  z.ZodNullable<z.ZodOptional<InferInputSchema<TFields>>>,
+  undefined,
+  undefined | { delete: true }
+> {
   return {
-    schema: generateCreateSchema(config.fields).nullish(),
+    schema: generateCreateSchema(config.fields).nullish(),
     processInput: async (value, processCtx) => {
       // ...

This aligns the declared type with the actual .nullish() schema.

  1. scalarField documentation still implies field‑level validation

The implementation now stores schema and expects validation to happen at the operation level, with processInput receiving an already‑validated value. The JSDoc still says “validates input using a Zod schema”; it would be less surprising to phrase this as “creates a field definition with an associated Zod schema (used by operation‑level validation), plus an optional transform applied to the validated value”, matching the behaviour used by generateCreateSchema and $dataSchema.

The code itself looks good; this is just documentation / typing alignment.

Also applies to: 80-89, 258-274, 275-277

examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts (1)

32-44: Correct nestedOneToOneField Zod schema generic and clarify scalarField behaviour

As in the template version:

  1. nestedOneToOneField schema generic

The return type currently advertises:

FieldDefinition<
  z.ZodOptional<z.ZodNullable<InferInputSchema<TFields>>>,
  undefined,
  undefined | { delete: true }
>

but schema is:

schema: generateCreateSchema(config.fields).nullish(),

and .nullish() actually produces ZodNullable<ZodOptional<...>>. To keep the public type surface honest, update the generic like this:

-): FieldDefinition<
-  z.ZodOptional<z.ZodNullable<InferInputSchema<TFields>>>,
-  undefined,
-  undefined | { delete: true }
-> {
+): FieldDefinition<
+  z.ZodNullable<z.ZodOptional<InferInputSchema<TFields>>>,
+  undefined,
+  undefined | { delete: true }
+> {
   return {
     schema: generateCreateSchema(config.fields).nullish(),
     // ...

This matches the runtime schema returned by .nullish().

  1. scalarField documentation

scalarField now:

  • Stores a Zod schema on schema.
  • Relies on operation‑level validation (e.g. via generateCreateSchema / $dataSchema).
  • Optionally transforms the already‑validated value before emitting create/update data.

The docstring still says it “validates input using a Zod schema”, which no longer reflects the implementation. Consider rewording it to emphasize that it provides the schema for operation‑level validation and applies an optional transform to the validated value, as suggested in earlier review comments.

Also applies to: 70-79, 80-89, 258-274, 275-277

examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts (1)

353-360: Export operation function types and add explicit type annotations to operation variables.

The issues raised in the previous review remain unresolved:

  1. CreateOperationFunction (line 353) and UpdateOperationFunction (line 630) are not exported. Per coding guidelines, all types should be exported. These types are part of the public API since they define the return types of exported functions.

  2. createOperation (line 418) and updateOperation (line 697) lack explicit type annotations. Without typing these variables, the $dataSchema property assignment (lines 523, 829) won't type-check properly.

As per coding guidelines.

Apply the fix pattern suggested in the previous review:

-type CreateOperationFunction<
+export type CreateOperationFunction<
   TModelName extends ModelPropName,
   TFields extends Record<string, AnyFieldDefinition>,
 > = (<TQueryArgs extends ModelQuery<TModelName>>(
   input: CreateOperationInput<TModelName, TFields, TQueryArgs>,
 ) => Promise<GetPayload<TModelName, TQueryArgs>>) & {
   $dataSchema: InferInputSchema<TFields>;
 };
-type UpdateOperationFunction<
+export type UpdateOperationFunction<
   TModelName extends ModelPropName,
   TFields extends Record<string, AnyFieldDefinition>,
 > = (<TQueryArgs extends ModelQuery<TModelName>>(
   input: UpdateOperationInput<TModelName, TFields, TQueryArgs>,
 ) => Promise<GetPayload<TModelName, TQueryArgs>>) & {
   $dataSchema: z.ZodObject<{
     [k in keyof TFields]: z.ZodOptional<TFields[k]['schema']>;
   }>;
 };

For the variable annotations, explicitly type them before attaching $dataSchema:

-  const createOperation = async <TQueryArgs extends ModelQuery<TModelName>>({
+  const createOperation: CreateOperationFunction<TModelName, TFields> =
+    async <TQueryArgs extends ModelQuery<TModelName>>({
-  const updateOperation = async <TQueryArgs extends ModelQuery<TModelName>>({
+  const updateOperation: UpdateOperationFunction<TModelName, TFields> =
+    async <TQueryArgs extends ModelQuery<TModelName>>({

Also applies to: 630-639, 415-525, 694-831

🧹 Nitpick comments (5)
plugins/plugin-storage/src/generators/fastify/storage-module/templates/module/services/file-field.ts (1)

24-42: Consider exporting FileFieldConfig for better API usability.

The FileFieldConfig interface is used as a parameter type for the exported fileField function. Exporting it would allow consumers to reference this type explicitly, which can improve type safety and developer experience when creating configuration objects.

Apply this diff to export the interface:

-interface FileFieldConfig<
+export interface FileFieldConfig<
   TFileCategory extends FileCategory,
   TOptional extends boolean = false,
 > {

As per coding guidelines.

examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts (3)

13-20: File input schema + alias look good; consider reusing alias in this file

The Zod schema and exported FileInput = z.infer<typeof fileInputSchema> are consistent and match the plugin template. You might optionally use FileInput in this file (e.g., in processInput’s parameter type) to keep the inferred type DRY and easier to update.


80-101: Align optional schema runtime type with generic FieldDefinition type

For the optional case, the generic uses:

TOptional extends true
  ? z.ZodOptional<z.ZodNullable<typeof fileInputSchema>>
  : typeof fileInputSchema

but the runtime value is fileInputSchema.nullish(), which is equivalent to .optional().nullable() and yields a different wrapper ordering. To make the implementation match the generic more closely and potentially drop the as cast, consider:

-    schema: (config.optional
-      ? fileInputSchema.nullish()
-      : fileInputSchema) as TOptional extends true
+    schema: (config.optional
+      ? fileInputSchema.nullable().optional()
+      : fileInputSchema) as TOptional extends true
       ? z.ZodOptional<z.ZodNullable<typeof fileInputSchema>>
       : typeof fileInputSchema,

Same semantics (id | null | undefined), but the type structure lines up with the declared conditional type.


102-104: Prefer using the FileInput alias in processInput

You can make the parameter type a bit clearer and reuse the exported alias:

-      value: z.infer<typeof fileInputSchema> | null | undefined,
+      value: FileInput | null | undefined,

This keeps the implementation consistent with what you export as the public file input type.

examples/todo-with-auth0/apps/backend/src/modules/accounts/users/schema/user.mutations.ts (1)

71-76: Confirm skipValidation: true semantics are honored end‑to‑end

Passing skipValidation: true into createUser/updateUser assumes those operations only run Zod validation when this flag is false, relying on Pothos’ .validate(...) to have already parsed input. Please double‑check that:

  • the create/update operations default skipValidation to false, and
  • they fully bypass schema parsing when skipValidation is true.

This avoids double validation and keeps behaviour consistent across other call sites that don’t set the flag.

Also applies to: 103-110

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 934f1ad and fb435cc.

⛔ Files ignored due to path filters (18)
  • examples/blog-with-auth/apps/backend/baseplate/generated/src/modules/accounts/schema/user.mutations.ts is excluded by !**/generated/**, !**/generated/**
  • examples/blog-with-auth/apps/backend/baseplate/generated/src/utils/data-operations/define-operations.ts is excluded by !**/generated/**, !**/generated/**
  • examples/blog-with-auth/apps/backend/baseplate/generated/src/utils/data-operations/field-definitions.ts is excluded by !**/generated/**, !**/generated/**
  • examples/blog-with-auth/apps/backend/baseplate/generated/src/utils/data-operations/types.ts is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-auth0/apps/backend/baseplate/generated/src/modules/accounts/users/schema/user.mutations.ts is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-auth0/apps/backend/baseplate/generated/src/modules/storage/services/file-field.ts is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-auth0/apps/backend/baseplate/generated/src/modules/todos/schema/todo-item.mutations.ts is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-auth0/apps/backend/baseplate/generated/src/modules/todos/schema/todo-list-share.mutations.ts is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-auth0/apps/backend/baseplate/generated/src/modules/todos/schema/todo-list.mutations.ts is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-auth0/apps/backend/baseplate/generated/src/utils/data-operations/define-operations.ts is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-auth0/apps/backend/baseplate/generated/src/utils/data-operations/field-definitions.ts is excluded by !**/generated/**, !**/generated/**
  • examples/todo-with-auth0/apps/backend/baseplate/generated/src/utils/data-operations/types.ts is excluded by !**/generated/**, !**/generated/**
  • tests/simple/apps/backend/baseplate/generated/src/utils/data-operations/define-operations.ts is excluded by !**/generated/**, !tests/**, !**/generated/**
  • tests/simple/apps/backend/baseplate/generated/src/utils/data-operations/field-definitions.ts is excluded by !**/generated/**, !tests/**, !**/generated/**
  • tests/simple/apps/backend/baseplate/generated/src/utils/data-operations/types.ts is excluded by !**/generated/**, !tests/**, !**/generated/**
  • tests/simple/apps/backend/src/utils/data-operations/define-operations.ts is excluded by !tests/**
  • tests/simple/apps/backend/src/utils/data-operations/field-definitions.ts is excluded by !tests/**
  • tests/simple/apps/backend/src/utils/data-operations/types.ts is excluded by !tests/**
📒 Files selected for processing (20)
  • examples/blog-with-auth/apps/backend/src/modules/accounts/schema/user.mutations.ts (3 hunks)
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts (12 hunks)
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts (6 hunks)
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts (5 hunks)
  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/schema/user.mutations.ts (3 hunks)
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts (4 hunks)
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-item.mutations.ts (3 hunks)
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts (3 hunks)
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts (3 hunks)
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/define-operations.ts (12 hunks)
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts (6 hunks)
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts (5 hunks)
  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts (3 hunks)
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/define-operations.ts (12 hunks)
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts (6 hunks)
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts (5 hunks)
  • packages/fastify-generators/src/generators/prisma/prisma-data-create/prisma-data-create.generator.ts (4 hunks)
  • packages/fastify-generators/src/generators/prisma/prisma-data-update/prisma-data-update.generator.ts (4 hunks)
  • packages/fastify-generators/src/types/service-dto-kinds.ts (1 hunks)
  • plugins/plugin-storage/src/generators/fastify/storage-module/templates/module/services/file-field.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • examples/blog-with-auth/apps/backend/src/modules/accounts/schema/user.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-item.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/define-operations.ts
  • packages/fastify-generators/src/generators/prisma/prisma-data-create/prisma-data-create.generator.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/code-style.mdc)

**/*.{ts,tsx}: TypeScript with strict type checking
Always include return types on top-level functions including React components (React.ReactElement)
Include absolute paths in import statements via tsconfig paths (@src/ is the alias for src/)
If a particular interface or type is not exported, change the file so it is exported

If a particular interface or type is not exported, update the TypeScript file so it is exported

Files:

  • packages/fastify-generators/src/generators/prisma/prisma-data-update/prisma-data-update.generator.ts
  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/schema/user.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
  • packages/fastify-generators/src/types/service-dto-kinds.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts
  • plugins/plugin-storage/src/generators/fastify/storage-module/templates/module/services/file-field.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/define-operations.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/code-style.mdc)

Node 16 module resolution - include file extensions in imports (.js)

Files:

  • packages/fastify-generators/src/generators/prisma/prisma-data-update/prisma-data-update.generator.ts
  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/schema/user.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
  • packages/fastify-generators/src/types/service-dto-kinds.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts
  • plugins/plugin-storage/src/generators/fastify/storage-module/templates/module/services/file-field.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/define-operations.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/code-style.mdc)

**/*.{ts,tsx,js}: Sort imports by group: external libs first, then local imports
Use camelCase for variables/functions, PascalCase for types/classes
Order functions such that functions are placed below the variables/functions they use
We use the prefer using nullish coalescing operator (??) ESLint rule instead of a logical or (||), as it is a safer operator
Use console.info/warn/error instead of console.log

Files:

  • packages/fastify-generators/src/generators/prisma/prisma-data-update/prisma-data-update.generator.ts
  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/schema/user.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
  • packages/fastify-generators/src/types/service-dto-kinds.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts
  • plugins/plugin-storage/src/generators/fastify/storage-module/templates/module/services/file-field.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/define-operations.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts
**/*

📄 CodeRabbit inference engine (.cursor/rules/code-style.mdc)

Use kebab-case for file names

Files:

  • packages/fastify-generators/src/generators/prisma/prisma-data-update/prisma-data-update.generator.ts
  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/schema/user.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
  • packages/fastify-generators/src/types/service-dto-kinds.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts
  • plugins/plugin-storage/src/generators/fastify/storage-module/templates/module/services/file-field.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/define-operations.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts
examples/todo-with-auth0/{apps/admin/src,apps/backend/src}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (examples/todo-with-auth0/CLAUDE.md)

examples/todo-with-auth0/{apps/admin/src,apps/backend/src}/**/*.{ts,tsx}: Always use .js extensions in import statements, even when importing from TypeScript files
Use import type for type-only imports
Always specify explicit return types for all functions
Add JSDoc to all exported functions, interfaces, and classes documenting purpose, parameters, returns, and fields

Files:

  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/schema/user.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
examples/todo-with-auth0/{apps/admin/src,apps/backend/src}/**/*

📄 CodeRabbit inference engine (examples/todo-with-auth0/CLAUDE.md)

Use kebab-case for all file and directory names

Files:

  • examples/todo-with-auth0/apps/backend/src/modules/accounts/users/schema/user.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts
examples/blog-with-auth/apps/**/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (examples/blog-with-auth/CLAUDE.md)

examples/blog-with-auth/apps/**/src/**/*.{ts,tsx}: Always use .js file extensions in import statements, even when importing from .ts files
Use import type for type-only imports
Always specify explicit return types for all functions
Add JSDoc to all exported functions, interfaces, and classes, documenting purpose, parameters, return values, and all fields

Files:

  • examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts
🧠 Learnings (29)
📚 Learning: 2025-05-05T06:36:50.687Z
Learnt from: kingston
Repo: halfdomelabs/baseplate PR: 521
File: packages/react-generators/src/generators/admin/admin-crud-edit/admin-crud-edit.generator.ts:90-94
Timestamp: 2025-05-05T06:36:50.687Z
Learning: In this codebase, import paths can include `.ts` extensions, and the `resolveModuleSpecifier` function will handle them appropriately. There's no need to strip file extensions before passing paths to functions like `TsCodeUtils.importFragment`.

Applied to files:

  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
📚 Learning: 2025-07-07T18:24:17.522Z
Learnt from: kingston
Repo: halfdomelabs/baseplate PR: 592
File: plugins/plugin-auth/src/auth0/generators/react/auth0-hooks/templates/src/hooks/use-required-user-id.ts:1-2
Timestamp: 2025-07-07T18:24:17.522Z
Learning: Files under templates/** directories can use `// ts-nocheck` because they are templates meant for code generation, not direct type checking.

Applied to files:

  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
📚 Learning: 2025-07-22T09:11:29.223Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: .cursor/rules/ui-rules.mdc:0-0
Timestamp: 2025-07-22T09:11:29.223Z
Learning: Applies to {packages/project-builder-web/**,packages/ui-components/**}/*.tsx : Use ShadCN-based components from `baseplate-dev/ui-components` and always prefer these components over creating custom ones

Applied to files:

  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
📚 Learning: 2025-05-05T06:37:43.106Z
Learnt from: kingston
Repo: halfdomelabs/baseplate PR: 521
File: plugins/baseplate-plugin-storage/src/generators/react/upload-components/upload-components.generator.ts:108-112
Timestamp: 2025-05-05T06:37:43.106Z
Learning: The template extractor in the baseplate codebase can automatically infer and determine the necessary import map providers for certain templates, making explicit specification of importMapProviders unnecessary in those cases.

Applied to files:

  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
📚 Learning: 2025-07-30T13:27:20.000Z
Learnt from: kingston
Repo: halfdomelabs/baseplate PR: 623
File: plugins/plugin-auth/src/local-auth/core/generators/react-session/templates/src/app/user-session-provider.tsx:6-12
Timestamp: 2025-07-30T13:27:20.000Z
Learning: Ignore ESLint import ordering rules for files in templates/** directories as these are code generation templates, not direct source code.

Applied to files:

  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
📚 Learning: 2025-05-05T06:37:51.001Z
Learnt from: kingston
Repo: halfdomelabs/baseplate PR: 521
File: packages/react-generators/src/generators/admin/admin-crud-list/admin-crud-list.generator.ts:163-166
Timestamp: 2025-05-05T06:37:51.001Z
Learning: For certain templates in the codebase, the `importMapProviders` property is not explicitly required as the template extractor will automatically determine and infer the necessary import map providers.

Applied to files:

  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
📚 Learning: 2025-06-11T18:31:22.247Z
Learnt from: kingston
Repo: halfdomelabs/baseplate PR: 571
File: packages/core-generators/src/renderers/extractor/plugins/typed-templates-file.ts:102-106
Timestamp: 2025-06-11T18:31:22.247Z
Learning: For `templateExtractorBarrelExportPlugin.addGeneratedBarrelExport`, the generated barrel exports are written into `generated/index.ts`, therefore the `moduleSpecifier` must be specified relative to that file (e.g., `./typed-templates.js`), not the project root.

Applied to files:

  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
📚 Learning: 2025-07-16T17:15:56.714Z
Learnt from: kingston
Repo: halfdomelabs/baseplate PR: 613
File: packages/react-generators/src/generators/core/react-components/templates/components/ui/circular-progress/circular-progress.tsx:0-0
Timestamp: 2025-07-16T17:15:56.714Z
Learning: For imports starting with `$` (template aliases), do not require `.js` extensions as these are resolved differently during the generation process, unlike regular file imports which require explicit `.js` extensions under Node 16 module resolution.

Applied to files:

  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
📚 Learning: 2025-08-17T01:30:00.344Z
Learnt from: kingston
Repo: halfdomelabs/baseplate PR: 633
File: packages/core-generators/src/renderers/typescript/extractor/apply-simple-replacements.ts:47-48
Timestamp: 2025-08-17T01:30:00.344Z
Learning: In template extraction systems like apply-simple-replacements.ts, it's intentional to skip processing import declarations to allow unused imports to be removed properly after template variable replacements are applied.

Applied to files:

  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
📚 Learning: 2025-10-23T21:01:15.331Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/todo-with-auth0/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:01:15.331Z
Learning: Applies to examples/todo-with-auth0/{apps/admin/src,apps/backend/src}/**/*.{ts,tsx} : Use `import type` for type-only imports

Applied to files:

  • packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
  • packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts
📚 Learning: 2025-10-23T21:01:15.331Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/todo-with-auth0/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:01:15.331Z
Learning: Applies to examples/todo-with-auth0/{tsconfig*.json,apps/{admin,backend}/tsconfig*.json} : Use TypeScript NodeNext module resolution and module ("moduleResolution": "NodeNext", "module": "NodeNext")

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
📚 Learning: 2025-10-23T21:01:15.331Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/todo-with-auth0/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:01:15.331Z
Learning: Applies to examples/todo-with-auth0/{apps/admin/src,apps/backend/src}/**/*.{ts,tsx} : Add JSDoc to all exported functions, interfaces, and classes documenting purpose, parameters, returns, and fields

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts
📚 Learning: 2025-10-23T21:01:15.331Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/todo-with-auth0/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:01:15.331Z
Learning: Applies to examples/todo-with-auth0/{apps/admin/src,apps/backend/src}/**/*.{ts,tsx} : Always specify explicit return types for all functions

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
📚 Learning: 2025-10-23T21:01:15.331Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/todo-with-auth0/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:01:15.331Z
Learning: Applies to examples/todo-with-auth0/{apps/admin/src,apps/backend/src}/**/*.{unit,int}.test.ts : Name test files with .unit.test.ts or .int.test.ts suffixes

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
📚 Learning: 2025-10-23T21:01:15.331Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/todo-with-auth0/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:01:15.331Z
Learning: Applies to examples/todo-with-auth0/{tsconfig*.json,apps/{admin,backend}/tsconfig*.json} : Enable "isolatedModules": true in TypeScript

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
📚 Learning: 2025-10-23T21:01:15.331Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/todo-with-auth0/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:01:15.331Z
Learning: Applies to examples/todo-with-auth0/{apps/admin/src,apps/backend/src}/**/*.{unit,int}.test.ts : Vitest tests must not use globals; import describe/it/expect from 'vitest'

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
📚 Learning: 2025-10-23T21:01:15.331Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/todo-with-auth0/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:01:15.331Z
Learning: Applies to examples/todo-with-auth0/{apps/admin/src,apps/backend/src}/**/*.{ts,tsx} : Always use .js extensions in import statements, even when importing from TypeScript files

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
📚 Learning: 2025-10-23T21:01:15.331Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/todo-with-auth0/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:01:15.331Z
Learning: Applies to examples/todo-with-auth0/{tsconfig*.json,apps/{admin,backend}/tsconfig*.json} : Enable strict type checking in TypeScript ("strict": true)

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts
  • examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
📚 Learning: 2025-10-23T21:00:29.010Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/blog-with-auth/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:00:29.010Z
Learning: Applies to examples/blog-with-auth/apps/**/src/**/*.{ts,tsx} : Add JSDoc to all exported functions, interfaces, and classes, documenting purpose, parameters, return values, and all fields

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts
  • examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts
📚 Learning: 2025-10-23T21:00:29.010Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/blog-with-auth/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:00:29.010Z
Learning: Applies to examples/blog-with-auth/**/tsconfig*.json : Use TypeScript module resolution NodeNext (and matching ESM settings)

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
📚 Learning: 2025-10-23T21:01:15.331Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/todo-with-auth0/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:01:15.331Z
Learning: Applies to examples/todo-with-auth0/{package.json,apps/{admin,backend}/package.json} : Use ESM only by setting "type": "module" in package.json

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
📚 Learning: 2025-01-23T09:12:46.178Z
Learnt from: kingston
Repo: halfdomelabs/baseplate PR: 428
File: packages/project-builder-server/src/sync/index.ts:5-5
Timestamp: 2025-01-23T09:12:46.178Z
Learning: Avoid importing directly from 'dist' directories. Instead, expose functionality through the package's public API and import from the main package entry point.

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
📚 Learning: 2025-10-23T21:00:29.010Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/blog-with-auth/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:00:29.010Z
Learning: Applies to examples/blog-with-auth/**/package.json : Module system must be ESM only by setting "type": "module" in package.json

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
📚 Learning: 2025-07-22T09:10:31.413Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/*.{js,ts,tsx} : Node 16 module resolution - include file extensions in imports (`.js`)

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
📚 Learning: 2025-07-22T09:10:31.413Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/index.{ts,tsx,js} : Prefer barrel exports e.g. export * from './foo.js' instead of individual named exports

Applied to files:

  • examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts
📚 Learning: 2025-10-14T08:07:58.492Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:07:58.492Z
Learning: Applies to **/*.{ts,tsx} : If a particular interface or type is not exported, update the TypeScript file so it is exported

Applied to files:

  • examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts
📚 Learning: 2025-07-22T09:11:16.930Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-22T09:11:16.930Z
Learning: Refactor code to be more easily testable, such as exporting types or functions

Applied to files:

  • examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts
📚 Learning: 2025-07-22T09:10:31.413Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: .cursor/rules/code-style.mdc:0-0
Timestamp: 2025-07-22T09:10:31.413Z
Learning: Applies to **/*.{ts,tsx} : If a particular interface or type is not exported, change the file so it is exported

Applied to files:

  • examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts
📚 Learning: 2025-10-23T21:00:29.010Z
Learnt from: CR
Repo: halfdomelabs/baseplate PR: 0
File: examples/blog-with-auth/CLAUDE.md:0-0
Timestamp: 2025-10-23T21:00:29.010Z
Learning: Applies to examples/blog-with-auth/apps/**/src/**/*.{ts,tsx} : Use `import type` for type-only imports

Applied to files:

  • examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts
🧬 Code graph analysis (14)
packages/fastify-generators/src/generators/prisma/prisma-data-update/prisma-data-update.generator.ts (3)
packages/core-generators/src/renderers/typescript/utils/ts-code-utils.ts (2)
  • TsCodeUtils (85-584)
  • tsTemplate (587-587)
packages/fastify-generators/src/types/service-output.ts (1)
  • createServiceOutputDtoInjectedArg (85-100)
packages/fastify-generators/src/types/service-dto-kinds.ts (1)
  • skipValidationKind (93-93)
packages/fastify-generators/src/generators/pothos/pothos-prisma-crud-mutation/pothos-prisma-crud-mutation.generator.ts (2)
packages/fastify-generators/src/types/service-dto-kinds.ts (1)
  • skipValidationKind (93-93)
packages/core-generators/src/renderers/typescript/utils/ts-code-utils.ts (1)
  • tsTemplate (587-587)
examples/todo-with-auth0/apps/backend/src/modules/accounts/users/schema/user.mutations.ts (1)
examples/blog-with-auth/apps/backend/src/plugins/graphql/builder.ts (1)
  • builder (28-80)
examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list-share.mutations.ts (1)
examples/blog-with-auth/apps/backend/src/plugins/graphql/builder.ts (1)
  • builder (28-80)
examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts (2)
examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts (3)
  • FieldDefinition (218-246)
  • InferInputSchema (284-294)
  • AnyFieldDefinition (249-249)
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts (3)
  • FieldDefinition (218-246)
  • InferInputSchema (284-294)
  • AnyFieldDefinition (249-249)
examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts (1)
plugins/plugin-storage/src/generators/fastify/storage-module/templates/module/services/file-field.ts (1)
  • FileInput (19-19)
examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts (1)
examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts (3)
  • AnyFieldDefinition (249-249)
  • InferInputSchema (284-294)
  • InferInput (317-318)
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/field-definitions.ts (3)
examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts (1)
  • scalarField (70-92)
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts (2)
  • FieldDefinition (218-246)
  • InferInputSchema (284-294)
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/define-operations.ts (1)
  • generateCreateSchema (240-250)
examples/blog-with-auth/apps/backend/src/utils/data-operations/field-definitions.ts (2)
examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts (2)
  • FieldDefinition (218-246)
  • InferInputSchema (284-294)
examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts (1)
  • generateCreateSchema (242-252)
examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts (2)
examples/blog-with-auth/apps/backend/src/plugins/graphql/builder.ts (1)
  • builder (28-80)
plugins/plugin-storage/src/generators/fastify/storage-module/templates/module/schema/file-input.input-type.ts (1)
  • fileInputInputType (5-11)
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts (2)
examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts (3)
  • FieldDefinition (218-246)
  • InferInputSchema (284-294)
  • AnyFieldDefinition (249-249)
examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts (3)
  • FieldDefinition (218-246)
  • InferInputSchema (284-294)
  • AnyFieldDefinition (249-249)
plugins/plugin-storage/src/generators/fastify/storage-module/templates/module/services/file-field.ts (2)
examples/todo-with-auth0/apps/backend/src/modules/storage/services/file-field.ts (1)
  • FileInput (20-20)
packages/fastify-generators/src/generators/core/config-service/templates/src/services/config.ts (1)
  • config (5-5)
examples/todo-with-auth0/apps/backend/src/utils/data-operations/field-definitions.ts (2)
examples/todo-with-auth0/apps/backend/src/utils/data-operations/types.ts (2)
  • FieldDefinition (218-246)
  • InferInputSchema (284-294)
examples/todo-with-auth0/apps/backend/src/utils/data-operations/define-operations.ts (1)
  • generateCreateSchema (242-252)
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/define-operations.ts (3)
examples/blog-with-auth/apps/backend/src/utils/data-operations/define-operations.ts (4)
  • generateCreateSchema (242-252)
  • CreateOperationInput (335-351)
  • transformFields (103-209)
  • UpdateOperationInput (610-628)
examples/blog-with-auth/apps/backend/src/utils/data-operations/types.ts (3)
  • AnyFieldDefinition (249-249)
  • InferInputSchema (284-294)
  • InferInput (317-318)
packages/fastify-generators/src/generators/prisma/data-utils/templates/src/utils/data-operations/types.ts (3)
  • AnyFieldDefinition (249-249)
  • InferInputSchema (284-294)
  • InferInput (317-318)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Verify Sync (todo-with-auth0)
  • GitHub Check: Verify Sync (blog-with-auth)
  • GitHub Check: Lint Examples (todo-with-auth0)
  • GitHub Check: Test E2E
  • GitHub Check: test
  • GitHub Check: Lint

Comment on lines +49 to +60
const updateTodoListDataInputType = builder
.inputType('UpdateTodoListData', {
fields: (t) => ({
ownerId: t.field({ type: 'Uuid' }),
position: t.int(),
name: t.string(),
createdAt: t.field({ type: 'DateTime' }),
status: t.field({ type: todoListStatusEnum }),
coverPhoto: t.field({ type: fileInputInputType }),
}),
})
.validate(updateTodoList.$dataSchema);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add JSDoc documentation to exported input type.

The exported updateTodoListDataInputType constant lacks JSDoc documentation. According to the coding guidelines for this path, all exported functions, interfaces, and classes should have JSDoc documenting their purpose and fields.

Based on learnings

Apply this diff to add JSDoc:

+/**
+ * Input type for updating an existing todo list
+ * Validated against the Zod schema from updateTodoList service
+ */
 const updateTodoListDataInputType = builder
   .inputType('UpdateTodoListData', {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const updateTodoListDataInputType = builder
.inputType('UpdateTodoListData', {
fields: (t) => ({
ownerId: t.field({ type: 'Uuid' }),
position: t.int(),
name: t.string(),
createdAt: t.field({ type: 'DateTime' }),
status: t.field({ type: todoListStatusEnum }),
coverPhoto: t.field({ type: fileInputInputType }),
}),
})
.validate(updateTodoList.$dataSchema);
/**
* Input type for updating an existing todo list
* Validated against the Zod schema from updateTodoList service
*/
const updateTodoListDataInputType = builder
.inputType('UpdateTodoListData', {
fields: (t) => ({
ownerId: t.field({ type: 'Uuid' }),
position: t.int(),
name: t.string(),
createdAt: t.field({ type: 'DateTime' }),
status: t.field({ type: todoListStatusEnum }),
coverPhoto: t.field({ type: fileInputInputType }),
}),
})
.validate(updateTodoList.$dataSchema);
🤖 Prompt for AI Agents
In
examples/todo-with-auth0/apps/backend/src/modules/todos/schema/todo-list.mutations.ts
around lines 49 to 60, the exported constant updateTodoListDataInputType is
missing JSDoc; add a JSDoc block immediately above the export that briefly
describes the purpose of this input type (used for updating a todo list) and
documents each field (ownerId: Uuid, position: number, name: string, createdAt:
DateTime, status: todoListStatusEnum, coverPhoto: fileInputInputType) and note
that the input is validated against updateTodoList.$dataSchema so readers know
validation is applied.

Comment on lines +351 to +358
type CreateOperationFunction<
TModelName extends ModelPropName,
TFields extends Record<string, AnyFieldDefinition>,
> = (<TQueryArgs extends ModelQuery<TModelName>>(
input: CreateOperationInput<TModelName, TFields, TQueryArgs>,
) => Promise<GetPayload<TModelName, TQueryArgs>>) & {
$dataSchema: InferInputSchema<TFields>;
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Export operation function types and add explicit type annotations (template file).

This template file has the same issues as the example file, but fixing them here is especially critical since this code will be generated for all projects using this template:

  1. CreateOperationFunction (line 351) and UpdateOperationFunction (line 628) are not exported. These types should be exported per coding guidelines.

  2. createOperation (line 416) and updateOperation (line 695) lack explicit type annotations. Without proper typing, the $dataSchema property assignments (lines 521, 827) won't type-check.

As per coding guidelines.

Apply these fixes:

-type CreateOperationFunction<
+export type CreateOperationFunction<
   TModelName extends ModelPropName,
   TFields extends Record<string, AnyFieldDefinition>,
 > = (<TQueryArgs extends ModelQuery<TModelName>>(
   input: CreateOperationInput<TModelName, TFields, TQueryArgs>,
 ) => Promise<GetPayload<TModelName, TQueryArgs>>) & {
   $dataSchema: InferInputSchema<TFields>;
 };
-type UpdateOperationFunction<
+export type UpdateOperationFunction<
   TModelName extends ModelPropName,
   TFields extends Record<string, AnyFieldDefinition>,
 > = (<TQueryArgs extends ModelQuery<TModelName>>(
   input: UpdateOperationInput<TModelName, TFields, TQueryArgs>,
 ) => Promise<GetPayload<TModelName, TQueryArgs>>) & {
   $dataSchema: z.ZodObject<{
     [k in keyof TFields]: z.ZodOptional<TFields[k]['schema']>;
   }>;
 };
-  const createOperation = async <TQueryArgs extends ModelQuery<TModelName>>({
+  const createOperation: CreateOperationFunction<TModelName, TFields> =
+    async <TQueryArgs extends ModelQuery<TModelName>>({
-  const updateOperation = async <TQueryArgs extends ModelQuery<TModelName>>({
+  const updateOperation: UpdateOperationFunction<TModelName, TFields> =
+    async <TQueryArgs extends ModelQuery<TModelName>>({

Also applies to: 628-637, 413-523, 692-829

import { STORAGE_ADAPTERS } from '$configAdapters';
import { BadRequestError } from '%errorHandlerServiceImports';
import { prisma } from '%prismaImports';
import { z } from 'zod';
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Reorder imports: external libraries should come before local imports.

The zod import should be placed before the local imports (lines 3-9) to comply with the import ordering guideline.

Apply this diff to fix the import order:

+import { z } from 'zod';
+
 import type { FileCategory } from '$typesFileCategory';
 import type { FieldDefinition } from '%dataUtilsImports';
 import type { Prisma } from '%prismaGeneratedImports';

 import { STORAGE_ADAPTERS } from '$configAdapters';
 import { BadRequestError } from '%errorHandlerServiceImports';
 import { prisma } from '%prismaImports';
-import { z } from 'zod';

As per coding guidelines.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { z } from 'zod';
import { z } from 'zod';
import type { FileCategory } from '$typesFileCategory';
import type { FieldDefinition } from '%dataUtilsImports';
import type { Prisma } from '%prismaGeneratedImports';
import { STORAGE_ADAPTERS } from '$configAdapters';
import { BadRequestError } from '%errorHandlerServiceImports';
import { prisma } from '%prismaImports';
🤖 Prompt for AI Agents
In
plugins/plugin-storage/src/generators/fastify/storage-module/templates/module/services/file-field.ts
around line 10, the import of the external library `zod` is placed after local
imports (lines 3-9); move the line "import { z } from 'zod';" so it appears
before any local/project imports to ensure external libraries are listed first
and comply with the import ordering guideline.

@coderabbitai coderabbitai bot mentioned this pull request Nov 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants