@nurama/sdk 0.0.0-stage → 1.4.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 (220) 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 +448 -0
  9. package/dist/NuramaClient.d.ts.map +1 -0
  10. package/dist/NuramaClient.js +864 -0
  11. package/dist/NuramaClient.js.map +1 -0
  12. package/dist/browser/nurama-bot-sdk.js +11780 -0
  13. package/dist/browser/nurama-bot-sdk.min.js +1 -0
  14. package/dist/browser/nurama-sdk.js +11732 -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 +147 -0
  37. package/dist/routes/bot.d.ts.map +1 -0
  38. package/dist/routes/bot.js +157 -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 +38 -0
  73. package/dist/routes/joinLink.d.ts.map +1 -0
  74. package/dist/routes/joinLink.js +81 -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/payment.d.ts +56 -0
  85. package/dist/routes/payment.d.ts.map +1 -0
  86. package/dist/routes/payment.js +78 -0
  87. package/dist/routes/payment.js.map +1 -0
  88. package/dist/routes/product.d.ts +43 -0
  89. package/dist/routes/product.d.ts.map +1 -0
  90. package/dist/routes/product.js +53 -0
  91. package/dist/routes/product.js.map +1 -0
  92. package/dist/routes/project.d.ts +821 -0
  93. package/dist/routes/project.d.ts.map +1 -0
  94. package/dist/routes/project.js +1153 -0
  95. package/dist/routes/project.js.map +1 -0
  96. package/dist/routes/public.d.ts +269 -0
  97. package/dist/routes/public.d.ts.map +1 -0
  98. package/dist/routes/public.js +412 -0
  99. package/dist/routes/public.js.map +1 -0
  100. package/dist/routes/scratch.d.ts +70 -0
  101. package/dist/routes/scratch.d.ts.map +1 -0
  102. package/dist/routes/scratch.js +67 -0
  103. package/dist/routes/scratch.js.map +1 -0
  104. package/dist/routes/settings.d.ts +102 -0
  105. package/dist/routes/settings.d.ts.map +1 -0
  106. package/dist/routes/settings.js +94 -0
  107. package/dist/routes/settings.js.map +1 -0
  108. package/dist/routes/shortlink.d.ts +79 -0
  109. package/dist/routes/shortlink.d.ts.map +1 -0
  110. package/dist/routes/shortlink.js +25 -0
  111. package/dist/routes/shortlink.js.map +1 -0
  112. package/dist/routes/socket.d.ts +108 -0
  113. package/dist/routes/socket.d.ts.map +1 -0
  114. package/dist/routes/socket.js +555 -0
  115. package/dist/routes/socket.js.map +1 -0
  116. package/dist/routes/storage.d.ts +44 -0
  117. package/dist/routes/storage.d.ts.map +1 -0
  118. package/dist/routes/storage.js +49 -0
  119. package/dist/routes/storage.js.map +1 -0
  120. package/dist/routes/subscription.d.ts +184 -0
  121. package/dist/routes/subscription.d.ts.map +1 -0
  122. package/dist/routes/subscription.js +219 -0
  123. package/dist/routes/subscription.js.map +1 -0
  124. package/dist/routes/supportChat.d.ts +40 -0
  125. package/dist/routes/supportChat.d.ts.map +1 -0
  126. package/dist/routes/supportChat.js +53 -0
  127. package/dist/routes/supportChat.js.map +1 -0
  128. package/dist/routes/supportTicket.d.ts +89 -0
  129. package/dist/routes/supportTicket.d.ts.map +1 -0
  130. package/dist/routes/supportTicket.js +54 -0
  131. package/dist/routes/supportTicket.js.map +1 -0
  132. package/dist/routes/tag.d.ts +72 -0
  133. package/dist/routes/tag.d.ts.map +1 -0
  134. package/dist/routes/tag.js +81 -0
  135. package/dist/routes/tag.js.map +1 -0
  136. package/dist/routes/task.d.ts +252 -0
  137. package/dist/routes/task.d.ts.map +1 -0
  138. package/dist/routes/task.js +284 -0
  139. package/dist/routes/task.js.map +1 -0
  140. package/dist/routes/taskRelation.d.ts +80 -0
  141. package/dist/routes/taskRelation.d.ts.map +1 -0
  142. package/dist/routes/taskRelation.js +71 -0
  143. package/dist/routes/taskRelation.js.map +1 -0
  144. package/dist/routes/token.d.ts +75 -0
  145. package/dist/routes/token.d.ts.map +1 -0
  146. package/dist/routes/token.js +51 -0
  147. package/dist/routes/token.js.map +1 -0
  148. package/dist/routes/user.d.ts +112 -0
  149. package/dist/routes/user.d.ts.map +1 -0
  150. package/dist/routes/user.js +151 -0
  151. package/dist/routes/user.js.map +1 -0
  152. package/dist/routes/version.d.ts +42 -0
  153. package/dist/routes/version.d.ts.map +1 -0
  154. package/dist/routes/version.js +38 -0
  155. package/dist/routes/version.js.map +1 -0
  156. package/dist/routes/webhook.d.ts +170 -0
  157. package/dist/routes/webhook.d.ts.map +1 -0
  158. package/dist/routes/webhook.js +173 -0
  159. package/dist/routes/webhook.js.map +1 -0
  160. package/dist/routes/workspace.d.ts +120 -0
  161. package/dist/routes/workspace.d.ts.map +1 -0
  162. package/dist/routes/workspace.js +199 -0
  163. package/dist/routes/workspace.js.map +1 -0
  164. package/dist/utils/uploadSessionManager.d.ts +133 -0
  165. package/dist/utils/uploadSessionManager.d.ts.map +1 -0
  166. package/dist/utils/uploadSessionManager.js +321 -0
  167. package/dist/utils/uploadSessionManager.js.map +1 -0
  168. package/dist/utils/urlParams.d.ts +35 -0
  169. package/dist/utils/urlParams.d.ts.map +1 -0
  170. package/dist/utils/urlParams.js +146 -0
  171. package/dist/utils/urlParams.js.map +1 -0
  172. package/dist/version.d.ts +15 -0
  173. package/dist/version.d.ts.map +1 -0
  174. package/dist/version.js +12 -0
  175. package/dist/version.js.map +1 -0
  176. package/package.json +87 -3
  177. package/src/BotClient.ts +113 -0
  178. package/src/NuramaClient.ts +1193 -0
  179. package/src/bot-browser-entry.js +15 -0
  180. package/src/browser-entry.js +20 -0
  181. package/src/routes/ai.ts +378 -0
  182. package/src/routes/asset.ts +1104 -0
  183. package/src/routes/auth.ts +587 -0
  184. package/src/routes/blogPosts.ts +29 -0
  185. package/src/routes/board.ts +403 -0
  186. package/src/routes/bot.ts +257 -0
  187. package/src/routes/chat.ts +1292 -0
  188. package/src/routes/chatAi.ts +125 -0
  189. package/src/routes/config.ts +31 -0
  190. package/src/routes/convo.ts +321 -0
  191. package/src/routes/credits.ts +112 -0
  192. package/src/routes/device.ts +133 -0
  193. package/src/routes/folder.ts +154 -0
  194. package/src/routes/invite.ts +133 -0
  195. package/src/routes/joinLink.ts +100 -0
  196. package/src/routes/membership.ts +237 -0
  197. package/src/routes/notification.ts +166 -0
  198. package/src/routes/payment.ts +104 -0
  199. package/src/routes/product.ts +67 -0
  200. package/src/routes/project.ts +1528 -0
  201. package/src/routes/public.ts +496 -0
  202. package/src/routes/scratch.ts +94 -0
  203. package/src/routes/settings.ts +152 -0
  204. package/src/routes/shortlink.ts +90 -0
  205. package/src/routes/socket.ts +739 -0
  206. package/src/routes/storage.ts +83 -0
  207. package/src/routes/subscription.ts +307 -0
  208. package/src/routes/supportChat.ts +62 -0
  209. package/src/routes/supportTicket.ts +114 -0
  210. package/src/routes/tag.ts +131 -0
  211. package/src/routes/task.ts +431 -0
  212. package/src/routes/taskRelation.ts +125 -0
  213. package/src/routes/token.ts +113 -0
  214. package/src/routes/user.ts +214 -0
  215. package/src/routes/version.ts +62 -0
  216. package/src/routes/webhook.ts +295 -0
  217. package/src/routes/workspace.ts +223 -0
  218. package/src/utils/uploadSessionManager.ts +407 -0
  219. package/src/utils/urlParams.ts +181 -0
  220. package/src/version.ts +22 -0
