@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,356 @@
1
+ import NuramaClient from '../NuramaClient.js';
2
+
3
+ export interface BotApiKeySummary {
4
+ id: string;
5
+ keyPrefix: string;
6
+ name: string;
7
+ /** Discriminator. Bot keys mint as 'botAccess'. */
8
+ kind?: 'botAccess' | 'pat' | 'oauthAccess' | 'oauthRefresh' | null;
9
+ /** Granted scopes. A bot key is minted with the full registry when none are chosen. */
10
+ scopes?: string[];
11
+ lastUsed?: string | null;
12
+ expiresAt?: string | null;
13
+ status: 'active' | 'revoked';
14
+ createdAt: string;
15
+ }
16
+
17
+ export interface Bot {
18
+ id: string;
19
+ displayName: string;
20
+ color: string;
21
+ accountType: 'bot';
22
+ status: string;
23
+ avatarId: string | null;
24
+ /**
25
+ * Populated avatar Asset (joined server-side from `avatarId`). The web client
26
+ * resolves the image URL from this field via `getAvatarUrl()`.
27
+ */
28
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
29
+ avatar?: any | null;
30
+ roles?: string[];
31
+ membershipId?: string;
32
+ apiKeys?: BotApiKeySummary[];
33
+ apiKey?: BotApiKeySummary;
34
+ /**
35
+ * Project memberships within the workspace the bot belongs to. Populated by
36
+ * `listBots` and `getBot`. Empty array if the bot has no project assignments.
37
+ */
38
+ projectMemberships?: BotProjectMembership[];
39
+ createdAt: string;
40
+ updatedAt: string;
41
+ }
42
+
43
+ export interface CreateBotData {
44
+ /** Display name for the bot. 1–50 characters. */
45
+ name: string;
46
+ /** Optional hex color from the approved palette. Auto-assigned if omitted. */
47
+ color?: string;
48
+ /** Workspace roles to grant the bot. Must be one or more of:
49
+ * workspaceAdmin, workspaceMember, workspaceChatMember. */
50
+ roles: Array<'workspaceAdmin' | 'workspaceMember' | 'workspaceChatMember'>;
51
+ /**
52
+ * Optional API-key scopes. Omit (or pass an empty array) to mint the key
53
+ * with the full scope registry, which is what the bot's roles already allow
54
+ * — every route declares a scope now, so a genuinely empty set would leave
55
+ * the key unable to call anything. Pass a subset to narrow it.
56
+ */
57
+ scopes?: string[];
58
+ }
59
+
60
+ export interface CreateBotResponse {
61
+ bot: Bot;
62
+ /** Raw API key, returned ONCE at creation time. Store it immediately — it
63
+ * cannot be retrieved again. */
64
+ rawKey: string;
65
+ }
66
+
67
+ export interface UpdateBotData {
68
+ name?: string;
69
+ color?: string;
70
+ }
71
+
72
+ export interface RotateBotKeyResponse {
73
+ apiKey: BotApiKeySummary;
74
+ /** New raw API key. Returned once. */
75
+ rawKey: string;
76
+ }
77
+
78
+ export interface CreateBotKeyData {
79
+ /** Label shown in the bot's key list. */
80
+ name: string;
81
+ /** Validated server-side against the token-scope registry. Omit for the full set. */
82
+ scopes?: string[];
83
+ /** Optional expiry, ISO 8601. Must be in the future. */
84
+ expiresAt?: string;
85
+ }
86
+
87
+ export interface CreateBotKeyResponse {
88
+ apiKey: BotApiKeySummary;
89
+ /** Raw API key. Returned once and not recoverable afterwards. */
90
+ rawKey: string;
91
+ }
92
+
93
+ export interface UpdateBotKeyScopesData {
94
+ /**
95
+ * The COMPLETE new scope set, not a delta — the same shape `createBotKey`
96
+ * takes. At least one scope; a scopeless key authenticates and is then
97
+ * refused by every gated route, so revoke it instead of emptying it.
98
+ */
99
+ scopes: string[];
100
+ }
101
+
102
+ export interface UpdateBotAvatarFileData {
103
+ name: string;
104
+ sizeInMB: number;
105
+ checksum: string;
106
+ }
107
+
108
+ export interface UpdateBotAvatarResponse {
109
+ user: { id: string; avatarId: string | null };
110
+ asset?: { id: string; [k: string]: unknown };
111
+ signedUrlData?: {
112
+ key: string;
113
+ uploadId: string;
114
+ urls: string[];
115
+ };
116
+ [k: string]: unknown;
117
+ }
118
+
119
+ export type BotProjectRole = 'creator' | 'reviewer' | 'projectAdmin';
120
+
121
+ export interface BotProjectMembership {
122
+ membershipId: string;
123
+ projectId: string;
124
+ projectName: string;
125
+ roles: BotProjectRole[];
126
+ }
127
+
128
+ /**
129
+ * Bot user administration methods. Used by workspace owners/admins (callers
130
+ * holding a JWT) to manage bot users in a workspace. Bots themselves cannot
131
+ * call these endpoints — bot administration is restricted server-side.
132
+ */
133
+ export default function createBotMethods(client: NuramaClient) {
134
+ return {
135
+ /**
136
+ * Create a bot user in a workspace.
137
+ * Returns the new bot and the raw API key (shown only once).
138
+ */
139
+ async createBot(workspaceId: string, data: CreateBotData): Promise<CreateBotResponse> {
140
+ if (!workspaceId) throw new Error('workspaceId is required.');
141
+ return client._request<CreateBotResponse>({
142
+ method: 'POST',
143
+ endpoint: `/v1/workspaces/${workspaceId}/bots`,
144
+ body: data,
145
+ sendJWT: true,
146
+ });
147
+ },
148
+
149
+ /** List bot users in a workspace. */
150
+ async listBots(workspaceId: string): Promise<Bot[]> {
151
+ if (!workspaceId) throw new Error('workspaceId is required.');
152
+ return client._request<Bot[]>({
153
+ method: 'GET',
154
+ endpoint: `/v1/workspaces/${workspaceId}/bots`,
155
+ sendJWT: true,
156
+ bypassCache: true,
157
+ });
158
+ },
159
+
160
+ /** Get a single bot's details, including all of its API key metadata (no secrets). */
161
+ async getBot(workspaceId: string, botId: string): Promise<Bot> {
162
+ if (!workspaceId) throw new Error('workspaceId is required.');
163
+ if (!botId) throw new Error('botId is required.');
164
+ return client._request<Bot>({
165
+ method: 'GET',
166
+ endpoint: `/v1/workspaces/${workspaceId}/bots/${botId}`,
167
+ sendJWT: true,
168
+ bypassCache: true,
169
+ });
170
+ },
171
+
172
+ /** Update a bot's display name and/or color. */
173
+ async updateBot(workspaceId: string, botId: string, data: UpdateBotData): Promise<Bot> {
174
+ if (!workspaceId) throw new Error('workspaceId is required.');
175
+ if (!botId) throw new Error('botId is required.');
176
+ return client._request<Bot>({
177
+ method: 'PUT',
178
+ endpoint: `/v1/workspaces/${workspaceId}/bots/${botId}`,
179
+ body: data,
180
+ sendJWT: true,
181
+ });
182
+ },
183
+
184
+ /**
185
+ * Delete a bot user. Revokes all API keys, removes the workspace
186
+ * membership, and marks the user inactive.
187
+ */
188
+ async deleteBot(workspaceId: string, botId: string): Promise<void> {
189
+ if (!workspaceId) throw new Error('workspaceId is required.');
190
+ if (!botId) throw new Error('botId is required.');
191
+ return client._request<void>({
192
+ method: 'DELETE',
193
+ endpoint: `/v1/workspaces/${workspaceId}/bots/${botId}`,
194
+ sendJWT: true,
195
+ });
196
+ },
197
+
198
+ /**
199
+ * Revoke the bot's current API key and issue a new one.
200
+ * The new raw key is returned once.
201
+ *
202
+ * The replacement carries the old key's scopes verbatim, so this is not a
203
+ * way to pick up scopes added to the registry since the key was minted —
204
+ * `updateBotKeyScopes` is.
205
+ */
206
+ async rotateBotKey(workspaceId: string, botId: string): Promise<RotateBotKeyResponse> {
207
+ if (!workspaceId) throw new Error('workspaceId is required.');
208
+ if (!botId) throw new Error('botId is required.');
209
+ return client._request<RotateBotKeyResponse>({
210
+ method: 'POST',
211
+ endpoint: `/v1/workspaces/${workspaceId}/bots/${botId}/rotate-key`,
212
+ sendJWT: true,
213
+ });
214
+ },
215
+
216
+ /**
217
+ * Mint an ADDITIONAL API key for the bot, up to 5 live keys.
218
+ *
219
+ * Unlike `rotateBotKey`, the bot's existing keys keep working — which is
220
+ * what makes a zero-downtime changeover possible: mint, move traffic over,
221
+ * then revoke the old key. The raw key is returned once.
222
+ */
223
+ async createBotKey(
224
+ workspaceId: string,
225
+ botId: string,
226
+ keyData: CreateBotKeyData,
227
+ ): Promise<CreateBotKeyResponse> {
228
+ if (!workspaceId) throw new Error('workspaceId is required.');
229
+ if (!botId) throw new Error('botId is required.');
230
+ if (!keyData?.name) throw new Error('name is required.');
231
+ return client._request<CreateBotKeyResponse>({
232
+ method: 'POST',
233
+ endpoint: `/v1/workspaces/${workspaceId}/bots/${botId}/keys`,
234
+ body: keyData,
235
+ sendJWT: true,
236
+ });
237
+ },
238
+
239
+ /**
240
+ * Replace the scopes on one of the bot's API keys, in place.
241
+ *
242
+ * A key's scopes are a snapshot taken when it was minted, and the registry
243
+ * grows — a key created before a scope existed cannot hold it. Rotation is
244
+ * not a substitute: `rotateBotKey` copies the old scope set onto the
245
+ * replacement, so a stale key stays stale through every rotation.
246
+ *
247
+ * This matters most for keys minted with `scopes` omitted, which means
248
+ * "the full registry" as it stood that day, not "whatever the full registry
249
+ * becomes".
250
+ *
251
+ * The secret is unchanged — every caller configured with this key keeps
252
+ * working, which is the whole point. Requires `canManageBots`.
253
+ */
254
+ async updateBotKeyScopes(
255
+ workspaceId: string,
256
+ botId: string,
257
+ keyId: string,
258
+ data: UpdateBotKeyScopesData,
259
+ ): Promise<BotApiKeySummary> {
260
+ if (!workspaceId) throw new Error('workspaceId is required.');
261
+ if (!botId) throw new Error('botId is required.');
262
+ if (!keyId) throw new Error('keyId is required.');
263
+ return client._request<BotApiKeySummary>({
264
+ method: 'PATCH',
265
+ endpoint: `/v1/workspaces/${workspaceId}/bots/${botId}/keys/${keyId}`,
266
+ body: data,
267
+ sendJWT: true,
268
+ });
269
+ },
270
+
271
+ /**
272
+ * Revoke one of the bot's API keys, leaving its others working.
273
+ * A revoked key stops authenticating immediately and frees a slot
274
+ * against the 5-key cap.
275
+ */
276
+ async revokeBotKey(workspaceId: string, botId: string, keyId: string): Promise<void> {
277
+ if (!workspaceId) throw new Error('workspaceId is required.');
278
+ if (!botId) throw new Error('botId is required.');
279
+ if (!keyId) throw new Error('keyId is required.');
280
+ return client._request<void>({
281
+ method: 'DELETE',
282
+ endpoint: `/v1/workspaces/${workspaceId}/bots/${botId}/keys/${keyId}`,
283
+ sendJWT: true,
284
+ });
285
+ },
286
+
287
+ /**
288
+ * Request signed URL data to upload a new avatar for the bot.
289
+ * Caller multipart-uploads the file to S3 using the returned `signedUrlData`,
290
+ * then calls `client.asset.completeUpload(...)` to finalize.
291
+ */
292
+ async updateBotAvatar(
293
+ workspaceId: string,
294
+ botId: string,
295
+ fileData: UpdateBotAvatarFileData,
296
+ ): Promise<UpdateBotAvatarResponse> {
297
+ if (!workspaceId) throw new Error('workspaceId is required.');
298
+ if (!botId) throw new Error('botId is required.');
299
+ return client._request<UpdateBotAvatarResponse>({
300
+ method: 'POST',
301
+ endpoint: `/v1/workspaces/${workspaceId}/bots/${botId}/avatar`,
302
+ body: fileData,
303
+ sendJWT: true,
304
+ });
305
+ },
306
+
307
+ /**
308
+ * List the bot's project memberships within the workspace.
309
+ */
310
+ async listProjectMemberships(workspaceId: string, botId: string): Promise<BotProjectMembership[]> {
311
+ if (!workspaceId) throw new Error('workspaceId is required.');
312
+ if (!botId) throw new Error('botId is required.');
313
+ return client._request<BotProjectMembership[]>({
314
+ method: 'GET',
315
+ endpoint: `/v1/workspaces/${workspaceId}/bots/${botId}/memberships`,
316
+ sendJWT: true,
317
+ bypassCache: true,
318
+ });
319
+ },
320
+
321
+ /**
322
+ * Upsert the bot's membership on a project. Replaces roles if a membership
323
+ * already exists; creates one otherwise. Idempotent.
324
+ */
325
+ async setProjectMembership(
326
+ workspaceId: string,
327
+ botId: string,
328
+ projectId: string,
329
+ data: { roles: BotProjectRole[] },
330
+ ): Promise<BotProjectMembership> {
331
+ if (!workspaceId) throw new Error('workspaceId is required.');
332
+ if (!botId) throw new Error('botId is required.');
333
+ if (!projectId) throw new Error('projectId is required.');
334
+ return client._request<BotProjectMembership>({
335
+ method: 'PUT',
336
+ endpoint: `/v1/workspaces/${workspaceId}/bots/${botId}/memberships/project/${projectId}`,
337
+ body: data,
338
+ sendJWT: true,
339
+ });
340
+ },
341
+
342
+ /**
343
+ * Remove the bot's membership on a project. Idempotent.
344
+ */
345
+ async removeProjectMembership(workspaceId: string, botId: string, projectId: string): Promise<void> {
346
+ if (!workspaceId) throw new Error('workspaceId is required.');
347
+ if (!botId) throw new Error('botId is required.');
348
+ if (!projectId) throw new Error('projectId is required.');
349
+ return client._request<void>({
350
+ method: 'DELETE',
351
+ endpoint: `/v1/workspaces/${workspaceId}/bots/${botId}/memberships/project/${projectId}`,
352
+ sendJWT: true,
353
+ });
354
+ },
355
+ };
356
+ }