Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]>",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion src/models/card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
33 changes: 32 additions & 1 deletion src/models/color.ts
Original file line number Diff line number Diff line change
@@ -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<typeof ColorSchema>;
2 changes: 1 addition & 1 deletion tests/unit/models/breadth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
37 changes: 37 additions & 0 deletions tests/unit/models/card.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
});