Skip to content

feat: add template gallery read endpoints to TemplateClient - #603

Draft
scottlovegrove wants to merge 5 commits into
mainfrom
scottl/templates-read
Draft

feat: add template gallery read endpoints to TemplateClient#603
scottlovegrove wants to merge 5 commits into
mainfrom
scottl/templates-read

Conversation

@scottlovegrove

Copy link
Copy Markdown
Contributor

Summary

  • Adds getTemplates, getTemplateCategories, and getTemplatesByIds to the SDK, exposing the Todoist template gallery (Doist, user, and workspace templates). These endpoints are live but absent from the public OpenAPI spec.
  • Introduces a full Zod TemplateSchema + TemplateCategorySchema with runtime validation.
  • Derives query-filter unions (TEMPLATE_TYPE_FILTERS, TEMPLATE_SOURCE_FILTERS) from base response unions to keep a single source of truth — adding 'all' / 'workspace' only as accepted query inputs while keeping the response schema strict.
  • Joins templateIds into a CSV (the API expects a comma-separated string param) and rebuilds the response map keyed by each template's own id so the auto camelCase conversion can't mangle the keys.

PR 1 of 2 — write endpoints (user-template CRUD + multipart upload) will follow in a separate PR.

Test plan

  • npm run check (oxlint + oxfmt) passes
  • npm test — full suite, 589 tests pass
  • New MSW-based tests cover camelCase conversion, snake_case query param serialization, and the /get ID-map quirk
  • Manual smoke test against the live API once merged

🤖 Generated with Claude Code

Adds getTemplates, getTemplateCategories, and getTemplatesByIds to
TemplateClient, exposing the Doist gallery, user templates, and
workspace templates. These endpoints are live but undocumented in the
public OpenAPI spec.

Introduces a full Zod TemplateSchema + TemplateCategorySchema with
runtime validation, derives query-filter unions from the base response
unions to keep a single source of truth, and joins template IDs into
a CSV for the GET /templates/get endpoint.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@scottlovegrove scottlovegrove self-assigned this May 15, 2026

@doistbot doistbot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This PR introduces the template gallery read endpoints to the SDK alongside comprehensive Zod schemas for runtime validation. Exposing these features is a great addition that carefully navigates API quirks like query-filter unions and response map keys. A few refinements would help polish the implementation, particularly around enforcing input constraints for template IDs, strictly validating raw transport shapes before parsing, reusing existing constants and request utilities, and making the test fixtures and assertions a bit more robust.

Share FeedbackReview Logs

Comment thread src/clients/template-client.ts Outdated
Comment thread src/clients/template-client.ts Outdated
Comment thread src/types/templates/types.ts Outdated
Comment thread src/clients/template-client.ts Outdated
Comment thread src/todoist-api.templates.test.ts Outdated
Comment thread src/clients/template-client.ts
Comment thread src/clients/template-client.ts
Comment thread src/todoist-api.templates.test.ts Outdated
scottlovegrove and others added 2 commits May 15, 2026 17:29
- Validate templateIds in getTemplatesByIds (non-empty array, 1..100 IDs,
  no empty strings) before building the CSV, throwing TodoistArgumentError.
- Validate that the /templates/get response actually contains a `templates`
  object instead of silently falling back to `{}` on malformed payloads.
- Type all three new request<> calls with raw transport shapes
  (RawGetTemplates*Response) so domain types only appear after validation,
  matching the rest of the client.
- Drop locally-defined TEMPLATE_VIEW_TYPES; reuse PROJECT_VIEW_STYLES per
  AGENTS.md single-source-of-truth rule.
- Use shared spreadIfDefined helper for optional locale/nextCursor.
- Hoist MOCK_TEMPLATE_API fixture to module scope so getTemplates and
  getTemplatesByIds tests share one source of truth.
- Assert template_ids via URL.searchParams instead of hard-coding the
  %2C-encoded form.
- Add unit tests covering each input-validation rejection and the
  malformed-response error path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…knowns

- Define GetTemplatesResponseSchema, GetTemplateCategoriesResponseSchema,
  and GetTemplatesByIdsResponseSchema in types/templates/types.ts, mirroring
  the server-side TypedDicts in todoist/apps/import_export.
- Derive GetTemplates*Response types via z.infer so the public TS types and
  the runtime validators stay in lockstep.
- GetTemplatesByIdsResponseSchema uses .transform() to rebuild the templates
  map keyed by each validated template's own `id`, sidestepping the HTTP
  client's snake_case → camelCase key mangling at the schema level instead
  of in the client.
- Drop the locally-defined RawGetTemplates*Response shapes and unknown
  fallbacks in TemplateClient; request<> is now typed with the published
  domain types like every other client, and the response is parsed through
  the new validators.
- Add validateGetTemplatesResponse / validateGetTemplateCategoriesResponse /
  validateGetTemplatesByIdsResponse via createValidator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
scottlovegrove and others added 2 commits May 17, 2026 14:45
User templates omit `import_url` entirely from the response (see
map_user_template_to_contentful_response in todoist/apps/import_export/
controllers/common.py), so the schema needs to accept undefined as well
as null. Surfaced by a live `getTemplates({ templateSource: 'user' })`
call, which was failing with "expected string, received undefined".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI's `npx @arethetypeswrong/cli` resolved attw 0.18.2 fresh each run, which
in turn pulled the latest transitive fflate. fflate 0.8.3 (published
2026-05-16) broke attw's tarball parsing with
"Cannot read properties of undefined (reading 'filename')". Local checks
were still passing because they had cached fflate 0.8.2.

- Install @arethetypeswrong/cli as a devDependency so it resolves through
  package-lock.json instead of the live registry, and call it as `attw`
  rather than via `npx`.
- Add an `overrides` entry forcing fflate@0.8.2 so attw can read the
  packed tarball again. Remove once attw / fflate ship a fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@scottlovegrove
scottlovegrove marked this pull request as draft May 22, 2026 19:53
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