Skip to content

fix(core): coerce calendarDay writes to Date before Prisma 7 validation#637

Merged
borisno2 merged 1 commit into
mainfrom
claude/issue-621-0traqo
Jul 10, 2026
Merged

fix(core): coerce calendarDay writes to Date before Prisma 7 validation#637
borisno2 merged 1 commit into
mainfrom
claude/issue-621-0traqo

Conversation

@borisno2

Copy link
Copy Markdown
Member

Summary

Test plan

  • Unit tests for the resolveInput hook (string→Date coercion, pass-through cases, reading resolvedData vs inputData)
  • Unit tests for the widened zod schema (string, Date, malformed string)
  • End-to-end tests via context.db.event.create/update against a mocked Prisma client asserting the value forwarded to Prisma is a Date, reproducing the issue's repro scenario
  • pnpm test (packages/core) — 752 passed
  • pnpm lint, pnpm manypkg fix, pnpm format
  • tsc --noEmit

Closes #621


Generated by Claude Code

… 7 validation

Prisma 7's client validator rejects a bare YYYY-MM-DD string for a
DateTime @db.Date column. Add a resolveInput hook that converts a valid
string to a UTC-midnight Date before the write reaches Prisma, and widen
the field's zod schema to accept either shape (resolveInput runs before
validation in the write pipeline).

Closes #621
@vercel

vercel Bot commented Jul 10, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
stack-docs Ready Ready Preview, Comment Jul 10, 2026 7:57am

@changeset-bot

changeset-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f38867e

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

This PR includes changesets to release 9 packages
Name Type
@opensaas/stack-core Patch
@opensaas/stack-auth Patch
@opensaas/stack-cli Patch
@opensaas/stack-rag Patch
@opensaas/stack-storage Patch
@opensaas/stack-tiptap Patch
@opensaas/stack-ui Patch
@opensaas/stack-storage-s3 Patch
@opensaas/stack-storage-vercel 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

Copy link
Copy Markdown
Member Author

Review

Overview

Fixes #621: calendarDay writes were 500ing on Prisma 7 because the documented YYYY-MM-DD string write path reached the client's @db.Date validator unconverted. This PR adds a field-level resolveInput hook that coerces a valid YYYY-MM-DD string to a UTC-midnight Date before the write pipeline's validation phase, and widens calendarDay's zod schema to z.union([stringSchema, z.date()]) to accept the post-coercion shape.

Correctness

  • Hook ordering is right: hook-pipeline.ts runs field resolveInput (phase 1.5) strictly before validateFieldRules/zod (phase 3), so a valid string is a Date by the time the schema checks it. Confirmed by tracing context/hook-pipeline.ts.
  • Reads resolvedData[fieldKey] rather than inputData, so a list-level resolveInput that injects a default for an omitted key is honored (loop in executeFieldResolveInputHooks only runs for keys present in resolvedData, which already reflects that injected default). Matches the issue's explicit ask and is covered by a test.
  • UTC midnight construction (${value}T00:00:00.000Z) avoids the day-drift footgun the read-side formatCalendarDay already guards against.
  • Malformed strings, null/undefined, and existing Date instances pass through the hook unchanged, so isRequired and format-error behavior is preserved.

Minor observation (non-blocking)

For a value that's neither a valid YYYY-MM-DD string nor a Date (e.g. a stray number/object reaching context.db from an untyped JS caller), the error message quality regresses slightly. Previously the schema was a plain z.string() with a custom "must be a valid date in ISO8601 format" message; now z.union([stringSchema, z.date()]) surfaces zod's generic "Invalid input" top-level message instead for non-string/non-date values (verified locally — a number input flips from the custom message to "Invalid input"). This is an edge case (the field's TS type is string, so a typed caller can't reach it), and it's not covered by a test either before or after this change, so it's not a regression this PR needs to fix — just worth a follow-up if better DX for that edge case matters.

Test coverage

