@ai-matrx/media 0.1.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.
package/dist/core.js ADDED
@@ -0,0 +1,559 @@
1
+ "use client";
2
+
3
+ // src/core/context.ts
4
+ import {
5
+ createContext,
6
+ createElement,
7
+ useContext
8
+ } from "react";
9
+ var CLIENT_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.media.client-context");
10
+ var PORTS_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.media.host-ports-context");
11
+ function clientContext() {
12
+ const host = globalThis;
13
+ host[CLIENT_SLOT] ??= createContext(null);
14
+ return host[CLIENT_SLOT];
15
+ }
16
+ var INERT_PORTS = {};
17
+ function portsContext() {
18
+ const host = globalThis;
19
+ host[PORTS_SLOT] ??= createContext(INERT_PORTS);
20
+ return host[PORTS_SLOT];
21
+ }
22
+ function MediaProvider({ client, ports, children }) {
23
+ const ClientCtx = clientContext();
24
+ const PortsCtx = portsContext();
25
+ return createElement(
26
+ ClientCtx.Provider,
27
+ { value: client },
28
+ createElement(PortsCtx.Provider, { value: ports ?? INERT_PORTS }, children)
29
+ );
30
+ }
31
+ function useMediaClient() {
32
+ const client = useContext(clientContext());
33
+ if (!client) {
34
+ throw new Error(
35
+ "@ai-matrx/media: no MediaClient. Mount <MediaProvider client={...}> above every media surface (canonically wired to @ai-matrx/data/files)."
36
+ );
37
+ }
38
+ return client;
39
+ }
40
+ function useMediaHostPorts() {
41
+ return useContext(portsContext());
42
+ }
43
+
44
+ // src/core/ref-key.ts
45
+ function stableRefKey(ref) {
46
+ if (!ref) return "<none>";
47
+ if (typeof ref === "string") return `s:${ref}`;
48
+ if (ref.file_id) return `id:${ref.file_id}:${ref.mime_type ?? ""}`;
49
+ if (ref.url) return `url:${ref.url}:${ref.mime_type ?? ""}`;
50
+ return "<empty-ref>";
51
+ }
52
+
53
+ // src/core/use-media-resolution.ts
54
+ import { useMemo } from "react";
55
+ function useMediaResolution(ref) {
56
+ const client = useMediaClient();
57
+ const refKey = stableRefKey(ref);
58
+ return useMemo(() => {
59
+ if (!ref) return { resolution: null, status: "empty", reason: null };
60
+ try {
61
+ const resolution = client.resolve(ref);
62
+ if (!resolution) return { resolution: null, status: "empty", reason: null };
63
+ return { resolution, status: "ready", reason: null };
64
+ } catch (err) {
65
+ return {
66
+ resolution: null,
67
+ status: "unavailable",
68
+ reason: client.classifyError(err)
69
+ };
70
+ }
71
+ }, [client, refKey]);
72
+ }
73
+
74
+ // src/core/use-media-load-recovery.ts
75
+ import { useEffect, useRef, useState } from "react";
76
+
77
+ // src/types.ts
78
+ function mintDurableSrc(url) {
79
+ return url;
80
+ }
81
+
82
+ // src/core/use-media-load-recovery.ts
83
+ function useMediaLoadRecovery(src, options) {
84
+ const client = useMediaClient();
85
+ const recoverable = options?.recoverable !== false;
86
+ const onTerminal = options?.onTerminal;
87
+ const [result, setResult] = useState({ source: src, retryKey: 0, failed: false });
88
+ const attemptRef = useRef(0);
89
+ useEffect(() => {
90
+ attemptRef.current = 0;
91
+ }, [src]);
92
+ const onLoadError = (event) => {
93
+ if (!src || !recoverable) {
94
+ setResult({ source: src, retryKey: 0, failed: true });
95
+ onTerminal?.(event);
96
+ return;
97
+ }
98
+ attemptRef.current += 1;
99
+ const attempt = attemptRef.current;
100
+ client.recoverLoadError(mintDurableSrc(src), attempt).then(
101
+ (verdict) => {
102
+ if (verdict === "retry") {
103
+ setResult((current) => ({
104
+ source: src,
105
+ retryKey: current.source === src ? current.retryKey + 1 : 1,
106
+ failed: false
107
+ }));
108
+ } else {
109
+ setResult({ source: src, retryKey: 0, failed: true });
110
+ onTerminal?.(event);
111
+ }
112
+ },
113
+ () => {
114
+ setResult({ source: src, retryKey: 0, failed: true });
115
+ onTerminal?.(event);
116
+ }
117
+ );
118
+ };
119
+ return {
120
+ retryKey: result.source === src ? result.retryKey : 0,
121
+ onLoadError,
122
+ failed: result.source === src ? result.failed : false
123
+ };
124
+ }
125
+
126
+ // src/core/use-media-blob.ts
127
+ import { useEffect as useEffect2, useState as useState2 } from "react";
128
+ function useMediaBlob(ref) {
129
+ const client = useMediaClient();
130
+ const refKey = stableRefKey(ref);
131
+ const [state, setState] = useState2({ url: null, blob: null, loading: !!ref, error: null });
132
+ const [retryToken, setRetryToken] = useState2(0);
133
+ useEffect2(() => {
134
+ if (!ref) {
135
+ setState({ url: null, blob: null, loading: false, error: null });
136
+ return void 0;
137
+ }
138
+ let cancelled = false;
139
+ let release = null;
140
+ setState({ url: null, blob: null, loading: true, error: null });
141
+ client.getBlob(ref).then(
142
+ (handle) => {
143
+ if (cancelled) {
144
+ handle.release();
145
+ return;
146
+ }
147
+ release = handle.release;
148
+ setState({ url: handle.url, blob: handle.blob, loading: false, error: null });
149
+ },
150
+ (err) => {
151
+ if (cancelled) return;
152
+ const message = err instanceof Error ? err.message : String(err ?? "Failed to load file");
153
+ setState({ url: null, blob: null, loading: false, error: message });
154
+ }
155
+ );
156
+ return () => {
157
+ cancelled = true;
158
+ release?.();
159
+ };
160
+ }, [client, refKey, retryToken]);
161
+ return {
162
+ ...state,
163
+ retry: () => setRetryToken((t) => t + 1)
164
+ };
165
+ }
166
+
167
+ // src/core/use-media-upload.ts
168
+ import { useCallback, useRef as useRef2, useState as useState3 } from "react";
169
+ var entrySeq = 0;
170
+ function useMediaUpload() {
171
+ const client = useMediaClient();
172
+ const [uploading, setUploading] = useState3(false);
173
+ const [progress, setProgress] = useState3(null);
174
+ const [result, setResult] = useState3(null);
175
+ const [error, setError] = useState3(null);
176
+ const [entries, setEntries] = useState3([]);
177
+ const activeCount = useRef2(0);
178
+ const patchEntry = useCallback(
179
+ (id, patch) => {
180
+ setEntries(
181
+ (current) => current.map((e) => e.id === id ? { ...e, ...patch } : e)
182
+ );
183
+ },
184
+ []
185
+ );
186
+ const upload = useCallback(
187
+ async (file, opts = {}) => {
188
+ const id = `up-${++entrySeq}`;
189
+ const fileName = opts.fileName ?? (file instanceof File ? file.name : "file");
190
+ setEntries((current) => [
191
+ ...current,
192
+ {
193
+ id,
194
+ fileName,
195
+ fileSize: file.size,
196
+ bytesUploaded: 0,
197
+ status: "uploading",
198
+ error: null,
199
+ fileId: null,
200
+ completedAt: null
201
+ }
202
+ ]);
203
+ activeCount.current += 1;
204
+ setUploading(true);
205
+ setError(null);
206
+ setProgress(null);
207
+ try {
208
+ const uploaded = await client.upload(file, {
209
+ ...opts,
210
+ onProgress: (loaded, total) => {
211
+ setProgress({ loaded, total, ratio: total > 0 ? loaded / total : 0 });
212
+ patchEntry(id, { bytesUploaded: loaded });
213
+ opts.onProgress?.(loaded, total);
214
+ }
215
+ });
216
+ setResult(uploaded);
217
+ patchEntry(id, {
218
+ status: "success",
219
+ fileId: uploaded.fileId,
220
+ bytesUploaded: file.size,
221
+ completedAt: Date.now()
222
+ });
223
+ return uploaded;
224
+ } catch (err) {
225
+ const e = err instanceof Error ? err : new Error(String(err));
226
+ setError(e);
227
+ patchEntry(id, {
228
+ status: "error",
229
+ error: e.message,
230
+ completedAt: Date.now()
231
+ });
232
+ throw e;
233
+ } finally {
234
+ activeCount.current -= 1;
235
+ if (activeCount.current <= 0) setUploading(false);
236
+ }
237
+ },
238
+ [client, patchEntry]
239
+ );
240
+ const uploadMany = useCallback(
241
+ async (files, opts = {}) => {
242
+ if (client.uploadMany) {
243
+ activeCount.current += 1;
244
+ setUploading(true);
245
+ try {
246
+ return await client.uploadMany(files, opts);
247
+ } finally {
248
+ activeCount.current -= 1;
249
+ if (activeCount.current <= 0) setUploading(false);
250
+ }
251
+ }
252
+ const uploaded = [];
253
+ const failed = [];
254
+ for (const file of files) {
255
+ try {
256
+ const one = await upload(file, opts);
257
+ uploaded.push(one.fileId);
258
+ } catch (err) {
259
+ failed.push({
260
+ name: file.name,
261
+ error: err instanceof Error ? err.message : String(err)
262
+ });
263
+ }
264
+ }
265
+ return { uploaded, failed, cancelled: false };
266
+ },
267
+ [client, upload]
268
+ );
269
+ const clearEntry = useCallback((id) => {
270
+ setEntries((current) => current.filter((e) => e.id !== id));
271
+ }, []);
272
+ const reset = useCallback(() => {
273
+ setResult(null);
274
+ setError(null);
275
+ setProgress(null);
276
+ setEntries([]);
277
+ }, []);
278
+ return {
279
+ upload,
280
+ uploadMany,
281
+ uploading,
282
+ progress,
283
+ result,
284
+ error,
285
+ entries,
286
+ clearEntry,
287
+ reset
288
+ };
289
+ }
290
+
291
+ // src/core/use-thumbnail-source.ts
292
+ import { useMemo as useMemo2 } from "react";
293
+ function useThumbnailSource(ref, options = {}) {
294
+ const { thumbnailUrl, allowSourceFallback = true } = options;
295
+ const client = useMediaClient();
296
+ const { resolution } = useMediaResolution(ref);
297
+ const explicitThumb = useMemo2(() => {
298
+ if (!thumbnailUrl) return null;
299
+ try {
300
+ return client.resolve(thumbnailUrl);
301
+ } catch {
302
+ return null;
303
+ }
304
+ }, [client, thumbnailUrl]);
305
+ const needsBlob = allowSourceFallback && !explicitThumb && !resolution?.thumbnailSrc && resolution?.transport === "blob";
306
+ const blob = useMediaBlob(needsBlob ? ref : null);
307
+ if (explicitThumb) {
308
+ return {
309
+ src: explicitThumb.src,
310
+ mode: "thumbnail",
311
+ loading: false,
312
+ resolution,
313
+ recoverable: explicitThumb.recoverable !== false
314
+ };
315
+ }
316
+ if (resolution?.thumbnailSrc) {
317
+ return {
318
+ src: resolution.thumbnailSrc,
319
+ mode: "thumbnail",
320
+ loading: false,
321
+ resolution,
322
+ recoverable: resolution.recoverable !== false
323
+ };
324
+ }
325
+ if (allowSourceFallback && resolution) {
326
+ if (needsBlob) {
327
+ return {
328
+ src: blob.url,
329
+ mode: blob.url ? resolution.kind === "video" ? "live-video-poster" : "live-image" : "icon",
330
+ loading: blob.loading,
331
+ resolution,
332
+ recoverable: false
333
+ };
334
+ }
335
+ if (resolution.kind === "image") {
336
+ return {
337
+ src: resolution.src,
338
+ mode: "live-image",
339
+ loading: false,
340
+ resolution,
341
+ recoverable: resolution.recoverable !== false
342
+ };
343
+ }
344
+ if (resolution.kind === "video") {
345
+ return {
346
+ src: resolution.src,
347
+ mode: "live-video-poster",
348
+ loading: false,
349
+ resolution,
350
+ recoverable: resolution.recoverable !== false
351
+ };
352
+ }
353
+ }
354
+ return {
355
+ src: null,
356
+ mode: "icon",
357
+ loading: false,
358
+ resolution,
359
+ recoverable: false
360
+ };
361
+ }
362
+
363
+ // src/core/use-media-actions.ts
364
+ import { useCallback as useCallback2, useMemo as useMemo3, useState as useState4 } from "react";
365
+ function useMediaActions(ref, options = {}) {
366
+ const ports = useMediaHostPorts();
367
+ const { resolution } = useMediaResolution(ref);
368
+ const [busy, setBusy] = useState4(null);
369
+ const [lastError, setLastError] = useState4(null);
370
+ const actions = ports.actions;
371
+ const { fileName, alt } = options;
372
+ const context = useMemo3(() => {
373
+ if (!ref) return null;
374
+ return { ref, resolution, fileName, alt };
375
+ }, [ref, resolution, fileName, alt]);
376
+ const isAvailable = useCallback2(
377
+ (kind) => {
378
+ if (!context || !actions) return false;
379
+ if (kind === "share") return Boolean(actions.share || actions.SharePopover);
380
+ return Boolean(actions[kind]);
381
+ },
382
+ [context, actions]
383
+ );
384
+ const run = useCallback2(
385
+ async (kind) => {
386
+ if (!context || !actions) return;
387
+ const handler = actions[kind];
388
+ if (!handler) return;
389
+ setBusy(kind);
390
+ setLastError(null);
391
+ try {
392
+ await handler(context);
393
+ } catch (err) {
394
+ setLastError({
395
+ kind,
396
+ message: err instanceof Error ? err.message : String(err)
397
+ });
398
+ } finally {
399
+ setBusy(null);
400
+ }
401
+ },
402
+ [context, actions]
403
+ );
404
+ return {
405
+ context,
406
+ isAvailable,
407
+ run,
408
+ busy,
409
+ lastError,
410
+ SharePopover: actions?.SharePopover ?? null
411
+ };
412
+ }
413
+
414
+ // src/core/file-kind.ts
415
+ var ROWS = [
416
+ [["jpg", "jpeg", "png", "gif", "webp", "avif", "heic", "heif", "bmp", "tif", "tiff", "ico"], "IMAGE", "text-emerald-500", "image", "Image"],
417
+ [["svg"], "IMAGE", "text-amber-500", "pen-tool", "SVG image"],
418
+ [["mp4", "mov", "webm", "mkv", "avi", "m4v"], "VIDEO", "text-purple-500", "video", "Video"],
419
+ [["mp3", "wav", "ogg", "m4a", "aac", "flac", "opus"], "AUDIO", "text-pink-500", "music", "Audio"],
420
+ [["pdf"], "DOCUMENT", "text-red-500", "file-type", "PDF Document"],
421
+ [["md", "markdown", "mdx", "rst", "adoc", "asciidoc", "org"], "DOCUMENT", "text-slate-400", "file-text", "Markdown"],
422
+ [["txt", "text", "asc", "me", "log", "out", "err"], "DOCUMENT", "text-muted-foreground", "file-text", "Text"],
423
+ [["dockerfile", "containerfile", "lua"], "CODE", "text-blue-500", "code", "Code"],
424
+ [["mk", "make", "swift", "ml", "mli", "fs", "fsi", "fsx", "svelte"], "CODE", "text-orange-500", "code", "Code"],
425
+ [["diff", "patch", "pem", "csr", "crt", "cer", "der", "key", "pub", "p7b", "p7c", "pfx", "p12"], "CODE", "text-amber-500", "file-text", "Text"],
426
+ [["ini", "cfg", "conf", "config", "properties", "prefs"], "CODE", "text-amber-400", "braces", "Config"],
427
+ [["tex", "latex", "ltx", "sty", "cls", "bib"], "CODE", "text-emerald-500", "file-text", "LaTeX"],
428
+ [["srt", "vtt"], "SUBTITLES", "text-cyan-500", "subtitles", "Subtitles"],
429
+ [["js", "mjs", "cjs", "jsx"], "CODE", "text-yellow-500", "file-code", "JavaScript"],
430
+ [["ts", "tsx"], "CODE", "text-blue-500", "file-code", "TypeScript"],
431
+ [["py", "clj", "cljs", "cljc", "edn", "vue", "styl", "stylus"], "CODE", "text-emerald-500", "code", "Code"],
432
+ [["rb", "rbw", "rake", "ru", "gemspec", "scala", "sbt"], "CODE", "text-red-500", "code", "Code"],
433
+ [["go", "dart"], "CODE", "text-cyan-500", "code", "Code"],
434
+ [["rs"], "CODE", "text-orange-600", "code", "Rust"],
435
+ [["java"], "CODE", "text-red-600", "code", "Java"],
436
+ [["c", "h"], "CODE", "text-blue-600", "code", "C"],
437
+ [["cpp", "cc", "cxx", "hpp"], "CODE", "text-blue-700", "code", "C++"],
438
+ [["cs"], "CODE", "text-purple-600", "code", "C#"],
439
+ [["html", "htm", "kt", "kts"], "CODE", "text-orange-400", "code", "Code"],
440
+ [["css"], "CODE", "text-sky-400", "code", "CSS"],
441
+ [["scss"], "CODE", "text-pink-400", "code", "SCSS"],
442
+ [["sh", "bash", "zsh", "fish", "ksh", "ash", "bat", "cmd", "twig", "jinja", "j2", "njk"], "CODE", "text-emerald-400", "code", "Script"],
443
+ [["sql"], "CODE", "text-amber-400", "code", "SQL"],
444
+ [["pl", "pm"], "CODE", "text-indigo-400", "code", "Perl"],
445
+ [["r", "rmd", "proto", "ps1", "psm1", "psd1", "less"], "CODE", "text-blue-400", "code", "Code"],
446
+ [["ex", "exs"], "CODE", "text-purple-400", "code", "Elixir"],
447
+ [["erl", "hrl"], "CODE", "text-rose-500", "code", "Erlang"],
448
+ [["hs", "lhs"], "CODE", "text-violet-500", "code", "Haskell"],
449
+ [["zig"], "CODE", "text-yellow-500", "code", "Zig"],
450
+ [["nim", "nims"], "CODE", "text-yellow-400", "code", "Nim"],
451
+ [["jl"], "CODE", "text-purple-500", "code", "Julia"],
452
+ [["astro"], "CODE", "text-fuchsia-500", "code", "Astro"],
453
+ [["graphql", "gql", "graphqls"], "CODE", "text-pink-500", "code", "GraphQL"],
454
+ [["sol"], "CODE", "text-slate-400", "code", "Solidity"],
455
+ [["php", "phtml", "phps"], "CODE", "text-indigo-500", "code", "PHP"],
456
+ [["hbs", "handlebars", "mustache", "ejs", "liquid"], "CODE", "text-amber-500", "code", "Template"],
457
+ [["json", "jsonc", "json5", "har", "geojson", "topojson"], "DATA", "text-amber-500", "file-json", "JSON"],
458
+ [["yaml", "yml", "toml"], "CODE", "text-amber-500", "braces", "Config"],
459
+ [["xml"], "DATA", "text-amber-500", "braces", "XML"],
460
+ [["csv", "tsv"], "DATA", "text-orange-500", "file-spreadsheet", "Spreadsheet data"],
461
+ [["sqlite", "sqlite3", "db"], "DATA", "text-blue-400", "database", "Database"],
462
+ [["ttl", "n3", "nt", "nq", "trig"], "DATA", "text-fuchsia-400", "braces", "RDF data"],
463
+ [["xlsx", "xls"], "DOCUMENT", "text-emerald-600", "file-spreadsheet", "Excel workbook"],
464
+ [["doc", "docx"], "DOCUMENT", "text-blue-500", "file-text", "Word document"],
465
+ [["ppt", "pptx"], "DOCUMENT", "text-orange-600", "file-type", "Presentation"],
466
+ [["ipynb"], "NOTEBOOK", "text-orange-400", "file-json", "Notebook"],
467
+ [["epub"], "EBOOK", "text-indigo-500", "file-text", "eBook"],
468
+ [["eml"], "EMAIL", "text-blue-400", "file-text", "Email"],
469
+ [["glb", "gltf", "stl", "obj", "fbx"], "MODEL_3D", "text-violet-400", "package", "3D model"],
470
+ [["zip", "rar", "7z"], "ARCHIVE", "text-amber-600", "archive", "Archive"],
471
+ [["tar", "gz", "tgz"], "ARCHIVE", "text-amber-600", "package", "Archive"]
472
+ ];
473
+ var BY_EXTENSION = /* @__PURE__ */ new Map();
474
+ for (const [extensions, category, colorClass, icon, displayName] of ROWS) {
475
+ for (const ext of extensions) {
476
+ BY_EXTENSION.set(ext, { category, colorClass, icon, displayName });
477
+ }
478
+ }
479
+ var UNKNOWN_DETAILS = {
480
+ category: "UNKNOWN",
481
+ displayName: "File",
482
+ colorClass: "text-muted-foreground",
483
+ icon: "file"
484
+ };
485
+ var ASSUMED_TEXT_DETAILS = {
486
+ category: "DOCUMENT",
487
+ displayName: "Text",
488
+ colorClass: "text-muted-foreground",
489
+ icon: "file-text"
490
+ };
491
+ var FOLDER_DETAILS = {
492
+ category: "FOLDER",
493
+ displayName: "Folder",
494
+ colorClass: "text-sky-500",
495
+ icon: "folder"
496
+ };
497
+ var IMAGE_DETAILS = BY_EXTENSION.get("png");
498
+ var VIDEO_DETAILS = BY_EXTENSION.get("mp4");
499
+ var AUDIO_DETAILS = BY_EXTENSION.get("mp3");
500
+ var PDF_DETAILS = BY_EXTENSION.get("pdf");
501
+ var SVG_DETAILS = BY_EXTENSION.get("svg");
502
+ function basenameOf(path) {
503
+ const idx = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
504
+ return idx >= 0 ? path.slice(idx + 1) : path;
505
+ }
506
+ function extOf(name) {
507
+ const idx = name.lastIndexOf(".");
508
+ if (idx <= 0 || idx === name.length - 1) return null;
509
+ return name.slice(idx + 1).toLowerCase();
510
+ }
511
+ function dotfileLooksLikeText(filename) {
512
+ const name = basenameOf(filename);
513
+ if (!name.startsWith(".")) return false;
514
+ for (let i = 1; i < name.length; i++) {
515
+ const c = name.charCodeAt(i);
516
+ if (c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122 || c === 95 || c === 45) {
517
+ return true;
518
+ }
519
+ }
520
+ return false;
521
+ }
522
+ function canonicalMimeBase(raw) {
523
+ return raw.split(";")[0]?.trim().toLowerCase() ?? raw;
524
+ }
525
+ function getFileKindDetails(fileName, mimeType) {
526
+ const name = basenameOf(fileName);
527
+ const lower = name.toLowerCase();
528
+ const ext = lower === "dockerfile" || lower === "containerfile" ? lower : extOf(name);
529
+ const fromExt = ext ? BY_EXTENSION.get(ext) : void 0;
530
+ const mime = mimeType ? canonicalMimeBase(mimeType) : null;
531
+ if (mime) {
532
+ if (mime === "image/svg+xml") return fromExt ?? SVG_DETAILS;
533
+ if (mime.startsWith("image/")) return fromExt?.category === "IMAGE" ? fromExt : IMAGE_DETAILS;
534
+ if (mime.startsWith("video/")) return fromExt?.category === "VIDEO" ? fromExt : VIDEO_DETAILS;
535
+ if (mime.startsWith("audio/")) return fromExt?.category === "AUDIO" ? fromExt : AUDIO_DETAILS;
536
+ if (mime === "application/pdf") return PDF_DETAILS;
537
+ }
538
+ if (fromExt) return fromExt;
539
+ if (dotfileLooksLikeText(fileName)) return ASSUMED_TEXT_DETAILS;
540
+ return UNKNOWN_DETAILS;
541
+ }
542
+ function getFolderKindDetails(open = false) {
543
+ return open ? { ...FOLDER_DETAILS, icon: "folder-open" } : FOLDER_DETAILS;
544
+ }
545
+ export {
546
+ MediaProvider,
547
+ getFileKindDetails,
548
+ getFolderKindDetails,
549
+ stableRefKey,
550
+ useMediaActions,
551
+ useMediaBlob,
552
+ useMediaClient,
553
+ useMediaHostPorts,
554
+ useMediaLoadRecovery,
555
+ useMediaResolution,
556
+ useMediaUpload,
557
+ useThumbnailSource
558
+ };
559
+ //# sourceMappingURL=core.js.map