@ai-matrx/media 0.8.0 → 0.9.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 (185) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/files/engine/api/assets.d.ts +223 -0
  3. package/dist/files/engine/api/assets.js +124 -0
  4. package/dist/files/engine/api/assets.js.map +1 -0
  5. package/dist/files/engine/api/direct.d.ts +43 -0
  6. package/dist/files/engine/api/direct.js +73 -0
  7. package/dist/files/engine/api/direct.js.map +1 -0
  8. package/dist/files/engine/api/fileOrganization.d.ts +34 -0
  9. package/dist/files/engine/api/fileOrganization.js +38 -0
  10. package/dist/files/engine/api/fileOrganization.js.map +1 -0
  11. package/dist/files/engine/api/files.d.ts +249 -0
  12. package/dist/files/engine/api/files.js +231 -0
  13. package/dist/files/engine/api/files.js.map +1 -0
  14. package/dist/files/engine/api/folders.d.ts +63 -0
  15. package/dist/files/engine/api/folders.js +56 -0
  16. package/dist/files/engine/api/folders.js.map +1 -0
  17. package/dist/files/engine/api/office.d.ts +27 -0
  18. package/dist/files/engine/api/office.js +19 -0
  19. package/dist/files/engine/api/office.js.map +1 -0
  20. package/dist/files/engine/api/permissions.d.ts +37 -0
  21. package/dist/files/engine/api/permissions.js +109 -0
  22. package/dist/files/engine/api/permissions.js.map +1 -0
  23. package/dist/files/engine/api/versions.d.ts +26 -0
  24. package/dist/files/engine/api/versions.js +37 -0
  25. package/dist/files/engine/api/versions.js.map +1 -0
  26. package/dist/files/engine/cache/idb-store.d.ts +95 -0
  27. package/dist/files/engine/cache/idb-store.js +172 -0
  28. package/dist/files/engine/cache/idb-store.js.map +1 -0
  29. package/dist/files/engine/cache/policy.d.ts +14 -0
  30. package/dist/files/engine/cache/policy.js +40 -0
  31. package/dist/files/engine/cache/policy.js.map +1 -0
  32. package/dist/files/engine/cache/register-service-worker.d.ts +57 -0
  33. package/dist/files/engine/cache/register-service-worker.js +80 -0
  34. package/dist/files/engine/cache/register-service-worker.js.map +1 -0
  35. package/dist/files/engine/db-types.d.ts +48865 -0
  36. package/dist/files/engine/db-types.js +1 -0
  37. package/dist/files/engine/db-types.js.map +1 -0
  38. package/dist/files/engine/filesDb.d.ts +1913 -0
  39. package/dist/files/engine/filesDb.js +28 -0
  40. package/dist/files/engine/filesDb.js.map +1 -0
  41. package/dist/files/engine/handler/handler.d.ts +82 -0
  42. package/dist/files/engine/handler/handler.js +124 -0
  43. package/dist/files/engine/handler/handler.js.map +1 -0
  44. package/dist/files/engine/handler/hooks/useFile.d.ts +17 -0
  45. package/dist/files/engine/handler/hooks/useFile.js +75 -0
  46. package/dist/files/engine/handler/hooks/useFile.js.map +1 -0
  47. package/dist/files/engine/handler/hooks/useFileUpload.d.ts +76 -0
  48. package/dist/files/engine/handler/hooks/useFileUpload.js +67 -0
  49. package/dist/files/engine/handler/hooks/useFileUpload.js.map +1 -0
  50. package/dist/files/engine/handler/input/normalize.d.ts +14 -0
  51. package/dist/files/engine/handler/input/normalize.js +365 -0
  52. package/dist/files/engine/handler/input/normalize.js.map +1 -0
  53. package/dist/files/engine/handler/intelligence/access.d.ts +35 -0
  54. package/dist/files/engine/handler/intelligence/access.js +85 -0
  55. package/dist/files/engine/handler/intelligence/access.js.map +1 -0
  56. package/dist/files/engine/handler/intelligence/magic-bytes.d.ts +21 -0
  57. package/dist/files/engine/handler/intelligence/magic-bytes.js +67 -0
  58. package/dist/files/engine/handler/intelligence/magic-bytes.js.map +1 -0
  59. package/dist/files/engine/handler/output/target.d.ts +19 -0
  60. package/dist/files/engine/handler/output/target.js +222 -0
  61. package/dist/files/engine/handler/output/target.js.map +1 -0
  62. package/dist/files/engine/handler/resolver.d.ts +34 -0
  63. package/dist/files/engine/handler/resolver.js +133 -0
  64. package/dist/files/engine/handler/resolver.js.map +1 -0
  65. package/dist/files/engine/handler/types.d.ts +367 -0
  66. package/dist/files/engine/handler/types.js +1 -0
  67. package/dist/files/engine/handler/types.js.map +1 -0
  68. package/dist/files/engine/handler/upload.d.ts +32 -0
  69. package/dist/files/engine/handler/upload.js +295 -0
  70. package/dist/files/engine/handler/upload.js.map +1 -0
  71. package/dist/files/engine/handler/utils/classify.d.ts +14 -0
  72. package/dist/files/engine/handler/utils/classify.js +27 -0
  73. package/dist/files/engine/handler/utils/classify.js.map +1 -0
  74. package/dist/files/engine/handler/utils/prefer-locator.d.ts +32 -0
  75. package/dist/files/engine/handler/utils/prefer-locator.js +34 -0
  76. package/dist/files/engine/handler/utils/prefer-locator.js.map +1 -0
  77. package/dist/files/engine/handler/utils/python-base.d.ts +129 -0
  78. package/dist/files/engine/handler/utils/python-base.js +60 -0
  79. package/dist/files/engine/handler/utils/python-base.js.map +1 -0
  80. package/dist/files/engine/hooks/blob-cache.d.ts +130 -0
  81. package/dist/files/engine/hooks/blob-cache.js +162 -0
  82. package/dist/files/engine/hooks/blob-cache.js.map +1 -0
  83. package/dist/files/engine/hooks/office-extraction-cache.d.ts +28 -0
  84. package/dist/files/engine/hooks/office-extraction-cache.js +67 -0
  85. package/dist/files/engine/hooks/office-extraction-cache.js.map +1 -0
  86. package/dist/files/engine/host/configure.d.ts +166 -0
  87. package/dist/files/engine/host/configure.js +30 -0
  88. package/dist/files/engine/host/configure.js.map +1 -0
  89. package/dist/files/engine/host/org.d.ts +8 -0
  90. package/dist/files/engine/host/org.js +16 -0
  91. package/dist/files/engine/host/org.js.map +1 -0
  92. package/dist/files/engine/host/python-client.d.ts +60 -0
  93. package/dist/files/engine/host/python-client.js +46 -0
  94. package/dist/files/engine/host/python-client.js.map +1 -0
  95. package/dist/files/engine/host/share-links.d.ts +20 -0
  96. package/dist/files/engine/host/share-links.js +32 -0
  97. package/dist/files/engine/host/share-links.js.map +1 -0
  98. package/dist/files/engine/host/store.d.ts +24 -0
  99. package/dist/files/engine/host/store.js +23 -0
  100. package/dist/files/engine/host/store.js.map +1 -0
  101. package/dist/files/engine/host/supabase.d.ts +3808 -0
  102. package/dist/files/engine/host/supabase.js +33 -0
  103. package/dist/files/engine/host/supabase.js.map +1 -0
  104. package/dist/files/engine/host/toast.d.ts +14 -0
  105. package/dist/files/engine/host/toast.js +20 -0
  106. package/dist/files/engine/host/toast.js.map +1 -0
  107. package/dist/files/engine/host/typed-client.d.ts +136 -0
  108. package/dist/files/engine/host/typed-client.js +66 -0
  109. package/dist/files/engine/host/typed-client.js.map +1 -0
  110. package/dist/files/engine/index.d.ts +22 -0
  111. package/dist/files/engine/index.js +49 -0
  112. package/dist/files/engine/index.js.map +1 -0
  113. package/dist/files/engine/media/our-file-sources.d.ts +39 -0
  114. package/dist/files/engine/media/our-file-sources.js +83 -0
  115. package/dist/files/engine/media/our-file-sources.js.map +1 -0
  116. package/dist/files/engine/media/signed-url.d.ts +1 -0
  117. package/dist/files/engine/media/signed-url.js +6 -0
  118. package/dist/files/engine/media/signed-url.js.map +1 -0
  119. package/dist/files/engine/redux/converters.d.ts +73 -0
  120. package/dist/files/engine/redux/converters.js +286 -0
  121. package/dist/files/engine/redux/converters.js.map +1 -0
  122. package/dist/files/engine/redux/file-hydration.d.ts +15 -0
  123. package/dist/files/engine/redux/file-hydration.js +46 -0
  124. package/dist/files/engine/redux/file-hydration.js.map +1 -0
  125. package/dist/files/engine/redux/file-tree-auth-boundary.d.ts +5 -0
  126. package/dist/files/engine/redux/file-tree-auth-boundary.js +28 -0
  127. package/dist/files/engine/redux/file-tree-auth-boundary.js.map +1 -0
  128. package/dist/files/engine/redux/file-tree-timeout.d.ts +32 -0
  129. package/dist/files/engine/redux/file-tree-timeout.js +73 -0
  130. package/dist/files/engine/redux/file-tree-timeout.js.map +1 -0
  131. package/dist/files/engine/redux/mutation-toast-middleware.d.ts +27 -0
  132. package/dist/files/engine/redux/mutation-toast-middleware.js +103 -0
  133. package/dist/files/engine/redux/mutation-toast-middleware.js.map +1 -0
  134. package/dist/files/engine/redux/realtime-middleware.d.ts +61 -0
  135. package/dist/files/engine/redux/realtime-middleware.js +431 -0
  136. package/dist/files/engine/redux/realtime-middleware.js.map +1 -0
  137. package/dist/files/engine/redux/request-ledger.d.ts +68 -0
  138. package/dist/files/engine/redux/request-ledger.js +66 -0
  139. package/dist/files/engine/redux/request-ledger.js.map +1 -0
  140. package/dist/files/engine/redux/selectors.d.ts +3254 -0
  141. package/dist/files/engine/redux/selectors.js +428 -0
  142. package/dist/files/engine/redux/selectors.js.map +1 -0
  143. package/dist/files/engine/redux/slice.d.ts +157 -0
  144. package/dist/files/engine/redux/slice.js +836 -0
  145. package/dist/files/engine/redux/slice.js.map +1 -0
  146. package/dist/files/engine/redux/thunks.d.ts +449 -0
  147. package/dist/files/engine/redux/thunks.js +1684 -0
  148. package/dist/files/engine/redux/thunks.js.map +1 -0
  149. package/dist/files/engine/redux/tree-utils.d.ts +90 -0
  150. package/dist/files/engine/redux/tree-utils.js +200 -0
  151. package/dist/files/engine/redux/tree-utils.js.map +1 -0
  152. package/dist/files/engine/support/claimsUser.d.ts +77 -0
  153. package/dist/files/engine/support/claimsUser.js +48 -0
  154. package/dist/files/engine/support/claimsUser.js.map +1 -0
  155. package/dist/files/engine/support/datetime.d.ts +6 -0
  156. package/dist/files/engine/support/datetime.js +15 -0
  157. package/dist/files/engine/support/datetime.js.map +1 -0
  158. package/dist/files/engine/support/document-visibility.d.ts +14 -0
  159. package/dist/files/engine/support/document-visibility.js +28 -0
  160. package/dist/files/engine/support/document-visibility.js.map +1 -0
  161. package/dist/files/engine/support/logger.d.ts +28 -0
  162. package/dist/files/engine/support/logger.js +36 -0
  163. package/dist/files/engine/support/logger.js.map +1 -0
  164. package/dist/files/engine/types.d.ts +1081 -0
  165. package/dist/files/engine/types.js +30 -0
  166. package/dist/files/engine/types.js.map +1 -0
  167. package/dist/files/engine/upload/cloudUpload.d.ts +182 -0
  168. package/dist/files/engine/upload/cloudUpload.js +418 -0
  169. package/dist/files/engine/upload/cloudUpload.js.map +1 -0
  170. package/dist/files/engine/upload/tusUpload.d.ts +100 -0
  171. package/dist/files/engine/upload/tusUpload.js +258 -0
  172. package/dist/files/engine/upload/tusUpload.js.map +1 -0
  173. package/dist/files/engine/upload/uploadDedupGuard.d.ts +58 -0
  174. package/dist/files/engine/upload/uploadDedupGuard.js +41 -0
  175. package/dist/files/engine/upload/uploadDedupGuard.js.map +1 -0
  176. package/dist/files/engine/upload/uploadGuardOpeners.d.ts +70 -0
  177. package/dist/files/engine/upload/uploadGuardOpeners.js +54 -0
  178. package/dist/files/engine/upload/uploadGuardOpeners.js.map +1 -0
  179. package/dist/files/engine/utils/file-types.d.ts +243 -0
  180. package/dist/files/engine/utils/file-types.js +1722 -0
  181. package/dist/files/engine/utils/file-types.js.map +1 -0
  182. package/dist/files/engine/utils/user-visible.d.ts +133 -0
  183. package/dist/files/engine/utils/user-visible.js +115 -0
  184. package/dist/files/engine/utils/user-visible.js.map +1 -0
  185. package/package.json +393 -9
