@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,214 @@
1
+ import NuramaClient from '../NuramaClient.js';
2
+ import { type User, type PublicUser } from '@nurama/types';
3
+
4
+ export interface FileData {
5
+ name: string;
6
+ checksum: string;
7
+ sizeInMB: number;
8
+ }
9
+
10
+ // Define the type for the update data based on backend validation
11
+ export interface UpdateUserData {
12
+ email?: string;
13
+ userName?: string;
14
+ password?: string;
15
+ firstName?: string;
16
+ middleName?: string;
17
+ lastName?: string;
18
+ company?: string;
19
+ displayName?: string;
20
+ color?: string;
21
+ allowOauthAutolink?: boolean;
22
+ }
23
+
24
+ export interface PreferencesData {
25
+ hide?: string[];
26
+ // Per-user UX dismissals — anything the user has explicitly opted
27
+ // out of seeing again. The BE merges this object one level deep, so a
28
+ // write to one `dismissed.*` key preserves its siblings. For each
29
+ // inner array the server treats the value as the full list — callers
30
+ // should merge the new id into the existing array before sending.
31
+ dismissed?: {
32
+ todos?: string[];
33
+ };
34
+ // Daily-tips carousel state. `disabled` opts out entirely; `lastShownDate`
35
+ // (local `YYYY-MM-DD`) gates the once-per-day rule cumulatively across
36
+ // workspaces and devices. Merged one level deep by the BE.
37
+ dailyTips?: {
38
+ disabled?: boolean;
39
+ lastShownDate?: string;
40
+ };
41
+ // Per-project feature-intro tutorials the user has seen, keyed by project
42
+ // id. Merged one level deep by the BE.
43
+ featureIntros?: Record<string, string[]>;
44
+ // Preferred date display format. Seeded at registration from the
45
+ // registrant's country (European unless month-first, e.g. the US → american);
46
+ // European is the fallback when unset. User-overridable, incl. ISO (YYYY-MM-DD).
47
+ dateFormat?: 'european' | 'american' | 'iso';
48
+ // Add other preferences
49
+ }
50
+
51
+ // Structural shape only — visible strings are looked up on the FE by
52
+ // `id` against the `auth.todos.<id>.{title,description,actionLabel}`
53
+ // i18n keys. Keeps the backend response language-agnostic.
54
+ export interface UserTodo {
55
+ id: string;
56
+ dismissible: boolean;
57
+ }
58
+
59
+ /**
60
+ * Defines user-related methods for the NuramaClient.
61
+ * @param {NuramaClient} client - The NuramaClient instance.
62
+ * @returns {object} An object containing the user-related methods.
63
+ */
64
+ export default function createUserMethods(client: NuramaClient) {
65
+ // Specify return type more accurately if possible, using UserMethods interface
66
+ return {
67
+ /**
68
+ * Retrieves the public profile of a specific user.
69
+ * Requires authentication.
70
+ * @param {string} userId - The ID of the user to retrieve.
71
+ * @returns {Promise<object>} Public user object.
72
+ */
73
+ async getUser(userId: string): Promise<PublicUser> {
74
+ if (!userId) {
75
+ throw new Error('userId is required.');
76
+ }
77
+ return client._request({
78
+ method: 'GET',
79
+ endpoint: `/v1/users/${userId}`,
80
+ sendJWT: true,
81
+ });
82
+ },
83
+
84
+ /**
85
+ * Retrieves the current user's profile.
86
+ * Requires authentication.
87
+ * @returns {Promise<PublicUser>} The current user's profile.
88
+ * @throws {Error} If no user ID is found in the token.
89
+ */
90
+ async getSelf(): Promise<PublicUser> {
91
+ return client._request({
92
+ method: 'GET',
93
+ endpoint: '/v1/users',
94
+ sendJWT: true,
95
+ });
96
+ },
97
+
98
+ /**
99
+ * Deletes the current user.
100
+ * Requires authentication.
101
+ * @returns {Promise<void>}
102
+ */
103
+ async deleteCurrentUser(): Promise<void> {
104
+ return client._request({
105
+ method: 'DELETE',
106
+ endpoint: '/v1/users',
107
+ sendJWT: true,
108
+ });
109
+ },
110
+ /**
111
+ * Updates the user's avatar.
112
+ * @param {object} fileData - File metadata (e.g., { name, checksum, sizeInMB }).
113
+ * @returns {Promise<object>} Object containing signed URL data and updated user info.
114
+ */
115
+ async updateAvatar(fileData: FileData): Promise<any> {
116
+ return client._request({
117
+ method: 'PUT',
118
+ endpoint: '/v1/users/avatar',
119
+ body: fileData,
120
+ sendJWT: true,
121
+ });
122
+ },
123
+ /**
124
+ * Creates a new avatar for the user.
125
+ * @param {object} fileData - File metadata (e.g., { name, checksum, sizeInMB }).
126
+ * @returns {Promise<object>} Object containing signed URL data and updated user info.
127
+ */
128
+ async createAvatar(fileData: FileData): Promise<any> {
129
+ return client._request({
130
+ method: 'POST',
131
+ endpoint: '/v1/users/avatar',
132
+ body: fileData,
133
+ sendJWT: true,
134
+ });
135
+ },
136
+ /**
137
+ * Updates the user's preferences.
138
+ * @param {object} preferenceData - Preference data to update (e.g., { hide: ['feedHint'] }).
139
+ * @returns {Promise<object>} Updated user object.
140
+ */
141
+ async updatePreferences(preferenceData: PreferencesData): Promise<User> {
142
+ return client._request({
143
+ method: 'PATCH',
144
+ endpoint: '/v1/users/preferences',
145
+ body: preferenceData,
146
+ sendJWT: true,
147
+ });
148
+ },
149
+
150
+ /**
151
+ * Record that the current user has seen a one-time UI element (welcome
152
+ * video, tutorial coachmark). Idempotent. Returns the updated user.
153
+ * @param {string} element - one-time element key (see backend oneTimeElements).
154
+ */
155
+ async markSeen(element: string): Promise<User> {
156
+ return client._request({
157
+ method: 'POST',
158
+ endpoint: '/v1/users/has-seen',
159
+ body: { element },
160
+ sendJWT: true,
161
+ });
162
+ },
163
+
164
+ /**
165
+ * Remove one-time UI elements from the current user's `hasSeen` so they
166
+ * display again. Pass specific element keys, or omit to clear ALL.
167
+ * Returns the updated user.
168
+ * @param {string[]} [elements] - elements to remove; omit to clear all.
169
+ */
170
+ async unmarkSeen(elements?: string[]): Promise<User> {
171
+ return client._request({
172
+ method: 'DELETE',
173
+ endpoint: '/v1/users/has-seen',
174
+ body: elements ? { elements } : {},
175
+ sendJWT: true,
176
+ });
177
+ },
178
+
179
+ /**
180
+ * Updates the logged-in user's profile.
181
+ * Requires authentication.
182
+ * At least one field must be provided.
183
+ * @param {UpdateUserData} updateData - The user data fields to update.
184
+ * @returns {Promise<User>} The updated user object.
185
+ */
186
+ async updateSelf(updateData: UpdateUserData): Promise<User> {
187
+ // Ensure at least one key is present, matching backend validation .min(1)
188
+ if (Object.keys(updateData).length === 0) {
189
+ throw new Error('At least one field must be provided to update the user.');
190
+ }
191
+ return client._request<User>({
192
+ method: 'PATCH',
193
+ endpoint: '/v1/users', // Endpoint for updating the logged-in user
194
+ body: updateData,
195
+ sendJWT: true,
196
+ });
197
+ },
198
+
199
+ /**
200
+ * Get the current user's active site-level Todos for the onboarding
201
+ * drawer. Returns only todos whose completion condition isn't met and
202
+ * (for dismissibles) that the user hasn't opted out of. Server
203
+ * computes from live state — no caching on the server side, so a
204
+ * fresh call always reflects ground truth.
205
+ */
206
+ async getTodos(): Promise<{ todos: UserTodo[] }> {
207
+ return client._request<{ todos: UserTodo[] }>({
208
+ method: 'GET',
209
+ endpoint: '/v1/users/todos',
210
+ sendJWT: true,
211
+ });
212
+ },
213
+ };
214
+ }
@@ -0,0 +1,62 @@
1
+ import NuramaClient from '../NuramaClient.js';
2
+
3
+ // --- Response Interfaces ---
4
+ export interface CommitResponse {
5
+ buildCommit: string;
6
+ }
7
+
8
+ export interface HealthStatus {
9
+ status: 'healthy' | 'degraded' | 'unhealthy';
10
+ /** Epoch milliseconds when the check ran. */
11
+ timestamp: number;
12
+ /** Process uptime in seconds. */
13
+ uptime: number;
14
+ /** Present when status is `degraded` or `unhealthy`. */
15
+ reason?: string;
16
+ postgres: { status: 'connected' | 'disconnected'; [key: string]: unknown };
17
+ memory: Record<string, unknown>;
18
+ [key: string]: unknown;
19
+ }
20
+
21
+ // --- Method Definitions ---
22
+
23
+ /**
24
+ * Defines version-related methods for the NuramaClient.
25
+ * @param {NuramaClient} client - The NuramaClient instance.
26
+ * @returns {object} An object containing the version-related methods.
27
+ */
28
+ export default function createVersionMethods(client: NuramaClient) {
29
+ return {
30
+ /**
31
+ * Retrieves the latest git commit hash of the deployed application.
32
+ * This is a public endpoint and does not require authentication.
33
+ * @returns {Promise<CommitResponse>} An object containing the buildCommit hash.
34
+ */
35
+ async getCommitHash(): Promise<CommitResponse> {
36
+ return client._request<CommitResponse>({
37
+ method: 'GET',
38
+ endpoint: '/v1/version/commit',
39
+ sendJWT: false,
40
+ });
41
+ },
42
+
43
+ /**
44
+ * Retrieves the API health report (database connectivity, memory, uptime).
45
+ * Public endpoint. Resolves normally for `healthy` and `degraded`; the API
46
+ * responds 503 for `unhealthy`, which surfaces as a thrown error with `status: 503`
47
+ * and the report on `data`.
48
+ * @returns {Promise<HealthStatus>} The health report.
49
+ */
50
+ async getHealth(): Promise<HealthStatus> {
51
+ return client._request<HealthStatus>({
52
+ method: 'GET',
53
+ endpoint: '/v1/version/health',
54
+ sendJWT: false,
55
+ bypassCache: true,
56
+ });
57
+ },
58
+ };
59
+ }
60
+
61
+ // --- Export Method Type ---
62
+ export type VersionMethods = ReturnType<typeof createVersionMethods>;
@@ -0,0 +1,295 @@
1
+ import NuramaClient from '../NuramaClient.js';
2
+
3
+ /**
4
+ * Wire-format webhook event names. Mirrors the backend's
5
+ * `@config/webhookEvents` registry. New events land here and on the
6
+ * backend together; the additive-only payload contract means receivers
7
+ * pinned to a specific event name keep working as fields are added.
8
+ */
9
+ export type WebhookEvent =
10
+ | 'task.created'
11
+ | 'task.updated'
12
+ | 'task.deleted'
13
+ | 'chat.message.created'
14
+ | 'asset.published'
15
+ | 'webhook.test';
16
+
17
+ export type WebhookSubscriptionStatus = 'active' | 'paused' | 'failedOut';
18
+
19
+ /**
20
+ * Public shape of a webhook subscription. Never includes the signing
21
+ * secret or the encrypted ciphertext — those are server-only fields.
22
+ */
23
+ export interface WebhookSubscription {
24
+ id: string;
25
+ workspaceId: string;
26
+ appId?: string | null;
27
+ name: string;
28
+ url: string;
29
+ events: WebhookEvent[];
30
+ status: WebhookSubscriptionStatus;
31
+ failedOutAt?: string | null;
32
+ failedOutReason?: string | null;
33
+ /**
34
+ * Optional expiration. When set and in the past, the worker stops
35
+ * fanning new attempts to this subscription, and any in-flight
36
+ * attempts DLQ with a clear reason rather than retrying. Null = no
37
+ * expiry; the subscription delivers indefinitely until manually
38
+ * paused or deleted.
39
+ */
40
+ expiresAt?: string | null;
41
+ createdAt: string;
42
+ updatedAt: string;
43
+ createdById: string;
44
+ lastDeliveryAt?: string | null;
45
+ lastSuccessAt?: string | null;
46
+ lastFailureAt?: string | null;
47
+ }
48
+
49
+ export interface CreateWebhookData {
50
+ name: string;
51
+ url: string;
52
+ events: WebhookEvent[];
53
+ /** Optional ISO timestamp. Must be in the future when set. */
54
+ expiresAt?: string | null;
55
+ }
56
+
57
+ export interface UpdateWebhookData {
58
+ name?: string;
59
+ url?: string;
60
+ events?: WebhookEvent[];
61
+ status?: 'active' | 'paused';
62
+ /** Pass null to clear an existing expiry; pass a future ISO date to set / extend. */
63
+ expiresAt?: string | null;
64
+ }
65
+
66
+ export interface CreateWebhookResponse {
67
+ subscription: WebhookSubscription;
68
+ /**
69
+ * The HMAC signing secret. Returned ONLY here (and from
70
+ * `rotateWebhookSecret`). The server keeps the ciphertext on the row
71
+ * and cannot recover the plaintext later — the customer must capture
72
+ * it now or rotate.
73
+ */
74
+ signingSecret: string;
75
+ }
76
+
77
+ export interface RotateWebhookSecretResponse extends CreateWebhookResponse {}
78
+
79
+ export type WebhookAttemptStatus = 'pending' | 'inflight' | 'succeeded' | 'failed' | 'dlq';
80
+
81
+ export interface WebhookAttempt {
82
+ id: string;
83
+ notificationId: string;
84
+ subscriptionId: string;
85
+ attempt: number;
86
+ maxAttempts: number;
87
+ status: WebhookAttemptStatus;
88
+ signatureV1: string;
89
+ scheduledAt: string;
90
+ startedAt?: string | null;
91
+ deliveredAt?: string | null;
92
+ nextRetryAt?: string | null;
93
+ responseCode?: number | null;
94
+ responseBody?: string | null;
95
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ responseHeaders?: Record<string, any> | null;
97
+ errorMessage?: string | null;
98
+ createdAt: string;
99
+ updatedAt: string;
100
+ }
101
+
102
+ export interface ListDeliveriesParams {
103
+ limit?: number;
104
+ cursor?: string;
105
+ status?: WebhookAttemptStatus;
106
+ }
107
+
108
+ export interface ListDeliveriesResponse {
109
+ items: WebhookAttempt[];
110
+ nextCursor: string | null;
111
+ }
112
+
113
+ export interface TestWebhookResponse {
114
+ queued: true;
115
+ message: string;
116
+ }
117
+
118
+ /**
119
+ * Outbound webhook subscription management. Admin-gated server-side
120
+ * by `canManageWebhooks`. All operations are workspace-scoped — there
121
+ * is no app-owned surface here yet (Phase 3 / OAuth).
122
+ */
123
+ export default function createWebhookMethods(client: NuramaClient) {
124
+ return {
125
+ /**
126
+ * Create a webhook subscription. The signing secret is in the
127
+ * response's `secret` field — store it immediately, it cannot be
128
+ * retrieved again.
129
+ *
130
+ * @requires `canManageWebhooks` on the workspace.
131
+ */
132
+ async createWebhook(
133
+ workspaceId: string,
134
+ data: CreateWebhookData,
135
+ ): Promise<CreateWebhookResponse> {
136
+ if (!workspaceId) throw new Error('workspaceId is required.');
137
+ return client._request<CreateWebhookResponse>({
138
+ method: 'POST',
139
+ endpoint: `/v1/workspaces/${workspaceId}/webhooks`,
140
+ body: data,
141
+ sendJWT: true,
142
+ });
143
+ },
144
+
145
+ /**
146
+ * List webhook subscriptions in a workspace. Secrets are never returned.
147
+ *
148
+ * @requires `canManageWebhooks` on the workspace.
149
+ */
150
+ async listWebhooks(workspaceId: string): Promise<WebhookSubscription[]> {
151
+ if (!workspaceId) throw new Error('workspaceId is required.');
152
+ return client._request<WebhookSubscription[]>({
153
+ method: 'GET',
154
+ endpoint: `/v1/workspaces/${workspaceId}/webhooks`,
155
+ sendJWT: true,
156
+ bypassCache: true,
157
+ });
158
+ },
159
+
160
+ /**
161
+ * Fetch a single webhook subscription by id.
162
+ *
163
+ * @requires `canManageWebhooks` on the workspace.
164
+ */
165
+ async getWebhook(workspaceId: string, webhookId: string): Promise<WebhookSubscription> {
166
+ if (!workspaceId) throw new Error('workspaceId is required.');
167
+ if (!webhookId) throw new Error('webhookId is required.');
168
+ return client._request<WebhookSubscription>({
169
+ method: 'GET',
170
+ endpoint: `/v1/workspaces/${workspaceId}/webhooks/${webhookId}`,
171
+ sendJWT: true,
172
+ bypassCache: true,
173
+ });
174
+ },
175
+
176
+ /**
177
+ * Update a webhook subscription's url, event filter, or active state.
178
+ *
179
+ * @requires `canManageWebhooks` on the workspace.
180
+ */
181
+ async updateWebhook(
182
+ workspaceId: string,
183
+ webhookId: string,
184
+ data: UpdateWebhookData,
185
+ ): Promise<WebhookSubscription> {
186
+ if (!workspaceId) throw new Error('workspaceId is required.');
187
+ if (!webhookId) throw new Error('webhookId is required.');
188
+ return client._request<WebhookSubscription>({
189
+ method: 'PATCH',
190
+ endpoint: `/v1/workspaces/${workspaceId}/webhooks/${webhookId}`,
191
+ body: data,
192
+ sendJWT: true,
193
+ });
194
+ },
195
+
196
+ /**
197
+ * Delete a webhook subscription. In-flight deliveries continue to
198
+ * the receiver until they exhaust retries; no new deliveries fire.
199
+ *
200
+ * @requires `canManageWebhooks` on the workspace.
201
+ */
202
+ async deleteWebhook(workspaceId: string, webhookId: string): Promise<void> {
203
+ if (!workspaceId) throw new Error('workspaceId is required.');
204
+ if (!webhookId) throw new Error('webhookId is required.');
205
+ return client._request<void>({
206
+ method: 'DELETE',
207
+ endpoint: `/v1/workspaces/${workspaceId}/webhooks/${webhookId}`,
208
+ sendJWT: true,
209
+ });
210
+ },
211
+
212
+ /**
213
+ * Generate a new HMAC signing secret for a subscription and return
214
+ * it once. The old secret is invalidated immediately.
215
+ *
216
+ * @requires `canManageWebhooks` on the workspace.
217
+ */
218
+ async rotateWebhookSecret(
219
+ workspaceId: string,
220
+ webhookId: string,
221
+ ): Promise<RotateWebhookSecretResponse> {
222
+ if (!workspaceId) throw new Error('workspaceId is required.');
223
+ if (!webhookId) throw new Error('webhookId is required.');
224
+ return client._request<RotateWebhookSecretResponse>({
225
+ method: 'POST',
226
+ endpoint: `/v1/workspaces/${workspaceId}/webhooks/${webhookId}/rotate-secret`,
227
+ sendJWT: true,
228
+ });
229
+ },
230
+
231
+ /**
232
+ * Fire a synthetic `webhook.test` delivery to the subscription's
233
+ * URL. The receiver gets a small payload they can use to verify
234
+ * their HMAC + parsing setup. Returns immediately; check the
235
+ * delivery log for the outcome.
236
+ */
237
+ async testWebhook(workspaceId: string, webhookId: string): Promise<TestWebhookResponse> {
238
+ if (!workspaceId) throw new Error('workspaceId is required.');
239
+ if (!webhookId) throw new Error('webhookId is required.');
240
+ return client._request<TestWebhookResponse>({
241
+ method: 'POST',
242
+ endpoint: `/v1/workspaces/${workspaceId}/webhooks/${webhookId}/test`,
243
+ sendJWT: true,
244
+ });
245
+ },
246
+
247
+ /**
248
+ * Paginated list of delivery attempts for a webhook subscription.
249
+ * Useful for diagnosing failures (HTTP status, response body snippet,
250
+ * retry timing).
251
+ *
252
+ * @requires `canManageWebhooks` on the workspace.
253
+ */
254
+ async listWebhookDeliveries(
255
+ workspaceId: string,
256
+ webhookId: string,
257
+ params: ListDeliveriesParams = {},
258
+ ): Promise<ListDeliveriesResponse> {
259
+ if (!workspaceId) throw new Error('workspaceId is required.');
260
+ if (!webhookId) throw new Error('webhookId is required.');
261
+ const search = new URLSearchParams();
262
+ if (params.limit !== undefined) search.set('limit', String(params.limit));
263
+ if (params.cursor !== undefined) search.set('cursor', params.cursor);
264
+ if (params.status !== undefined) search.set('status', params.status);
265
+ const qs = search.toString();
266
+ return client._request<ListDeliveriesResponse>({
267
+ method: 'GET',
268
+ endpoint: `/v1/workspaces/${workspaceId}/webhooks/${webhookId}/deliveries${qs ? `?${qs}` : ''}`,
269
+ sendJWT: true,
270
+ bypassCache: true,
271
+ });
272
+ },
273
+
274
+ /**
275
+ * Re-fire a specific past delivery attempt. Useful for confirming a
276
+ * receiver fix without waiting for the next real event.
277
+ *
278
+ * @requires `canManageWebhooks` on the workspace.
279
+ */
280
+ async replayWebhookDelivery(
281
+ workspaceId: string,
282
+ webhookId: string,
283
+ attemptId: string,
284
+ ): Promise<{ attempt: WebhookAttempt }> {
285
+ if (!workspaceId) throw new Error('workspaceId is required.');
286
+ if (!webhookId) throw new Error('webhookId is required.');
287
+ if (!attemptId) throw new Error('attemptId is required.');
288
+ return client._request<{ attempt: WebhookAttempt }>({
289
+ method: 'POST',
290
+ endpoint: `/v1/workspaces/${workspaceId}/webhooks/${webhookId}/deliveries/${attemptId}/replay`,
291
+ sendJWT: true,
292
+ });
293
+ },
294
+ };
295
+ }