@@ -0,0 +1,15 @@
1
+ import BotClient from './BotClient.js';
2
+
3
+ const OriginalBotClient = BotClient;
4
+ class BrowserBotClient extends OriginalBotClient {
5
+ constructor(apiKey, options = {}) {
6
+ super(apiKey, {
7
+ ...options,
8
+ fetch: options.fetch || ((url, init) => window.fetch(url, init)),
9
+ });
10
+ }
11
+ }
12
+
13
+ window.NuramaBotClient = BrowserBotClient;
14
+
15
+ export default BrowserBotClient;
@@ -0,0 +1,20 @@
1
+ import NuramaClient from './NuramaClient.js';
2
+
3
+
4
+ const OriginalNuramaClient = NuramaClient;
5
+ class BrowserNuramaClient extends OriginalNuramaClient {
6
+ constructor(baseURL, options = {}) {
7
+ // Ensure fetch is properly bound to window
8
+ const browserOptions = {
9
+ ...options,
10
+ // Wrap fetch in a function that explicitly binds to window
11
+ fetch: (url, init) => window.fetch(url, init)
12
+ };
13
+ super(baseURL, browserOptions);
14
+ }
15
+ }
16
+
17
+ // Explicitly assign the constructor to the global window object
18
+ window.NuramaClient = BrowserNuramaClient;
19
+
20
+ export default BrowserNuramaClient;
@@ -0,0 +1,378 @@
1
+ import NuramaClient from '../NuramaClient.js';
2
+
3
+ /** One turn of the drafting conversation, as sent back on each request. */
4
+ export interface ComposeWithNuTurn {
5
+ role: 'user' | 'assistant';
6
+ text: string;
7
+ /**
8
+ * Wording this turn offered. Held per turn so an earlier draft stays
9
+ * takeable after the conversation has moved on — the user may prefer the
10
+ * version from three turns ago.
11
+ */
12
+ proposal?: string | null;
13
+ }
14
+
15
+ export interface ComposeWithNuRequest {
16
+ workspaceId: string;
17
+ /** Chat being composed into. Read server-side for context and tone. */
18
+ chatId: string;
19
+ projectId?: string;
20
+ messages: ComposeWithNuTurn[];
21
+ }
22
+
23
+ export interface ComposeWithNuResponse {
24
+ /** What Nu said to the user. Never posted anywhere. */
25
+ text: string;
26
+ /** Wording the user may put in their composer, or null for a pure question. */
27
+ proposal: string | null;
28
+ billedCredits: number;
29
+ balanceAfter: number | null;
30
+ eventId: string | null;
31
+ }
32
+
33
+ /** One Nu Feedback submission. */
34
+ export interface SubmitAiFeedbackRequest {
35
+ rating: 'positive' | 'negative';
36
+ /** Which AI surface produced the reply — the two are tuned separately. */
37
+ surface: 'chat' | 'assist';
38
+ chatId: string;
39
+ messageId?: string;
40
+ /** The user's own words on what worked or didn't. Optional. */
41
+ notes?: string;
42
+ workspaceId?: string;
43
+ projectId?: string;
44
+ /** Extras the client already holds, folded into the stored snapshot. */
45
+ pageContext?: Record<string, unknown>;
46
+ contextItems?: Array<Record<string, unknown>>;
47
+ }
48
+
49
+ export interface PolishRequest {
50
+ workspaceId: string;
51
+ text: string;
52
+ toneId: string;
53
+ projectId?: string;
54
+ }
55
+
56
+ export interface PolishResponse {
57
+ polishedText: string;
58
+ billedCredits: number;
59
+ balanceAfter: number;
60
+ eventId: string | null;
61
+ }
62
+
63
+ export interface TaskGenerationContextMessage {
64
+ /** Display name of the message author. Optional but improves the prompt. */
65
+ authorName?: string;
66
+ content: string;
67
+ }
68
+
69
+ export interface GenerateTasksRequest {
70
+ workspaceId: string;
71
+ projectId: string;
72
+ messageText: string;
73
+ /** Optional source chat message id — reserved for future audit linking. */
74
+ messageId?: string;
75
+ /**
76
+ * Preceding chat messages (oldest first) to give the model conversational
77
+ * lead-in. Server caps at 10 messages and trims long content per-message;
78
+ * the focal `messageText` is the actual instruction.
79
+ */
80
+ contextMessages?: TaskGenerationContextMessage[];
81
+ }
82
+
83
+ export interface GeneratedTask {
84
+ subject: string;
85
+ description: string;
86
+ }
87
+
88
+ export interface GenerateTasksResponse {
89
+ tasks: GeneratedTask[];
90
+ billedCredits: number;
91
+ balanceAfter: number;
92
+ eventId: string | null;
93
+ }
94
+
95
+ export interface ToneEntry {
96
+ id: string;
97
+ label: string;
98
+ }
99
+
100
+ export interface ListTonesResponse {
101
+ tones: ToneEntry[];
102
+ }
103
+
104
+ /**
105
+ * Source for an image revision call. Exactly one of:
106
+ * - `url` — public media URL (typical for image assets).
107
+ * - `scratchId` — id of a Scratch row the FE uploaded via
108
+ * `createRevisionSourceUpload`. Preferred for
109
+ * captured video frames so bytes never transit the
110
+ * API node.
111
+ * - `dataUrl` — DEPRECATED legacy path: FE-captured video frame
112
+ * serialised as a base64 data URL inline in the
113
+ * request body. Kept here for back-compat during
114
+ * FE rollout; new code should always use the
115
+ * `scratchId` flow.
116
+ */
117
+ export type ImageRevisionSource =
118
+ | { url: string }
119
+ | { scratchId: string }
120
+ | { dataUrl: string };
121
+
122
+ export interface GenerateImageRevisionRequest {
123
+ workspaceId: string;
124
+ projectId?: string;
125
+ /** Audit-only — the caller has already resolved the asset's media URL. */
126
+ assetId?: string;
127
+ source: ImageRevisionSource;
128
+ prompt: string;
129
+ /** Prior revisions to condition on (public URLs or data URLs). */
130
+ references?: string[];
131
+ /**
132
+ * Optional alpha-channel mask PNG (data URL) matching the source
133
+ * image's dimensions. Transparent pixels mark the edit region; opaque
134
+ * pixels are preserved. When supplied, the server forwards it as
135
+ * OpenAI's top-level `mask` field — NOT as another `references[]`
136
+ * entry — and auto-augments the prompt with a region directive.
137
+ */
138
+ mask?: { dataUrl: string };
139
+ /** Groups all revisions from one modal session. */
140
+ jobId?: string;
141
+ /**
142
+ * Source image's aspect ratio (width / height). Two effects when set:
143
+ * 1. The server picks the closest OpenAI-supported generation
144
+ * size — landscape, portrait, or square — instead of always
145
+ * generating 1024×1024. Reduces the gap between the model's
146
+ * output aspect and the source aspect before any padding.
147
+ * 2. After generation, the server pads the result with black
148
+ * bars (letterbox/pillarbox) so the final bytes exactly
149
+ * match this aspect. The user gets an output image whose
150
+ * framing matches the input they started from, with the
151
+ * generated content centred and the unfilled edges padded.
152
+ *
153
+ * Omit (or pass `1.0`) for legacy square output.
154
+ */
155
+ sourceAspect?: number;
156
+ }
157
+
158
+ export interface GenerateImageRevisionResponse {
159
+ /**
160
+ * Scratch id. The FE forwards this in one of two outcomes:
161
+ * - "Upload to project" → call `promoteRevision` (this SDK module)
162
+ * to materialise as a project-scoped Asset.
163
+ * - "Attach to chat" → pass `{ scratchId }` as a chat-message
164
+ * attachment item; the chat-send endpoint promotes it to a
165
+ * chat-scoped Asset at send time.
166
+ */
167
+ revisionId: string;
168
+ /** Public URL the FE can render directly. */
169
+ revisionUrl: string | null;
170
+ model: string;
171
+ quality: string;
172
+ billedCredits: number;
173
+ balanceAfter: number | null;
174
+ eventId: string | null;
175
+ }
176
+
177
+ /**
178
+ * Source-upload mint request. Returns a multipart upload bundle the
179
+ * FE drives like any other scratch / asset upload (PUT each `urls[i]`
180
+ * with the corresponding part, collect the ETags, call complete-
181
+ * upload). Server hardcodes mime to `image/jpeg` — the only producer
182
+ * is the captured video frame, which is always JPEG. Size cap
183
+ * (matches OpenAI's images/edits per-image limit): 25 MB.
184
+ */
185
+ export interface CreateRevisionSourceUploadRequest {
186
+ workspaceId: string;
187
+ projectId?: string;
188
+ /** Audit-only lineage — the originating asset id. */
189
+ assetId?: string;
190
+ sizeInMB: number;
191
+ }
192
+
193
+ export interface CreateRevisionSourceUploadResponse {
194
+ /** Use as `source.scratchId` on the subsequent `generateRevision` call. */
195
+ scratchId: string;
196
+ /**
197
+ * Bucket-side keyPath. Pass to `nuramaClient.asset.multipartUpload`
198
+ * which threads it through into its session-progress + result shape.
199
+ */
200
+ key: string;
201
+ /** Pass back to `POST /v1/scratch/:id/complete-upload` along with parts. */
202
+ uploadId: string;
203
+ /**
204
+ * One signed PUT URL per multipart part. Single-element array for
205
+ * sub-chunk-size payloads (1080p JPEG frames are well under).
206
+ */
207
+ urls: string[];
208
+ /** ISO-string TTL — the row is reaped after this. */
209
+ expires: string;
210
+ }
211
+
212
+ // Scratch promotion moved to the scratch namespace —
213
+ // `nuramaClient.scratch.promote(id, { fileName? })`. The AI module
214
+ // no longer carries a `promoteRevision`. Two reasons for the move:
215
+ // 1. Scratch is a generic primitive; promote applies to ALL scratch
216
+ // jobTypes, not just AI Revision.
217
+ // 2. Destination (workspace + project) is derived from the scratch
218
+ // row's own state on the server — keeps promote a single-arg
219
+ // operation from the FE's perspective ("promote this row") and
220
+ // removes the cross-workspace-promote attack surface.
221
+
222
+ /**
223
+ * Methods for the Nu AI assistant integration points.
224
+ *
225
+ * Nu is the platform-native AI feature set. Each integration point is gated
226
+ * by workspace settings (`allowAiFeatures` master switch + per-feature toggle
227
+ * + role allowlist) and metered against the workspace's credit balance.
228
+ *
229
+ * MVP exposes a single integration point — Polish — used by the chat
230
+ * composer to rewrite a draft message in a selected tone.
231
+ */
232
+ export default function createAiMethods(client: NuramaClient) {
233
+ return {
234
+ /**
235
+ * Rewrite a draft chat message in a selected tone. Charges the workspace's
236
+ * credit balance based on the underlying provider cost plus markup.
237
+ *
238
+ * @param data - Polish request payload.
239
+ * @returns The polished text plus billing telemetry.
240
+ */
241
+ /**
242
+ * One turn of a Compose-with-Nu drafting conversation.
243
+ *
244
+ * Send only the drafting thread — the chat being written into is read
245
+ * server-side from `chatId`, under the caller's own permissions. The
246
+ * result is Nu's commentary plus, when it has one, a proposed message.
247
+ * Nothing is posted: the proposal is the user's to take or discard.
248
+ */
249
+ async composeWithNu(data: ComposeWithNuRequest): Promise<ComposeWithNuResponse> {
250
+ if (!data?.workspaceId) throw new Error('workspaceId is required.');
251
+ if (!data?.chatId) throw new Error('chatId is required.');
252
+ if (!data?.messages?.length) throw new Error('messages is required.');
253
+ return client._request({
254
+ endpoint: '/v1/ai/compose',
255
+ method: 'POST',
256
+ body: data,
257
+ sendJWT: true,
258
+ });
259
+ },
260
+
261
+ /**
262
+ * Record a thumbs-up / thumbs-down on one assistant reply.
263
+ *
264
+ * `chatId` is required because it is what the server authorises against —
265
+ * a user can only rate a reply in a chat they can already read — and it is
266
+ * what the stored transcript snapshot is built from.
267
+ */
268
+ async submitFeedback(data: SubmitAiFeedbackRequest): Promise<{ id: string }> {
269
+ if (!data?.chatId) throw new Error('chatId is required.');
270
+ if (!data?.rating) throw new Error('rating is required.');
271
+ if (!data?.surface) throw new Error('surface is required.');
272
+ return client._request({
273
+ endpoint: '/v1/ai/feedback',
274
+ method: 'POST',
275
+ body: data,
276
+ sendJWT: true,
277
+ });
278
+ },
279
+
280
+ async polish(data: PolishRequest): Promise<PolishResponse> {
281
+ if (!data?.workspaceId) throw new Error('workspaceId is required.');
282
+ if (!data?.text) throw new Error('text is required.');
283
+ if (!data?.toneId) throw new Error('toneId is required.');
284
+ return client._request({
285
+ endpoint: '/v1/ai/polish',
286
+ method: 'POST',
287
+ body: data,
288
+ sendJWT: true,
289
+ });
290
+ },
291
+
292
+ /**
293
+ * Convert a chat message into one or more board-task drafts. The
294
+ * frontend opens the EnhancedTaskCreatorModal in a loading state, calls
295
+ * this method, and seeds the modal's draft list from the response's
296
+ * `tasks` array. Requires both the AI add-on AND the Boards add-on on
297
+ * the workspace; the server returns `productNotActive` if either is
298
+ * missing.
299
+ *
300
+ * @param data - Task generation request payload.
301
+ * @returns Tasks plus billing telemetry.
302
+ */
303
+ async generateTasks(data: GenerateTasksRequest): Promise<GenerateTasksResponse> {
304
+ if (!data?.workspaceId) throw new Error('workspaceId is required.');
305
+ if (!data?.projectId) throw new Error('projectId is required.');
306
+ if (!data?.messageText) throw new Error('messageText is required.');
307
+ return client._request({
308
+ endpoint: '/v1/ai/task-generation',
309
+ method: 'POST',
310
+ body: data,
311
+ sendJWT: true,
312
+ });
313
+ },
314
+
315
+ /**
316
+ * Returns the catalogue of polish tones the platform supports. The FE
317
+ * uses this to populate the tone dropdown without hard-coding the IDs.
318
+ */
319
+ async listTones(): Promise<ListTonesResponse> {
320
+ return client._request({
321
+ endpoint: '/v1/ai/tones',
322
+ method: 'GET',
323
+ sendJWT: true,
324
+ });
325
+ },
326
+
327
+ /**
328
+ * Generate one image revision (prompt-driven variant of a source
329
+ * image or video frame). The result is staged on Scratch — the FE
330
+ * then chooses one of two outcomes:
331
+ * - "Add to project" → call `nuramaClient.scratch.promote(id)` to
332
+ * create a project-scoped Asset immediately.
333
+ * - "Attach to chat" → leave the scratch id in the chat
334
+ * composer's pending attachments; the chat-send endpoint
335
+ * accepts `{ scratchId, name? }` items in `attachments[]` and
336
+ * promotes each to a chat-scoped Asset at send time.
337
+ */
338
+ async generateRevision(
339
+ data: GenerateImageRevisionRequest,
340
+ ): Promise<GenerateImageRevisionResponse> {
341
+ if (!data?.workspaceId) throw new Error('workspaceId is required.');
342
+ if (!data?.source) throw new Error('source is required.');
343
+ if (!data?.prompt) throw new Error('prompt is required.');
344
+ return client._request({
345
+ endpoint: '/v1/ai/revisions',
346
+ method: 'POST',
347
+ body: data,
348
+ sendJWT: true,
349
+ });
350
+ },
351
+
352
+ /**
353
+ * Mint a signed-URL bundle for uploading a source image (typically
354
+ * a captured video frame) into Scratch BEFORE calling
355
+ * `generateRevision`. Use the resulting `scratchId` as the
356
+ * `source.scratchId` on the generate call.
357
+ *
358
+ * Why this exists: video frames are captured client-side and need
359
+ * to reach OpenAI as a public media URL. Posting the bytes inline
360
+ * (as `dataUrl`) makes the API node a pass-through for multi-MB
361
+ * payloads; staging on Scratch first keeps the node out of the
362
+ * byte path entirely.
363
+ */
364
+ async createRevisionSourceUpload(
365
+ data: CreateRevisionSourceUploadRequest,
366
+ ): Promise<CreateRevisionSourceUploadResponse> {
367
+ if (!data?.workspaceId) throw new Error('workspaceId is required.');
368
+ if (!(data?.sizeInMB > 0)) throw new Error('sizeInMB must be a positive number.');
369
+ return client._request({
370
+ endpoint: '/v1/ai/revisions/source-upload',
371
+ method: 'POST',
372
+ body: data,
373
+ sendJWT: true,
374
+ });
375
+ },
376
+
377
+ };
378
+ }