Strong — new tests cover the resolveInput hook directly (string→Date, Date/null/undefined pass-through, malformed-string pass-through, resolvedData vs inputData), the widened zod schema, and — notably — an end-to-end repro via context.db.event.create/update against a mocked Prisma client that asserts the exact value forwarded to the client is a Date, which is the most direct verification of the original bug. Read-side normalization back to YYYY-MM-DD is also re-verified end-to-end.

Style / conventions

  • Follows the existing field-self-containment pattern (no switch statements added elsewhere).
  • Comments explain the non-obvious "why" (hook ordering constraint, UTC-midnight rationale) rather than restating code.
  • Changeset present and correctly scoped as patch.

Risk

Low. Change is scoped to a single field builder, additive to the hook object (still overridable by user-provided hooks per the existing merge pattern), and read behavior is untouched. All 752 core tests + typecheck + lint pass.

No blocking issues found.


Generated by Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Core Package Coverage (./packages/core)

Status Category Percentage Covered / Total
🔵 Lines 92.11% (🎯 65%) 888 / 964
🔵 Statements 91.42% (🎯 65%) 928 / 1015
🔵 Functions 98% (🎯 62%) 147 / 150
🔵 Branches 80.64% (🎯 50%) 604 / 749
File CoverageNo changed files found.
Generated in workflow #1231 for commit f38867e by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for UI Package Coverage (./packages/ui)

Status Category Percentage Covered / Total
🔵 Lines 76.03% 92 / 121
🔵 Statements 75.39% 95 / 126
🔵 Functions 75.6% 31 / 41
🔵 Branches 65.78% 75 / 114
File CoverageNo changed files found.
Generated in workflow #1231 for commit f38867e by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for CLI Package Coverage (./packages/cli)

Status Category Percentage Covered / Total
🔵 Lines 79.21% 1490 / 1881
🔵 Statements 78.92% 1550 / 1964
🔵 Functions 84.45% 201 / 238
🔵 Branches 67.25% 653 / 971
File CoverageNo changed files found.
Generated in workflow #1231 for commit f38867e by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Auth Package Coverage (./packages/auth)

Status Category Percentage Covered / Total
🔵 Lines 74.64% 159 / 213
🔵 Statements 69.74% 166 / 238
🔵 Functions 83.11% 64 / 77
🔵 Branches 70.67% 94 / 133
File CoverageNo changed files found.
Generated in workflow #1231 for commit f38867e by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Storage Package Coverage (./packages/storage)

Status Category Percentage Covered / Total
🔵 Lines 74.8% 190 / 254
🔵 Statements 76.44% 211 / 276
🔵 Functions 85.89% 67 / 78
🔵 Branches 70.73% 174 / 246
File CoverageNo changed files found.
Generated in workflow #1231 for commit f38867e by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for RAG Package Coverage (./packages/rag)

Status Category Percentage Covered / Total
🔵 Lines 47.97% 355 / 740
🔵 Statements 48.14% 377 / 783
🔵 Functions 54.26% 70 / 129
🔵 Branches 42.55% 180 / 423
File CoverageNo changed files found.
Generated in workflow #1231 for commit f38867e by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Storage S3 Package Coverage (./packages/storage-s3)

Status Category Percentage Covered / Total
🔵 Lines 100% 40 / 40
🔵 Statements 100% 40 / 40
🔵 Functions 100% 9 / 9
🔵 Branches 100% 19 / 19
File CoverageNo changed files found.
Generated in workflow #1231 for commit f38867e by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Storage Vercel Package Coverage (./packages/storage-vercel)

Status Category Percentage Covered / Total
🔵 Lines 100% 38 / 38
🔵 Statements 100% 38 / 38
🔵 Functions 100% 8 / 8
🔵 Branches 100% 22 / 22
File CoverageNo changed files found.
Generated in workflow #1231 for commit f38867e by the Vitest Coverage Report Action

@borisno2 borisno2 merged commit 002e755 into main Jul 10, 2026
6 checks passed
@borisno2 borisno2 deleted the claude/issue-621-0traqo branch July 10, 2026 08:15
@github-actions github-actions Bot mentioned this pull request Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants