@nurama/sdk 0.0.0-stage → 1.4.1

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 (225) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +5 -0
  3. package/README.md +1080 -2
  4. package/dist/BotClient.d.ts +66 -0
  5. package/dist/BotClient.d.ts.map +1 -0
  6. package/dist/BotClient.js +68 -0
  7. package/dist/BotClient.js.map +1 -0
  8. package/dist/NuramaClient.d.ts +480 -0
  9. package/dist/NuramaClient.d.ts.map +1 -0
  10. package/dist/NuramaClient.js +902 -0
  11. package/dist/NuramaClient.js.map +1 -0
  12. package/dist/browser/nurama-bot-sdk.js +12051 -0
  13. package/dist/browser/nurama-bot-sdk.min.js +1 -0
  14. package/dist/browser/nurama-sdk.js +12003 -0
  15. package/dist/browser/nurama-sdk.min.js +1 -0
  16. package/dist/routes/ai.d.ts +280 -0
  17. package/dist/routes/ai.d.ts.map +1 -0
  18. package/dist/routes/ai.js +173 -0
  19. package/dist/routes/ai.js.map +1 -0
  20. package/dist/routes/asset.d.ts +493 -0
  21. package/dist/routes/asset.d.ts.map +1 -0
  22. package/dist/routes/asset.js +848 -0
  23. package/dist/routes/asset.js.map +1 -0
  24. package/dist/routes/auth.d.ts +218 -0
  25. package/dist/routes/auth.d.ts.map +1 -0
  26. package/dist/routes/auth.js +454 -0
  27. package/dist/routes/auth.js.map +1 -0
  28. package/dist/routes/blogPosts.d.ts +17 -0
  29. package/dist/routes/blogPosts.d.ts.map +1 -0
  30. package/dist/routes/blogPosts.js +29 -0
  31. package/dist/routes/blogPosts.js.map +1 -0
  32. package/dist/routes/board.d.ts +187 -0
  33. package/dist/routes/board.d.ts.map +1 -0
  34. package/dist/routes/board.js +270 -0
  35. package/dist/routes/board.js.map +1 -0
  36. package/dist/routes/bot.d.ts +202 -0
  37. package/dist/routes/bot.d.ts.map +1 -0
  38. package/dist/routes/bot.js +229 -0
  39. package/dist/routes/bot.js.map +1 -0
  40. package/dist/routes/chat.d.ts +842 -0
  41. package/dist/routes/chat.d.ts.map +1 -0
  42. package/dist/routes/chat.js +863 -0
  43. package/dist/routes/chat.js.map +1 -0
  44. package/dist/routes/chatAi.d.ts +51 -0
  45. package/dist/routes/chatAi.d.ts.map +1 -0
  46. package/dist/routes/chatAi.js +109 -0
  47. package/dist/routes/chatAi.js.map +1 -0
  48. package/dist/routes/config.d.ts +11 -0
  49. package/dist/routes/config.d.ts.map +1 -0
  50. package/dist/routes/config.js +24 -0
  51. package/dist/routes/config.js.map +1 -0
  52. package/dist/routes/convo.d.ts +169 -0
  53. package/dist/routes/convo.d.ts.map +1 -0
  54. package/dist/routes/convo.js +284 -0
  55. package/dist/routes/convo.js.map +1 -0
  56. package/dist/routes/credits.d.ts +82 -0
  57. package/dist/routes/credits.d.ts.map +1 -0
  58. package/dist/routes/credits.js +49 -0
  59. package/dist/routes/credits.js.map +1 -0
  60. package/dist/routes/device.d.ts +74 -0
  61. package/dist/routes/device.d.ts.map +1 -0
  62. package/dist/routes/device.js +122 -0
  63. package/dist/routes/device.js.map +1 -0
  64. package/dist/routes/folder.d.ts +75 -0
  65. package/dist/routes/folder.d.ts.map +1 -0
  66. package/dist/routes/folder.js +99 -0
  67. package/dist/routes/folder.js.map +1 -0
  68. package/dist/routes/invite.d.ts +61 -0
  69. package/dist/routes/invite.d.ts.map +1 -0
  70. package/dist/routes/invite.js +86 -0
  71. package/dist/routes/invite.js.map +1 -0
  72. package/dist/routes/joinLink.d.ts +88 -0
  73. package/dist/routes/joinLink.d.ts.map +1 -0
  74. package/dist/routes/joinLink.js +205 -0
  75. package/dist/routes/joinLink.js.map +1 -0
  76. package/dist/routes/membership.d.ts +116 -0
  77. package/dist/routes/membership.d.ts.map +1 -0
  78. package/dist/routes/membership.js +183 -0
  79. package/dist/routes/membership.js.map +1 -0
  80. package/dist/routes/notification.d.ts +103 -0
  81. package/dist/routes/notification.d.ts.map +1 -0
  82. package/dist/routes/notification.js +89 -0
  83. package/dist/routes/notification.js.map +1 -0
  84. package/dist/routes/oauthGrant.d.ts +45 -0
  85. package/dist/routes/oauthGrant.d.ts.map +1 -0
  86. package/dist/routes/oauthGrant.js +32 -0
  87. package/dist/routes/oauthGrant.js.map +1 -0
  88. package/dist/routes/payment.d.ts +56 -0
  89. package/dist/routes/payment.d.ts.map +1 -0
  90. package/dist/routes/payment.js +78 -0
  91. package/dist/routes/payment.js.map +1 -0
  92. package/dist/routes/product.d.ts +43 -0
  93. package/dist/routes/product.d.ts.map +1 -0
  94. package/dist/routes/product.js +53 -0
  95. package/dist/routes/product.js.map +1 -0
  96. package/dist/routes/project.d.ts +821 -0
  97. package/dist/routes/project.d.ts.map +1 -0
  98. package/dist/routes/project.js +1153 -0
  99. package/dist/routes/project.js.map +1 -0
  100. package/dist/routes/public.d.ts +269 -0
  101. package/dist/routes/public.d.ts.map +1 -0
  102. package/dist/routes/public.js +412 -0
  103. package/dist/routes/public.js.map +1 -0
  104. package/dist/routes/scratch.d.ts +70 -0
  105. package/dist/routes/scratch.d.ts.map +1 -0
  106. package/dist/routes/scratch.js +67 -0
  107. package/dist/routes/scratch.js.map +1 -0
  108. package/dist/routes/settings.d.ts +102 -0
  109. package/dist/routes/settings.d.ts.map +1 -0
  110. package/dist/routes/settings.js +94 -0
  111. package/dist/routes/settings.js.map +1 -0
  112. package/dist/routes/shortlink.d.ts +79 -0
  113. package/dist/routes/shortlink.d.ts.map +1 -0
  114. package/dist/routes/shortlink.js +25 -0
  115. package/dist/routes/shortlink.js.map +1 -0
  116. package/dist/routes/socket.d.ts +108 -0
  117. package/dist/routes/socket.d.ts.map +1 -0
  118. package/dist/routes/socket.js +573 -0
  119. package/dist/routes/socket.js.map +1 -0
  120. package/dist/routes/storage.d.ts +44 -0
  121. package/dist/routes/storage.d.ts.map +1 -0
  122. package/dist/routes/storage.js +49 -0
  123. package/dist/routes/storage.js.map +1 -0
  124. package/dist/routes/subscription.d.ts +184 -0
  125. package/dist/routes/subscription.d.ts.map +1 -0
  126. package/dist/routes/subscription.js +219 -0
  127. package/dist/routes/subscription.js.map +1 -0
  128. package/dist/routes/supportChat.d.ts +40 -0
  129. package/dist/routes/supportChat.d.ts.map +1 -0
  130. package/dist/routes/supportChat.js +53 -0
  131. package/dist/routes/supportChat.js.map +1 -0
  132. package/dist/routes/supportTicket.d.ts +89 -0
  133. package/dist/routes/supportTicket.d.ts.map +1 -0
  134. package/dist/routes/supportTicket.js +54 -0
  135. package/dist/routes/supportTicket.js.map +1 -0
  136. package/dist/routes/tag.d.ts +72 -0
  137. package/dist/routes/tag.d.ts.map +1 -0
  138. package/dist/routes/tag.js +81 -0
  139. package/dist/routes/tag.js.map +1 -0
  140. package/dist/routes/task.d.ts +252 -0
  141. package/dist/routes/task.d.ts.map +1 -0
  142. package/dist/routes/task.js +284 -0
  143. package/dist/routes/task.js.map +1 -0
  144. package/dist/routes/taskRelation.d.ts +80 -0
  145. package/dist/routes/taskRelation.d.ts.map +1 -0
  146. package/dist/routes/taskRelation.js +71 -0
  147. package/dist/routes/taskRelation.js.map +1 -0
  148. package/dist/routes/token.d.ts +97 -0
  149. package/dist/routes/token.d.ts.map +1 -0
  150. package/dist/routes/token.js +73 -0
  151. package/dist/routes/token.js.map +1 -0
  152. package/dist/routes/user.d.ts +112 -0
  153. package/dist/routes/user.d.ts.map +1 -0
  154. package/dist/routes/user.js +151 -0
  155. package/dist/routes/user.js.map +1 -0
  156. package/dist/routes/version.d.ts +42 -0
  157. package/dist/routes/version.d.ts.map +1 -0
  158. package/dist/routes/version.js +38 -0
  159. package/dist/routes/version.js.map +1 -0
  160. package/dist/routes/webhook.d.ts +170 -0
  161. package/dist/routes/webhook.d.ts.map +1 -0
  162. package/dist/routes/webhook.js +173 -0
  163. package/dist/routes/webhook.js.map +1 -0
  164. package/dist/routes/workspace.d.ts +120 -0
  165. package/dist/routes/workspace.d.ts.map +1 -0
  166. package/dist/routes/workspace.js +199 -0
  167. package/dist/routes/workspace.js.map +1 -0
  168. package/dist/utils/uploadSessionManager.d.ts +133 -0
  169. package/dist/utils/uploadSessionManager.d.ts.map +1 -0
  170. package/dist/utils/uploadSessionManager.js +321 -0
  171. package/dist/utils/uploadSessionManager.js.map +1 -0
  172. package/dist/utils/urlParams.d.ts +35 -0
  173. package/dist/utils/urlParams.d.ts.map +1 -0
  174. package/dist/utils/urlParams.js +146 -0
  175. package/dist/utils/urlParams.js.map +1 -0
  176. package/dist/version.d.ts +15 -0
  177. package/dist/version.d.ts.map +1 -0
  178. package/dist/version.js +12 -0
  179. package/dist/version.js.map +1 -0
  180. package/package.json +87 -3
  181. package/src/BotClient.ts +113 -0
  182. package/src/NuramaClient.ts +1253 -0
  183. package/src/bot-browser-entry.js +15 -0
  184. package/src/browser-entry.js +20 -0
  185. package/src/routes/ai.ts +378 -0
  186. package/src/routes/asset.ts +1104 -0
  187. package/src/routes/auth.ts +587 -0
  188. package/src/routes/blogPosts.ts +29 -0
  189. package/src/routes/board.ts +403 -0
  190. package/src/routes/bot.ts +356 -0
  191. package/src/routes/chat.ts +1292 -0
  192. package/src/routes/chatAi.ts +125 -0
  193. package/src/routes/config.ts +31 -0
  194. package/src/routes/convo.ts +321 -0
  195. package/src/routes/credits.ts +112 -0
  196. package/src/routes/device.ts +133 -0
  197. package/src/routes/folder.ts +154 -0
  198. package/src/routes/invite.ts +133 -0
  199. package/src/routes/joinLink.ts +233 -0
  200. package/src/routes/membership.ts +237 -0
  201. package/src/routes/notification.ts +166 -0
  202. package/src/routes/oauthGrant.ts +64 -0
  203. package/src/routes/payment.ts +104 -0
  204. package/src/routes/product.ts +67 -0
  205. package/src/routes/project.ts +1528 -0
  206. package/src/routes/public.ts +496 -0
  207. package/src/routes/scratch.ts +94 -0
  208. package/src/routes/settings.ts +152 -0
  209. package/src/routes/shortlink.ts +90 -0
  210. package/src/routes/socket.ts +757 -0
  211. package/src/routes/storage.ts +83 -0
  212. package/src/routes/subscription.ts +307 -0
  213. package/src/routes/supportChat.ts +62 -0
  214. package/src/routes/supportTicket.ts +114 -0
  215. package/src/routes/tag.ts +131 -0
  216. package/src/routes/task.ts +431 -0
  217. package/src/routes/taskRelation.ts +125 -0
  218. package/src/routes/token.ts +152 -0
  219. package/src/routes/user.ts +214 -0
  220. package/src/routes/version.ts +62 -0
  221. package/src/routes/webhook.ts +295 -0
  222. package/src/routes/workspace.ts +223 -0
  223. package/src/utils/uploadSessionManager.ts +407 -0
  224. package/src/utils/urlParams.ts +181 -0
  225. package/src/version.ts +22 -0
