@harkenapp/sdk-react-native 0.0.1-alpha.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 (235) hide show
  1. package/README.md +67 -0
  2. package/app.plugin.cjs +135 -0
  3. package/app.plugin.js +1 -0
  4. package/dist/api/client.d.ts +67 -0
  5. package/dist/api/client.d.ts.map +1 -0
  6. package/dist/api/client.js +163 -0
  7. package/dist/api/client.js.map +1 -0
  8. package/dist/api/errors.d.ts +46 -0
  9. package/dist/api/errors.d.ts.map +1 -0
  10. package/dist/api/errors.js +72 -0
  11. package/dist/api/errors.js.map +1 -0
  12. package/dist/api/index.d.ts +7 -0
  13. package/dist/api/index.d.ts.map +1 -0
  14. package/dist/api/index.js +20 -0
  15. package/dist/api/index.js.map +1 -0
  16. package/dist/api/retry.d.ts +29 -0
  17. package/dist/api/retry.d.ts.map +1 -0
  18. package/dist/api/retry.js +74 -0
  19. package/dist/api/retry.js.map +1 -0
  20. package/dist/attachments/FeedbackSheet.d.ts +88 -0
  21. package/dist/attachments/FeedbackSheet.d.ts.map +1 -0
  22. package/dist/attachments/FeedbackSheet.js +250 -0
  23. package/dist/attachments/FeedbackSheet.js.map +1 -0
  24. package/dist/attachments/index.d.ts +20 -0
  25. package/dist/attachments/index.d.ts.map +1 -0
  26. package/dist/attachments/index.js +40 -0
  27. package/dist/attachments/index.js.map +1 -0
  28. package/dist/components/AttachmentGrid.d.ts +94 -0
  29. package/dist/components/AttachmentGrid.d.ts.map +1 -0
  30. package/dist/components/AttachmentGrid.js +132 -0
  31. package/dist/components/AttachmentGrid.js.map +1 -0
  32. package/dist/components/AttachmentPicker.d.ts +98 -0
  33. package/dist/components/AttachmentPicker.d.ts.map +1 -0
  34. package/dist/components/AttachmentPicker.js +297 -0
  35. package/dist/components/AttachmentPicker.js.map +1 -0
  36. package/dist/components/AttachmentPreview.d.ts +78 -0
  37. package/dist/components/AttachmentPreview.d.ts.map +1 -0
  38. package/dist/components/AttachmentPreview.js +133 -0
  39. package/dist/components/AttachmentPreview.js.map +1 -0
  40. package/dist/components/CategorySelector.d.ts +77 -0
  41. package/dist/components/CategorySelector.d.ts.map +1 -0
  42. package/dist/components/CategorySelector.js +117 -0
  43. package/dist/components/CategorySelector.js.map +1 -0
  44. package/dist/components/FeedbackForm.d.ts +50 -0
  45. package/dist/components/FeedbackForm.d.ts.map +1 -0
  46. package/dist/components/FeedbackForm.js +141 -0
  47. package/dist/components/FeedbackForm.js.map +1 -0
  48. package/dist/components/FeedbackSheet.d.ts +75 -0
  49. package/dist/components/FeedbackSheet.d.ts.map +1 -0
  50. package/dist/components/FeedbackSheet.js +215 -0
  51. package/dist/components/FeedbackSheet.js.map +1 -0
  52. package/dist/components/ThemedButton.d.ts +23 -0
  53. package/dist/components/ThemedButton.d.ts.map +1 -0
  54. package/dist/components/ThemedButton.js +77 -0
  55. package/dist/components/ThemedButton.js.map +1 -0
  56. package/dist/components/ThemedText.d.ts +16 -0
  57. package/dist/components/ThemedText.d.ts.map +1 -0
  58. package/dist/components/ThemedText.js +44 -0
  59. package/dist/components/ThemedText.js.map +1 -0
  60. package/dist/components/ThemedTextInput.d.ts +13 -0
  61. package/dist/components/ThemedTextInput.d.ts.map +1 -0
  62. package/dist/components/ThemedTextInput.js +76 -0
  63. package/dist/components/ThemedTextInput.js.map +1 -0
  64. package/dist/components/UploadStatusOverlay.d.ts +82 -0
  65. package/dist/components/UploadStatusOverlay.d.ts.map +1 -0
  66. package/dist/components/UploadStatusOverlay.js +319 -0
  67. package/dist/components/UploadStatusOverlay.js.map +1 -0
  68. package/dist/components/index.d.ts +19 -0
  69. package/dist/components/index.d.ts.map +1 -0
  70. package/dist/components/index.js +28 -0
  71. package/dist/components/index.js.map +1 -0
  72. package/dist/context/HarkenContext.d.ts +62 -0
  73. package/dist/context/HarkenContext.d.ts.map +1 -0
  74. package/dist/context/HarkenContext.js +128 -0
  75. package/dist/context/HarkenContext.js.map +1 -0
  76. package/dist/context/index.d.ts +3 -0
  77. package/dist/context/index.d.ts.map +1 -0
  78. package/dist/context/index.js +7 -0
  79. package/dist/context/index.js.map +1 -0
  80. package/dist/domain/index.d.ts +3 -0
  81. package/dist/domain/index.d.ts.map +1 -0
  82. package/dist/domain/index.js +7 -0
  83. package/dist/domain/index.js.map +1 -0
  84. package/dist/domain/upload-queue.d.ts +116 -0
  85. package/dist/domain/upload-queue.d.ts.map +1 -0
  86. package/dist/domain/upload-queue.js +34 -0
  87. package/dist/domain/upload-queue.js.map +1 -0
  88. package/dist/hooks/index.d.ts +6 -0
  89. package/dist/hooks/index.d.ts.map +1 -0
  90. package/dist/hooks/index.js +16 -0
  91. package/dist/hooks/index.js.map +1 -0
  92. package/dist/hooks/useAnonymousId.d.ts +28 -0
  93. package/dist/hooks/useAnonymousId.d.ts.map +1 -0
  94. package/dist/hooks/useAnonymousId.js +59 -0
  95. package/dist/hooks/useAnonymousId.js.map +1 -0
  96. package/dist/hooks/useAttachmentPicker.d.ts +84 -0
  97. package/dist/hooks/useAttachmentPicker.d.ts.map +1 -0
  98. package/dist/hooks/useAttachmentPicker.js +181 -0
  99. package/dist/hooks/useAttachmentPicker.js.map +1 -0
  100. package/dist/hooks/useAttachmentStatus.d.ts +51 -0
  101. package/dist/hooks/useAttachmentStatus.d.ts.map +1 -0
  102. package/dist/hooks/useAttachmentStatus.js +69 -0
  103. package/dist/hooks/useAttachmentStatus.js.map +1 -0
  104. package/dist/hooks/useAttachmentUpload.d.ts +101 -0
  105. package/dist/hooks/useAttachmentUpload.d.ts.map +1 -0
  106. package/dist/hooks/useAttachmentUpload.js +293 -0
  107. package/dist/hooks/useAttachmentUpload.js.map +1 -0
  108. package/dist/hooks/useFeedback.d.ts +55 -0
  109. package/dist/hooks/useFeedback.d.ts.map +1 -0
  110. package/dist/hooks/useFeedback.js +96 -0
  111. package/dist/hooks/useFeedback.js.map +1 -0
  112. package/dist/hooks/useHarkenContext.d.ts +25 -0
  113. package/dist/hooks/useHarkenContext.d.ts.map +1 -0
  114. package/dist/hooks/useHarkenContext.js +35 -0
  115. package/dist/hooks/useHarkenContext.js.map +1 -0
  116. package/dist/hooks/useHarkenTheme.d.ts +26 -0
  117. package/dist/hooks/useHarkenTheme.d.ts.map +1 -0
  118. package/dist/hooks/useHarkenTheme.js +36 -0
  119. package/dist/hooks/useHarkenTheme.js.map +1 -0
  120. package/dist/index.d.ts +49 -0
  121. package/dist/index.d.ts.map +1 -0
  122. package/dist/index.js +91 -0
  123. package/dist/index.js.map +1 -0
  124. package/dist/services/index.d.ts +4 -0
  125. package/dist/services/index.d.ts.map +1 -0
  126. package/dist/services/index.js +9 -0
  127. package/dist/services/index.js.map +1 -0
  128. package/dist/services/uploadQueueService.d.ts +193 -0
  129. package/dist/services/uploadQueueService.d.ts.map +1 -0
  130. package/dist/services/uploadQueueService.js +623 -0
  131. package/dist/services/uploadQueueService.js.map +1 -0
  132. package/dist/services/uploadQueueStorage.d.ts +30 -0
  133. package/dist/services/uploadQueueStorage.d.ts.map +1 -0
  134. package/dist/services/uploadQueueStorage.js +77 -0
  135. package/dist/services/uploadQueueStorage.js.map +1 -0
  136. package/dist/storage/IdentityStore.d.ts +38 -0
  137. package/dist/storage/IdentityStore.d.ts.map +1 -0
  138. package/dist/storage/IdentityStore.js +83 -0
  139. package/dist/storage/IdentityStore.js.map +1 -0
  140. package/dist/storage/SecureStoreAdapter.d.ts +28 -0
  141. package/dist/storage/SecureStoreAdapter.d.ts.map +1 -0
  142. package/dist/storage/SecureStoreAdapter.js +52 -0
  143. package/dist/storage/SecureStoreAdapter.js.map +1 -0
  144. package/dist/storage/defaultStorage.d.ts +20 -0
  145. package/dist/storage/defaultStorage.d.ts.map +1 -0
  146. package/dist/storage/defaultStorage.js +131 -0
  147. package/dist/storage/defaultStorage.js.map +1 -0
  148. package/dist/storage/index.d.ts +6 -0
  149. package/dist/storage/index.d.ts.map +1 -0
  150. package/dist/storage/index.js +13 -0
  151. package/dist/storage/index.js.map +1 -0
  152. package/dist/storage/types.d.ts +32 -0
  153. package/dist/storage/types.d.ts.map +1 -0
  154. package/dist/storage/types.js +11 -0
  155. package/dist/storage/types.js.map +1 -0
  156. package/dist/theme/defaults.d.ts +43 -0
  157. package/dist/theme/defaults.d.ts.map +1 -0
  158. package/dist/theme/defaults.js +128 -0
  159. package/dist/theme/defaults.js.map +1 -0
  160. package/dist/theme/index.d.ts +3 -0
  161. package/dist/theme/index.d.ts.map +1 -0
  162. package/dist/theme/index.js +14 -0
  163. package/dist/theme/index.js.map +1 -0
  164. package/dist/theme/types.d.ts +136 -0
  165. package/dist/theme/types.d.ts.map +1 -0
  166. package/dist/theme/types.js +3 -0
  167. package/dist/theme/types.js.map +1 -0
  168. package/dist/types/config.d.ts +100 -0
  169. package/dist/types/config.d.ts.map +1 -0
  170. package/dist/types/config.js +3 -0
  171. package/dist/types/config.js.map +1 -0
  172. package/dist/types/index.d.ts +3 -0
  173. package/dist/types/index.d.ts.map +1 -0
  174. package/dist/types/index.js +3 -0
  175. package/dist/types/index.js.map +1 -0
  176. package/dist/types/openapi.d.ts +601 -0
  177. package/dist/types/openapi.d.ts.map +1 -0
  178. package/dist/types/openapi.js +7 -0
  179. package/dist/types/openapi.js.map +1 -0
  180. package/dist/utils/index.d.ts +2 -0
  181. package/dist/utils/index.d.ts.map +1 -0
  182. package/dist/utils/index.js +6 -0
  183. package/dist/utils/index.js.map +1 -0
  184. package/dist/utils/uuid.d.ts +10 -0
  185. package/dist/utils/uuid.d.ts.map +1 -0
  186. package/dist/utils/uuid.js +60 -0
  187. package/dist/utils/uuid.js.map +1 -0
  188. package/package.json +124 -0
  189. package/src/@types/expo-file-system-legacy.d.ts +13 -0
  190. package/src/api/client.ts +250 -0
  191. package/src/api/errors.ts +84 -0
  192. package/src/api/index.ts +15 -0
  193. package/src/api/retry.ts +99 -0
  194. package/src/attachments/FeedbackSheet.tsx +400 -0
  195. package/src/attachments/index.ts +70 -0
  196. package/src/components/AttachmentGrid.tsx +247 -0
  197. package/src/components/AttachmentPicker.tsx +391 -0
  198. package/src/components/AttachmentPreview.tsx +210 -0
  199. package/src/components/CategorySelector.tsx +174 -0
  200. package/src/components/FeedbackForm.tsx +216 -0
  201. package/src/components/FeedbackSheet.tsx +321 -0
  202. package/src/components/ThemedButton.tsx +127 -0
  203. package/src/components/ThemedText.tsx +65 -0
  204. package/src/components/ThemedTextInput.tsx +65 -0
  205. package/src/components/UploadStatusOverlay.tsx +440 -0
  206. package/src/components/index.ts +39 -0
  207. package/src/context/HarkenContext.tsx +129 -0
  208. package/src/context/index.ts +2 -0
  209. package/src/domain/index.ts +12 -0
  210. package/src/domain/upload-queue.ts +131 -0
  211. package/src/hooks/index.ts +10 -0
  212. package/src/hooks/useAnonymousId.ts +68 -0
  213. package/src/hooks/useAttachmentPicker.ts +243 -0
  214. package/src/hooks/useAttachmentStatus.ts +86 -0
  215. package/src/hooks/useAttachmentUpload.ts +370 -0
  216. package/src/hooks/useFeedback.ts +139 -0
  217. package/src/hooks/useHarkenContext.ts +35 -0
  218. package/src/hooks/useHarkenTheme.ts +36 -0
  219. package/src/index.ts +168 -0
  220. package/src/services/index.ts +11 -0
  221. package/src/services/uploadQueueService.ts +727 -0
  222. package/src/services/uploadQueueStorage.ts +78 -0
  223. package/src/storage/IdentityStore.ts +89 -0
  224. package/src/storage/SecureStoreAdapter.ts +59 -0
  225. package/src/storage/defaultStorage.ts +109 -0
  226. package/src/storage/index.ts +5 -0
  227. package/src/storage/types.ts +34 -0
  228. package/src/theme/defaults.ts +151 -0
  229. package/src/theme/index.ts +23 -0
  230. package/src/theme/types.ts +157 -0
  231. package/src/types/config.ts +112 -0
  232. package/src/types/index.ts +10 -0
  233. package/src/types/openapi.ts +601 -0
  234. package/src/utils/index.ts +1 -0
  235. package/src/utils/uuid.ts +77 -0
