@todoist/sdk 0.0.1 → 18.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (335) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +293 -29
  3. package/dist/esm/authentication.js +307 -0
  4. package/dist/esm/clients/activity-client.js +60 -0
  5. package/dist/esm/clients/app-client.js +366 -0
  6. package/dist/esm/clients/backup-client.js +47 -0
  7. package/dist/esm/clients/base-client.js +29 -0
  8. package/dist/esm/clients/billing-client.js +160 -0
  9. package/dist/esm/clients/comment-client.js +92 -0
  10. package/dist/esm/clients/email-client.js +41 -0
  11. package/dist/esm/clients/filter-client.js +26 -0
  12. package/dist/esm/clients/folder-client.js +80 -0
  13. package/dist/esm/clients/id-mapping-client.js +37 -0
  14. package/dist/esm/clients/insights-client.js +89 -0
  15. package/dist/esm/clients/label-client.js +131 -0
  16. package/dist/esm/clients/productivity-client.js +24 -0
  17. package/dist/esm/clients/project-client.js +284 -0
  18. package/dist/esm/clients/reminder-client.js +204 -0
  19. package/dist/esm/clients/section-client.js +121 -0
  20. package/dist/esm/clients/task-client.js +264 -0
  21. package/dist/esm/clients/template-client.js +89 -0
  22. package/dist/esm/clients/ui-extension-client.js +110 -0
  23. package/dist/esm/clients/upload-client.js +153 -0
  24. package/dist/esm/clients/view-options-client.js +21 -0
  25. package/dist/esm/clients/workspace-client.js +384 -0
  26. package/dist/esm/consts/endpoints.js +193 -0
  27. package/dist/esm/index.js +5 -0
  28. package/dist/esm/test-utils/asserts.js +8 -0
  29. package/dist/esm/test-utils/msw-setup.js +88 -0
  30. package/dist/esm/test-utils/obsidian-fetch-adapter.js +51 -0
  31. package/dist/esm/test-utils/test-defaults.js +367 -0
  32. package/dist/esm/test-utils/transport-seam.js +15 -0
  33. package/dist/esm/test-utils/webhook-fixtures.js +26 -0
  34. package/dist/esm/todoist-api.js +1757 -0
  35. package/dist/esm/transport/fetch-with-retry.js +216 -0
  36. package/dist/esm/transport/http-client.js +140 -0
  37. package/dist/esm/transport/http-dispatcher.js +158 -0
  38. package/dist/esm/transport/sync-request.js +106 -0
  39. package/dist/esm/types/activity/index.js +2 -0
  40. package/dist/esm/types/activity/requests.js +1 -0
  41. package/dist/esm/types/activity/types.js +45 -0
  42. package/dist/esm/types/apps/index.js +2 -0
  43. package/dist/esm/types/apps/requests.js +1 -0
  44. package/dist/esm/types/apps/types.js +249 -0
  45. package/dist/esm/types/backups/index.js +2 -0
  46. package/dist/esm/types/backups/requests.js +1 -0
  47. package/dist/esm/types/backups/types.js +5 -0
  48. package/dist/esm/types/billing/index.js +2 -0
  49. package/dist/esm/types/billing/requests.js +1 -0
  50. package/dist/esm/types/billing/types.js +89 -0
  51. package/dist/esm/types/comments/index.js +2 -0
  52. package/dist/esm/types/comments/requests.js +1 -0
  53. package/dist/esm/types/comments/types.js +57 -0
  54. package/dist/esm/types/common.js +7 -0
  55. package/dist/esm/types/emails/index.js +1 -0
  56. package/dist/esm/types/emails/requests.js +2 -0
  57. package/dist/esm/types/errors.js +41 -0
  58. package/dist/esm/types/folders/index.js +1 -0
  59. package/dist/esm/types/folders/requests.js +1 -0
  60. package/dist/esm/types/http.js +20 -0
  61. package/dist/esm/types/id-mappings/index.js +2 -0
  62. package/dist/esm/types/id-mappings/requests.js +17 -0
  63. package/dist/esm/types/id-mappings/types.js +9 -0
  64. package/dist/esm/types/index.js +24 -0
  65. package/dist/esm/types/insights/index.js +2 -0
  66. package/dist/esm/types/insights/requests.js +1 -0
  67. package/dist/esm/types/insights/types.js +77 -0
  68. package/dist/esm/types/labels/index.js +2 -0
  69. package/dist/esm/types/labels/requests.js +1 -0
  70. package/dist/esm/types/labels/types.js +8 -0
  71. package/dist/esm/types/productivity/index.js +1 -0
  72. package/dist/esm/types/productivity/types.js +65 -0
  73. package/dist/esm/types/projects/index.js +2 -0
  74. package/dist/esm/types/projects/requests.js +1 -0
  75. package/dist/esm/types/projects/types.js +65 -0
  76. package/dist/esm/types/reminders/index.js +1 -0
  77. package/dist/esm/types/reminders/requests.js +92 -0
  78. package/dist/esm/types/sections/index.js +2 -0
  79. package/dist/esm/types/sections/requests.js +1 -0
  80. package/dist/esm/types/sections/types.js +23 -0
  81. package/dist/esm/types/sync/commands/calendars.js +1 -0
  82. package/dist/esm/types/sync/commands/filters.js +1 -0
  83. package/dist/esm/types/sync/commands/folders.js +1 -0
  84. package/dist/esm/types/sync/commands/index.js +18 -0
  85. package/dist/esm/types/sync/commands/labels.js +2 -0
  86. package/dist/esm/types/sync/commands/notes.js +1 -0
  87. package/dist/esm/types/sync/commands/notifications.js +1 -0
  88. package/dist/esm/types/sync/commands/others.js +1 -0
  89. package/dist/esm/types/sync/commands/project-view-options.js +1 -0
  90. package/dist/esm/types/sync/commands/projects.js +1 -0
  91. package/dist/esm/types/sync/commands/reminders.js +1 -0
  92. package/dist/esm/types/sync/commands/sections.js +1 -0
  93. package/dist/esm/types/sync/commands/shared.js +16 -0
  94. package/dist/esm/types/sync/commands/sharing.js +1 -0
  95. package/dist/esm/types/sync/commands/tasks.js +1 -0
  96. package/dist/esm/types/sync/commands/view-options.js +1 -0
  97. package/dist/esm/types/sync/commands/workspace-filters.js +1 -0
  98. package/dist/esm/types/sync/commands/workspaces.js +1 -0
  99. package/dist/esm/types/sync/index.js +6 -0
  100. package/dist/esm/types/sync/request.js +1 -0
  101. package/dist/esm/types/sync/resource-types.js +36 -0
  102. package/dist/esm/types/sync/resources/calendars.js +24 -0
  103. package/dist/esm/types/sync/resources/collaborators.js +21 -0
  104. package/dist/esm/types/sync/resources/completed-info.js +21 -0
  105. package/dist/esm/types/sync/resources/filters.js +12 -0
  106. package/dist/esm/types/sync/resources/folders.js +10 -0
  107. package/dist/esm/types/sync/resources/index.js +18 -0
  108. package/dist/esm/types/sync/resources/labels.js +7 -0
  109. package/dist/esm/types/sync/resources/live-notifications.js +35 -0
  110. package/dist/esm/types/sync/resources/notes.js +18 -0
  111. package/dist/esm/types/sync/resources/reminders.js +58 -0
  112. package/dist/esm/types/sync/resources/suggestions.js +33 -0
  113. package/dist/esm/types/sync/resources/tooltips.js +5 -0
  114. package/dist/esm/types/sync/resources/user-plan-limits.js +21 -0
  115. package/dist/esm/types/sync/resources/user-settings.js +41 -0
  116. package/dist/esm/types/sync/resources/user-status.js +22 -0
  117. package/dist/esm/types/sync/resources/user.js +109 -0
  118. package/dist/esm/types/sync/resources/view-options.js +128 -0
  119. package/dist/esm/types/sync/resources/workspace-filters.js +17 -0
  120. package/dist/esm/types/sync/resources/workspaces.js +69 -0
  121. package/dist/esm/types/sync/response.js +57 -0
  122. package/dist/esm/types/sync/user-preferences.js +68 -0
  123. package/dist/esm/types/tasks/index.js +2 -0
  124. package/dist/esm/types/tasks/requests.js +1 -0
  125. package/dist/esm/types/tasks/types.js +56 -0
  126. package/dist/esm/types/templates/index.js +1 -0
  127. package/dist/esm/types/templates/requests.js +1 -0
  128. package/dist/esm/types/ui-extensions/index.js +2 -0
  129. package/dist/esm/types/ui-extensions/requests.js +1 -0
  130. package/dist/esm/types/ui-extensions/types.js +74 -0
  131. package/dist/esm/types/uploads/index.js +1 -0
  132. package/dist/esm/types/uploads/requests.js +1 -0
  133. package/dist/esm/types/users/index.js +1 -0
  134. package/dist/esm/types/users/types.js +49 -0
  135. package/dist/esm/types/webhooks/comments.js +93 -0
  136. package/dist/esm/types/webhooks/envelope.js +23 -0
  137. package/dist/esm/types/webhooks/filters.js +27 -0
  138. package/dist/esm/types/webhooks/index.js +9 -0
  139. package/dist/esm/types/webhooks/labels.js +51 -0
  140. package/dist/esm/types/webhooks/projects.js +33 -0
  141. package/dist/esm/types/webhooks/reminders.js +32 -0
  142. package/dist/esm/types/webhooks/sections.js +50 -0
  143. package/dist/esm/types/webhooks/tasks.js +65 -0
  144. package/dist/esm/types/webhooks/types.js +52 -0
  145. package/dist/esm/types/workspaces/index.js +2 -0
  146. package/dist/esm/types/workspaces/requests.js +1 -0
  147. package/dist/esm/types/workspaces/types.js +151 -0
  148. package/dist/esm/utils/activity-helpers.js +53 -0
  149. package/dist/esm/utils/case-conversion.js +84 -0
  150. package/dist/esm/utils/colors.js +145 -0
  151. package/dist/esm/utils/file-response.js +29 -0
  152. package/dist/esm/utils/filter-queries.js +231 -0
  153. package/dist/esm/utils/filter-query-definitions.js +2789 -0
  154. package/dist/esm/utils/headers.js +42 -0
  155. package/dist/esm/utils/index.js +11 -0
  156. package/dist/esm/utils/multipart-upload.js +267 -0
  157. package/dist/esm/utils/person-names.js +61 -0
  158. package/dist/esm/utils/processing-helpers.js +12 -0
  159. package/dist/esm/utils/project-helpers.js +29 -0
  160. package/dist/esm/utils/request-helpers.js +43 -0
  161. package/dist/esm/utils/sanitization.js +131 -0
  162. package/dist/esm/utils/sync-helpers.js +19 -0
  163. package/dist/esm/utils/task-sorting.js +280 -0
  164. package/dist/esm/utils/uncompletable-helpers.js +54 -0
  165. package/dist/esm/utils/url-helpers.js +196 -0
  166. package/dist/esm/utils/validators.js +102 -0
  167. package/dist/esm/utils/view-options.js +15 -0
  168. package/dist/esm/utils/webhook-parser.js +56 -0
  169. package/dist/types/authentication.d.ts +262 -0
  170. package/dist/types/clients/activity-client.d.ts +12 -0
  171. package/dist/types/clients/app-client.d.ts +37 -0
  172. package/dist/types/clients/backup-client.d.ts +14 -0
  173. package/dist/types/clients/base-client.d.ts +23 -0
  174. package/dist/types/clients/billing-client.d.ts +22 -0
  175. package/dist/types/clients/comment-client.d.ts +15 -0
  176. package/dist/types/clients/email-client.d.ts +13 -0
  177. package/dist/types/clients/filter-client.d.ts +10 -0
  178. package/dist/types/clients/folder-client.d.ts +16 -0
  179. package/dist/types/clients/id-mapping-client.d.ts +13 -0
  180. package/dist/types/clients/insights-client.d.ts +18 -0
  181. package/dist/types/clients/label-client.d.ts +19 -0
  182. package/dist/types/clients/productivity-client.d.ts +12 -0
  183. package/dist/types/clients/project-client.d.ts +22 -0
  184. package/dist/types/clients/reminder-client.d.ts +25 -0
  185. package/dist/types/clients/section-client.d.ts +18 -0
  186. package/dist/types/clients/task-client.d.ts +25 -0
  187. package/dist/types/clients/template-client.d.ts +17 -0
  188. package/dist/types/clients/ui-extension-client.d.ts +18 -0
  189. package/dist/types/clients/upload-client.d.ts +17 -0
  190. package/dist/types/clients/view-options-client.d.ts +8 -0
  191. package/dist/types/clients/workspace-client.d.ts +43 -0
  192. package/dist/types/consts/endpoints.d.ts +120 -0
  193. package/dist/types/index.d.ts +6 -0
  194. package/dist/types/test-utils/asserts.d.ts +1 -0
  195. package/dist/types/test-utils/msw-setup.d.ts +33 -0
  196. package/dist/types/test-utils/obsidian-fetch-adapter.d.ts +29 -0
  197. package/dist/types/test-utils/test-defaults.d.ts +286 -0
  198. package/dist/types/test-utils/transport-seam.d.ts +1 -0
  199. package/dist/types/test-utils/webhook-fixtures.d.ts +13 -0
  200. package/dist/types/todoist-api.d.ts +1437 -0
  201. package/dist/types/transport/fetch-with-retry.d.ts +12 -0
  202. package/dist/types/transport/http-client.d.ts +25 -0
  203. package/dist/types/transport/http-dispatcher.d.ts +65 -0
  204. package/dist/types/transport/sync-request.d.ts +31 -0
  205. package/dist/types/types/activity/index.d.ts +2 -0
  206. package/dist/types/types/activity/requests.d.ts +85 -0
  207. package/dist/types/types/activity/types.d.ts +56 -0
  208. package/dist/types/types/apps/index.d.ts +2 -0
  209. package/dist/types/types/apps/requests.d.ts +89 -0
  210. package/dist/types/types/apps/types.d.ts +418 -0
  211. package/dist/types/types/backups/index.d.ts +2 -0
  212. package/dist/types/types/backups/requests.d.ts +16 -0
  213. package/dist/types/types/backups/types.d.ts +7 -0
  214. package/dist/types/types/billing/index.d.ts +2 -0
  215. package/dist/types/types/billing/requests.d.ts +62 -0
  216. package/dist/types/types/billing/types.d.ts +207 -0
  217. package/dist/types/types/comments/index.d.ts +2 -0
  218. package/dist/types/types/comments/requests.d.ts +64 -0
  219. package/dist/types/types/comments/types.d.ts +141 -0
  220. package/dist/types/types/common.d.ts +13 -0
  221. package/dist/types/types/emails/index.d.ts +1 -0
  222. package/dist/types/types/emails/requests.d.ts +30 -0
  223. package/dist/types/types/errors.d.ts +29 -0
  224. package/dist/types/types/folders/index.d.ts +1 -0
  225. package/dist/types/types/folders/requests.d.ts +20 -0
  226. package/dist/types/types/http.d.ts +104 -0
  227. package/dist/types/types/id-mappings/index.d.ts +2 -0
  228. package/dist/types/types/id-mappings/requests.d.ts +28 -0
  229. package/dist/types/types/id-mappings/types.d.ts +13 -0
  230. package/dist/types/types/index.d.ts +24 -0
  231. package/dist/types/types/insights/index.d.ts +2 -0
  232. package/dist/types/types/insights/requests.d.ts +26 -0
  233. package/dist/types/types/insights/types.d.ts +167 -0
  234. package/dist/types/types/labels/index.d.ts +2 -0
  235. package/dist/types/types/labels/requests.d.ts +75 -0
  236. package/dist/types/types/labels/types.d.ts +13 -0
  237. package/dist/types/types/productivity/index.d.ts +1 -0
  238. package/dist/types/types/productivity/types.d.ts +115 -0
  239. package/dist/types/types/projects/index.d.ts +2 -0
  240. package/dist/types/types/projects/requests.d.ts +206 -0
  241. package/dist/types/types/projects/types.d.ts +286 -0
  242. package/dist/types/types/reminders/index.d.ts +1 -0
  243. package/dist/types/types/reminders/requests.d.ts +205 -0
  244. package/dist/types/types/sections/index.d.ts +2 -0
  245. package/dist/types/types/sections/requests.d.ts +49 -0
  246. package/dist/types/types/sections/types.d.ts +70 -0
  247. package/dist/types/types/sync/commands/calendars.d.ts +14 -0
  248. package/dist/types/types/sync/commands/filters.d.ts +24 -0
  249. package/dist/types/types/sync/commands/folders.d.ts +20 -0
  250. package/dist/types/types/sync/commands/index.d.ts +167 -0
  251. package/dist/types/types/sync/commands/labels.d.ts +32 -0
  252. package/dist/types/types/sync/commands/notes.d.ts +27 -0
  253. package/dist/types/types/sync/commands/notifications.d.ts +10 -0
  254. package/dist/types/types/sync/commands/others.d.ts +61 -0
  255. package/dist/types/types/sync/commands/project-view-options.d.ts +13 -0
  256. package/dist/types/types/sync/commands/projects.d.ts +96 -0
  257. package/dist/types/types/sync/commands/reminders.d.ts +51 -0
  258. package/dist/types/types/sync/commands/sections.d.ts +36 -0
  259. package/dist/types/types/sync/commands/shared.d.ts +51 -0
  260. package/dist/types/types/sync/commands/sharing.d.ts +16 -0
  261. package/dist/types/types/sync/commands/tasks.d.ts +78 -0
  262. package/dist/types/types/sync/commands/view-options.d.ts +18 -0
  263. package/dist/types/types/sync/commands/workspace-filters.d.ts +25 -0
  264. package/dist/types/types/sync/commands/workspaces.d.ts +82 -0
  265. package/dist/types/types/sync/index.d.ts +6 -0
  266. package/dist/types/types/sync/request.d.ts +7 -0
  267. package/dist/types/types/sync/resource-types.d.ts +5 -0
  268. package/dist/types/types/sync/resources/calendars.d.ts +38 -0
  269. package/dist/types/types/sync/resources/collaborators.d.ts +45 -0
  270. package/dist/types/types/sync/resources/completed-info.d.ts +33 -0
  271. package/dist/types/types/sync/resources/filters.d.ts +13 -0
  272. package/dist/types/types/sync/resources/folders.d.ts +11 -0
  273. package/dist/types/types/sync/resources/index.d.ts +18 -0
  274. package/dist/types/types/sync/resources/labels.d.ts +12 -0
  275. package/dist/types/types/sync/resources/live-notifications.d.ts +32 -0
  276. package/dist/types/types/sync/resources/notes.d.ts +34 -0
  277. package/dist/types/types/sync/resources/reminders.d.ts +213 -0
  278. package/dist/types/types/sync/resources/suggestions.d.ts +96 -0
  279. package/dist/types/types/sync/resources/tooltips.d.ts +6 -0
  280. package/dist/types/types/sync/resources/user-plan-limits.d.ts +47 -0
  281. package/dist/types/types/sync/resources/user-settings.d.ts +40 -0
  282. package/dist/types/types/sync/resources/user-status.d.ts +46 -0
  283. package/dist/types/types/sync/resources/user.d.ts +151 -0
  284. package/dist/types/types/sync/resources/view-options.d.ts +157 -0
  285. package/dist/types/types/sync/resources/workspace-filters.d.ts +18 -0
  286. package/dist/types/types/sync/resources/workspaces.d.ts +142 -0
  287. package/dist/types/types/sync/response.d.ts +930 -0
  288. package/dist/types/types/sync/user-preferences.d.ts +39 -0
  289. package/dist/types/types/tasks/index.d.ts +2 -0
  290. package/dist/types/types/tasks/requests.d.ts +197 -0
  291. package/dist/types/types/tasks/types.d.ts +162 -0
  292. package/dist/types/types/templates/index.d.ts +1 -0
  293. package/dist/types/types/templates/requests.d.ts +92 -0
  294. package/dist/types/types/ui-extensions/index.d.ts +2 -0
  295. package/dist/types/types/ui-extensions/requests.d.ts +108 -0
  296. package/dist/types/types/ui-extensions/types.d.ts +185 -0
  297. package/dist/types/types/uploads/index.d.ts +1 -0
  298. package/dist/types/types/uploads/requests.d.ts +32 -0
  299. package/dist/types/types/users/index.d.ts +1 -0
  300. package/dist/types/types/users/types.d.ts +67 -0
  301. package/dist/types/types/webhooks/comments.d.ts +1600 -0
  302. package/dist/types/types/webhooks/envelope.d.ts +34 -0
  303. package/dist/types/types/webhooks/filters.d.ts +99 -0
  304. package/dist/types/types/webhooks/index.d.ts +9 -0
  305. package/dist/types/types/webhooks/labels.d.ts +160 -0
  306. package/dist/types/types/webhooks/projects.d.ts +365 -0
  307. package/dist/types/types/webhooks/reminders.d.ts +82 -0
  308. package/dist/types/types/webhooks/sections.d.ts +372 -0
  309. package/dist/types/types/webhooks/tasks.d.ts +981 -0
  310. package/dist/types/types/webhooks/types.d.ts +2606 -0
  311. package/dist/types/types/workspaces/index.d.ts +2 -0
  312. package/dist/types/types/workspaces/requests.d.ts +260 -0
  313. package/dist/types/types/workspaces/types.d.ts +266 -0
  314. package/dist/types/utils/activity-helpers.d.ts +28 -0
  315. package/dist/types/utils/case-conversion.d.ts +20 -0
  316. package/dist/types/utils/colors.d.ts +201 -0
  317. package/dist/types/utils/file-response.d.ts +15 -0
  318. package/dist/types/utils/filter-queries.d.ts +42 -0
  319. package/dist/types/utils/filter-query-definitions.d.ts +27 -0
  320. package/dist/types/utils/headers.d.ts +20 -0
  321. package/dist/types/utils/index.d.ts +15 -0
  322. package/dist/types/utils/multipart-upload.d.ts +58 -0
  323. package/dist/types/utils/person-names.d.ts +52 -0
  324. package/dist/types/utils/processing-helpers.d.ts +1 -0
  325. package/dist/types/utils/project-helpers.d.ts +21 -0
  326. package/dist/types/utils/request-helpers.d.ts +33 -0
  327. package/dist/types/utils/sanitization.d.ts +52 -0
  328. package/dist/types/utils/sync-helpers.d.ts +17 -0
  329. package/dist/types/utils/task-sorting.d.ts +46 -0
  330. package/dist/types/utils/uncompletable-helpers.d.ts +30 -0
  331. package/dist/types/utils/url-helpers.d.ts +120 -0
  332. package/dist/types/utils/validators.d.ts +1917 -0
  333. package/dist/types/utils/view-options.d.ts +11 -0
  334. package/dist/types/utils/webhook-parser.d.ts +48 -0
  335. package/package.json +87 -8