@@ -0,0 +1,431 @@
1
+ import NuramaClient from '../NuramaClient.js';
2
+ import { type UpdateTaskDetailsData, type LinkTaskData } from './board.js';
3
+ import {
4
+ type Task, // Import Task type
5
+ type PaginatedResult, // Import pagination types
6
+ type CursorPaginatedResult,
7
+ type TaskLink,
8
+ } from '@nurama/types';
9
+
10
+ // Combine pagination metadata with a results array
11
+ // (Should be defined centrally or imported if used across multiple route files)
12
+ export type PaginatedResponse<T> = (PaginatedResult | CursorPaginatedResult) & {
13
+ results?: T[];
14
+ };
15
+
16
+ // --- Common Interfaces ---
17
+ export interface SortParams {
18
+ sort?: Record<string, 1 | -1>;
19
+ }
20
+
21
+ export type TaskVisibility = 'creator' | 'reviewer';
22
+ export type TaskStatus = 'pending' | 'complete' | 'cancelled'; // Based on standard status types, adjust if needed
23
+
24
+ // --- Query Parameter Interfaces ---
25
+ export interface GetTasksBaseParams extends SortParams {
26
+ projectId?: string;
27
+ creatorId?: string;
28
+ relatedToId?: string;
29
+ visibility?: TaskVisibility;
30
+ acknowledged?: boolean;
31
+ limit?: number;
32
+ }
33
+
34
+ export interface GetTasksIndexParams extends GetTasksBaseParams {
35
+ paginate?: 'index';
36
+ page?: number;
37
+ createdBefore?: number | string; // Timestamp or ObjectId string
38
+ createdAfter?: number | string; // Timestamp or ObjectId string
39
+ }
40
+
41
+ export interface GetTasksCursorParams extends GetTasksBaseParams {
42
+ paginate: 'cursor';
43
+ cursor?: string;
44
+ paginateReverse?: boolean;
45
+ includeCounts?: boolean;
46
+ includeCursorRecord?: boolean;
47
+ startAt?: string; // ObjectId string
48
+ includeStartAtRecord?: boolean;
49
+ }
50
+
51
+ export type GetTasksParams = GetTasksIndexParams | GetTasksCursorParams;
52
+
53
+ // --- Request Body Interfaces ---
54
+ export interface UpdateTaskStatusData {
55
+ status: TaskStatus;
56
+ }
57
+
58
+ // --- Response Interfaces ---
59
+ // Task type is imported from nurama-types
60
+
61
+ export type GetTasksResponse = PaginatedResponse<Task>;
62
+
63
+ // Keep local definition as it's not in nurama-types
64
+ export interface UnacknowledgedTaskCountResponse {
65
+ total: number;
66
+ creator: number;
67
+ reviewer: number;
68
+ }
69
+
70
+ export interface AcknowledgeAllTasksResponse {
71
+ /** Number of tasks that were acknowledged by this call. */
72
+ acknowledged: number;
73
+ /** The user's remaining unacknowledged count for the project (should be all-zero). */
74
+ unacknowledgedCount: UnacknowledgedTaskCountResponse;
75
+ }
76
+
77
+ // --- Event Interfaces ---
78
+ export interface TaskEventActor {
79
+ id: string;
80
+ displayName?: string;
81
+ firstName?: string;
82
+ lastName?: string;
83
+ color?: string;
84
+ avatar?: unknown;
85
+ }
86
+
87
+ export interface TaskEvent {
88
+ id: string;
89
+ taskId: string;
90
+ projectId: string;
91
+ eventType: string;
92
+ detail?: Record<string, unknown>;
93
+ createdAt: string;
94
+ actor: TaskEventActor | null;
95
+ }
96
+
97
+ export interface GetTaskEventsParams {
98
+ page?: number;
99
+ limit?: number;
100
+ sort?: Record<string, 1 | -1>;
101
+ eventType?: string;
102
+ }
103
+
104
+ export type GetTaskEventsResponse = PaginatedResponse<TaskEvent>;
105
+
106
+ // --- Method Definitions ---
107
+
108
+ /**
109
+ * Defines task-related methods for the NuramaClient.
110
+ * @param {NuramaClient} client - The NuramaClient instance.
111
+ * @returns {object} An object containing the task-related methods.
112
+ */
113
+ export interface BulkTaskDraft {
114
+ /** FE-assigned id; echoed back in `results` so the caller can map a
115
+ * per-task outcome onto the originating draft. */
116
+ clientId: string;
117
+ boardId: string;
118
+ columnId?: string;
119
+ subject: string;
120
+ description?: string | null;
121
+ assignedToId?: string;
122
+ tagIds?: string[];
123
+ }
124
+
125
+ export interface BulkCreateTasksRequest {
126
+ projectId: string;
127
+ tasks: BulkTaskDraft[];
128
+ /** When present, the server posts a single Nu reply in the chat after
129
+ * the batch creates, threaded as `replyToId = messageId` and carrying
130
+ * every newly-created task as a taskCard. Replaces the standalone
131
+ * `ai.announceTasksFromMessage` endpoint we shipped previously. */
132
+ announce?: {
133
+ chatId: string;
134
+ messageId: string;
135
+ };
136
+ }
137
+
138
+ export interface BulkCreateTaskResult {
139
+ clientId: string;
140
+ status: 'created' | 'error';
141
+ task?: Task;
142
+ error?: { code: string; message: string };
143
+ }
144
+
145
+ export interface BulkCreateTasksResponse {
146
+ results: BulkCreateTaskResult[];
147
+ announce?: {
148
+ posted: boolean;
149
+ messageId: string | null;
150
+ };
151
+ }
152
+
153
+ export default function createTaskMethods(client: NuramaClient) {
154
+ return {
155
+ /**
156
+ * Retrieves tasks assigned to the currently authenticated user.
157
+ * Supports filtering, sorting, and both index and cursor pagination.
158
+ * @param {GetTasksParams} [params] - Optional query parameters for filtering, sorting, and pagination.
159
+ * @returns {Promise<GetTasksResponse>} Paginated list of tasks.
160
+ */
161
+ async getMyTasks(params?: GetTasksParams): Promise<GetTasksResponse> {
162
+ return client._request<GetTasksResponse>({
163
+ method: 'GET',
164
+ endpoint: '/v1/tasks/',
165
+ params: params,
166
+ sendJWT: true,
167
+ });
168
+ },
169
+
170
+ /**
171
+ * Bulk-create one or more tasks under a single project — single
172
+ * round-trip replacement for the per-draft create loop the
173
+ * EnhancedTaskCreatorModal used to drive. Per-task partial success
174
+ * is returned in `results[]`; if `announce` is set and at least
175
+ * one task creates, the server also posts a Nu reply linking the
176
+ * new tasks back to the source message and rendering them as
177
+ * inline taskCards.
178
+ */
179
+ async bulkCreate(data: BulkCreateTasksRequest): Promise<BulkCreateTasksResponse> {
180
+ if (!data?.projectId) throw new Error('projectId is required.');
181
+ if (!Array.isArray(data?.tasks) || data.tasks.length === 0) {
182
+ throw new Error('tasks is required and must contain at least one draft.');
183
+ }
184
+ return client._request<BulkCreateTasksResponse>({
185
+ method: 'POST',
186
+ endpoint: '/v1/tasks/bulk-create',
187
+ body: data,
188
+ sendJWT: true,
189
+ });
190
+ },
191
+
192
+ /**
193
+ * Updates the status of a specific task.
194
+ * Requires authentication and permission.
195
+ * @param {string} taskId - The ID of the task to update.
196
+ * @param {UpdateTaskStatusData} data - The new status for the task.
197
+ * @returns {Promise<Task>} The updated task object.
198
+ */
199
+ async updateTaskStatus(taskId: string, data: UpdateTaskStatusData): Promise<Task> {
200
+ if (!taskId) throw new Error('taskId is required.');
201
+ if (!data || !data.status) throw new Error('status is required in the request body.');
202
+ return client._request<Task>({
203
+ method: 'PUT',
204
+ endpoint: `/v1/tasks/${taskId}`,
205
+ body: data,
206
+ sendJWT: true,
207
+ });
208
+ },
209
+
210
+ /**
211
+ * Toggles the acknowledgement status of a specific task.
212
+ * Requires authentication and permission.
213
+ * @param {string} taskId - The ID of the task to acknowledge/unacknowledge.
214
+ * @returns {Promise<Task>} The updated task object with the new acknowledgement status.
215
+ */
216
+ async acknowledgeTask(taskId: string): Promise<Task> {
217
+ if (!taskId) throw new Error('taskId is required.');
218
+ return client._request<Task>({
219
+ method: 'PUT',
220
+ endpoint: `/v1/tasks/acknowledge/${taskId}`,
221
+ sendJWT: true,
222
+ });
223
+ },
224
+
225
+ /**
226
+ * Retrieves the count of unacknowledged tasks for the current user within a specific project.
227
+ * Requires authentication.
228
+ * @param {string} projectId - The ID of the project.
229
+ * @returns {Promise<UnacknowledgedTaskCountResponse>} An object containing total, creator, and reviewer unacknowledged task counts.
230
+ */
231
+ async getUnacknowledgedTaskCount(projectId: string): Promise<UnacknowledgedTaskCountResponse> {
232
+ if (!projectId) throw new Error('projectId is required.');
233
+ return client._request<UnacknowledgedTaskCountResponse>({
234
+ method: 'GET',
235
+ endpoint: `/v1/tasks/unacknowledged/${projectId}`,
236
+ sendJWT: true,
237
+ });
238
+ },
239
+
240
+ /**
241
+ * Acknowledge every unacknowledged mention-task the current user has in a
242
+ * project. Idempotent server-side.
243
+ * @param {string} projectId - The ID of the project.
244
+ * @returns {Promise<AcknowledgeAllTasksResponse>} The number acknowledged and the remaining unacknowledged count.
245
+ */
246
+ async acknowledgeAllTasks(projectId: string): Promise<AcknowledgeAllTasksResponse> {
247
+ if (!projectId) throw new Error('projectId is required.');
248
+ return client._request<AcknowledgeAllTasksResponse>({
249
+ method: 'PUT',
250
+ endpoint: `/v1/tasks/acknowledge-all/${projectId}`,
251
+ sendJWT: true,
252
+ });
253
+ },
254
+
255
+ /**
256
+ * Add the calling user to a task's `followers` list.
257
+ * Idempotent server-side — following an already-followed task is a no-op
258
+ * and still returns the current task.
259
+ * @param taskId - The ID of the task to follow.
260
+ * @returns The updated task with the new followers array.
261
+ */
262
+ async followTask(taskId: string): Promise<Task> {
263
+ if (!taskId) throw new Error('taskId is required.');
264
+ return client._request<Task>({
265
+ method: 'PUT',
266
+ endpoint: `/v1/tasks/${taskId}/follow`,
267
+ sendJWT: true,
268
+ });
269
+ },
270
+
271
+ /**
272
+ * Remove the calling user from a task's `followers` list.
273
+ * Idempotent server-side — unfollowing a task you don't follow is a
274
+ * no-op and still returns the current task.
275
+ * @param taskId - The ID of the task to unfollow.
276
+ * @returns The updated task with the new followers array.
277
+ */
278
+ async unfollowTask(taskId: string): Promise<Task> {
279
+ if (!taskId) throw new Error('taskId is required.');
280
+ return client._request<Task>({
281
+ method: 'PUT',
282
+ endpoint: `/v1/tasks/${taskId}/unfollow`,
283
+ sendJWT: true,
284
+ });
285
+ },
286
+
287
+ /**
288
+ * Permanently delete a task. Gated server-side by
289
+ * `canRemove{Visibility}BoardTask` for at least one of the parent
290
+ * board's visibility tiers (see `boardPermission('Remove', 'BoardTask')`).
291
+ *
292
+ * Returns void; the server responds with 204 No Content.
293
+ *
294
+ * @param taskId - The ID of the task to delete.
295
+ */
296
+ async deleteTask(taskId: string): Promise<void> {
297
+ if (!taskId) throw new Error('taskId is required.');
298
+ return client._request<void>({
299
+ method: 'DELETE',
300
+ endpoint: `/v1/tasks/${taskId}`,
301
+ sendJWT: true,
302
+ });
303
+ },
304
+
305
+ /**
306
+ * Retrieves the event log for a specific task.
307
+ * Returns paginated events in reverse chronological order with populated actor info.
308
+ * @param {string} taskId - The ID of the task.
309
+ * @param {GetTaskEventsParams} [params] - Optional pagination, sort, search, and filter params.
310
+ * @returns {Promise<GetTaskEventsResponse>} Paginated list of task events.
311
+ */
312
+ async getTaskEvents(taskId: string, params?: GetTaskEventsParams): Promise<GetTaskEventsResponse> {
313
+ if (!taskId) throw new Error('taskId is required.');
314
+ return client._request<GetTaskEventsResponse>({
315
+ method: 'GET',
316
+ endpoint: `/v1/tasks/${taskId}/events`,
317
+ params,
318
+ sendJWT: true,
319
+ });
320
+ },
321
+
322
+ // ========================================================================
323
+ // Task details, links and tags
324
+ // ========================================================================
325
+
326
+ /**
327
+ * Update a board task's subject, description, assignee or status.
328
+ * Requires the boards capability and board-task write permission.
329
+ * @param {string} taskId - The task ID.
330
+ * @param {UpdateTaskDetailsData} data - Fields to change.
331
+ * @returns {Promise<Task>} The updated task.
332
+ * @throws {Error} 'taskId is required.' when `taskId` is falsy.
333
+ */
334
+ async updateTaskDetails(taskId: string, data: UpdateTaskDetailsData): Promise<Task> {
335
+ if (!taskId) throw new Error('taskId is required.');
336
+ return client._request<Task>({
337
+ method: 'PUT',
338
+ endpoint: `/v1/tasks/${taskId}/details`,
339
+ body: data,
340
+ sendJWT: true,
341
+ });
342
+ },
343
+
344
+ /**
345
+ * Link two tasks with a typed relation (related, blocks, blockedBy, duplicate).
346
+ * The link is symmetrical: both tasks reflect the relationship.
347
+ * @param {string} taskId - The task ID.
348
+ * @param {LinkTaskData} data - `linkedTaskId` and `type`.
349
+ * @returns {Promise<TaskLink>} The created link.
350
+ * @throws {Error} 'taskId is required.' or 'linkedTaskId is required.'.
351
+ */
352
+ async linkTask(taskId: string, data: LinkTaskData): Promise<TaskLink> {
353
+ if (!taskId) throw new Error('taskId is required.');
354
+ if (!data.linkedTaskId) throw new Error('linkedTaskId is required.');
355
+ return client._request<TaskLink>({
356
+ method: 'POST',
357
+ endpoint: `/v1/tasks/${taskId}/links`,
358
+ body: data,
359
+ sendJWT: true,
360
+ });
361
+ },
362
+
363
+ /**
364
+ * Remove a task-to-task link.
365
+ * @param {string} taskId - The task ID.
366
+ * @param {string} linkedTaskId - The other task in the link.
367
+ * @returns {Promise<void>} Resolves once removed.
368
+ * @throws {Error} 'taskId is required.' or 'linkedTaskId is required.'.
369
+ */
370
+ async unlinkTask(taskId: string, linkedTaskId: string): Promise<void> {
371
+ if (!taskId) throw new Error('taskId is required.');
372
+ if (!linkedTaskId) throw new Error('linkedTaskId is required.');
373
+ await client._request<void>({
374
+ method: 'DELETE',
375
+ endpoint: `/v1/tasks/${taskId}/links/${linkedTaskId}`,
376
+ sendJWT: true,
377
+ });
378
+ },
379
+
380
+ /**
381
+ * List the tasks linked to a task, with the relation type of each link.
382
+ * @param {string} taskId - The task ID.
383
+ * @returns {Promise<TaskLink[]>} The task's links.
384
+ * @throws {Error} 'taskId is required.' when `taskId` is falsy.
385
+ */
386
+ async getTaskLinks(taskId: string): Promise<TaskLink[]> {
387
+ if (!taskId) throw new Error('taskId is required.');
388
+ return client._request<TaskLink[]>({
389
+ method: 'GET',
390
+ endpoint: `/v1/tasks/${taskId}/links`,
391
+ sendJWT: true,
392
+ });
393
+ },
394
+
395
+ /**
396
+ * Attach a project tag to a task.
397
+ * @param {string} taskId - The task ID.
398
+ * @param {string} tagId - The tag ID.
399
+ * @returns {Promise<Task>} The updated task.
400
+ * @throws {Error} 'taskId is required.' or 'tagId is required.'.
401
+ */
402
+ async tagTask(taskId: string, tagId: string): Promise<Task> {
403
+ if (!taskId) throw new Error('taskId is required.');
404
+ if (!tagId) throw new Error('tagId is required.');
405
+ return client._request<Task>({
406
+ method: 'PUT',
407
+ endpoint: `/v1/tasks/${taskId}/tag`,
408
+ body: { tagId },
409
+ sendJWT: true,
410
+ });
411
+ },
412
+
413
+ /**
414
+ * Detach a project tag from a task.
415
+ * @param {string} taskId - The task ID.
416
+ * @param {string} tagId - The tag ID.
417
+ * @returns {Promise<Task>} The updated task.
418
+ * @throws {Error} 'taskId is required.' or 'tagId is required.'.
419
+ */
420
+ async untagTask(taskId: string, tagId: string): Promise<Task> {
421
+ if (!taskId) throw new Error('taskId is required.');
422
+ if (!tagId) throw new Error('tagId is required.');
423
+ return client._request<Task>({
424
+ method: 'PUT',
425
+ endpoint: `/v1/tasks/${taskId}/untag`,
426
+ body: { tagId },
427
+ sendJWT: true,
428
+ });
429
+ },
430
+ };
431
+ }
@@ -0,0 +1,125 @@
1
+ import NuramaClient from '../NuramaClient.js';
2
+
3
+ export type RelationResourceType = 'chat' | 'chatMessage';
4
+
5
+ export interface TaskRelation {
6
+ id: string;
7
+ taskId: string;
8
+ resourceId: string;
9
+ resourceType: RelationResourceType;
10
+ creatorId: string;
11
+ createdAt: string;
12
+ relatedBy?: any;
13
+ chat?: {
14
+ id: string;
15
+ topicId: string;
16
+ topicType: string;
17
+ visibility: string;
18
+ chatType: string;
19
+ subject?: string | null;
20
+ publicId?: string | null;
21
+ } | null;
22
+ asset?: any | null;
23
+ submission?: { id: string; name: string } | null;
24
+ publicLink?: { id: string; name: string } | null;
25
+ message?: {
26
+ id: string;
27
+ chatId: string;
28
+ content: string | null;
29
+ authorId: string | null;
30
+ author: any;
31
+ mentions: string[];
32
+ assetMentions: string[];
33
+ folderMentions: string[];
34
+ createdAt: string;
35
+ } | null;
36
+ }
37
+
38
+ export interface PaginatedTaskRelations {
39
+ results: TaskRelation[];
40
+ page: number;
41
+ limit: number;
42
+ totalPages: number;
43
+ totalResults: number;
44
+ hasNextPage?: boolean;
45
+ hasPrevPage?: boolean;
46
+ }
47
+
48
+ export default function createTaskRelationMethods(client: NuramaClient) {
49
+ return {
50
+ /**
51
+ * List the relations attached to a task — chat messages, chats, or
52
+ * other resources that reference this task as context.
53
+ */
54
+ async getTaskRelations(
55
+ taskId: string,
56
+ params?: { page?: number; limit?: number }
57
+ ): Promise<PaginatedTaskRelations> {
58
+ if (!taskId) throw new Error('taskId is required.');
59
+ return client._request<PaginatedTaskRelations>({
60
+ method: 'GET',
61
+ endpoint: `/v1/tasks/${taskId}/relations`,
62
+ params,
63
+ sendJWT: true,
64
+ });
65
+ },
66
+
67
+ /**
68
+ * Attach a related resource (chat message, chat, etc.) to a task,
69
+ * so the task surface shows the originating context.
70
+ */
71
+ async createTaskRelation(
72
+ taskId: string,
73
+ data: { resourceId: string; resourceType: RelationResourceType }
74
+ ): Promise<TaskRelation> {
75
+ if (!taskId) throw new Error('taskId is required.');
76
+ if (!data?.resourceId) throw new Error('resourceId is required.');
77
+ if (!data?.resourceType) throw new Error('resourceType is required.');
78
+ return client._request<TaskRelation>({
79
+ method: 'POST',
80
+ endpoint: `/v1/tasks/${taskId}/relations`,
81
+ body: data,
82
+ sendJWT: true,
83
+ });
84
+ },
85
+
86
+ /** Detach a related resource from a task. */
87
+ async deleteTaskRelation(taskId: string, relationId: string): Promise<void> {
88
+ if (!taskId) throw new Error('taskId is required.');
89
+ if (!relationId) throw new Error('relationId is required.');
90
+ return client._request<void>({
91
+ method: 'DELETE',
92
+ endpoint: `/v1/tasks/${taskId}/relations/${relationId}`,
93
+ sendJWT: true,
94
+ });
95
+ },
96
+
97
+ /** List task relations referencing a chat (reverse lookup). */
98
+ async getRelationsForChat(
99
+ chatId: string,
100
+ params?: { page?: number; limit?: number }
101
+ ): Promise<PaginatedTaskRelations> {
102
+ if (!chatId) throw new Error('chatId is required.');
103
+ return client._request<PaginatedTaskRelations>({
104
+ method: 'GET',
105
+ endpoint: `/v1/chats/${chatId}/relations`,
106
+ params,
107
+ sendJWT: true,
108
+ });
109
+ },
110
+
111
+ /** List task relations referencing a specific chat message (reverse lookup). */
112
+ async getRelationsForMessage(
113
+ messageId: string,
114
+ params?: { page?: number; limit?: number }
115
+ ): Promise<PaginatedTaskRelations> {
116
+ if (!messageId) throw new Error('messageId is required.');
117
+ return client._request<PaginatedTaskRelations>({
118
+ method: 'GET',
119
+ endpoint: `/v1/chat-messages/${messageId}/relations`,
120
+ params,
121
+ sendJWT: true,
122
+ });
123
+ },
124
+ };
125
+ }
@@ -0,0 +1,152 @@
1
+ import NuramaClient from '../NuramaClient.js';
2
+
3
+ /**
4
+ * Personal Access Token kinds. v1 only mints `pat`; the rest are
5
+ * reserved for the future OAuth grant flow and are listed here so
6
+ * downstream code can switch on the kind without importing a server-
7
+ * side enum.
8
+ */
9
+ export type TokenKind = 'pat' | 'oauthAccess' | 'oauthRefresh' | 'botAccess';
10
+
11
+ /**
12
+ * Granted action verbs on a token. Mirrors the backend's
13
+ * `@config/tokenScopes` registry; adding a scope on the BE means
14
+ * adding it here too (or callers fall back to `string` when they
15
+ * accept arbitrary scopes from configuration).
16
+ */
17
+ export type TokenScope =
18
+ | 'chat:read'
19
+ | 'chat:write'
20
+ | 'tasks:read'
21
+ | 'tasks:write'
22
+ | 'assets:read'
23
+ | 'assets:write'
24
+ | 'projects:read'
25
+ | 'projects:write'
26
+ | 'workspaces:read'
27
+ | 'workspaces:write'
28
+ | 'convos:read'
29
+ | 'convos:write'
30
+ | 'notifications:read'
31
+ | 'notifications:write'
32
+ | 'ai:use';
33
+
34
+ /**
35
+ * The shape returned by `listTokens` and (without the `token` field)
36
+ * the metadata half of `createToken`. Never includes the raw secret —
37
+ * that is shown exactly once at creation time and is the caller's
38
+ * responsibility to capture.
39
+ */
40
+ export interface TokenSummary {
41
+ id: string;
42
+ name: string;
43
+ prefix: string;
44
+ scopes: TokenScope[];
45
+ kind: TokenKind;
46
+ lastUsed?: string | null;
47
+ expiresAt?: string | null;
48
+ createdAt: string;
49
+ }
50
+
51
+ export interface CreateTokenData {
52
+ /** Customer-facing label. 1–80 characters. */
53
+ name: string;
54
+ /** At least one scope. Validated against the backend registry. */
55
+ scopes: TokenScope[];
56
+ /** Optional ISO date. Null / omitted = non-expiring. */
57
+ expiresAt?: string | null;
58
+ }
59
+
60
+ export interface UpdateTokenScopesData {
61
+ /**
62
+ * The COMPLETE new scope set, not a delta — the same shape
63
+ * `createToken` takes, so what a token may do is always stated in
64
+ * full rather than accumulated through edits nobody can review.
65
+ * At least one scope.
66
+ */
67
+ scopes: TokenScope[];
68
+ }
69
+
70
+ export interface CreateTokenResponse extends TokenSummary {
71
+ /**
72
+ * The raw secret. Returned ONLY in this response. The server keeps a
73
+ * one-way hash and cannot recover this value — the customer must
74
+ * capture it immediately (typical pattern: reveal-once modal with a
75
+ * copy button).
76
+ */
77
+ token: string;
78
+ }
79
+
80
+ /**
81
+ * Personal Access Token surface — auth-gated, owner-scoped. Any
82
+ * logged-in user can mint, list, and revoke their own tokens; there
83
+ * is no admin-on-behalf surface here (admins managing bot keys do
84
+ * that via the `bot` methods).
85
+ */
86
+ export default function createTokenMethods(client: NuramaClient) {
87
+ return {
88
+ /**
89
+ * Mint a new Personal Access Token for the calling user.
90
+ * The raw secret is in the response's `token` field — store it
91
+ * immediately, it cannot be retrieved again.
92
+ */
93
+ async createToken(data: CreateTokenData): Promise<CreateTokenResponse> {
94
+ return client._request<CreateTokenResponse>({
95
+ method: 'POST',
96
+ endpoint: '/v1/tokens',
97
+ body: data,
98
+ sendJWT: true,
99
+ });
100
+ },
101
+
102
+ /**
103
+ * List the caller's Personal Access Tokens. Bot-access keys held
104
+ * by the same user (rare but possible — admin who's also a bot
105
+ * owner) are filtered out server-side and surface via the bot
106
+ * management screens instead.
107
+ */
108
+ async listTokens(): Promise<TokenSummary[]> {
109
+ return client._request<TokenSummary[]>({
110
+ method: 'GET',
111
+ endpoint: '/v1/tokens',
112
+ sendJWT: true,
113
+ bypassCache: true,
114
+ });
115
+ },
116
+
117
+ /**
118
+ * Replace the scopes on one of the caller's Personal Access Tokens.
119
+ *
120
+ * `scopes` is the complete new set, not a delta. This exists because
121
+ * the scope registry grows over time: a token minted before a scope
122
+ * existed cannot hold it, and without this the only remedy is minting
123
+ * a replacement and reconfiguring everywhere the old one is used.
124
+ *
125
+ * The change takes effect on the token's very next request. Scopes
126
+ * remain a ceiling, never a floor — widening a token never lets it do
127
+ * anything its owner cannot already do.
128
+ */
129
+ async updateTokenScopes(tokenId: string, data: UpdateTokenScopesData): Promise<TokenSummary> {
130
+ if (!tokenId) throw new Error('tokenId is required.');
131
+ return client._request<TokenSummary>({
132
+ method: 'PATCH',
133
+ endpoint: `/v1/tokens/${tokenId}`,
134
+ body: data,
135
+ sendJWT: true,
136
+ });
137
+ },
138
+
139
+ /**
140
+ * Revoke one of the caller's Personal Access Tokens. The revocation
141
+ * is immediate — the token will return 401 on the very next request.
142
+ */
143
+ async deleteToken(tokenId: string): Promise<void> {
144
+ if (!tokenId) throw new Error('tokenId is required.');
145
+ return client._request<void>({
146
+ method: 'DELETE',
147
+ endpoint: `/v1/tokens/${tokenId}`,
148
+ sendJWT: true,
149
+ });
150
+ },
151
+ };
152
+ }