Skip to content

Conversation

@JeanMeijer
Copy link
Collaborator

@JeanMeijer JeanMeijer commented Oct 31, 2025

Description

Adds validation to the Events API to ensure the event's start date is before its end date using a Zod schema and Temporal.Instant.compare().

Screenshots / Recordings

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • UI/UX update
  • Docs update
  • Refactor / Cleanup

Related Areas

  • Authentication
  • Calendar UI
  • Data/API
  • Docs

Testing

  • Manual testing performed
  • Cross-browser testing (if UI changes)
  • Mobile responsiveness verified (if UI changes)

Checklist

  • I’ve read the CONTRIBUTING guide
  • My code works and is understandable and follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in complex areas
  • I have updated the documentation
  • Any dependent changes are merged and published

Notes


Want me to make any changes? Add a review or comment with @tembo and i'll get back to work!

tembo.io


Summary by cubic

Validate event date ranges in the Events API to ensure start is before end. This blocks invalid events across create and update.

  • New Features
    • Use isBefore with an isSameType guard from @repo/temporal to only compare matching Temporal types.
    • Added Zod refine to createEventInputSchema with a clear error on start.
    • Switched updateEventInputSchema to safeExtend to keep the validation on updates.

Written for commit b4d71dd. Summary will update automatically on new commits.

Co-authored-by: Jean <jean@analoginterface.io>
@vercel
Copy link

vercel bot commented Oct 31, 2025

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

Project Deployment Preview Comments Updated (UTC)
analog Ready Ready Preview Comment Nov 5, 2025 11:12am

@coderabbitai
Copy link

coderabbitai bot commented Oct 31, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.


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.

@JeanMeijer
Copy link
Collaborator Author

@tembo use isBefore from @repo/temporal instead

@tembo
Copy link
Contributor

tembo bot commented Oct 31, 2025

@tembo use isBefore from @repo/temporal instead

Updated to use isBefore from @repo/temporal as requested. Replaced the custom isStartBeforeEnd helper function with the standardized utility.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 1 file

Prompt for AI agents (all 1 issues)

Understand the root cause of the following 1 issues and fix them.


<file name="packages/schemas/src/events.ts">

<violation number="1" location="packages/schemas/src/events.ts:236">
Calling `isBefore(data.start, data.end)` without options will throw for mixed Temporal types/time zones allowed by `dateInputSchema`, causing validation to blow up instead of returning a proper error. Please guard these cases or provide the required compare options before calling `isBefore`.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

createdAt: z.instanceof(Temporal.Instant).optional(),
updatedAt: z.instanceof(Temporal.Instant).optional(),
})
.refine((data) => isBefore(data.start, data.end), {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 31, 2025

Choose a reason for hiding this comment

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

Calling isBefore(data.start, data.end) without options will throw for mixed Temporal types/time zones allowed by dateInputSchema, causing validation to blow up instead of returning a proper error. Please guard these cases or provide the required compare options before calling isBefore.

Prompt for AI agents
Address the following comment on packages/schemas/src/events.ts at line 236:

<comment>Calling `isBefore(data.start, data.end)` without options will throw for mixed Temporal types/time zones allowed by `dateInputSchema`, causing validation to blow up instead of returning a proper error. Please guard these cases or provide the required compare options before calling `isBefore`.</comment>

<file context>
@@ -205,33 +207,38 @@ export const recurrenceSchema = z
+    createdAt: z.instanceof(Temporal.Instant).optional(),
+    updatedAt: z.instanceof(Temporal.Instant).optional(),
+  })
+  .refine((data) =&gt; isBefore(data.start, data.end), {
+    message: &quot;Event start time must be earlier than end time&quot;,
+    path: [&quot;start&quot;],
</file context>

✅ Addressed in b4d71dd

@JeanMeijer
Copy link
Collaborator Author

@tembo add a function to the temporal package to check whether two temporal objects are the same type plaindate, zoneddatetime, or instant. performed a check first in refine don't add any comments and choose the same style as we for example with it before function.

@tembo
Copy link
Contributor

tembo bot commented Oct 31, 2025

@tembo add a function to the temporal package to check whether two temporal objects are the same type plaindate, zoneddatetime, or instant. performed a check first in refine don't add any comments and choose the same style as we for example with it before function.

Added isSameType utility function to the temporal package to check if two temporal objects share the same type. Updated the refine check to skip validation when start and end are different types, preventing comparison errors between mixed temporal types like PlainDate and ZonedDateTime.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

Reviewed changes from recent commits (found 1 issue).

1 issue found across 2 files

Prompt for AI agents (all 1 issues)

Understand the root cause of the following 1 issues and fix them.


<file name="packages/schemas/src/events.ts">

<violation number="1" location="packages/schemas/src/events.ts:236">
The new refine short-circuits for mixed Temporal types, so events where the end precedes the start (e.g., PlainDate start vs Instant end) now pass validation. Please keep the comparison and fail when types differ instead of bypassing the check.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

createdAt: z.instanceof(Temporal.Instant).optional(),
updatedAt: z.instanceof(Temporal.Instant).optional(),
})
.refine((data) => !isSameType(data.start, data.end) || isBefore(data.start, data.end), {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 31, 2025

Choose a reason for hiding this comment

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

The new refine short-circuits for mixed Temporal types, so events where the end precedes the start (e.g., PlainDate start vs Instant end) now pass validation. Please keep the comparison and fail when types differ instead of bypassing the check.

Prompt for AI agents
Address the following comment on packages/schemas/src/events.ts at line 236:

<comment>The new refine short-circuits for mixed Temporal types, so events where the end precedes the start (e.g., PlainDate start vs Instant end) now pass validation. Please keep the comparison and fail when types differ instead of bypassing the check.</comment>

<file context>
@@ -233,7 +233,7 @@ export const createEventInputSchema = z
     updatedAt: z.instanceof(Temporal.Instant).optional(),
   })
-  .refine((data) =&gt; isBefore(data.start, data.end), {
+  .refine((data) =&gt; !isSameType(data.start, data.end) || isBefore(data.start, data.end), {
     message: &quot;Event start time must be earlier than end time&quot;,
     path: [&quot;start&quot;],
</file context>
Suggested change
.refine((data) => !isSameType(data.start, data.end) || isBefore(data.start, data.end), {
.refine((data) => isSameType(data.start, data.end) && isBefore(data.start, data.end), {

✅ Addressed in b4d71dd

@JeanMeijer
Copy link
Collaborator Author

@tembo resolve the merge conflict, fix the type errors, and run format

@tembo
Copy link
Contributor

tembo bot commented Nov 5, 2025

@tembo resolve the merge conflict, fix the type errors, and run format

Resolved the merge conflict, fixed type errors by adding explicit type guards for each Temporal type (PlainDate, Instant, ZonedDateTime) before calling isBefore, and ran formatter to clean up imports and formatting.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 1 file

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