@@ -0,0 +1,601 @@
1
+ /**
2
+ * This file was auto-generated by openapi-typescript.
3
+ * Do not make direct changes to the file.
4
+ */
5
+
6
+ export interface paths {
7
+ "/v1/feedback": {
8
+ parameters: {
9
+ query?: never;
10
+ header?: never;
11
+ path?: never;
12
+ cookie?: never;
13
+ };
14
+ get?: never;
15
+ put?: never;
16
+ /**
17
+ * Submit feedback
18
+ * @description Submit user feedback from a mobile app.
19
+ *
20
+ * **Attachments:** If `attachments` are provided, they will be linked to
21
+ * this feedback and their status will be updated from 'pending' to 'uploaded'.
22
+ * Only attachments in 'pending' or 'uploaded' status that are not already
23
+ * linked to other feedback can be used.
24
+ */
25
+ post: operations["submitFeedback"];
26
+ delete?: never;
27
+ options?: never;
28
+ head?: never;
29
+ patch?: never;
30
+ trace?: never;
31
+ };
32
+ "/v1/feedback/attachments/presign": {
33
+ parameters: {
34
+ query?: never;
35
+ header?: never;
36
+ path?: never;
37
+ cookie?: never;
38
+ };
39
+ get?: never;
40
+ put?: never;
41
+ /**
42
+ * Create attachment upload
43
+ * @description Get a presigned URL for uploading an attachment.
44
+ *
45
+ * **Upload Flow:**
46
+ * 1. Call this endpoint to get a presigned upload URL
47
+ * 2. Upload the file directly to the presigned URL (PUT request)
48
+ * 3. Include the `attachment_id` in your feedback submission
49
+ *
50
+ * **Important:** The presigned URL expires in 2 hours. The attachment record
51
+ * is created immediately with status 'pending'.
52
+ *
53
+ * **Cleanup Policy:** Attachments not linked to submitted feedback are
54
+ * automatically cleaned up after a server-configured period (typically
55
+ * 7 days). Ensure you submit the feedback with the attachments to
56
+ * complete the lifecycle.
57
+ */
58
+ post: operations["createAttachmentUpload"];
59
+ delete?: never;
60
+ options?: never;
61
+ head?: never;
62
+ patch?: never;
63
+ trace?: never;
64
+ };
65
+ "/v1/feedback/attachments/{attachment_id}": {
66
+ parameters: {
67
+ query?: never;
68
+ header?: never;
69
+ path?: never;
70
+ cookie?: never;
71
+ };
72
+ /**
73
+ * Get attachment status
74
+ * @description Poll for attachment upload and processing status.
75
+ * Use this to check if thumbnail generation is complete.
76
+ */
77
+ get: operations["getAttachmentStatus"];
78
+ put?: never;
79
+ post?: never;
80
+ delete?: never;
81
+ options?: never;
82
+ head?: never;
83
+ patch?: never;
84
+ trace?: never;
85
+ };
86
+ "/v1/feedback/attachments/{attachment_id}/confirm": {
87
+ parameters: {
88
+ query?: never;
89
+ header?: never;
90
+ path?: never;
91
+ cookie?: never;
92
+ };
93
+ get?: never;
94
+ put?: never;
95
+ /**
96
+ * Confirm attachment upload
97
+ * @description Called by SDK after successfully uploading to the presigned URL.
98
+ * Triggers server-side thumbnail generation.
99
+ * Poll GET /v1/feedback/attachments/{id} for processing status.
100
+ */
101
+ post: operations["confirmAttachmentUpload"];
102
+ delete?: never;
103
+ options?: never;
104
+ head?: never;
105
+ patch?: never;
106
+ trace?: never;
107
+ };
108
+ "/v1/feedback/attachments/{attachment_id}/fail": {
109
+ parameters: {
110
+ query?: never;
111
+ header?: never;
112
+ path?: never;
113
+ cookie?: never;
114
+ };
115
+ get?: never;
116
+ put?: never;
117
+ /**
118
+ * Report attachment upload failure
119
+ * @description Called by SDK when upload fails after retries exhausted.
120
+ * Allows backend to clean up and track failure metrics.
121
+ */
122
+ post: operations["reportAttachmentFailure"];
123
+ delete?: never;
124
+ options?: never;
125
+ head?: never;
126
+ patch?: never;
127
+ trace?: never;
128
+ };
129
+ }
130
+ export type webhooks = Record<string, never>;
131
+ export interface components {
132
+ schemas: {
133
+ /**
134
+ * @description Category of feedback.
135
+ * @enum {string}
136
+ */
137
+ FeedbackCategory: "bug" | "idea" | "ux" | "other";
138
+ /**
139
+ * @description Client platform.
140
+ * @enum {string}
141
+ */
142
+ Platform: "ios" | "android" | "web";
143
+ /**
144
+ * @description Attachment lifecycle status:
145
+ * - pending: Presign created, awaiting upload and feedback submission
146
+ * - uploaded: Attachment successfully linked to submitted feedback
147
+ * - failed: Upload failed (client-reported)
148
+ *
149
+ * **Lifecycle:**
150
+ * 1. SDK calls presign → status becomes 'pending'
151
+ * 2. SDK uploads file to presigned URL
152
+ * 3. SDK submits feedback with attachments → status becomes 'uploaded'
153
+ *
154
+ * **Cleanup Policy:**
155
+ * Attachments that remain in 'pending' status (not linked to feedback)
156
+ * are automatically deleted after a server-configured cleanup period
157
+ * (typically 7 days). This handles cases where:
158
+ * - User abandons the feedback form
159
+ * - Network failure prevents feedback submission
160
+ * - App crashes after upload but before submission
161
+ * @enum {string}
162
+ */
163
+ AttachmentStatus: "pending" | "uploaded" | "failed";
164
+ DeviceMetadata: {
165
+ /**
166
+ * @description Version of the host application.
167
+ * @example 1.2.3
168
+ */
169
+ app_version?: string;
170
+ platform?: components["schemas"]["Platform"];
171
+ /**
172
+ * @description Device model or identifier.
173
+ * @example iPhone 15 Pro
174
+ */
175
+ device?: string;
176
+ /**
177
+ * @description Operating system version.
178
+ * @example 17.2
179
+ */
180
+ os_version?: string;
181
+ /**
182
+ * @description Device locale.
183
+ * @example en-US
184
+ */
185
+ locale?: string;
186
+ } & {
187
+ [key: string]: unknown;
188
+ };
189
+ FeedbackSubmission: {
190
+ /** @description Optional short title or subject for the feedback. */
191
+ title?: string;
192
+ /** @description The feedback message content. */
193
+ message: string;
194
+ category: components["schemas"]["FeedbackCategory"];
195
+ /**
196
+ * Format: uuid
197
+ * @description Anonymous device identifier (UUIDv4), stable per install.
198
+ * Required - requests without anon_id will be rejected with 400.
199
+ */
200
+ anon_id: string;
201
+ metadata?: components["schemas"]["DeviceMetadata"];
202
+ /** @description List of attachment IDs from presigned uploads. */
203
+ attachments?: string[];
204
+ };
205
+ FeedbackSubmissionResponse: {
206
+ /**
207
+ * Format: uuid
208
+ * @description Unique identifier for the submitted feedback.
209
+ */
210
+ id: string;
211
+ /**
212
+ * Format: date-time
213
+ * @description Timestamp when feedback was created.
214
+ */
215
+ created_at: string;
216
+ };
217
+ AttachmentPresignRequest: {
218
+ /**
219
+ * @description Original filename.
220
+ * @example screenshot.png
221
+ */
222
+ filename: string;
223
+ /**
224
+ * @description MIME type of the file.
225
+ * @example image/png
226
+ */
227
+ content_type: string;
228
+ /** @description File size in bytes (max 10MB). */
229
+ size: number;
230
+ };
231
+ AttachmentPresignResponse: {
232
+ /**
233
+ * Format: uuid
234
+ * @description Unique identifier for the attachment.
235
+ */
236
+ attachment_id: string;
237
+ /**
238
+ * Format: uri
239
+ * @description Presigned URL for uploading the file.
240
+ */
241
+ upload_url: string;
242
+ /**
243
+ * Format: date-time
244
+ * @description Expiration time of the upload URL.
245
+ */
246
+ upload_expires_at: string;
247
+ status: components["schemas"]["AttachmentStatus"];
248
+ };
249
+ AttachmentConfirmRequest: {
250
+ /** @description Actual bytes uploaded (for verification). */
251
+ bytes_uploaded?: number;
252
+ };
253
+ AttachmentStatusResponse: {
254
+ /** Format: uuid */
255
+ attachment_id: string;
256
+ status: components["schemas"]["AttachmentStatus"];
257
+ /** @description Original filename. Present when known. */
258
+ filename?: string;
259
+ /** @description MIME type. Present when known. */
260
+ content_type?: string;
261
+ /** @description File size in bytes. Present when known. */
262
+ size?: number;
263
+ /**
264
+ * @description Error message when status is failed.
265
+ * May be omitted if the failure was client-side and not reported.
266
+ */
267
+ error?: string;
268
+ /**
269
+ * @description Available URLs. Presence depends on status:
270
+ * - pending: not present (file may not be uploaded yet)
271
+ * - uploaded: original URL available
272
+ * - failed: not present
273
+ */
274
+ urls?: components["schemas"]["AttachmentUrls"];
275
+ };
276
+ /**
277
+ * @description URLs for accessing attachment at different sizes.
278
+ * - original: Always present when urls object exists
279
+ * - thumbnail: Present for image attachments when generation succeeded
280
+ */
281
+ AttachmentUrls: {
282
+ /**
283
+ * Format: uri
284
+ * @description URL to original uploaded file.
285
+ */
286
+ original: string;
287
+ /**
288
+ * Format: uri
289
+ * @description URL to thumbnail (480px wide WebP).
290
+ * Only present for image attachments where thumbnail generation succeeded.
291
+ * If absent for an image, client should fall back to original or show placeholder.
292
+ */
293
+ thumbnail?: string;
294
+ };
295
+ ErrorResponse: {
296
+ error: {
297
+ /**
298
+ * @description Machine-readable error code.
299
+ * @example validation_error
300
+ */
301
+ code: string;
302
+ /**
303
+ * @description Human-readable error message.
304
+ * @example Invalid request body
305
+ */
306
+ message: string;
307
+ /** @description Additional error details for validation errors. */
308
+ details?: components["schemas"]["ErrorDetail"][];
309
+ };
310
+ };
311
+ ErrorDetail: {
312
+ /**
313
+ * @description Field path that caused the error.
314
+ * @example message
315
+ */
316
+ field: string;
317
+ /**
318
+ * @description Description of the error.
319
+ * @example Required field is missing
320
+ */
321
+ message: string;
322
+ /**
323
+ * @description Machine-readable error code for this field.
324
+ * @example required
325
+ */
326
+ code?: string;
327
+ };
328
+ };
329
+ responses: {
330
+ /** @description Invalid request body or parameters. */
331
+ BadRequest: {
332
+ headers: {
333
+ [name: string]: unknown;
334
+ };
335
+ content: {
336
+ /**
337
+ * @example {
338
+ * "error": {
339
+ * "code": "validation_error",
340
+ * "message": "Invalid request body",
341
+ * "details": [
342
+ * {
343
+ * "field": "message",
344
+ * "message": "Required field is missing",
345
+ * "code": "required"
346
+ * }
347
+ * ]
348
+ * }
349
+ * }
350
+ */
351
+ "application/json": components["schemas"]["ErrorResponse"];
352
+ };
353
+ };
354
+ /** @description Missing or invalid API key. */
355
+ Unauthorized: {
356
+ headers: {
357
+ [name: string]: unknown;
358
+ };
359
+ content: {
360
+ /**
361
+ * @example {
362
+ * "error": {
363
+ * "code": "unauthorized",
364
+ * "message": "Invalid or missing X-Publishable-Key header"
365
+ * }
366
+ * }
367
+ */
368
+ "application/json": components["schemas"]["ErrorResponse"];
369
+ };
370
+ };
371
+ /** @description Access denied. */
372
+ Forbidden: {
373
+ headers: {
374
+ [name: string]: unknown;
375
+ };
376
+ content: {
377
+ /**
378
+ * @example {
379
+ * "error": {
380
+ * "code": "forbidden",
381
+ * "message": "Access denied"
382
+ * }
383
+ * }
384
+ */
385
+ "application/json": components["schemas"]["ErrorResponse"];
386
+ };
387
+ };
388
+ /** @description Resource not found. */
389
+ NotFound: {
390
+ headers: {
391
+ [name: string]: unknown;
392
+ };
393
+ content: {
394
+ /**
395
+ * @example {
396
+ * "error": {
397
+ * "code": "not_found",
398
+ * "message": "Resource not found"
399
+ * }
400
+ * }
401
+ */
402
+ "application/json": components["schemas"]["ErrorResponse"];
403
+ };
404
+ };
405
+ /** @description Rate limit exceeded. */
406
+ TooManyRequests: {
407
+ headers: {
408
+ /** @description Seconds to wait before retrying. */
409
+ "Retry-After"?: number;
410
+ [name: string]: unknown;
411
+ };
412
+ content: {
413
+ /**
414
+ * @example {
415
+ * "error": {
416
+ * "code": "rate_limited",
417
+ * "message": "Too many requests. Please try again later."
418
+ * }
419
+ * }
420
+ */
421
+ "application/json": components["schemas"]["ErrorResponse"];
422
+ };
423
+ };
424
+ /** @description Internal server error. */
425
+ InternalError: {
426
+ headers: {
427
+ [name: string]: unknown;
428
+ };
429
+ content: {
430
+ /**
431
+ * @example {
432
+ * "error": {
433
+ * "code": "internal_error",
434
+ * "message": "An unexpected error occurred"
435
+ * }
436
+ * }
437
+ */
438
+ "application/json": components["schemas"]["ErrorResponse"];
439
+ };
440
+ };
441
+ };
442
+ parameters: never;
443
+ requestBodies: never;
444
+ headers: never;
445
+ pathItems: never;
446
+ }
447
+ export type $defs = Record<string, never>;
448
+ export interface operations {
449
+ submitFeedback: {
450
+ parameters: {
451
+ query?: never;
452
+ header?: never;
453
+ path?: never;
454
+ cookie?: never;
455
+ };
456
+ requestBody: {
457
+ content: {
458
+ "application/json": components["schemas"]["FeedbackSubmission"];
459
+ };
460
+ };
461
+ responses: {
462
+ /** @description Feedback submitted successfully. */
463
+ 201: {
464
+ headers: {
465
+ [name: string]: unknown;
466
+ };
467
+ content: {
468
+ "application/json": components["schemas"]["FeedbackSubmissionResponse"];
469
+ };
470
+ };
471
+ 400: components["responses"]["BadRequest"];
472
+ 401: components["responses"]["Unauthorized"];
473
+ 429: components["responses"]["TooManyRequests"];
474
+ 500: components["responses"]["InternalError"];
475
+ };
476
+ };
477
+ createAttachmentUpload: {
478
+ parameters: {
479
+ query?: never;
480
+ header?: never;
481
+ path?: never;
482
+ cookie?: never;
483
+ };
484
+ requestBody: {
485
+ content: {
486
+ "application/json": components["schemas"]["AttachmentPresignRequest"];
487
+ };
488
+ };
489
+ responses: {
490
+ /** @description Presigned upload URL created. */
491
+ 200: {
492
+ headers: {
493
+ [name: string]: unknown;
494
+ };
495
+ content: {
496
+ "application/json": components["schemas"]["AttachmentPresignResponse"];
497
+ };
498
+ };
499
+ 400: components["responses"]["BadRequest"];
500
+ 401: components["responses"]["Unauthorized"];
501
+ 429: components["responses"]["TooManyRequests"];
502
+ 500: components["responses"]["InternalError"];
503
+ };
504
+ };
505
+ getAttachmentStatus: {
506
+ parameters: {
507
+ query?: never;
508
+ header?: never;
509
+ path: {
510
+ attachment_id: string;
511
+ };
512
+ cookie?: never;
513
+ };
514
+ requestBody?: never;
515
+ responses: {
516
+ /** @description Attachment status. */
517
+ 200: {
518
+ headers: {
519
+ [name: string]: unknown;
520
+ };
521
+ content: {
522
+ "application/json": components["schemas"]["AttachmentStatusResponse"];
523
+ };
524
+ };
525
+ 401: components["responses"]["Unauthorized"];
526
+ 404: components["responses"]["NotFound"];
527
+ 500: components["responses"]["InternalError"];
528
+ };
529
+ };
530
+ confirmAttachmentUpload: {
531
+ parameters: {
532
+ query?: never;
533
+ header?: never;
534
+ path: {
535
+ attachment_id: string;
536
+ };
537
+ cookie?: never;
538
+ };
539
+ requestBody?: {
540
+ content: {
541
+ "application/json": components["schemas"]["AttachmentConfirmRequest"];
542
+ };
543
+ };
544
+ responses: {
545
+ /** @description Upload confirmed, processing started. */
546
+ 202: {
547
+ headers: {
548
+ [name: string]: unknown;
549
+ };
550
+ content: {
551
+ "application/json": components["schemas"]["AttachmentStatusResponse"];
552
+ };
553
+ };
554
+ 400: components["responses"]["BadRequest"];
555
+ 401: components["responses"]["Unauthorized"];
556
+ 404: components["responses"]["NotFound"];
557
+ /** @description Attachment already confirmed or failed. */
558
+ 409: {
559
+ headers: {
560
+ [name: string]: unknown;
561
+ };
562
+ content: {
563
+ "application/json": components["schemas"]["ErrorResponse"];
564
+ };
565
+ };
566
+ 500: components["responses"]["InternalError"];
567
+ };
568
+ };
569
+ reportAttachmentFailure: {
570
+ parameters: {
571
+ query?: never;
572
+ header?: never;
573
+ path: {
574
+ attachment_id: string;
575
+ };
576
+ cookie?: never;
577
+ };
578
+ requestBody?: {
579
+ content: {
580
+ "application/json": {
581
+ /** @description Error message or code from the upload failure. */
582
+ error?: string;
583
+ };
584
+ };
585
+ };
586
+ responses: {
587
+ /** @description Failure recorded. */
588
+ 200: {
589
+ headers: {
590
+ [name: string]: unknown;
591
+ };
592
+ content: {
593
+ "application/json": components["schemas"]["AttachmentStatusResponse"];
594
+ };
595
+ };
596
+ 401: components["responses"]["Unauthorized"];
597
+ 404: components["responses"]["NotFound"];
598
+ 500: components["responses"]["InternalError"];
599
+ };
600
+ };
601
+ }
@@ -0,0 +1 @@
1
+ export { generateUUID } from './uuid';
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Crypto interface for UUID generation.
3
+ * Available in React Native via Hermes or JavaScriptCore.
4
+ */
5
+ declare const crypto:
6
+ | {
7
+ getRandomValues<T extends ArrayBufferView>(array: T): T;
8
+ }
9
+ | undefined;
10
+
11
+ /**
12
+ * Generate a RFC4122 version 4 UUID.
13
+ *
14
+ * Uses crypto.getRandomValues when available (React Native),
15
+ * falls back to Math.random for older environments.
16
+ *
17
+ * @returns A random UUID string in the format xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
18
+ */
19
+ export function generateUUID(): string {
20
+ // Use crypto.getRandomValues if available (React Native has this)
21
+ if (
22
+ typeof crypto !== 'undefined' &&
23
+ typeof crypto.getRandomValues === 'function'
24
+ ) {
25
+ return generateUUIDCrypto();
26
+ }
27
+
28
+ // Fallback to Math.random-based generation
29
+ return generateUUIDFallback();
30
+ }
31
+
32
+ /**
33
+ * Generate UUID using crypto.getRandomValues
34
+ */
35
+ function generateUUIDCrypto(): string {
36
+ const bytes = new Uint8Array(16);
37
+ crypto!.getRandomValues(bytes);
38
+
39
+ // Set version (4) and variant (RFC4122)
40
+ bytes[6] = (bytes[6]! & 0x0f) | 0x40; // Version 4
41
+ bytes[8] = (bytes[8]! & 0x3f) | 0x80; // Variant RFC4122
42
+
43
+ return formatUUID(bytes);
44
+ }
45
+
46
+ /**
47
+ * Generate UUID using Math.random (fallback)
48
+ */
49
+ function generateUUIDFallback(): string {
50
+ const bytes = new Uint8Array(16);
51
+ for (let i = 0; i < 16; i++) {
52
+ bytes[i] = Math.floor(Math.random() * 256);
53
+ }
54
+
55
+ // Set version (4) and variant (RFC4122)
56
+ bytes[6] = (bytes[6]! & 0x0f) | 0x40; // Version 4
57
+ bytes[8] = (bytes[8]! & 0x3f) | 0x80; // Variant RFC4122
58
+
59
+ return formatUUID(bytes);
60
+ }
61
+
62
+ /**
63
+ * Format bytes as UUID string
64
+ */
65
+ function formatUUID(bytes: Uint8Array): string {
66
+ const hex = Array.from(bytes)
67
+ .map((b) => b.toString(16).padStart(2, '0'))
68
+ .join('');
69
+
70
+ return [
71
+ hex.slice(0, 8),
72
+ hex.slice(8, 12),
73
+ hex.slice(12, 16),
74
+ hex.slice(16, 20),
75
+ hex.slice(20, 32),
76
+ ].join('-');
77
+ }