@@ -0,0 +1,151 @@
1
+ var __rest = (this && this.__rest) || function (s, e) {
2
+ var t = {};
3
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
+ t[p] = s[p];
5
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
+ t[p[i]] = s[p[i]];
9
+ }
10
+ return t;
11
+ };
12
+ import { z } from 'zod';
13
+ import { StringOrNumberSchema } from '../common.js';
14
+ import { DueDateSchema, DeadlineSchema } from '../tasks/types.js';
15
+ /** Available project collaborator roles. */
16
+ export const COLLABORATOR_ROLES = [
17
+ 'CREATOR',
18
+ 'ADMIN',
19
+ 'READ_WRITE',
20
+ 'EDIT_ONLY',
21
+ 'COMPLETE_ONLY',
22
+ ];
23
+ /**
24
+ * Available workspace roles.
25
+ */
26
+ export const WORKSPACE_ROLES = ['ADMIN', 'MEMBER', 'GUEST'];
27
+ export const WorkspaceRoleSchema = z.enum(WORKSPACE_ROLES);
28
+ export const WorkspaceUserSchema = z.object({
29
+ userId: z.string(),
30
+ workspaceId: z.string(),
31
+ userEmail: z.string(),
32
+ fullName: z.string(),
33
+ timezone: z.string(),
34
+ role: WorkspaceRoleSchema,
35
+ imageId: z.string().nullable(),
36
+ isDeleted: z.boolean().default(false),
37
+ });
38
+ export const WorkspaceInvitationSchema = z.object({
39
+ id: z.string().default('0'),
40
+ inviterId: z.string(),
41
+ userEmail: z.string(),
42
+ workspaceId: z.string(),
43
+ role: WorkspaceRoleSchema,
44
+ });
45
+ export const PlanPriceSchema = z.object({
46
+ currency: z.string(),
47
+ amount: z.union([z.number(), z.string()]),
48
+ interval: z.string().optional(),
49
+ });
50
+ export const FormattedPriceListingSchema = z.object({
51
+ currency: z.string().optional(),
52
+ amount: z.number().optional(),
53
+ interval: z.string().optional(),
54
+ formatted: z.string().optional(),
55
+ });
56
+ /** Available workspace plan names. */
57
+ export const WORKSPACE_CURRENT_PLANS = ['Business', 'Starter'];
58
+ /** Available workspace plan statuses. */
59
+ export const WORKSPACE_PLAN_STATUSES = [
60
+ 'Active',
61
+ 'Downgraded',
62
+ 'Cancelled',
63
+ 'NeverSubscribed',
64
+ ];
65
+ export const WorkspacePlanDetailsSchema = z.object({
66
+ currentMemberCount: z.number(),
67
+ currentPlan: z.enum(WORKSPACE_CURRENT_PLANS),
68
+ currentPlanStatus: z.enum(WORKSPACE_PLAN_STATUSES),
69
+ downgradeAt: z.string().nullable(),
70
+ currentActiveProjects: z.number(),
71
+ maximumActiveProjects: z.number(),
72
+ priceList: z.array(FormattedPriceListingSchema),
73
+ workspaceId: StringOrNumberSchema,
74
+ isTrialing: z.boolean(),
75
+ trialEndsAt: z.string().nullable(),
76
+ cancelAtPeriodEnd: z.boolean(),
77
+ hasTrialed: z.boolean(),
78
+ planPrice: PlanPriceSchema.nullable(),
79
+ hasBillingPortal: z.boolean(),
80
+ hasBillingPortalSwitchToAnnual: z.boolean(),
81
+ });
82
+ export const JoinWorkspaceResultSchema = z.object({
83
+ customSortingApplied: z.boolean(),
84
+ projectSortPreference: z.string(),
85
+ role: WorkspaceRoleSchema,
86
+ userId: z.string(),
87
+ workspaceId: z.string(),
88
+ });
89
+ /**
90
+ * Available workspace plans.
91
+ */
92
+ export const WORKSPACE_PLANS = ['STARTER', 'BUSINESS'];
93
+ export const WorkspacePlanSchema = z.enum(WORKSPACE_PLANS);
94
+ /**
95
+ * Workspace resource limits.
96
+ */
97
+ export const WorkspaceLimitsSchema = z
98
+ .object({
99
+ current: z.record(z.string(), z.any()).nullable(),
100
+ next: z.record(z.string(), z.any()).nullable(),
101
+ })
102
+ .catchall(z.any());
103
+ /**
104
+ * Workspace properties (flexible object for unknown fields).
105
+ */
106
+ export const WorkspacePropertiesSchema = z.record(z.string(), z.unknown());
107
+ /**
108
+ * Represents a workspace in Todoist.
109
+ */
110
+ export const WorkspaceSchema = z
111
+ .object({
112
+ id: StringOrNumberSchema,
113
+ name: z.string(),
114
+ plan: WorkspacePlanSchema,
115
+ role: WorkspaceRoleSchema.optional(),
116
+ inviteCode: z.string(),
117
+ isLinkSharingEnabled: z.boolean(),
118
+ isGuestAllowed: z.boolean(),
119
+ limits: WorkspaceLimitsSchema.optional(),
120
+ logoBig: z.string().nullish(),
121
+ logoMedium: z.string().nullish(),
122
+ logoSmall: z.string().nullish(),
123
+ logoS640: z.string().nullish(),
124
+ createdAt: z.coerce.date().optional(),
125
+ dateCreated: z.coerce.date().optional(),
126
+ creatorId: StringOrNumberSchema,
127
+ properties: WorkspacePropertiesSchema,
128
+ })
129
+ .transform((_a) => {
130
+ var { dateCreated, createdAt } = _a, rest = __rest(_a, ["dateCreated", "createdAt"]);
131
+ return (Object.assign(Object.assign({}, rest), { createdAt: createdAt !== null && createdAt !== void 0 ? createdAt : dateCreated }));
132
+ });
133
+ export const MemberActivityInfoSchema = z.object({
134
+ userId: z.string(),
135
+ tasksAssigned: z.number().int(),
136
+ tasksOverdue: z.number().int(),
137
+ });
138
+ export const WorkspaceUserTaskSchema = z.object({
139
+ id: z.string(),
140
+ content: z.string(),
141
+ responsibleUid: z.string().nullable(),
142
+ due: DueDateSchema.nullable(),
143
+ deadline: DeadlineSchema.nullable(),
144
+ labels: z.array(z.string()),
145
+ notesCount: z.number().int(),
146
+ projectId: z.string(),
147
+ projectName: z.string(),
148
+ priority: z.number().int(),
149
+ description: z.string(),
150
+ isOverdue: z.boolean(),
151
+ });
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Converts modern SDK object type naming to legacy API naming.
3
+ * Maps 'task' -> 'item' and 'comment' -> 'note' for API requests.
4
+ * Other values pass through unchanged.
5
+ *
6
+ * @internal
7
+ * @param objectType The object type using modern naming.
8
+ * @returns The object type using legacy API naming.
9
+ */
10
+ export function normalizeObjectTypeForApi(objectType) {
11
+ if (!objectType)
12
+ return objectType;
13
+ if (objectType === 'task')
14
+ return 'item';
15
+ if (objectType === 'comment')
16
+ return 'note';
17
+ return objectType;
18
+ }
19
+ /**
20
+ * Converts legacy API object type naming to modern SDK naming.
21
+ * Maps 'item' -> 'task' and 'note' -> 'comment' for SDK responses.
22
+ * Other values pass through unchanged.
23
+ *
24
+ * @internal
25
+ * @param objectType The object type using legacy API naming.
26
+ * @returns The object type using modern SDK naming.
27
+ */
28
+ export function denormalizeObjectTypeFromApi(objectType) {
29
+ if (!objectType)
30
+ return objectType;
31
+ if (objectType === 'item')
32
+ return 'task';
33
+ if (objectType === 'note')
34
+ return 'comment';
35
+ return objectType;
36
+ }
37
+ /**
38
+ * Normalizes an `ActivityObjectEventType` filter string for the API,
39
+ * converting modern object type names to legacy API names.
40
+ * e.g. 'task:added' -> 'item:added', 'comment:' -> 'note:', ':deleted' -> ':deleted'
41
+ *
42
+ * @internal
43
+ */
44
+ export function normalizeObjectEventTypeForApi(filter) {
45
+ var _a, _b;
46
+ const colonIndex = filter.indexOf(':');
47
+ if (colonIndex === -1) {
48
+ return (_a = normalizeObjectTypeForApi(filter)) !== null && _a !== void 0 ? _a : filter;
49
+ }
50
+ const objectPart = filter.slice(0, colonIndex);
51
+ const eventPart = filter.slice(colonIndex); // includes the colon
52
+ return `${(_b = normalizeObjectTypeForApi(objectPart)) !== null && _b !== void 0 ? _b : objectPart}${eventPart}`;
53
+ }
@@ -0,0 +1,84 @@
1
+ import camelcase from 'camelcase';
2
+ import emojiRegex from 'emoji-regex';
3
+ /**
4
+ * Checks if a string is a solitary emoji
5
+ */
6
+ function isEmojiKey(input) {
7
+ const regex = emojiRegex();
8
+ const match = input.match(regex);
9
+ return match !== null && match.join('') === input;
10
+ }
11
+ /**
12
+ * Custom camelCase function that preserves emoji strings
13
+ */
14
+ export function customCamelCase(input) {
15
+ // If the value is a solitary emoji string, return the key as-is
16
+ if (isEmojiKey(input)) {
17
+ return input;
18
+ }
19
+ return camelcase(input);
20
+ }
21
+ function isPlainObject(value) {
22
+ return typeof value === 'object' && value !== null && value.constructor === Object;
23
+ }
24
+ /**
25
+ * Fields, by their API name, whose value crosses case conversion untouched in both
26
+ * directions; only the field name itself is converted. View options' `property_settings`
27
+ * is keyed by opaque property IDs (`field:6Jf8VQXx`) and keeps attributes the SDK doesn't
28
+ * know, which can hold IDs of their own, so no key inside it is safe to rename.
29
+ */
30
+ const VERBATIM_FIELDS = new Set(['property_settings']);
31
+ /**
32
+ * Converts object keys from snake_case to camelCase recursively
33
+ *
34
+ * @param obj - The value to convert.
35
+ * @param options.opaqueKeyMaps - Top-level fields whose value is a map keyed by
36
+ * identifiers rather than field names, such as the Sync API's `sync_status`
37
+ * (keyed by command UUID). Those identifiers are kept exactly as received, since
38
+ * camel-casing would rewrite them; the map's values are still converted.
39
+ */
40
+ export function camelCaseKeys(obj, { opaqueKeyMaps } = {}) {
41
+ if (obj === null || obj === undefined) {
42
+ return obj;
43
+ }
44
+ if (Array.isArray(obj)) {
45
+ return obj.map((item) => camelCaseKeys(item));
46
+ }
47
+ if (isPlainObject(obj)) {
48
+ const converted = {};
49
+ for (const [key, value] of Object.entries(obj)) {
50
+ const camelKey = customCamelCase(key);
51
+ if (VERBATIM_FIELDS.has(key)) {
52
+ converted[camelKey] = value;
53
+ continue;
54
+ }
55
+ converted[camelKey] =
56
+ (opaqueKeyMaps === null || opaqueKeyMaps === void 0 ? void 0 : opaqueKeyMaps.has(key)) && isPlainObject(value)
57
+ ? Object.fromEntries(Object.entries(value).map(([id, entry]) => [id, camelCaseKeys(entry)]))
58
+ : camelCaseKeys(value);
59
+ }
60
+ return converted;
61
+ }
62
+ return obj;
63
+ }
64
+ /**
65
+ * Converts object keys from camelCase to snake_case recursively
66
+ */
67
+ export function snakeCaseKeys(obj) {
68
+ if (obj === null || obj === undefined) {
69
+ return obj;
70
+ }
71
+ if (Array.isArray(obj)) {
72
+ return obj.map((item) => snakeCaseKeys(item));
73
+ }
74
+ if (typeof obj === 'object' && obj.constructor === Object) {
75
+ const converted = {};
76
+ for (const [key, value] of Object.entries(obj)) {
77
+ // Convert camelCase to snake_case
78
+ const snakeKey = key.replace(/([A-Z])/g, '_$1').toLowerCase();
79
+ converted[snakeKey] = VERBATIM_FIELDS.has(snakeKey) ? value : snakeCaseKeys(value);
80
+ }
81
+ return converted;
82
+ }
83
+ return obj;
84
+ }
@@ -0,0 +1,145 @@
1
+ import { colorForDisplay } from '@doist/sdk-kmp/shared-todoist-all';
2
+ export const berryRed = {
3
+ key: 'berry_red',
4
+ displayName: 'Berry Red',
5
+ hexValue: '#b8255f',
6
+ };
7
+ export const red = {
8
+ key: 'red',
9
+ displayName: 'Red',
10
+ hexValue: '#db4035',
11
+ };
12
+ export const orange = {
13
+ key: 'orange',
14
+ displayName: 'Orange',
15
+ hexValue: '#ff9933',
16
+ };
17
+ export const yellow = {
18
+ key: 'yellow',
19
+ displayName: 'Yellow',
20
+ hexValue: '#fad000',
21
+ };
22
+ export const oliveGreen = {
23
+ key: 'olive_green',
24
+ displayName: 'Olive Green',
25
+ hexValue: '#afb83b',
26
+ };
27
+ export const limeGreen = {
28
+ key: 'lime_green',
29
+ displayName: 'Lime Green',
30
+ hexValue: '#7ecc49',
31
+ };
32
+ export const green = {
33
+ key: 'green',
34
+ displayName: 'Green',
35
+ hexValue: '#299438',
36
+ };
37
+ export const mintGreen = {
38
+ key: 'mint_green',
39
+ displayName: 'Mint Green',
40
+ hexValue: '#6accbc',
41
+ };
42
+ export const teal = {
43
+ key: 'teal',
44
+ displayName: 'Teal',
45
+ hexValue: '#158fad',
46
+ };
47
+ export const skyBlue = {
48
+ key: 'sky_blue',
49
+ displayName: 'Sky Blue',
50
+ hexValue: '#14aaf5',
51
+ };
52
+ export const lightBlue = {
53
+ key: 'light_blue',
54
+ displayName: 'Light Blue',
55
+ hexValue: '#96c3eb',
56
+ };
57
+ export const blue = {
58
+ key: 'blue',
59
+ displayName: 'Blue',
60
+ hexValue: '#4073ff',
61
+ };
62
+ export const grape = {
63
+ key: 'grape',
64
+ displayName: 'Grape',
65
+ hexValue: '#884dff',
66
+ };
67
+ export const violet = {
68
+ key: 'violet',
69
+ displayName: 'Violet',
70
+ hexValue: '#af38eb',
71
+ };
72
+ export const lavender = {
73
+ key: 'lavender',
74
+ displayName: 'Lavender',
75
+ hexValue: '#eb96eb',
76
+ };
77
+ export const magenta = {
78
+ key: 'magenta',
79
+ displayName: 'Magenta',
80
+ hexValue: '#e05194',
81
+ };
82
+ export const salmon = {
83
+ key: 'salmon',
84
+ displayName: 'Salmon',
85
+ hexValue: '#ff8d85',
86
+ };
87
+ export const charcoal = {
88
+ key: 'charcoal',
89
+ displayName: 'Charcoal',
90
+ hexValue: '#808080',
91
+ };
92
+ export const grey = {
93
+ key: 'grey',
94
+ displayName: 'Grey',
95
+ hexValue: '#b8b8b8',
96
+ };
97
+ export const taupe = {
98
+ key: 'taupe',
99
+ displayName: 'Taupe',
100
+ hexValue: '#ccac93',
101
+ };
102
+ /**
103
+ * Every color, in the order the apps show them. The keys mirror `TodoistColor` from
104
+ * `@doist/sdk-kmp/shared-todoist-all`; the display names and hex values are the SDK's own.
105
+ */
106
+ export const colors = [
107
+ berryRed,
108
+ red,
109
+ orange,
110
+ yellow,
111
+ oliveGreen,
112
+ limeGreen,
113
+ green,
114
+ mintGreen,
115
+ teal,
116
+ skyBlue,
117
+ lightBlue,
118
+ blue,
119
+ grape,
120
+ violet,
121
+ lavender,
122
+ magenta,
123
+ salmon,
124
+ charcoal,
125
+ grey,
126
+ taupe,
127
+ ];
128
+ export const defaultColor = charcoal;
129
+ /**
130
+ * Retrieves a {@link Color} object by its key identifier.
131
+ *
132
+ * @param colorKey - The unique key identifier of the color to find (e.g., 'berry_red', 'sky_blue')
133
+ * @returns The matching Color object if found, otherwise returns the default color (charcoal)
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * const color = getColorByKey('berry_red');
138
+ * console.log(color.hexValue); // '#b8255f'
139
+ * ```
140
+ */
141
+ export function getColorByKey(colorKey) {
142
+ var _a;
143
+ const { key } = colorForDisplay(colorKey);
144
+ return (_a = colors.find((color) => color.key === key)) !== null && _a !== void 0 ? _a : defaultColor;
145
+ }
@@ -0,0 +1,29 @@
1
+ import { headersToRecord } from './headers.js';
2
+ /**
3
+ * Wraps either a native `Response` or a `CustomFetchResponse` into the SDK's
4
+ * `FileResponse` shape (binary endpoints: `viewAttachment`, `downloadBackup`).
5
+ *
6
+ * `arrayBuffer()` is resolved lazily. A customFetch implementation that omits
7
+ * `arrayBuffer()` is still valid for callers that only read `text()`/`json()`;
8
+ * the descriptive error is thrown only if the caller actually requests binary
9
+ * bytes. This avoids the lossy `text()` → `TextEncoder` round-trip that
10
+ * corrupts non-UTF-8 bytes (every `0x80`-`0xFF` byte not part of a valid UTF-8
11
+ * sequence is replaced with `U+FFFD`).
12
+ */
13
+ export function wrapAsFileResponse(response, context) {
14
+ const headers = response.headers instanceof Headers ? headersToRecord(response.headers) : response.headers;
15
+ return {
16
+ ok: response.ok,
17
+ status: response.status,
18
+ statusText: response.statusText,
19
+ headers,
20
+ text: () => response.text(),
21
+ json: () => response.json(),
22
+ arrayBuffer: () => {
23
+ if (typeof response.arrayBuffer !== 'function') {
24
+ throw new Error(`customFetch response must implement arrayBuffer() for ${context} (binary endpoint); reading the body via text() corrupts non-UTF-8 bytes`);
25
+ }
26
+ return response.arrayBuffer();
27
+ },
28
+ };
29
+ }
@@ -0,0 +1,231 @@
1
+ import { FILTER_QUERY_DATE_TOKENS, FILTER_QUERY_LANGUAGES, FILTER_QUERY_OPERATOR_TOKENS, FILTER_QUERY_PATTERNS, FILTER_QUERY_TOKENS, } from './filter-query-definitions.js';
2
+ const DEFAULT_LANGUAGE = 'en';
3
+ const DATE_TOKENS = new Set(FILTER_QUERY_DATE_TOKENS);
4
+ const OPERATOR_TOKENS = new Set(FILTER_QUERY_OPERATOR_TOKENS);
5
+ /** Operators are the same symbols in every language, and they end a bare date. */
6
+ const OPERATOR_PATTERN = /[()!&|]/;
7
+ /**
8
+ * Deepest run of parentheses this reads before giving up.
9
+ *
10
+ * Parentheses are the only construct left that recurses, and Todoist caps a
11
+ * saved query long before this. The limit is what keeps a hostile string from
12
+ * reaching the call stack.
13
+ */
14
+ const MAX_NESTING_DEPTH = 100;
15
+ /** Codes the parser answers to beyond the language names themselves. */
16
+ const LANGUAGE_ALIASES = new Map([
17
+ ['zh-cn', 'zh_cn'],
18
+ ['zh-hans', 'zh_cn'],
19
+ ['zh_hans', 'zh_cn'],
20
+ ['zh-tw', 'zh_tw'],
21
+ ['zh-hant', 'zh_tw'],
22
+ ['zh_hant', 'zh_tw'],
23
+ ]);
24
+ const MATCHERS_BY_LANGUAGE = new Map();
25
+ function lookUpLanguage(code) {
26
+ var _a;
27
+ return ((_a = LANGUAGE_ALIASES.get(code)) !== null && _a !== void 0 ? _a : FILTER_QUERY_LANGUAGES.find((language) => language === code));
28
+ }
29
+ function resolveLanguage(lang) {
30
+ var _a, _b;
31
+ if (!lang)
32
+ return DEFAULT_LANGUAGE;
33
+ const code = lang.toLowerCase();
34
+ return (_b = (_a = lookUpLanguage(code)) !== null && _a !== void 0 ? _a : lookUpLanguage(code.split(/[-_]/)[0])) !== null && _b !== void 0 ? _b : DEFAULT_LANGUAGE;
35
+ }
36
+ function createMatchers(language) {
37
+ const patterns = FILTER_QUERY_PATTERNS[language];
38
+ const matchers = [];
39
+ for (const token of FILTER_QUERY_TOKENS) {
40
+ for (const pattern of patterns[token]) {
41
+ matchers.push({
42
+ token,
43
+ length: pattern.length,
44
+ regex: new RegExp(`\\s*${pattern}\\s*`, 'iuy'),
45
+ });
46
+ }
47
+ }
48
+ // Longest pattern first, as the engine does. Otherwise `all` claims the
49
+ // front of Dutch's `alles bekijken` and the rest reads as a date.
50
+ return matchers.sort((a, b) => b.length - a.length);
51
+ }
52
+ function matchersFor(language) {
53
+ const cached = MATCHERS_BY_LANGUAGE.get(language);
54
+ if (cached)
55
+ return cached;
56
+ const matchers = createMatchers(language);
57
+ MATCHERS_BY_LANGUAGE.set(language, matchers);
58
+ return matchers;
59
+ }
60
+ function matchAt(query, cursor, matchers) {
61
+ for (const matcher of matchers) {
62
+ matcher.regex.lastIndex = cursor;
63
+ if (matcher.regex.test(query) && matcher.regex.lastIndex > cursor) {
64
+ return { token: matcher.token, end: matcher.regex.lastIndex };
65
+ }
66
+ }
67
+ return null;
68
+ }
69
+ /**
70
+ * Splits a query on unescaped commas, the way Todoist does before parsing.
71
+ * Each part is drawn as its own list.
72
+ */
73
+ function splitSubqueries(query) {
74
+ const subqueries = [];
75
+ let current = '';
76
+ let escaped = false;
77
+ for (let index = 0; index < query.length; index += 1) {
78
+ const character = query[index];
79
+ if (character === ',' && !escaped) {
80
+ subqueries.push(current);
81
+ current = '';
82
+ continue;
83
+ }
84
+ current += character;
85
+ escaped = !escaped && character === '\\';
86
+ }
87
+ subqueries.push(current);
88
+ return subqueries.map((subquery) => subquery.trim()).filter((subquery) => subquery.length > 0);
89
+ }
90
+ /**
91
+ * Reads a subquery into tokens.
92
+ *
93
+ * Anything the vocabulary doesn't claim is a bare date: the engine tries every
94
+ * keyword first and hands what is left to its date parser, which is what reads
95
+ * `today`, `hoy` and `2026-12-24`. A bare date runs to the next operator.
96
+ */
97
+ function tokenize(subquery, matchers) {
98
+ const tokens = [];
99
+ let cursor = 0;
100
+ while (cursor < subquery.length) {
101
+ const match = matchAt(subquery, cursor, matchers);
102
+ if (match) {
103
+ tokens.push(match.token);
104
+ cursor = match.end;
105
+ continue;
106
+ }
107
+ const offset = subquery.slice(cursor + 1).search(OPERATOR_PATTERN);
108
+ tokens.push('BARE_DATE');
109
+ cursor = offset === -1 ? subquery.length : cursor + 1 + offset;
110
+ }
111
+ return tokens;
112
+ }
113
+ function peek(reader) {
114
+ return reader.index < reader.tokens.length ? reader.tokens[reader.index] : undefined;
115
+ }
116
+ function next(reader) {
117
+ const token = peek(reader);
118
+ reader.index += 1;
119
+ return token;
120
+ }
121
+ /**
122
+ * `<expression 4> ::= <expression 3> [ or <expression 4> ]`
123
+ *
124
+ * The engine nests this to the right and folds with a minimum, so reading the
125
+ * chain in a loop lands on the same grouping without a frame per operator.
126
+ */
127
+ function readOr(reader) {
128
+ let grouping = readAnd(reader);
129
+ while (grouping !== null && peek(reader) === 'OR') {
130
+ next(reader);
131
+ const right = readAnd(reader);
132
+ if (right === null)
133
+ return null;
134
+ // `|` keeps the lower grouping, so one flat side flattens the pair.
135
+ grouping = grouping === 'DAY' && right === 'DAY' ? 'DAY' : 'FLAT';
136
+ }
137
+ return grouping;
138
+ }
139
+ /** `<expression 3> ::= <expression 2> [ and <expression 3> ]` */
140
+ function readAnd(reader) {
141
+ let grouping = readNot(reader);
142
+ while (grouping !== null && peek(reader) === 'AND') {
143
+ next(reader);
144
+ const right = readNot(reader);
145
+ if (right === null)
146
+ return null;
147
+ // `&` keeps the higher grouping, so one dated side leads the pair.
148
+ grouping = grouping === 'DAY' || right === 'DAY' ? 'DAY' : 'FLAT';
149
+ }
150
+ return grouping;
151
+ }
152
+ /** `<expression 2> ::= { [ not ] <expression 2> } | <expression 1>` */
153
+ function readNot(reader) {
154
+ let negated = false;
155
+ while (peek(reader) === 'NOT') {
156
+ next(reader);
157
+ negated = true;
158
+ }
159
+ const grouping = readOperand(reader);
160
+ if (grouping === null)
161
+ return null;
162
+ // A negation never groups by day, however the expression under it reads.
163
+ return negated ? 'FLAT' : grouping;
164
+ }
165
+ /** `<expression 1> ::= { "(" <expression> ")" } | <query>` */
166
+ function readOperand(reader) {
167
+ const token = next(reader);
168
+ if (token === undefined)
169
+ return null;
170
+ if (token === 'LEFT') {
171
+ if (reader.depth >= MAX_NESTING_DEPTH)
172
+ return null;
173
+ reader.depth += 1;
174
+ const grouping = readOr(reader);
175
+ reader.depth -= 1;
176
+ if (grouping === null || next(reader) !== 'RIGHT')
177
+ return null;
178
+ return grouping;
179
+ }
180
+ if (token === 'BARE_DATE')
181
+ return 'DAY';
182
+ if (OPERATOR_TOKENS.has(token))
183
+ return null;
184
+ return DATE_TOKENS.has(token) ? 'DAY' : 'FLAT';
185
+ }
186
+ function groupingOf(subquery, matchers) {
187
+ const reader = { tokens: tokenize(subquery, matchers), index: 0, depth: 0 };
188
+ const grouping = readOr(reader);
189
+ // Tokens left over mean the query doesn't parse, which the engine rejects.
190
+ return grouping !== null && reader.index === reader.tokens.length ? grouping : null;
191
+ }
192
+ /**
193
+ * Returns whether a filter query leads with dates rather than with priority.
194
+ *
195
+ * Todoist gives every filter one of two default hierarchies, and a query that
196
+ * mentions dates gets the date-first one. Pass the answer to {@link sortTasks}
197
+ * as its `defaultOrder`:
198
+ *
199
+ * ```ts
200
+ * sortTasks(tasks, {
201
+ * sortedBy: savedOptions?.sortedBy,
202
+ * sortOrder: savedOptions?.sortOrder,
203
+ * defaultOrder: isDateDrivenQuery(query, { lang }) ? 'DATE_FIRST' : 'PRIORITY_FIRST',
204
+ * })
205
+ * ```
206
+ *
207
+ * The query is read in `lang`, the account language `getUser` returns, the way
208
+ * the API reads it. English keywords parse under every language, so `lang` only
209
+ * matters for a query written in the account's own: `sin fecha` is a keyword
210
+ * under `es` and an unreadable phrase under `en`.
211
+ *
212
+ * Commas divide a filter into subqueries and Todoist draws each one as its own
213
+ * list, with its own hierarchy. Classify them one at a time for exact results;
214
+ * a whole query answers true only when every subquery is date-driven.
215
+ *
216
+ * Two kinds of unreadable query part company here. One that breaks the grammar,
217
+ * such as `(today`, returns false. One that only breaks the vocabulary, such as
218
+ * `sin fecha` under `en`, returns true, because a word this package doesn't
219
+ * recognize is treated as a bare date. Pass the account's own `lang` and the
220
+ * question doesn't arise; get it wrong and a keyword can read as a date.
221
+ *
222
+ * The function performs no I/O.
223
+ *
224
+ * @see sortTasks
225
+ */
226
+ export function isDateDrivenQuery(query, options = {}) {
227
+ const matchers = matchersFor(resolveLanguage(options.lang));
228
+ const subqueries = splitSubqueries(query);
229
+ return (subqueries.length > 0 &&
230
+ subqueries.every((subquery) => groupingOf(subquery, matchers) === 'DAY'));
231
+ }