@@ -0,0 +1,1722 @@
1
+ import {
2
+ Archive,
3
+ Braces,
4
+ Code,
5
+ Database,
6
+ File as FileIcon,
7
+ FileCode,
8
+ FileJson,
9
+ FileSpreadsheet,
10
+ FileText,
11
+ FileType,
12
+ Folder,
13
+ FolderOpen,
14
+ Image as ImageIcon,
15
+ Music,
16
+ Package,
17
+ PenTool,
18
+ Subtitles,
19
+ Video
20
+ } from "lucide-react";
21
+ const MAX_INLINE_PREVIEW_BYTES = 10 * 1024 * 1024;
22
+ const FILE_TYPES = [
23
+ // ────────────────────── IMAGE ──────────────────────
24
+ {
25
+ extensions: ["jpg", "jpeg"],
26
+ mime: "image/jpeg",
27
+ category: "IMAGE",
28
+ subCategory: "JPEG",
29
+ displayName: "JPEG image",
30
+ previewKind: "image",
31
+ thumbnailStrategy: "image",
32
+ color: "text-emerald-500",
33
+ icon: ImageIcon
34
+ },
35
+ {
36
+ extensions: ["png"],
37
+ mime: "image/png",
38
+ category: "IMAGE",
39
+ subCategory: "PNG",
40
+ displayName: "PNG image",
41
+ previewKind: "image",
42
+ thumbnailStrategy: "image",
43
+ color: "text-emerald-500",
44
+ icon: ImageIcon
45
+ },
46
+ {
47
+ extensions: ["gif"],
48
+ mime: "image/gif",
49
+ category: "IMAGE",
50
+ subCategory: "GIF",
51
+ displayName: "GIF image",
52
+ previewKind: "image",
53
+ thumbnailStrategy: "image",
54
+ color: "text-emerald-500",
55
+ icon: ImageIcon
56
+ },
57
+ {
58
+ extensions: ["webp"],
59
+ mime: "image/webp",
60
+ category: "IMAGE",
61
+ subCategory: "WEBP",
62
+ displayName: "WebP image",
63
+ previewKind: "image",
64
+ thumbnailStrategy: "image",
65
+ color: "text-emerald-500",
66
+ icon: ImageIcon
67
+ },
68
+ // AVIF — modern image format, supported natively by all evergreen browsers.
69
+ {
70
+ extensions: ["avif"],
71
+ mime: "image/avif",
72
+ category: "IMAGE",
73
+ subCategory: "AVIF",
74
+ displayName: "AVIF image",
75
+ previewKind: "image",
76
+ thumbnailStrategy: "image",
77
+ color: "text-emerald-500",
78
+ icon: ImageIcon
79
+ },
80
+ // SVG is text-under-the-hood (XML) so it gets its own previewKind. The
81
+ // SvgPreview renderer shows the rasterized vector on a transparency grid
82
+ // and exposes a "Source" toggle for the raw markup; the inline Monaco
83
+ // editor opens it as XML for direct edits. A distinct PenTool icon flags
84
+ // it as vector rather than the generic raster ImageIcon used by PNG/JPG.
85
+ {
86
+ extensions: ["svg"],
87
+ mime: "image/svg+xml",
88
+ category: "IMAGE",
89
+ subCategory: "SVG",
90
+ displayName: "SVG image",
91
+ previewKind: "svg",
92
+ thumbnailStrategy: "image",
93
+ color: "text-amber-500",
94
+ icon: PenTool
95
+ },
96
+ // HEIC / HEIF — Apple still uses these heavily. The canonical asset
97
+ // pipeline emits an aspect-preserving JPEG `preview_url` plus universal
98
+ // thumbnail variants; clients never bind the source bytes to `<img>`.
99
+ {
100
+ extensions: ["heic"],
101
+ mime: "image/heic",
102
+ category: "IMAGE",
103
+ subCategory: "HEIC",
104
+ displayName: "HEIC image (iOS)",
105
+ previewKind: "image",
106
+ thumbnailStrategy: "image",
107
+ color: "text-emerald-500",
108
+ icon: ImageIcon
109
+ },
110
+ {
111
+ extensions: ["heif"],
112
+ mime: "image/heif",
113
+ category: "IMAGE",
114
+ subCategory: "HEIF",
115
+ displayName: "HEIF image",
116
+ previewKind: "image",
117
+ thumbnailStrategy: "image",
118
+ color: "text-emerald-500",
119
+ icon: ImageIcon
120
+ },
121
+ // BMP / TIFF — older raster formats. Browser support is uneven (TIFF only
122
+ // on Safari) but `<img>` will fail gracefully to the icon on others.
123
+ {
124
+ extensions: ["bmp"],
125
+ mime: "image/bmp",
126
+ category: "IMAGE",
127
+ subCategory: "BMP",
128
+ displayName: "Bitmap image",
129
+ previewKind: "image",
130
+ thumbnailStrategy: "image",
131
+ color: "text-emerald-500",
132
+ icon: ImageIcon
133
+ },
134
+ {
135
+ extensions: ["tif", "tiff"],
136
+ mime: "image/tiff",
137
+ category: "IMAGE",
138
+ subCategory: "TIFF",
139
+ displayName: "TIFF image",
140
+ previewKind: "image",
141
+ thumbnailStrategy: "image",
142
+ color: "text-emerald-500",
143
+ icon: ImageIcon
144
+ },
145
+ {
146
+ extensions: ["ico"],
147
+ mime: "image/x-icon",
148
+ category: "IMAGE",
149
+ subCategory: "ICO",
150
+ displayName: "Icon image",
151
+ previewKind: "image",
152
+ thumbnailStrategy: "image",
153
+ color: "text-emerald-500",
154
+ icon: ImageIcon
155
+ },
156
+ // ────────────────────── VIDEO ──────────────────────
157
+ // Video gets a `video-poster` thumbnail strategy: a muted, tiny `<video>`
158
+ // element renders the first frame in place of a generic icon.
159
+ {
160
+ extensions: ["mp4"],
161
+ mime: "video/mp4",
162
+ category: "VIDEO",
163
+ subCategory: "MP4",
164
+ displayName: "MP4 video",
165
+ previewKind: "video",
166
+ thumbnailStrategy: "video-poster",
167
+ color: "text-purple-500",
168
+ icon: Video,
169
+ previewSizeCapOverride: null
170
+ // streamed inline — no cap
171
+ },
172
+ {
173
+ extensions: ["mov"],
174
+ mime: "video/quicktime",
175
+ category: "VIDEO",
176
+ subCategory: "MOV",
177
+ displayName: "QuickTime video",
178
+ previewKind: "video",
179
+ thumbnailStrategy: "video-poster",
180
+ color: "text-purple-500",
181
+ icon: Video,
182
+ previewSizeCapOverride: null
183
+ },
184
+ {
185
+ extensions: ["webm"],
186
+ mime: "video/webm",
187
+ category: "VIDEO",
188
+ subCategory: "WEBM",
189
+ displayName: "WebM video",
190
+ previewKind: "video",
191
+ thumbnailStrategy: "video-poster",
192
+ color: "text-purple-500",
193
+ icon: Video,
194
+ previewSizeCapOverride: null
195
+ },
196
+ {
197
+ extensions: ["mkv"],
198
+ mime: "video/x-matroska",
199
+ category: "VIDEO",
200
+ subCategory: "MKV",
201
+ displayName: "Matroska video",
202
+ previewKind: "video",
203
+ thumbnailStrategy: "video-poster",
204
+ color: "text-purple-500",
205
+ icon: Video,
206
+ previewSizeCapOverride: null
207
+ },
208
+ {
209
+ extensions: ["avi"],
210
+ mime: "video/x-msvideo",
211
+ category: "VIDEO",
212
+ subCategory: "AVI",
213
+ displayName: "AVI video",
214
+ previewKind: "video",
215
+ thumbnailStrategy: "video-poster",
216
+ color: "text-purple-500",
217
+ icon: Video,
218
+ previewSizeCapOverride: null
219
+ },
220
+ {
221
+ extensions: ["m4v"],
222
+ mime: "video/mp4",
223
+ category: "VIDEO",
224
+ subCategory: "M4V",
225
+ displayName: "iTunes video",
226
+ previewKind: "video",
227
+ thumbnailStrategy: "video-poster",
228
+ color: "text-purple-500",
229
+ icon: Video,
230
+ previewSizeCapOverride: null
231
+ },
232
+ // ────────────────────── AUDIO ──────────────────────
233
+ // Audio thumbs stay as icons — waveform extraction is not worth the
234
+ // bundle cost. Long-term: a backend cover-art / waveform field.
235
+ {
236
+ extensions: ["mp3"],
237
+ mime: "audio/mpeg",
238
+ category: "AUDIO",
239
+ subCategory: "MP3",
240
+ displayName: "MP3 audio",
241
+ previewKind: "audio",
242
+ thumbnailStrategy: "icon",
243
+ color: "text-pink-500",
244
+ icon: Music,
245
+ previewSizeCapOverride: null
246
+ },
247
+ {
248
+ extensions: ["wav"],
249
+ mime: "audio/wav",
250
+ category: "AUDIO",
251
+ subCategory: "WAV",
252
+ displayName: "WAV audio",
253
+ previewKind: "audio",
254
+ thumbnailStrategy: "icon",
255
+ color: "text-pink-500",
256
+ icon: Music,
257
+ previewSizeCapOverride: null
258
+ },
259
+ {
260
+ extensions: ["ogg"],
261
+ mime: "audio/ogg",
262
+ category: "AUDIO",
263
+ subCategory: "OGG",
264
+ displayName: "Ogg audio",
265
+ previewKind: "audio",
266
+ thumbnailStrategy: "icon",
267
+ color: "text-pink-500",
268
+ icon: Music,
269
+ previewSizeCapOverride: null
270
+ },
271
+ {
272
+ extensions: ["m4a"],
273
+ mime: "audio/mp4",
274
+ category: "AUDIO",
275
+ subCategory: "M4A",
276
+ displayName: "AAC audio (M4A)",
277
+ previewKind: "audio",
278
+ thumbnailStrategy: "icon",
279
+ color: "text-pink-500",
280
+ icon: Music,
281
+ previewSizeCapOverride: null
282
+ },
283
+ {
284
+ extensions: ["aac"],
285
+ mime: "audio/aac",
286
+ category: "AUDIO",
287
+ subCategory: "AAC",
288
+ displayName: "AAC audio",
289
+ previewKind: "audio",
290
+ thumbnailStrategy: "icon",
291
+ color: "text-pink-500",
292
+ icon: Music,
293
+ previewSizeCapOverride: null
294
+ },
295
+ {
296
+ extensions: ["flac"],
297
+ mime: "audio/flac",
298
+ category: "AUDIO",
299
+ subCategory: "FLAC",
300
+ displayName: "FLAC audio",
301
+ previewKind: "audio",
302
+ thumbnailStrategy: "icon",
303
+ color: "text-pink-500",
304
+ icon: Music,
305
+ previewSizeCapOverride: null
306
+ },
307
+ {
308
+ extensions: ["opus"],
309
+ mime: "audio/opus",
310
+ category: "AUDIO",
311
+ subCategory: "OPUS",
312
+ displayName: "Opus audio",
313
+ previewKind: "audio",
314
+ thumbnailStrategy: "icon",
315
+ color: "text-pink-500",
316
+ icon: Music,
317
+ previewSizeCapOverride: null
318
+ },
319
+ // MIME-only — `.webm` extension stays mapped to VIDEO below because the
320
+ // container can hold either track type. Rows whose server MIME is
321
+ // `audio/webm` (MediaRecorder speech captures, FastFire, transcripts)
322
+ // resolve via BY_MIME in `getFilePreviewProfile`. See
323
+ // docs/files/transcript-recordings-system-relocation.md.
324
+ {
325
+ extensions: [],
326
+ mime: "audio/webm",
327
+ category: "AUDIO",
328
+ subCategory: "WEBM",
329
+ displayName: "WebM audio",
330
+ previewKind: "audio",
331
+ thumbnailStrategy: "icon",
332
+ color: "text-pink-500",
333
+ icon: Music,
334
+ previewSizeCapOverride: null
335
+ },
336
+ // ────────────────────── PDF ──────────────────────
337
+ {
338
+ extensions: ["pdf"],
339
+ mime: "application/pdf",
340
+ category: "DOCUMENT",
341
+ subCategory: "PDF",
342
+ displayName: "PDF document",
343
+ previewKind: "pdf",
344
+ // First-page render via pdfjs is a future enhancement. For now we use the
345
+ // category icon — pdfjs is too heavy to load just for thumbs in a folder
346
+ // listing. When backend thumbs land we'll switch this to "backend-thumb".
347
+ thumbnailStrategy: "icon",
348
+ color: "text-red-500",
349
+ icon: FileType,
350
+ previewSizeCapOverride: null
351
+ },
352
+ // ────────────────────── MARKDOWN ──────────────────────
353
+ {
354
+ extensions: ["md", "markdown"],
355
+ mime: "text/markdown",
356
+ category: "DOCUMENT",
357
+ subCategory: "MARKDOWN",
358
+ displayName: "Markdown",
359
+ previewKind: "markdown",
360
+ thumbnailStrategy: "icon",
361
+ color: "text-slate-400",
362
+ icon: FileText
363
+ },
364
+ {
365
+ extensions: ["mdx"],
366
+ mime: "text/markdown",
367
+ category: "DOCUMENT",
368
+ subCategory: "MDX",
369
+ displayName: "MDX (Markdown + JSX)",
370
+ previewKind: "markdown",
371
+ thumbnailStrategy: "icon",
372
+ color: "text-slate-400",
373
+ icon: FileText
374
+ },
375
+ // ────────────────────── PLAIN TEXT / LOG / SUBTITLES ──────────────────────
376
+ {
377
+ extensions: ["txt", "text", "asc", "me"],
378
+ aliases: [
379
+ // Project metadata that ships without an extension
380
+ "README",
381
+ "Readme",
382
+ "readme",
383
+ "LICENSE",
384
+ "License",
385
+ "license",
386
+ "LICENCE",
387
+ "COPYING",
388
+ "COPYRIGHT",
389
+ "NOTICE",
390
+ "AUTHORS",
391
+ "CONTRIBUTORS",
392
+ "MAINTAINERS",
393
+ "CHANGELOG",
394
+ "CHANGES",
395
+ "HISTORY",
396
+ "NEWS",
397
+ "TODO",
398
+ "INSTALL",
399
+ "VERSION",
400
+ "MANIFEST",
401
+ "PATENTS",
402
+ "ROADMAP",
403
+ "SECURITY"
404
+ ],
405
+ mime: "text/plain",
406
+ category: "DOCUMENT",
407
+ subCategory: "PLAIN",
408
+ displayName: "Plain text",
409
+ previewKind: "text",
410
+ thumbnailStrategy: "icon",
411
+ color: "text-muted-foreground",
412
+ icon: FileText
413
+ },
414
+ {
415
+ extensions: ["log", "out", "err"],
416
+ mime: "text/plain",
417
+ category: "DOCUMENT",
418
+ subCategory: "LOG",
419
+ displayName: "Log file",
420
+ previewKind: "text",
421
+ thumbnailStrategy: "icon",
422
+ color: "text-muted-foreground",
423
+ icon: FileText
424
+ },
425
+ // Dockerfile-family — text with custom syntax. We keep them in the CODE
426
+ // category so they get a syntax-highlighting language hint downstream.
427
+ {
428
+ extensions: ["dockerfile", "containerfile"],
429
+ aliases: ["Dockerfile", "Containerfile", "dockerfile"],
430
+ aliasPrefixes: ["Dockerfile.", "dockerfile.", "Containerfile."],
431
+ mime: "text/x-dockerfile",
432
+ category: "CODE",
433
+ subCategory: "DOCKERFILE",
434
+ displayName: "Dockerfile",
435
+ previewKind: "code",
436
+ thumbnailStrategy: "icon",
437
+ color: "text-blue-500",
438
+ icon: Code
439
+ },
440
+ // Makefile-family — also custom-syntax text.
441
+ {
442
+ extensions: ["mk", "make"],
443
+ aliases: [
444
+ "Makefile",
445
+ "makefile",
446
+ "GNUmakefile",
447
+ "BSDmakefile",
448
+ "Procfile",
449
+ "Pipfile",
450
+ "Justfile",
451
+ "justfile",
452
+ "Earthfile"
453
+ ],
454
+ aliasPrefixes: ["Makefile.", "makefile."],
455
+ mime: "text/x-makefile",
456
+ category: "CODE",
457
+ subCategory: "MAKEFILE",
458
+ displayName: "Makefile",
459
+ previewKind: "code",
460
+ thumbnailStrategy: "icon",
461
+ color: "text-orange-500",
462
+ icon: Code
463
+ },
464
+ // Patches & diffs — text.
465
+ {
466
+ extensions: ["diff", "patch"],
467
+ mime: "text/x-diff",
468
+ category: "CODE",
469
+ subCategory: "PATCH",
470
+ displayName: "Patch / diff",
471
+ previewKind: "code",
472
+ thumbnailStrategy: "icon",
473
+ color: "text-amber-500",
474
+ icon: FileText
475
+ },
476
+ // INI / properties / cfg — historically common config text formats.
477
+ {
478
+ extensions: ["ini", "cfg", "conf", "config", "properties", "prefs"],
479
+ mime: "text/x-properties",
480
+ category: "CODE",
481
+ subCategory: "CONFIG",
482
+ displayName: "Config file",
483
+ previewKind: "code",
484
+ thumbnailStrategy: "icon",
485
+ color: "text-amber-400",
486
+ icon: Braces
487
+ },
488
+ // BibTeX / TeX / LaTeX — plain text with markup.
489
+ {
490
+ extensions: ["tex", "latex", "ltx", "sty", "cls", "bib"],
491
+ mime: "text/x-tex",
492
+ category: "CODE",
493
+ subCategory: "TEX",
494
+ displayName: "TeX / LaTeX",
495
+ previewKind: "code",
496
+ thumbnailStrategy: "icon",
497
+ color: "text-emerald-500",
498
+ icon: FileText
499
+ },
500
+ // reStructuredText / AsciiDoc — text doc formats.
501
+ {
502
+ extensions: ["rst", "adoc", "asciidoc", "org"],
503
+ mime: "text/plain",
504
+ category: "DOCUMENT",
505
+ subCategory: "DOC",
506
+ displayName: "Document",
507
+ previewKind: "text",
508
+ thumbnailStrategy: "icon",
509
+ color: "text-slate-400",
510
+ icon: FileText
511
+ },
512
+ {
513
+ extensions: ["srt"],
514
+ mime: "application/x-subrip",
515
+ category: "SUBTITLES",
516
+ subCategory: "SRT",
517
+ displayName: "SubRip subtitles",
518
+ previewKind: "text",
519
+ thumbnailStrategy: "icon",
520
+ color: "text-cyan-500",
521
+ icon: Subtitles
522
+ },
523
+ {
524
+ extensions: ["vtt"],
525
+ mime: "text/vtt",
526
+ category: "SUBTITLES",
527
+ subCategory: "VTT",
528
+ displayName: "WebVTT subtitles",
529
+ previewKind: "text",
530
+ thumbnailStrategy: "icon",
531
+ color: "text-cyan-500",
532
+ icon: Subtitles
533
+ },
534
+ // ────────────────────── CODE ──────────────────────
535
+ {
536
+ extensions: ["js", "mjs", "cjs"],
537
+ mime: "text/javascript",
538
+ category: "CODE",
539
+ subCategory: "JAVASCRIPT",
540
+ displayName: "JavaScript",
541
+ previewKind: "code",
542
+ thumbnailStrategy: "icon",
543
+ color: "text-yellow-500",
544
+ icon: FileCode
545
+ },
546
+ {
547
+ extensions: ["jsx"],
548
+ mime: "text/javascript",
549
+ category: "CODE",
550
+ subCategory: "JAVASCRIPT",
551
+ displayName: "JSX",
552
+ previewKind: "code",
553
+ thumbnailStrategy: "icon",
554
+ color: "text-yellow-500",
555
+ icon: FileCode
556
+ },
557
+ {
558
+ extensions: ["ts"],
559
+ mime: "text/typescript",
560
+ category: "CODE",
561
+ subCategory: "TYPESCRIPT",
562
+ displayName: "TypeScript",
563
+ previewKind: "code",
564
+ thumbnailStrategy: "icon",
565
+ color: "text-blue-500",
566
+ icon: FileCode
567
+ },
568
+ {
569
+ extensions: ["tsx"],
570
+ mime: "text/typescript",
571
+ category: "CODE",
572
+ subCategory: "TYPESCRIPT",
573
+ displayName: "TSX",
574
+ previewKind: "code",
575
+ thumbnailStrategy: "icon",
576
+ color: "text-blue-500",
577
+ icon: FileCode
578
+ },
579
+ {
580
+ extensions: ["py"],
581
+ mime: "text/x-python",
582
+ category: "CODE",
583
+ subCategory: "PYTHON",
584
+ displayName: "Python",
585
+ previewKind: "code",
586
+ thumbnailStrategy: "icon",
587
+ color: "text-emerald-500",
588
+ icon: Code
589
+ },
590
+ {
591
+ extensions: ["rb", "rbw", "rake", "ru", "gemspec"],
592
+ aliases: [
593
+ "Rakefile",
594
+ "Gemfile",
595
+ "Vagrantfile",
596
+ "Berksfile",
597
+ "Brewfile",
598
+ "Capfile",
599
+ "Guardfile",
600
+ "Podfile",
601
+ "Fastfile",
602
+ "Appfile",
603
+ "Deliverfile",
604
+ "Matchfile",
605
+ "Pluginfile",
606
+ "Snapfile",
607
+ "Scanfile",
608
+ "Gymfile"
609
+ ],
610
+ mime: "text/x-ruby",
611
+ category: "CODE",
612
+ subCategory: "RUBY",
613
+ displayName: "Ruby",
614
+ previewKind: "code",
615
+ thumbnailStrategy: "icon",
616
+ color: "text-red-500",
617
+ icon: Code
618
+ },
619
+ {
620
+ extensions: ["go"],
621
+ mime: "text/x-go",
622
+ category: "CODE",
623
+ subCategory: "GO",
624
+ displayName: "Go",
625
+ previewKind: "code",
626
+ thumbnailStrategy: "icon",
627
+ color: "text-cyan-500",
628
+ icon: Code
629
+ },
630
+ {
631
+ extensions: ["rs"],
632
+ mime: "text/x-rust",
633
+ category: "CODE",
634
+ subCategory: "RUST",
635
+ displayName: "Rust",
636
+ previewKind: "code",
637
+ thumbnailStrategy: "icon",
638
+ color: "text-orange-600",
639
+ icon: Code
640
+ },
641
+ {
642
+ extensions: ["java"],
643
+ mime: "text/x-java",
644
+ category: "CODE",
645
+ subCategory: "JAVA",
646
+ displayName: "Java",
647
+ previewKind: "code",
648
+ thumbnailStrategy: "icon",
649
+ color: "text-red-600",
650
+ icon: Code
651
+ },
652
+ {
653
+ extensions: ["swift"],
654
+ mime: "text/x-swift",
655
+ category: "CODE",
656
+ subCategory: "SWIFT",
657
+ displayName: "Swift",
658
+ previewKind: "code",
659
+ thumbnailStrategy: "icon",
660
+ color: "text-orange-500",
661
+ icon: Code
662
+ },
663
+ {
664
+ extensions: ["c", "h"],
665
+ mime: "text/x-c",
666
+ category: "CODE",
667
+ subCategory: "C",
668
+ displayName: "C",
669
+ previewKind: "code",
670
+ thumbnailStrategy: "icon",
671
+ color: "text-blue-600",
672
+ icon: Code
673
+ },
674
+ {
675
+ extensions: ["cpp", "cc", "cxx", "hpp"],
676
+ mime: "text/x-c++",
677
+ category: "CODE",
678
+ subCategory: "CPP",
679
+ displayName: "C++",
680
+ previewKind: "code",
681
+ thumbnailStrategy: "icon",
682
+ color: "text-blue-700",
683
+ icon: Code
684
+ },
685
+ {
686
+ extensions: ["cs"],
687
+ mime: "text/x-csharp",
688
+ category: "CODE",
689
+ subCategory: "CSHARP",
690
+ displayName: "C#",
691
+ previewKind: "code",
692
+ thumbnailStrategy: "icon",
693
+ color: "text-purple-600",
694
+ icon: Code
695
+ },
696
+ // HTML — `previewKind: "html"` so the previewer can offer a Rendered /
697
+ // Source toggle (sandboxed iframe vs syntax-highlighted markup). Without
698
+ // the split, opening a saved web page in /files just showed its source,
699
+ // which is the wrong default for almost every consumer. The Edit tab
700
+ // mounts Monaco with `html` language (see CloudFileInlineEditor's
701
+ // LANGUAGE_BY_EXT) and source-of-truth editing happens there.
702
+ {
703
+ extensions: ["html", "htm"],
704
+ mime: "text/html",
705
+ category: "CODE",
706
+ subCategory: "HTML",
707
+ displayName: "HTML",
708
+ previewKind: "html",
709
+ thumbnailStrategy: "icon",
710
+ color: "text-orange-400",
711
+ icon: Code
712
+ },
713
+ {
714
+ extensions: ["css"],
715
+ mime: "text/css",
716
+ category: "CODE",
717
+ subCategory: "CSS",
718
+ displayName: "CSS",
719
+ previewKind: "code",
720
+ thumbnailStrategy: "icon",
721
+ color: "text-sky-400",
722
+ icon: Code
723
+ },
724
+ {
725
+ extensions: ["scss"],
726
+ mime: "text/x-scss",
727
+ category: "CODE",
728
+ subCategory: "SCSS",
729
+ displayName: "SCSS",
730
+ previewKind: "code",
731
+ thumbnailStrategy: "icon",
732
+ color: "text-pink-400",
733
+ icon: Code
734
+ },
735
+ {
736
+ extensions: ["sh", "bash", "zsh", "fish", "ksh", "ash"],
737
+ aliases: [
738
+ // Bash / shell config dotfiles
739
+ ".bashrc",
740
+ ".bash_logout",
741
+ ".bash_profile",
742
+ ".bash_history",
743
+ ".bash_aliases",
744
+ ".profile",
745
+ ".zshrc",
746
+ ".zshenv",
747
+ ".zprofile",
748
+ ".zlogin",
749
+ ".zlogout",
750
+ ".zsh_history",
751
+ ".inputrc",
752
+ ".curlrc",
753
+ ".wgetrc",
754
+ ".npmrc",
755
+ ".yarnrc",
756
+ ".pypirc",
757
+ ".tool-versions",
758
+ ".nvmrc",
759
+ ".node-version",
760
+ ".python-version",
761
+ ".ruby-version",
762
+ // Env files (exact)
763
+ ".env",
764
+ ".envrc",
765
+ ".sandbox_env",
766
+ // Editor / formatter / linter config dotfiles (no extension variants)
767
+ ".editorconfig",
768
+ ".gitignore",
769
+ ".gitattributes",
770
+ ".gitmodules",
771
+ ".gitkeep",
772
+ ".gitconfig",
773
+ ".dockerignore",
774
+ ".eslintignore",
775
+ ".prettierignore",
776
+ ".npmignore",
777
+ ".browserslistrc",
778
+ ".stylelintignore",
779
+ ".rsync-filter",
780
+ // SSH / system config that is plain text
781
+ "authorized_keys",
782
+ "known_hosts",
783
+ "config",
784
+ "hosts",
785
+ "passwd",
786
+ "group",
787
+ "shadow",
788
+ "fstab",
789
+ "crontab",
790
+ "resolv.conf",
791
+ "ssh_config",
792
+ "sshd_config",
793
+ // Build / cache markers (text)
794
+ "CACHEDIR.TAG",
795
+ "CODEOWNERS"
796
+ ],
797
+ aliasPrefixes: [
798
+ // .env.local, .env.production, .env.development, .env.test, etc.
799
+ ".env.",
800
+ ".envrc."
801
+ ],
802
+ mime: "text/x-shellscript",
803
+ category: "CODE",
804
+ subCategory: "SHELL",
805
+ displayName: "Shell script",
806
+ previewKind: "code",
807
+ thumbnailStrategy: "icon",
808
+ color: "text-emerald-400",
809
+ icon: Code
810
+ },
811
+ {
812
+ extensions: ["sql"],
813
+ mime: "application/sql",
814
+ category: "CODE",
815
+ subCategory: "SQL",
816
+ displayName: "SQL",
817
+ previewKind: "code",
818
+ thumbnailStrategy: "icon",
819
+ color: "text-amber-400",
820
+ icon: Code
821
+ },
822
+ {
823
+ extensions: ["lua"],
824
+ mime: "text/x-lua",
825
+ category: "CODE",
826
+ subCategory: "LUA",
827
+ displayName: "Lua",
828
+ previewKind: "code",
829
+ thumbnailStrategy: "icon",
830
+ color: "text-blue-500",
831
+ icon: Code
832
+ },
833
+ {
834
+ extensions: ["pl", "pm"],
835
+ mime: "text/x-perl",
836
+ category: "CODE",
837
+ subCategory: "PERL",
838
+ displayName: "Perl",
839
+ previewKind: "code",
840
+ thumbnailStrategy: "icon",
841
+ color: "text-indigo-400",
842
+ icon: Code
843
+ },
844
+ {
845
+ extensions: ["r", "R", "rmd", "Rmd"],
846
+ mime: "text/x-r",
847
+ category: "CODE",
848
+ subCategory: "R",
849
+ displayName: "R",
850
+ previewKind: "code",
851
+ thumbnailStrategy: "icon",
852
+ color: "text-blue-400",
853
+ icon: Code
854
+ },
855
+ {
856
+ extensions: ["dart"],
857
+ mime: "text/x-dart",
858
+ category: "CODE",
859
+ subCategory: "DART",
860
+ displayName: "Dart",
861
+ previewKind: "code",
862
+ thumbnailStrategy: "icon",
863
+ color: "text-cyan-500",
864
+ icon: Code
865
+ },
866
+ {
867
+ extensions: ["kt", "kts"],
868
+ mime: "text/x-kotlin",
869
+ category: "CODE",
870
+ subCategory: "KOTLIN",
871
+ displayName: "Kotlin",
872
+ previewKind: "code",
873
+ thumbnailStrategy: "icon",
874
+ color: "text-orange-400",
875
+ icon: Code
876
+ },
877
+ {
878
+ extensions: ["scala", "sbt"],
879
+ mime: "text/x-scala",
880
+ category: "CODE",
881
+ subCategory: "SCALA",
882
+ displayName: "Scala",
883
+ previewKind: "code",
884
+ thumbnailStrategy: "icon",
885
+ color: "text-red-500",
886
+ icon: Code
887
+ },
888
+ {
889
+ extensions: ["clj", "cljs", "cljc", "edn"],
890
+ mime: "text/x-clojure",
891
+ category: "CODE",
892
+ subCategory: "CLOJURE",
893
+ displayName: "Clojure",
894
+ previewKind: "code",
895
+ thumbnailStrategy: "icon",
896
+ color: "text-emerald-500",
897
+ icon: Code
898
+ },
899
+ {
900
+ extensions: ["ex", "exs"],
901
+ mime: "text/x-elixir",
902
+ category: "CODE",
903
+ subCategory: "ELIXIR",
904
+ displayName: "Elixir",
905
+ previewKind: "code",
906
+ thumbnailStrategy: "icon",
907
+ color: "text-purple-400",
908
+ icon: Code
909
+ },
910
+ {
911
+ extensions: ["erl", "hrl"],
912
+ mime: "text/x-erlang",
913
+ category: "CODE",
914
+ subCategory: "ERLANG",
915
+ displayName: "Erlang",
916
+ previewKind: "code",
917
+ thumbnailStrategy: "icon",
918
+ color: "text-rose-500",
919
+ icon: Code
920
+ },
921
+ {
922
+ extensions: ["hs", "lhs"],
923
+ mime: "text/x-haskell",
924
+ category: "CODE",
925
+ subCategory: "HASKELL",
926
+ displayName: "Haskell",
927
+ previewKind: "code",
928
+ thumbnailStrategy: "icon",
929
+ color: "text-violet-500",
930
+ icon: Code
931
+ },
932
+ {
933
+ extensions: ["ml", "mli", "fs", "fsi", "fsx"],
934
+ mime: "text/x-ocaml",
935
+ category: "CODE",
936
+ subCategory: "ML",
937
+ displayName: "OCaml / F#",
938
+ previewKind: "code",
939
+ thumbnailStrategy: "icon",
940
+ color: "text-orange-500",
941
+ icon: Code
942
+ },
943
+ {
944
+ extensions: ["zig"],
945
+ mime: "text/x-zig",
946
+ category: "CODE",
947
+ subCategory: "ZIG",
948
+ displayName: "Zig",
949
+ previewKind: "code",
950
+ thumbnailStrategy: "icon",
951
+ color: "text-yellow-500",
952
+ icon: Code
953
+ },
954
+ {
955
+ extensions: ["nim", "nims"],
956
+ mime: "text/x-nim",
957
+ category: "CODE",
958
+ subCategory: "NIM",
959
+ displayName: "Nim",
960
+ previewKind: "code",
961
+ thumbnailStrategy: "icon",
962
+ color: "text-yellow-400",
963
+ icon: Code
964
+ },
965
+ {
966
+ extensions: ["jl"],
967
+ mime: "text/x-julia",
968
+ category: "CODE",
969
+ subCategory: "JULIA",
970
+ displayName: "Julia",
971
+ previewKind: "code",
972
+ thumbnailStrategy: "icon",
973
+ color: "text-purple-500",
974
+ icon: Code
975
+ },
976
+ {
977
+ extensions: ["vue"],
978
+ mime: "text/x-vue",
979
+ category: "CODE",
980
+ subCategory: "VUE",
981
+ displayName: "Vue",
982
+ previewKind: "code",
983
+ thumbnailStrategy: "icon",
984
+ color: "text-emerald-500",
985
+ icon: Code
986
+ },
987
+ {
988
+ extensions: ["svelte"],
989
+ mime: "text/x-svelte",
990
+ category: "CODE",
991
+ subCategory: "SVELTE",
992
+ displayName: "Svelte",
993
+ previewKind: "code",
994
+ thumbnailStrategy: "icon",
995
+ color: "text-orange-500",
996
+ icon: Code
997
+ },
998
+ {
999
+ extensions: ["astro"],
1000
+ mime: "text/x-astro",
1001
+ category: "CODE",
1002
+ subCategory: "ASTRO",
1003
+ displayName: "Astro",
1004
+ previewKind: "code",
1005
+ thumbnailStrategy: "icon",
1006
+ color: "text-fuchsia-500",
1007
+ icon: Code
1008
+ },
1009
+ {
1010
+ extensions: ["graphql", "gql", "graphqls"],
1011
+ mime: "application/graphql",
1012
+ category: "CODE",
1013
+ subCategory: "GRAPHQL",
1014
+ displayName: "GraphQL",
1015
+ previewKind: "code",
1016
+ thumbnailStrategy: "icon",
1017
+ color: "text-pink-500",
1018
+ icon: Code
1019
+ },
1020
+ {
1021
+ extensions: ["proto"],
1022
+ mime: "text/x-protobuf",
1023
+ category: "CODE",
1024
+ subCategory: "PROTO",
1025
+ displayName: "Protocol Buffers",
1026
+ previewKind: "code",
1027
+ thumbnailStrategy: "icon",
1028
+ color: "text-blue-400",
1029
+ icon: Code
1030
+ },
1031
+ {
1032
+ extensions: ["sol"],
1033
+ mime: "text/x-solidity",
1034
+ category: "CODE",
1035
+ subCategory: "SOLIDITY",
1036
+ displayName: "Solidity",
1037
+ previewKind: "code",
1038
+ thumbnailStrategy: "icon",
1039
+ color: "text-slate-400",
1040
+ icon: Code
1041
+ },
1042
+ {
1043
+ extensions: ["bat", "cmd"],
1044
+ mime: "text/x-msdos-batch",
1045
+ category: "CODE",
1046
+ subCategory: "BATCH",
1047
+ displayName: "Batch script",
1048
+ previewKind: "code",
1049
+ thumbnailStrategy: "icon",
1050
+ color: "text-emerald-400",
1051
+ icon: Code
1052
+ },
1053
+ {
1054
+ extensions: ["ps1", "psm1", "psd1"],
1055
+ mime: "application/x-powershell",
1056
+ category: "CODE",
1057
+ subCategory: "POWERSHELL",
1058
+ displayName: "PowerShell",
1059
+ previewKind: "code",
1060
+ thumbnailStrategy: "icon",
1061
+ color: "text-blue-400",
1062
+ icon: Code
1063
+ },
1064
+ {
1065
+ extensions: ["less"],
1066
+ mime: "text/x-less",
1067
+ category: "CODE",
1068
+ subCategory: "LESS",
1069
+ displayName: "LESS",
1070
+ previewKind: "code",
1071
+ thumbnailStrategy: "icon",
1072
+ color: "text-blue-400",
1073
+ icon: Code
1074
+ },
1075
+ {
1076
+ extensions: ["styl", "stylus"],
1077
+ mime: "text/x-stylus",
1078
+ category: "CODE",
1079
+ subCategory: "STYLUS",
1080
+ displayName: "Stylus",
1081
+ previewKind: "code",
1082
+ thumbnailStrategy: "icon",
1083
+ color: "text-emerald-500",
1084
+ icon: Code
1085
+ },
1086
+ {
1087
+ extensions: ["php", "phtml", "phps"],
1088
+ mime: "application/x-php",
1089
+ category: "CODE",
1090
+ subCategory: "PHP",
1091
+ displayName: "PHP",
1092
+ previewKind: "code",
1093
+ thumbnailStrategy: "icon",
1094
+ color: "text-indigo-500",
1095
+ icon: Code
1096
+ },
1097
+ {
1098
+ extensions: ["twig", "jinja", "j2", "njk"],
1099
+ mime: "text/x-twig",
1100
+ category: "CODE",
1101
+ subCategory: "TEMPLATE",
1102
+ displayName: "Template",
1103
+ previewKind: "code",
1104
+ thumbnailStrategy: "icon",
1105
+ color: "text-emerald-400",
1106
+ icon: Code
1107
+ },
1108
+ {
1109
+ extensions: ["hbs", "handlebars", "mustache", "ejs", "liquid"],
1110
+ mime: "text/x-template",
1111
+ category: "CODE",
1112
+ subCategory: "TEMPLATE",
1113
+ displayName: "Template",
1114
+ previewKind: "code",
1115
+ thumbnailStrategy: "icon",
1116
+ color: "text-amber-500",
1117
+ icon: Code
1118
+ },
1119
+ // ────────────────────── DATA / CONFIG ──────────────────────
1120
+ {
1121
+ extensions: ["json", "jsonc", "json5", "har", "geojson", "topojson"],
1122
+ aliases: [
1123
+ ".babelrc",
1124
+ ".eslintrc",
1125
+ ".prettierrc",
1126
+ ".stylelintrc",
1127
+ ".swcrc",
1128
+ ".huskyrc",
1129
+ ".lintstagedrc"
1130
+ ],
1131
+ mime: "application/json",
1132
+ category: "DATA",
1133
+ subCategory: "JSON",
1134
+ displayName: "JSON",
1135
+ previewKind: "data",
1136
+ thumbnailStrategy: "icon",
1137
+ color: "text-amber-500",
1138
+ icon: FileJson
1139
+ },
1140
+ {
1141
+ extensions: ["yaml", "yml"],
1142
+ aliases: [".yamllint", ".clang-format", ".clang-tidy"],
1143
+ mime: "application/yaml",
1144
+ category: "CODE",
1145
+ subCategory: "YAML",
1146
+ displayName: "YAML",
1147
+ previewKind: "code",
1148
+ thumbnailStrategy: "icon",
1149
+ color: "text-amber-500",
1150
+ icon: Braces
1151
+ },
1152
+ {
1153
+ extensions: ["toml"],
1154
+ mime: "application/toml",
1155
+ category: "CODE",
1156
+ subCategory: "TOML",
1157
+ displayName: "TOML",
1158
+ previewKind: "code",
1159
+ thumbnailStrategy: "icon",
1160
+ color: "text-amber-500",
1161
+ icon: Braces
1162
+ },
1163
+ {
1164
+ extensions: ["xml"],
1165
+ mime: "application/xml",
1166
+ category: "DATA",
1167
+ subCategory: "XML",
1168
+ displayName: "XML",
1169
+ previewKind: "data",
1170
+ thumbnailStrategy: "icon",
1171
+ color: "text-amber-500",
1172
+ icon: Braces
1173
+ },
1174
+ {
1175
+ extensions: ["csv"],
1176
+ mime: "text/csv",
1177
+ category: "DATA",
1178
+ subCategory: "CSV",
1179
+ displayName: "CSV",
1180
+ previewKind: "data",
1181
+ thumbnailStrategy: "icon",
1182
+ color: "text-orange-500",
1183
+ icon: FileSpreadsheet
1184
+ },
1185
+ {
1186
+ extensions: ["tsv"],
1187
+ mime: "text/tab-separated-values",
1188
+ category: "DATA",
1189
+ subCategory: "TSV",
1190
+ displayName: "TSV",
1191
+ previewKind: "data",
1192
+ thumbnailStrategy: "icon",
1193
+ color: "text-orange-500",
1194
+ icon: FileSpreadsheet
1195
+ },
1196
+ {
1197
+ extensions: ["sqlite", "sqlite3", "db"],
1198
+ mime: "application/x-sqlite3",
1199
+ category: "DATA",
1200
+ subCategory: "SQLITE",
1201
+ displayName: "SQLite database",
1202
+ previewKind: "generic",
1203
+ thumbnailStrategy: "icon",
1204
+ color: "text-blue-400",
1205
+ icon: Database
1206
+ },
1207
+ // PEM-encoded certs / CSRs are armored base64 — i.e. text. `.pem`
1208
+ // and `.csr` are PEM by convention; `.crt` / `.cer` / `.key` / `.pub`
1209
+ // can be either PEM or DER (binary), so they stay `generic` and the
1210
+ // binary viewer's byte sniff offers "View as text" when the bytes
1211
+ // turn out to be ASCII-armored.
1212
+ {
1213
+ extensions: ["pem", "csr"],
1214
+ mime: "application/x-pem-file",
1215
+ category: "CODE",
1216
+ subCategory: "PEM",
1217
+ displayName: "PEM certificate / key",
1218
+ previewKind: "text",
1219
+ thumbnailStrategy: "icon",
1220
+ color: "text-amber-500",
1221
+ icon: FileText
1222
+ },
1223
+ {
1224
+ extensions: ["crt", "cer", "der", "key", "pub", "p7b", "p7c", "pfx", "p12"],
1225
+ mime: "application/x-x509-ca-cert",
1226
+ category: "CODE",
1227
+ subCategory: "CERT",
1228
+ displayName: "Certificate",
1229
+ previewKind: "generic",
1230
+ thumbnailStrategy: "icon",
1231
+ color: "text-amber-500",
1232
+ icon: FileText
1233
+ },
1234
+ // RDF / Turtle / N-Triples — text-based RDF data formats.
1235
+ {
1236
+ extensions: ["ttl", "n3", "nt", "nq", "trig"],
1237
+ mime: "text/turtle",
1238
+ category: "DATA",
1239
+ subCategory: "RDF",
1240
+ displayName: "RDF / Turtle",
1241
+ previewKind: "code",
1242
+ thumbnailStrategy: "icon",
1243
+ color: "text-fuchsia-400",
1244
+ icon: Braces
1245
+ },
1246
+ // ────────────────────── SPREADSHEET (Excel) ──────────────────────
1247
+ {
1248
+ extensions: ["xlsx"],
1249
+ mime: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1250
+ category: "DOCUMENT",
1251
+ subCategory: "EXCEL",
1252
+ displayName: "Excel workbook",
1253
+ previewKind: "spreadsheet",
1254
+ thumbnailStrategy: "icon",
1255
+ color: "text-emerald-600",
1256
+ icon: FileSpreadsheet,
1257
+ previewSizeCapOverride: null
1258
+ },
1259
+ {
1260
+ extensions: ["xls"],
1261
+ mime: "application/vnd.ms-excel",
1262
+ category: "DOCUMENT",
1263
+ subCategory: "EXCEL",
1264
+ displayName: "Excel workbook (legacy)",
1265
+ previewKind: "spreadsheet",
1266
+ thumbnailStrategy: "icon",
1267
+ color: "text-emerald-600",
1268
+ icon: FileSpreadsheet,
1269
+ previewSizeCapOverride: null
1270
+ },
1271
+ // ────────────────────── OFFICE (Word / PowerPoint) ──────────────────────
1272
+ // Server-side extraction preview: OfficePreview calls aidream
1273
+ // `GET /office/{file_id}/markdown` (the matrx-files Office codec) and renders
1274
+ // the document / deck as markdown, slide-by-slide for pptx. Legacy .doc/.ppt
1275
+ // ride the server's LibreOffice bridge. xlsx stays on the SheetJS previewer.
1276
+ {
1277
+ extensions: ["doc", "docx"],
1278
+ mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1279
+ category: "DOCUMENT",
1280
+ subCategory: "WORD",
1281
+ displayName: "Word document",
1282
+ previewKind: "office",
1283
+ thumbnailStrategy: "icon",
1284
+ color: "text-blue-500",
1285
+ icon: FileText
1286
+ // No size cap needed: "office" is in the streamable-kind list of
1287
+ // getFilePreviewProfile — bytes never reach the browser (server extracts).
1288
+ },
1289
+ {
1290
+ extensions: ["ppt", "pptx"],
1291
+ mime: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
1292
+ category: "DOCUMENT",
1293
+ subCategory: "POWERPOINT",
1294
+ displayName: "PowerPoint",
1295
+ previewKind: "office",
1296
+ thumbnailStrategy: "icon",
1297
+ color: "text-orange-600",
1298
+ icon: FileType
1299
+ },
1300
+ // ────────────────────── NOTEBOOK ──────────────────────
1301
+ // .ipynb is JSON under the hood, so it works in our DataPreview today.
1302
+ // Eventually we'll ship a dedicated notebook renderer (cells + outputs).
1303
+ {
1304
+ extensions: ["ipynb"],
1305
+ mime: "application/x-ipynb+json",
1306
+ category: "NOTEBOOK",
1307
+ subCategory: "JUPYTER",
1308
+ displayName: "Jupyter notebook",
1309
+ previewKind: "data",
1310
+ thumbnailStrategy: "icon",
1311
+ color: "text-orange-400",
1312
+ icon: FileJson
1313
+ },
1314
+ // ────────────────────── EBOOK ──────────────────────
1315
+ {
1316
+ extensions: ["epub"],
1317
+ mime: "application/epub+zip",
1318
+ category: "EBOOK",
1319
+ subCategory: "EPUB",
1320
+ displayName: "EPUB ebook",
1321
+ previewKind: "generic",
1322
+ thumbnailStrategy: "icon",
1323
+ color: "text-indigo-500",
1324
+ icon: FileText
1325
+ },
1326
+ // ────────────────────── EMAIL ──────────────────────
1327
+ {
1328
+ extensions: ["eml"],
1329
+ mime: "message/rfc822",
1330
+ category: "EMAIL",
1331
+ subCategory: "EML",
1332
+ displayName: "Email message",
1333
+ previewKind: "text",
1334
+ thumbnailStrategy: "icon",
1335
+ color: "text-blue-400",
1336
+ icon: FileText
1337
+ },
1338
+ // ────────────────────── 3D / CAD ──────────────────────
1339
+ // No previewer yet (Three.js loader would be needed). Icons only.
1340
+ {
1341
+ extensions: ["glb", "gltf"],
1342
+ mime: "model/gltf-binary",
1343
+ category: "MODEL_3D",
1344
+ subCategory: "GLTF",
1345
+ displayName: "3D model (glTF)",
1346
+ previewKind: "generic",
1347
+ thumbnailStrategy: "icon",
1348
+ color: "text-violet-400",
1349
+ icon: Package
1350
+ },
1351
+ {
1352
+ extensions: ["stl", "obj", "fbx"],
1353
+ mime: "model/stl",
1354
+ category: "MODEL_3D",
1355
+ subCategory: "MESH",
1356
+ displayName: "3D mesh",
1357
+ previewKind: "generic",
1358
+ thumbnailStrategy: "icon",
1359
+ color: "text-violet-400",
1360
+ icon: Package
1361
+ },
1362
+ // ────────────────────── ARCHIVES ──────────────────────
1363
+ {
1364
+ extensions: ["zip"],
1365
+ mime: "application/zip",
1366
+ category: "ARCHIVE",
1367
+ subCategory: "ZIP",
1368
+ displayName: "ZIP archive",
1369
+ previewKind: "generic",
1370
+ thumbnailStrategy: "icon",
1371
+ color: "text-amber-600",
1372
+ icon: Archive
1373
+ },
1374
+ {
1375
+ extensions: ["rar"],
1376
+ mime: "application/vnd.rar",
1377
+ category: "ARCHIVE",
1378
+ subCategory: "RAR",
1379
+ displayName: "RAR archive",
1380
+ previewKind: "generic",
1381
+ thumbnailStrategy: "icon",
1382
+ color: "text-amber-600",
1383
+ icon: Archive
1384
+ },
1385
+ {
1386
+ extensions: ["7z"],
1387
+ mime: "application/x-7z-compressed",
1388
+ category: "ARCHIVE",
1389
+ subCategory: "7Z",
1390
+ displayName: "7-Zip archive",
1391
+ previewKind: "generic",
1392
+ thumbnailStrategy: "icon",
1393
+ color: "text-amber-600",
1394
+ icon: Archive
1395
+ },
1396
+ {
1397
+ extensions: ["tar"],
1398
+ mime: "application/x-tar",
1399
+ category: "ARCHIVE",
1400
+ subCategory: "TAR",
1401
+ displayName: "TAR archive",
1402
+ previewKind: "generic",
1403
+ thumbnailStrategy: "icon",
1404
+ color: "text-amber-600",
1405
+ icon: Package
1406
+ },
1407
+ {
1408
+ extensions: ["gz", "tgz"],
1409
+ mime: "application/gzip",
1410
+ category: "ARCHIVE",
1411
+ subCategory: "GZ",
1412
+ displayName: "Gzip archive",
1413
+ previewKind: "generic",
1414
+ thumbnailStrategy: "icon",
1415
+ color: "text-amber-600",
1416
+ icon: Package
1417
+ }
1418
+ ];
1419
+ const UNKNOWN_DETAILS = {
1420
+ category: "UNKNOWN",
1421
+ subCategory: "UNKNOWN",
1422
+ displayName: "File",
1423
+ previewKind: "generic",
1424
+ thumbnailStrategy: "icon",
1425
+ color: "text-muted-foreground",
1426
+ icon: FileIcon,
1427
+ canPreview: false,
1428
+ previewSizeCapOverride: null,
1429
+ mime: "application/octet-stream"
1430
+ };
1431
+ const ASSUMED_TEXT_DETAILS = {
1432
+ category: "DOCUMENT",
1433
+ subCategory: "PLAIN",
1434
+ displayName: "Text",
1435
+ previewKind: "text",
1436
+ thumbnailStrategy: "icon",
1437
+ color: "text-muted-foreground",
1438
+ icon: FileText,
1439
+ canPreview: true,
1440
+ previewSizeCapOverride: null,
1441
+ mime: "text/plain"
1442
+ };
1443
+ const FOLDER_DETAILS = {
1444
+ category: "FOLDER",
1445
+ subCategory: "FOLDER",
1446
+ displayName: "Folder",
1447
+ previewKind: "generic",
1448
+ thumbnailStrategy: "icon",
1449
+ color: "text-sky-500",
1450
+ icon: Folder,
1451
+ canPreview: false,
1452
+ previewSizeCapOverride: null,
1453
+ mime: "inode/directory"
1454
+ };
1455
+ const BY_EXTENSION = /* @__PURE__ */ new Map();
1456
+ const BY_MIME = /* @__PURE__ */ new Map();
1457
+ const BY_NAME_EXACT = /* @__PURE__ */ new Map();
1458
+ const BY_NAME_LOWER = /* @__PURE__ */ new Map();
1459
+ const NAME_PREFIX_RULES = [];
1460
+ for (const entry of FILE_TYPES) {
1461
+ for (const ext of entry.extensions)
1462
+ BY_EXTENSION.set(ext.toLowerCase(), entry);
1463
+ if (!BY_MIME.has(entry.mime)) BY_MIME.set(entry.mime, entry);
1464
+ if (entry.aliases) {
1465
+ for (const alias of entry.aliases) {
1466
+ BY_NAME_EXACT.set(alias, entry);
1467
+ const lower = alias.toLowerCase();
1468
+ if (!BY_NAME_LOWER.has(lower)) BY_NAME_LOWER.set(lower, entry);
1469
+ }
1470
+ }
1471
+ if (entry.aliasPrefixes) {
1472
+ for (const prefix of entry.aliasPrefixes) {
1473
+ NAME_PREFIX_RULES.push({ prefix: prefix.toLowerCase(), entry });
1474
+ }
1475
+ }
1476
+ }
1477
+ NAME_PREFIX_RULES.sort((a, b) => b.prefix.length - a.prefix.length);
1478
+ function entryToDetails(entry) {
1479
+ return {
1480
+ category: entry.category,
1481
+ subCategory: entry.subCategory,
1482
+ displayName: entry.displayName,
1483
+ previewKind: entry.previewKind,
1484
+ thumbnailStrategy: entry.thumbnailStrategy,
1485
+ color: entry.color,
1486
+ icon: entry.icon,
1487
+ canPreview: entry.previewKind !== "generic",
1488
+ previewSizeCapOverride: entry.previewSizeCapOverride !== void 0 ? entry.previewSizeCapOverride : null,
1489
+ mime: entry.mime
1490
+ };
1491
+ }
1492
+ function extOf(filename) {
1493
+ const i = filename.lastIndexOf(".");
1494
+ if (i <= 0 || i === filename.length - 1) return "";
1495
+ return filename.slice(i + 1).toLowerCase();
1496
+ }
1497
+ function basenameOf(filename) {
1498
+ const slash = Math.max(filename.lastIndexOf("/"), filename.lastIndexOf("\\"));
1499
+ return slash >= 0 ? filename.slice(slash + 1) : filename;
1500
+ }
1501
+ function resolveEntry(filename) {
1502
+ const name = basenameOf(filename);
1503
+ const exact = BY_NAME_EXACT.get(name);
1504
+ if (exact) return exact;
1505
+ const ci = BY_NAME_LOWER.get(name.toLowerCase());
1506
+ if (ci) return ci;
1507
+ const ext = extOf(name);
1508
+ if (ext) {
1509
+ const byExt = BY_EXTENSION.get(ext);
1510
+ if (byExt) return byExt;
1511
+ }
1512
+ const lower = name.toLowerCase();
1513
+ for (const rule of NAME_PREFIX_RULES) {
1514
+ if (lower.startsWith(rule.prefix)) return rule.entry;
1515
+ }
1516
+ return null;
1517
+ }
1518
+ function dotfileLooksLikeText(filename) {
1519
+ const name = basenameOf(filename);
1520
+ if (!name.startsWith(".")) return false;
1521
+ for (let i = 1; i < name.length; i++) {
1522
+ const c = name.charCodeAt(i);
1523
+ if (c >= 48 && c <= 57 || // 0-9
1524
+ c >= 65 && c <= 90 || // A-Z
1525
+ c >= 97 && c <= 122 || // a-z
1526
+ c === 95 || // _
1527
+ c === 45) {
1528
+ return true;
1529
+ }
1530
+ }
1531
+ return false;
1532
+ }
1533
+ function getFileTypeDetails(filename) {
1534
+ const entry = resolveEntry(filename);
1535
+ if (entry) return entryToDetails(entry);
1536
+ if (dotfileLooksLikeText(filename)) return ASSUMED_TEXT_DETAILS;
1537
+ return UNKNOWN_DETAILS;
1538
+ }
1539
+ function getAssumedTextDetails(filename) {
1540
+ const entry = resolveEntry(filename);
1541
+ if (entry) {
1542
+ const details = entryToDetails(entry);
1543
+ if (details.previewKind === "generic") {
1544
+ return { ...details, previewKind: "text", canPreview: true };
1545
+ }
1546
+ if (details.previewKind === "html") {
1547
+ return { ...details, previewKind: "text" };
1548
+ }
1549
+ return details;
1550
+ }
1551
+ return ASSUMED_TEXT_DETAILS;
1552
+ }
1553
+ function isLikelyTextFilename(filename) {
1554
+ const entry = resolveEntry(filename);
1555
+ if (entry) {
1556
+ return entry.previewKind === "code" || entry.previewKind === "text" || entry.previewKind === "markdown" || entry.previewKind === "data" || // HTML and SVG are markup-under-the-hood. The binary viewer / sniffer
1557
+ // should treat them as text so "View as text" works on edge cases.
1558
+ entry.previewKind === "html" || entry.previewKind === "svg";
1559
+ }
1560
+ return dotfileLooksLikeText(filename);
1561
+ }
1562
+ function getFolderTypeDetails(open = false) {
1563
+ return open ? { ...FOLDER_DETAILS, icon: FolderOpen } : FOLDER_DETAILS;
1564
+ }
1565
+ function canonicalMimeBase(raw) {
1566
+ return raw.split(";")[0]?.trim().toLowerCase() ?? raw;
1567
+ }
1568
+ function mimeFromFilename(filename) {
1569
+ const entry = resolveEntry(filename);
1570
+ return entry ? entry.mime : "application/octet-stream";
1571
+ }
1572
+ function resolveMime(explicit, filename) {
1573
+ if (explicit && explicit !== "application/octet-stream") {
1574
+ return canonicalMimeBase(explicit);
1575
+ }
1576
+ return mimeFromFilename(filename);
1577
+ }
1578
+ function getFilePreviewProfile(fileName, mimeType, fileSize) {
1579
+ const mime = resolveMime(mimeType, fileName);
1580
+ const fromExt = getFileTypeDetails(fileName);
1581
+ const mimeEntry = BY_MIME.get(mime);
1582
+ let baseDetails = fromExt;
1583
+ const genericXmlSvg = fromExt.previewKind === "svg" && (mime === "application/xml" || mime === "text/xml");
1584
+ if (mimeEntry && !genericXmlSvg && (mimeEntry.category !== fromExt.category || mimeEntry.previewKind !== fromExt.previewKind)) {
1585
+ baseDetails = entryToDetails(mimeEntry);
1586
+ }
1587
+ let kind = baseDetails.previewKind;
1588
+ let thumb = baseDetails.thumbnailStrategy;
1589
+ if (mime === "image/svg+xml" || genericXmlSvg) {
1590
+ kind = "svg";
1591
+ thumb = "image";
1592
+ } else if (mime.startsWith("image/")) {
1593
+ kind = "image";
1594
+ thumb = "image";
1595
+ } else if (mime.startsWith("video/")) {
1596
+ kind = "video";
1597
+ thumb = thumb === "icon" ? "video-poster" : thumb;
1598
+ } else if (mime.startsWith("audio/")) {
1599
+ kind = "audio";
1600
+ thumb = "icon";
1601
+ if (baseDetails.category === "VIDEO") {
1602
+ const audioEntry = BY_MIME.get(mime);
1603
+ if (audioEntry) baseDetails = entryToDetails(audioEntry);
1604
+ }
1605
+ } else if (mime === "application/pdf") {
1606
+ kind = "pdf";
1607
+ } else if (kind === "generic" && isTextMime(mime)) {
1608
+ kind = "text";
1609
+ }
1610
+ const canPreviewKind = kind !== "generic";
1611
+ const cap = baseDetails.previewSizeCapOverride ?? // Streamable kinds are always allowed regardless of size. SVG joins the
1612
+ // group: even though it's text underneath, it streams as an image via
1613
+ // its durable URL — never read into memory by the renderer. HTML joins
1614
+ // too: the Rendered view drives a sandboxed iframe on the durable URL
1615
+ // (no client-side blob read), and the Source view fetches the bytes
1616
+ // through the standard blob path which has its own truncation.
1617
+ (kind === "image" || kind === "svg" || kind === "html" || kind === "video" || kind === "audio" || kind === "pdf" || kind === "spreadsheet" || // Office previews are SERVER-extracted (the browser only receives
1618
+ // markdown) — the file's own byte size is irrelevant to the client.
1619
+ kind === "office" ? Number.POSITIVE_INFINITY : MAX_INLINE_PREVIEW_BYTES);
1620
+ const sizeOk = fileSize == null || fileSize <= cap;
1621
+ return {
1622
+ details: { ...baseDetails, previewKind: kind, thumbnailStrategy: thumb },
1623
+ previewKind: kind,
1624
+ canPreview: canPreviewKind && sizeOk,
1625
+ sizeOk,
1626
+ effectiveSizeCap: cap,
1627
+ thumbnailStrategy: thumb,
1628
+ mime
1629
+ };
1630
+ }
1631
+ function isTextMime(mime) {
1632
+ if (mime.startsWith("text/")) return true;
1633
+ return mime === "application/json" || mime === "application/xml" || mime === "application/yaml" || mime === "application/x-yaml" || mime === "application/toml" || mime === "application/sql" || mime === "application/x-subrip" || mime === "message/rfc822";
1634
+ }
1635
+ function isImageMime(mime) {
1636
+ return mime.startsWith("image/");
1637
+ }
1638
+ function isBrowserRenderableImageMime(mime) {
1639
+ return mime === "image/avif" || mime === "image/bmp" || mime === "image/gif" || mime === "image/jpeg" || mime === "image/png" || mime === "image/svg+xml" || mime === "image/webp";
1640
+ }
1641
+ function isVideoMime(mime) {
1642
+ return mime.startsWith("video/");
1643
+ }
1644
+ function isAudioMime(mime) {
1645
+ return mime.startsWith("audio/");
1646
+ }
1647
+ function isPdfMime(mime) {
1648
+ return mime === "application/pdf";
1649
+ }
1650
+ function sniffTextBytes(bytes, sampleSize = 4096) {
1651
+ if (bytes.length === 0) {
1652
+ return { isText: true, confidence: "high", reason: "empty file" };
1653
+ }
1654
+ const sample = bytes.subarray(0, Math.min(sampleSize, bytes.length));
1655
+ if (sample.length >= 3 && sample[0] === 239 && sample[1] === 187 && sample[2] === 191) {
1656
+ return { isText: true, confidence: "high", reason: "UTF-8 BOM" };
1657
+ }
1658
+ if (sample.length >= 2 && (sample[0] === 255 && sample[1] === 254 || sample[0] === 254 && sample[1] === 255)) {
1659
+ return { isText: true, confidence: "high", reason: "UTF-16 BOM" };
1660
+ }
1661
+ if (typeof TextDecoder !== "undefined") {
1662
+ try {
1663
+ new TextDecoder("utf-8", { fatal: true }).decode(sample);
1664
+ return { isText: true, confidence: "high", reason: "valid UTF-8" };
1665
+ } catch {
1666
+ }
1667
+ }
1668
+ let printable = 0;
1669
+ for (let i = 0; i < sample.length; i++) {
1670
+ const b = sample[i];
1671
+ if (b === 0) {
1672
+ return { isText: false, confidence: "high", reason: "null byte" };
1673
+ }
1674
+ if (b === 9 || b === 10 || b === 13 || b >= 32 && b <= 126) {
1675
+ printable++;
1676
+ }
1677
+ }
1678
+ const ratio = printable / sample.length;
1679
+ if (ratio >= 0.95) {
1680
+ return {
1681
+ isText: true,
1682
+ confidence: "medium",
1683
+ reason: `${Math.round(ratio * 100)}% printable`
1684
+ };
1685
+ }
1686
+ return {
1687
+ isText: false,
1688
+ confidence: "low",
1689
+ reason: `only ${Math.round(ratio * 100)}% printable`
1690
+ };
1691
+ }
1692
+ function listSupportedTypes() {
1693
+ return FILE_TYPES.map((e) => ({
1694
+ extensions: e.extensions,
1695
+ mime: e.mime,
1696
+ category: e.category,
1697
+ displayName: e.displayName,
1698
+ previewKind: e.previewKind,
1699
+ thumbnailStrategy: e.thumbnailStrategy,
1700
+ canPreview: e.previewKind !== "generic"
1701
+ }));
1702
+ }
1703
+ export {
1704
+ FILE_TYPES,
1705
+ MAX_INLINE_PREVIEW_BYTES,
1706
+ getAssumedTextDetails,
1707
+ getFilePreviewProfile,
1708
+ getFileTypeDetails,
1709
+ getFolderTypeDetails,
1710
+ isAudioMime,
1711
+ isBrowserRenderableImageMime,
1712
+ isImageMime,
1713
+ isLikelyTextFilename,
1714
+ isPdfMime,
1715
+ isTextMime,
1716
+ isVideoMime,
1717
+ listSupportedTypes,
1718
+ mimeFromFilename,
1719
+ resolveMime,
1720
+ sniffTextBytes
1721
+ };
1722
+ //# sourceMappingURL=file-types.js.map