✨ feat(timeline): intuitive since/until window bounds for queryTimeline (BREAKING)#77
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces a breaking change to the queryTimeline endpoint and SDK by renaming the date bounds from startDate/endDate to since/until with conventional, optional semantics. It rewrites loadTimelinePeriods to dynamically derive week, month, and year rollup periods from the day nodes actually present in the database within the specified range, which resolves a bug where past periods were incorrectly excluded. Additionally, it updates documentation, migration guides, and tests, and adds a prepublishOnly script to package.json to automate SDK builds before publishing. The reviewer suggested relaxing the strict regex validation on the optional since and until fields in the Zod schema to prevent validation failures when empty strings are passed, recommending that validation be handled in the resolver instead.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| since: z | ||
| .string() | ||
| .regex(dateRegex, "startDate must be in YYYY-MM-DD format") | ||
| .regex(dateRegex, "since must be in YYYY-MM-DD format") | ||
| .optional(), | ||
| endDate: z | ||
| until: z | ||
| .string() | ||
| .regex(dateRegex, "endDate must be in YYYY-MM-DD format") | ||
| .regex(dateRegex, "until must be in YYYY-MM-DD format") | ||
| .optional(), |
There was a problem hiding this comment.
To prevent the entire schema validation from failing when empty strings are passed for the optional since or until fields, we should avoid strict validation directly on these optional fields in the schema. Instead, we should allow any string in the schema and handle trimming, empty string checks, and date format validation in the resolver function. This prevents discarding other valid fields if these optional fields are empty.
since: z.string().optional(),
until: z.string().optional(),References
- Avoid using strict validation like
.min(1)on optional fields in Zod schemas when an empty string could cause the entire schema validation to fail. Instead, allow any string in the schema and handle trimming and non-empty checks in the resolver function to prevent discarding other valid fields.
What & why
queryTimeline's date bounds were named and defaulted backwards:startDatewas the newest edge (default today),endDatethe oldest (default 90 days ago) — the reverse of the universalstart ≤ endconvention. Petals, reading the names the obvious way, sent{ endDate: today }, which the backend resolved to the window[today, today]and starved every past period — so every week/month/year recap in the memory timeline showed "no recap" even though the rollup nodes (e.g.2026-W23) existed with real summaries.queryTimelineis consumed only by Petals (no n8n node, no other repo), so this corrects the contract cleanly instead of working around it.Changes
startDate/endDate→since/untilwith conventional, optional semantics:since= earliest day inclusive,until= latest day inclusive; both optional; an omitted bound is open on that side. No implicittoday/90-days-ago defaults, no defensive min/max swap.includePeriodsderives rollup periods from the day nodes actually in range —loadTimelinePeriodscollects the week/month/year keys of the in-rangeYYYY-MM-DDday nodes and loads exactly those rollups (deleting the oldperiodKeysForWindowcalendar-enumeration). Open bounds work for free, and an open{ until: today }feed now returns past-period summaries. Regression test pins this.prepublishOnlyhook runspnpm run build-sdkbeforepnpm publish, closing the stale-distpublishing footgun.build:checktype errors insrc/lib/query/sample-nodes.{ts,test.ts}that shipped onmain(1.30.0) — see note below.Breaking change
This renames public
@marcelsamyn/memorySDK request fields → major version bump (next release2.0.0). Petals is the sole consumer and is updated in a follow-on PR once2.0.0publishes; the n8n node is unaffected.How to test
All green (DB-backed tests run against Postgres on
localhost:5431). Full suite: 546 tests passing.Drive-by:
sample-nodesbuild:check fixbuild:checkwas already failing onmain(1.30.0) with type errors insrc/lib/query/sample-nodes.ts+sample-nodes.test.ts(nullableobjectNodeIdbreakingunionAllbranch-type matching;string[]vs theNodeTypeunion; aClientvsPooltest-helper annotation; and an invalidassertedByKind: "user_stated"value that isn't in the enum). Folded type-only fixes in here so CI goes green — no runtime/query behavior change; thesample-nodesDB test runs and passes.Checklist