diff --git a/CHANGELOG.md b/CHANGELOG.md index 68252853..83a84d23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Trello.js changelog +## v2.1.6 (2026-07-05) + +### Fixed + +- `Card.dueReminder` is now typed as `number` instead of `string`. The live Trello API returns this field as a number (minutes before the due date), so every card-returning endpoint could reject with `ZodError: expected string, received number` — surfaced on `getBoardCards` / `getListCards` as `path [n, "dueReminder"]`. Now matches the already-correct `CheckItem.dueReminder`. +- `ColorSchema` now accepts the `_light` / `_dark` shade variants (e.g. `sky_dark`, `green_light`). The documented palette is 10 base colors, but the live API also returns the shade variants introduced in the May 2023 label redesign (30 values total); a label using one raised `ZodError: invalid_value` on `labels[].color`, breaking `getBoardCards` / `getListCards`. Closes [#48](https://github.com/MrRefactoring/trello.js/issues/48) — thanks to [@sampgoes97-ux](https://github.com/sampgoes97-ux) for the detailed report. + ## v2.1.5 (2026-07-04) ### Fixed diff --git a/package.json b/package.json index b9f1ee96..d0168202 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "imports": { "#/*": "./src/*" }, - "version": "2.1.5", + "version": "2.1.6", "description": "Type-safe Trello REST API client for TypeScript and JavaScript. ESM-only, tree-shakable, runtime-validated by Zod 4. Full coverage of boards, cards, lists, checklists, members, webhooks, organizations. Atlassian Trello SDK for Node.js 22+ and modern browsers.", "author": "Vladislav Tupikin ", "license": "MIT", diff --git a/src/models/card.ts b/src/models/card.ts index fb90522c..1f521873 100644 --- a/src/models/card.ts +++ b/src/models/card.ts @@ -45,7 +45,7 @@ export const CardSchema = apiObject({ emoji: z.record(z.string(), z.any()).optional(), }).optional(), due: z.coerce.date().nullish(), - dueReminder: z.string().nullish(), + dueReminder: z.number().nullish(), idBoard: z.string().optional(), idChecklists: z.array(z.union([ChecklistSchema, z.string()])).optional(), idLabels: z.array(z.union([LabelSchema, z.string()])).optional(), diff --git a/src/models/color.ts b/src/models/color.ts index 4cfeb3fb..e72c68b2 100644 --- a/src/models/color.ts +++ b/src/models/color.ts @@ -1,7 +1,38 @@ import { z } from 'zod'; export const ColorSchema = z - .enum(['yellow', 'purple', 'blue', 'red', 'green', 'orange', 'black', 'sky', 'pink', 'lime']) + .enum([ + 'yellow', + 'purple', + 'blue', + 'red', + 'green', + 'orange', + 'black', + 'sky', + 'pink', + 'lime', + 'yellow_dark', + 'purple_dark', + 'blue_dark', + 'red_dark', + 'green_dark', + 'orange_dark', + 'black_dark', + 'sky_dark', + 'pink_dark', + 'lime_dark', + 'yellow_light', + 'purple_light', + 'blue_light', + 'red_light', + 'green_light', + 'orange_light', + 'black_light', + 'sky_light', + 'pink_light', + 'lime_light', + ]) .nullable(); export type Color = z.infer; diff --git a/tests/unit/models/breadth.test.ts b/tests/unit/models/breadth.test.ts index 823d85f0..c444ee8e 100644 --- a/tests/unit/models/breadth.test.ts +++ b/tests/unit/models/breadth.test.ts @@ -60,7 +60,7 @@ describe('response schema breadth — minimal vs maximal', () => { desc: 'a description', descData: { emoji: {} }, due: ISO, - dueReminder: '1440', + dueReminder: 1440, idBoard: ID, idChecklists: [ID], idLabels: [ID], diff --git a/tests/unit/models/card.test.ts b/tests/unit/models/card.test.ts index cd9558b4..d6c19b37 100644 --- a/tests/unit/models/card.test.ts +++ b/tests/unit/models/card.test.ts @@ -54,3 +54,40 @@ describe('CardSchema — checkItemStates objects', () => { ).toThrow(); }); }); + +// Drift surfaced in issue #48 (ZodError on getBoardCards). The API returns +// `dueReminder` as a number (minutes before the due date), not a string, and +// labels can carry the undocumented `_light` / `_dark` shade colors. +describe('CardSchema — dueReminder is a number (issue #48)', () => { + const baseCard = { id: 'a'.repeat(24) }; + + it('accepts dueReminder as a number', () => { + expect(() => CardSchema.parse({ ...baseCard, dueReminder: 1440 })).not.toThrow(); + }); + + it('accepts dueReminder as null', () => { + expect(() => CardSchema.parse({ ...baseCard, dueReminder: null })).not.toThrow(); + }); + + it('rejects dueReminder as a string (the old, wrong shape)', () => { + expect(() => CardSchema.parse({ ...baseCard, dueReminder: '1440' })).toThrow(); + }); +}); + +describe('CardSchema — label shade colors (issue #48)', () => { + const baseCard = { id: 'a'.repeat(24) }; + const label = (color: string) => ({ id: 'l'.repeat(24), color }); + + it('accepts the new `_dark` / `_light` shade variants on labels', () => { + expect(() => + CardSchema.parse({ + ...baseCard, + labels: [label('sky_dark'), label('green_light'), label('blue')], + }), + ).not.toThrow(); + }); + + it('rejects an unknown color that is not part of the palette', () => { + expect(() => CardSchema.parse({ ...baseCard, labels: [label('teal')] })).toThrow(); + }); +});