@devultur/convex 1.4.3 → 1.5.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.
- package/README.md +123 -7
- package/dist/chunk-BDEO67OT.js +110 -0
- package/dist/{chunk-JZYKPLI4.js → chunk-RDVBE3G3.js} +20 -1
- package/dist/component/http.js +2 -2
- package/dist/component/library.d.ts +2 -2
- package/dist/component/library.js +3 -3
- package/dist/component/lock.js +3 -3
- package/dist/component/mediaClient.js +1 -1
- package/dist/component/metadata.js +2 -2
- package/dist/component/public.js +9 -9
- package/dist/component/uploads.js +6 -6
- package/dist/component/workerErrors.d.ts +1 -1
- package/dist/component/workerErrors.js +1 -1
- package/dist/hooks-uqpBd5UF.d.ts +171 -0
- package/dist/index.d.ts +74 -20
- package/dist/index.js +23 -4
- package/dist/locales/es-formal.d.ts +5 -3
- package/dist/locales/es-formal.js +6 -3
- package/dist/locales/es.d.ts +5 -3
- package/dist/locales/es.js +5 -3
- package/dist/{preview-labels-B7HNa7Va.d.ts → preview-labels-C2nUUY_f.d.ts} +1 -1
- package/dist/react/hooks.d.ts +6 -0
- package/dist/react/hooks.js +23 -0
- package/dist/react.d.ts +157 -275
- package/dist/react.js +958 -931
- package/dist/{types-DZxN6Eij.d.ts → types-C0ruHUcu.d.ts} +14 -8
- package/docs/guides/object-lock.md +517 -0
- package/docs/guides/plugins.md +205 -0
- package/docs/guides/self-host.md +523 -0
- package/docs/guides/video-player.md +105 -0
- package/package.json +10 -5
package/dist/react.d.ts
CHANGED
|
@@ -1,59 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { V as VideoProps, a as ViewerTokenAction, b as ViewerTokenArgs, D as DevulturApi } from './hooks-uqpBd5UF.js';
|
|
3
|
+
export { c as DevulturApiContext, d as DevulturContext, e as DevulturContextValue, f as DevulturProgressContext, g as DevulturProgressContextValue, T as TokenStatus, U as UploadOptions, h as UploadedMedia, i as ViewerTokenResult, u as useDevultur, j as useDevulturApi, k as useDevulturOptional, l as useDevulturProgress, m as useMediaUrl, n as useVideoProps } from './hooks-uqpBd5UF.js';
|
|
4
|
+
import { BakeOutputFormat, MediaUploadState, MediaUploadError } from '@devultur/react';
|
|
4
5
|
export { MediaUploadError, MediaUploadState, UploadProgress } from '@devultur/react';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
import { M as MediaRecord } from './types-DZxN6Eij.js';
|
|
6
|
+
import { A as AttachmentLabels, b as MediaFetchError, M as MediaLibraryLabels, P as PreviewLabels, a as MediaPickerLabels } from './preview-labels-C2nUUY_f.js';
|
|
7
|
+
export { c as AttachmentKind, d as MediaFetchErrorCode, e as defaultAttachmentLabels, f as defaultMediaLibraryLabels, g as defaultMediaPickerLabels, h as defaultPreviewLabels, i as formatDuration, j as formatFileSize } from './preview-labels-C2nUUY_f.js';
|
|
8
|
+
import { Visibility, DevulturMedia, MediaUrlOptions, MediaStatusValue, ProcessingPhase, FailureReason } from '@devultur/core';
|
|
9
|
+
import { M as MediaRecord } from './types-C0ruHUcu.js';
|
|
10
10
|
import { P as PdfjsLoader } from './pdf-render-BwJGagvz.js';
|
|
11
11
|
export { a as PdfjsModule } from './pdf-render-BwJGagvz.js';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
type ViewerTokenResult = {
|
|
15
|
-
token: string;
|
|
16
|
-
expiresIn: number;
|
|
17
|
-
} | string;
|
|
18
|
-
/** Extra arguments sent with `sessionSecret` to the viewer token action. */
|
|
19
|
-
type ViewerTokenArgs = Record<string, Value>;
|
|
20
|
-
/**
|
|
21
|
-
* Where the viewer token for the current `tokenArgs` stands: not requested yet, being issued (no token yet), held, or
|
|
22
|
-
* failed (the action threw or returned no token). A renewal in flight, or one that failed, keeps `"ready"`.
|
|
23
|
-
*/
|
|
24
|
-
type TokenStatus = "idle" | "loading" | "ready" | "error";
|
|
25
|
-
|
|
26
|
-
/** Transform/delivery options for media URLs (without `token`, which the context injects). */
|
|
27
|
-
type MediaRenderOptions = Omit<MediaUrlOptions, "token">;
|
|
28
|
-
/**
|
|
29
|
-
* The viewer token action: the component's `issueViewerToken` (as `defineDevulturFunctions` or `exposeApi` export it,
|
|
30
|
-
* where `sessionSecret` is optional) or an app's own, which may require it. The providers always send it.
|
|
31
|
-
*/
|
|
32
|
-
type ViewerTokenAction = FunctionReference<"action", "public", {
|
|
33
|
-
sessionSecret?: string;
|
|
34
|
-
}>;
|
|
35
|
-
interface MediaSession {
|
|
36
|
-
token: string | null;
|
|
37
|
-
/** Where the viewer token stands; `"error"` makes private previews fail fast with `token_unavailable`. */
|
|
38
|
-
tokenStatus: TokenStatus;
|
|
39
|
-
/** Why the last issuance failed (the action threw or returned no token), while `tokenStatus` is `"error"`. */
|
|
40
|
-
tokenError: Error | null;
|
|
41
|
-
/** Issues the viewer token again (after a failure, for example). Resolves to the new token, or `null`. */
|
|
42
|
-
retryToken: () => Promise<string | null>;
|
|
43
|
-
baseUrl: string | null;
|
|
44
|
-
/** Browser session secret → sent in `${SESSION_HEADER}` on every private delivery. */
|
|
45
|
-
sessionSecret: string;
|
|
46
|
-
/** Delivery URL from a reference (non-hook → usable in handlers and `.map`). Token-transparent. */
|
|
47
|
-
url: (media: DevulturMedia, options?: MediaRenderOptions) => string;
|
|
48
|
-
/** Downloads a video's subtitle text for a locale (auth-transparent). */
|
|
49
|
-
getCaptionsText: (media: DevulturMedia, locale: string) => Promise<string>;
|
|
50
|
-
/**
|
|
51
|
-
* Re-issues the viewer token (new session fingerprint with the current UA/IP) and updates the context.
|
|
52
|
-
* Single-flight: concurrent calls share the same issuance. Returns the new token (or null if it
|
|
53
|
-
* failed). The render uses it to transparently recover from a 401 `session_mismatch`.
|
|
54
|
-
*/
|
|
55
|
-
reissueToken: () => Promise<string | null>;
|
|
56
|
-
}
|
|
12
|
+
import 'convex/server';
|
|
13
|
+
import 'convex/values';
|
|
57
14
|
|
|
58
15
|
/** What `useDevultur()` can do only under a `<DevulturProvider>` given the matching actions. */
|
|
59
16
|
type DevulturCapability = "upload" | "uploadUrl" | "deleteMedia" | "api";
|
|
@@ -159,6 +116,27 @@ interface AttachmentCardProps extends Omit<React.HTMLAttributes<HTMLElement>, "c
|
|
|
159
116
|
*/
|
|
160
117
|
declare function AttachmentCard({ media, contentType, onOpen, preview, headingLevel, locale, labels, ...articleProps }: AttachmentCardProps): React.JSX.Element | null;
|
|
161
118
|
|
|
119
|
+
interface DownloadLinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href" | "download" | "media"> {
|
|
120
|
+
media: DevulturMedia | null | undefined;
|
|
121
|
+
/** Name it downloads as. Without this it uses the upload's original name. */
|
|
122
|
+
filename?: string;
|
|
123
|
+
/**
|
|
124
|
+
* A private download that failed: `token_unavailable` right away when the viewer token couldn't be issued
|
|
125
|
+
* (`useDevultur().retryToken()` tries again), `http_error` when the delivery refused it.
|
|
126
|
+
*/
|
|
127
|
+
onDownloadError?: (error: MediaFetchError) => void;
|
|
128
|
+
children: React.ReactNode;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* `<a>` that downloads a media with its original name (token-transparent). The worker serves it with
|
|
132
|
+
* `Content-Disposition: attachment`, so a click downloads the file instead of opening it in a tab.
|
|
133
|
+
*
|
|
134
|
+
* Private: an `<a download>` NAVIGATES, and a navigation can't send `${SESSION_HEADER}` → with session
|
|
135
|
+
* binding the gate gives a 401. So, for private media, we intercept the click, blob-fetch with the header
|
|
136
|
+
* (like private `<Image>`) and trigger the download from the object URL. Public keeps native navigation.
|
|
137
|
+
*/
|
|
138
|
+
declare function DownloadLink({ media, filename, onDownloadError, children, ...anchorProps }: DownloadLinkProps): React.JSX.Element | null;
|
|
139
|
+
|
|
162
140
|
/** An explicit `srcSet` is passed through to the `<img>` as is, and wins over the one `widths` builds. */
|
|
163
141
|
interface ImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src" | "width" | "height"> {
|
|
164
142
|
/** Typed reference. `null`/`undefined` → renders `fallback` (or `externalFallback`). Its `alt` is the default `alt`. */
|
|
@@ -200,6 +178,68 @@ interface ImageProps extends Omit<React.ImgHTMLAttributes<HTMLImageElement>, "sr
|
|
|
200
178
|
*/
|
|
201
179
|
declare function Image({ media, width, height, fit, format, quality, widths, sizes, fallback, externalFallback, render, alt, onLoadError, ...imgProps }: ImageProps): React.JSX.Element;
|
|
202
180
|
|
|
181
|
+
interface MediaStatusReturn {
|
|
182
|
+
status: MediaStatusValue;
|
|
183
|
+
/** Typed progress: `phase` is the pipeline step (no `as any`). */
|
|
184
|
+
progress: {
|
|
185
|
+
current: number;
|
|
186
|
+
total: number;
|
|
187
|
+
percent: number;
|
|
188
|
+
phase?: ProcessingPhase;
|
|
189
|
+
} | null;
|
|
190
|
+
error: string | null;
|
|
191
|
+
/** Categorized failure reason (null if it didn't fail). */
|
|
192
|
+
failureReason: FailureReason | null;
|
|
193
|
+
/** Whether the failure is retriable (null if it didn't fail). */
|
|
194
|
+
retriable: boolean | null;
|
|
195
|
+
isQueued: boolean;
|
|
196
|
+
isTranscoding: boolean;
|
|
197
|
+
isCaptioning: boolean;
|
|
198
|
+
isReady: boolean;
|
|
199
|
+
isFailed: boolean;
|
|
200
|
+
playlistUrl: string | null;
|
|
201
|
+
thumbnailKey: string | null;
|
|
202
|
+
captionLocales: string[];
|
|
203
|
+
duration: number | null;
|
|
204
|
+
isLoading: boolean;
|
|
205
|
+
}
|
|
206
|
+
declare function useDevulturMedia(key: string | null | undefined): MediaStatusReturn;
|
|
207
|
+
interface CaptionTrack {
|
|
208
|
+
locale: string;
|
|
209
|
+
label: string;
|
|
210
|
+
src: string;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* A video's pipeline state as a **discriminated union** on `phase`: the render is an exhaustive
|
|
214
|
+
* `switch` (no boolean ordering or `as any`), and adding a new phase is a compile error until it's
|
|
215
|
+
* handled. `processing` carries typed `step`/`percent`; `ready` carries the ref + props ready for
|
|
216
|
+
* `<VideoPlayer>` (token-transparent); `failed` carries a categorized `reason` + `retriable`.
|
|
217
|
+
*/
|
|
218
|
+
type VideoState = {
|
|
219
|
+
phase: "idle";
|
|
220
|
+
} | {
|
|
221
|
+
phase: "queued";
|
|
222
|
+
} | {
|
|
223
|
+
phase: "processing";
|
|
224
|
+
step: ProcessingPhase;
|
|
225
|
+
percent: number;
|
|
226
|
+
} | {
|
|
227
|
+
phase: "ready";
|
|
228
|
+
media: DevulturMedia;
|
|
229
|
+
playlist: string;
|
|
230
|
+
duration: number;
|
|
231
|
+
captions: CaptionTrack[];
|
|
232
|
+
playerProps: VideoProps;
|
|
233
|
+
} | {
|
|
234
|
+
phase: "failed";
|
|
235
|
+
reason: FailureReason;
|
|
236
|
+
message: string;
|
|
237
|
+
retriable: boolean;
|
|
238
|
+
};
|
|
239
|
+
declare function useVideoState(media: DevulturMedia | null | undefined, options?: {
|
|
240
|
+
locales?: string[];
|
|
241
|
+
}): VideoState;
|
|
242
|
+
|
|
203
243
|
/** What `renderItem` gets besides the record. */
|
|
204
244
|
interface MediaLibraryItemState {
|
|
205
245
|
/** The record's reference (`mediaFromRecord`), `null` for a record without a visibility. */
|
|
@@ -528,6 +568,11 @@ interface PreviewProps {
|
|
|
528
568
|
pdfWorkerSrc?: string;
|
|
529
569
|
/** Overrides any string shown or announced; wins over `PdfPreviewProvider`'s `labels`. English by default. */
|
|
530
570
|
labels?: Partial<PreviewLabels>;
|
|
571
|
+
/**
|
|
572
|
+
* A video's playback metrics (`<VideoPlayer metrics>`): anonymous, no cookies, sent to the media host. On by
|
|
573
|
+
* default; `false` turns them off.
|
|
574
|
+
*/
|
|
575
|
+
metrics?: boolean;
|
|
531
576
|
}
|
|
532
577
|
/**
|
|
533
578
|
* Renders a media inline by its content type: images in an `<img>`, PDFs on `<canvas>` pages with pdf.js under a
|
|
@@ -538,7 +583,7 @@ interface PreviewProps {
|
|
|
538
583
|
* @example
|
|
539
584
|
* <Preview media={document.file} maxBytes={20_000_000} className="h-[80vh] w-full" />
|
|
540
585
|
*/
|
|
541
|
-
declare function Preview({ media, contentType, fallback, loading, labels, ...viewProps }: PreviewProps): React.JSX.Element | null;
|
|
586
|
+
declare function Preview({ media, contentType, fallback, loading, labels, metrics, ...viewProps }: PreviewProps): React.JSX.Element | null;
|
|
542
587
|
|
|
543
588
|
/** How a content type renders inline: `<img>`, a PDF view (pdf.js canvases or `<iframe>`), `<audio>` or `<pre>`. */
|
|
544
589
|
type PreviewKind = "image" | "pdf" | "audio" | "text";
|
|
@@ -577,228 +622,8 @@ interface MediaLibraryState {
|
|
|
577
622
|
*/
|
|
578
623
|
declare function useMediaLibrary(options?: UseMediaLibraryOptions): MediaLibraryState;
|
|
579
624
|
|
|
580
|
-
type AnyAction = FunctionReference<"action">;
|
|
581
|
-
type AnyMutation = FunctionReference<"mutation">;
|
|
582
|
-
type AnyQuery = FunctionReference<"query">;
|
|
583
|
-
interface DevulturApi {
|
|
584
|
-
issueViewerToken: AnyAction;
|
|
585
|
-
createUploadUrl: AnyAction;
|
|
586
|
-
/** Records an upload in the component after its PUT, so it shows in `listMedia`. Optional (uploads still work). */
|
|
587
|
-
confirmUpload?: AnyAction;
|
|
588
|
-
deleteMedia: AnyAction;
|
|
589
|
-
/** Deletes the full folder of a video (raw/hls/thumbnails/captions). Required to delete videos. */
|
|
590
|
-
deleteVideo?: AnyAction;
|
|
591
|
-
/** Requests the transcode of an uploaded video. Required by `useMediaUpload` for auto-process. */
|
|
592
|
-
processVideo?: AnyAction;
|
|
593
|
-
getMedia?: AnyQuery;
|
|
594
|
-
/** The library, newest first. Required by `useMediaLibrary` and `<MediaLibrary>`. */
|
|
595
|
-
listMediaPage?: AnyQuery;
|
|
596
|
-
/** The library matching a search. Required by `useMediaLibrary` and `<MediaLibrary>` to search. */
|
|
597
|
-
searchMedia?: AnyQuery;
|
|
598
|
-
saveProgress?: AnyMutation;
|
|
599
|
-
loadProgress?: AnyQuery;
|
|
600
|
-
markComplete?: AnyMutation;
|
|
601
|
-
resetProgress?: AnyMutation;
|
|
602
|
-
}
|
|
603
|
-
interface UploadOptions {
|
|
604
|
-
/** Visibility override for this resource. Omitted → inherits the router's default by type. */
|
|
605
|
-
visibility?: Visibility;
|
|
606
|
-
/** Progress of the PUT: bytes sent, total bytes and their fraction (0 to 1). */
|
|
607
|
-
onProgress?: (progress: UploadProgress) => void;
|
|
608
|
-
/** Aborts the PUT → `upload()` rejects with an `AbortError`. */
|
|
609
|
-
signal?: AbortSignal;
|
|
610
|
-
/** A PDF's page count to record with it, a hint (`countPdfPages` from `@devultur/convex/pdfjs` counts it). */
|
|
611
|
-
pageCount?: number;
|
|
612
|
-
}
|
|
613
|
-
/**
|
|
614
|
-
* The reference `upload()` resolves to: a `DevulturMedia` whose `key` is always set (the uploaded object's key; a
|
|
615
|
-
* video's raw file, what `processVideo` takes). It stores as-is in a `dv.media()` field.
|
|
616
|
-
*/
|
|
617
|
-
type UploadedMedia = DevulturMedia & {
|
|
618
|
-
readonly key: string;
|
|
619
|
-
};
|
|
620
|
-
/**
|
|
621
|
-
* What `useDevultur()` returns. Under a `<DevulturViewerProvider>`, `uploadUrl`, `upload` and `deleteMedia` throw a
|
|
622
|
-
* `DevulturCapabilityError` (`capability_unavailable`).
|
|
623
|
-
*/
|
|
624
|
-
interface DevulturContextValue extends MediaSession {
|
|
625
|
-
uploadUrl: (file: File) => Promise<{
|
|
626
|
-
url: string;
|
|
627
|
-
key: string;
|
|
628
|
-
}>;
|
|
629
|
-
/** Uploads a file (reporting progress), records it in the component, and returns the reference ready to save. */
|
|
630
|
-
upload: (file: File, options?: UploadOptions) => Promise<UploadedMedia>;
|
|
631
|
-
/** Deletes a media by reference: video → full folder; image/file → the object. */
|
|
632
|
-
deleteMedia: (media: DevulturMedia) => void;
|
|
633
|
-
}
|
|
634
|
-
interface ProgressContextValue {
|
|
635
|
-
save: (videoId: string, position: number) => Promise<void>;
|
|
636
|
-
load: (videoId: string) => Promise<{
|
|
637
|
-
lastPosition: number;
|
|
638
|
-
completedAt: Date | null;
|
|
639
|
-
} | null>;
|
|
640
|
-
markComplete: (videoId: string) => Promise<void>;
|
|
641
|
-
reset: (videoId: string) => Promise<void>;
|
|
642
|
-
}
|
|
643
|
-
interface DevulturProviderProps {
|
|
644
|
-
api: DevulturApi;
|
|
645
|
-
/** Media worker base (e.g. `https://media.your-domain.com`). Required for `useMediaUrl`. */
|
|
646
|
-
baseUrl?: string;
|
|
647
|
-
/**
|
|
648
|
-
* Extra arguments sent with `sessionSecret` on every viewer token issuance (first, renewal and re-issue), for
|
|
649
|
-
* example `{ workspaceId }`. Compared by value: when they change, the current token is dropped and a new one is
|
|
650
|
-
* issued. The component's own `issueViewerToken` accepts only `sessionSecret`, so pass your own action in
|
|
651
|
-
* `issueViewerToken` that takes these arguments.
|
|
652
|
-
*/
|
|
653
|
-
tokenArgs?: ViewerTokenArgs;
|
|
654
|
-
/**
|
|
655
|
-
* Your own viewer token action, used instead of `api.issueViewerToken`. It receives `{ sessionSecret, ...tokenArgs }`
|
|
656
|
-
* and returns what the component's `issueViewerToken` returns.
|
|
657
|
-
*/
|
|
658
|
-
issueViewerToken?: ViewerTokenAction;
|
|
659
|
-
children: React.ReactNode;
|
|
660
|
-
}
|
|
661
|
-
declare function DevulturProvider({ api, baseUrl, tokenArgs, issueViewerToken, children }: DevulturProviderProps): React.JSX.Element;
|
|
662
|
-
declare function useDevultur(): DevulturContextValue;
|
|
663
|
-
/**
|
|
664
|
-
* The `api` passed to `<DevulturProvider>`: your app's exported Devultur functions. Under a `<DevulturViewerProvider>`
|
|
665
|
-
* it throws a `DevulturCapabilityError`.
|
|
666
|
-
*/
|
|
667
|
-
declare function useDevulturApi(): DevulturApi;
|
|
668
|
-
interface DevulturViewerProviderProps {
|
|
669
|
-
/** Media worker base (e.g. `https://media.your-domain.com`). */
|
|
670
|
-
baseUrl: string;
|
|
671
|
-
/** Your viewer token action. It receives `{ sessionSecret, ...tokenArgs }`, like `<DevulturProvider>`'s. */
|
|
672
|
-
issueViewerToken: ViewerTokenAction;
|
|
673
|
-
/** Extra arguments for `issueViewerToken`, compared by value (see `<DevulturProvider tokenArgs>`). */
|
|
674
|
-
tokenArgs?: ViewerTokenArgs;
|
|
675
|
-
children: React.ReactNode;
|
|
676
|
-
}
|
|
677
|
-
/**
|
|
678
|
-
* A provider for apps that only display media: it issues and renews the viewer token, so `<Image>`, `<Preview>`,
|
|
679
|
-
* `<DownloadLink>`, `useMediaObjectUrl` and the video hooks work, and it needs no upload or delete actions. `upload`,
|
|
680
|
-
* `uploadUrl` and `deleteMedia` throw a `DevulturCapabilityError`, as do the hooks that need the `api`
|
|
681
|
-
* (`useMediaUpload`, `useDevulturApi`, `<MediaLibrary>`, `<MediaPicker>`).
|
|
682
|
-
*
|
|
683
|
-
* @example
|
|
684
|
-
* <DevulturViewerProvider baseUrl={MEDIA_URL} issueViewerToken={api.admin.issueViewerToken} tokenArgs={{ workspaceId }}>
|
|
685
|
-
* <Preview media={document.file} />
|
|
686
|
-
* </DevulturViewerProvider>
|
|
687
|
-
*/
|
|
688
|
-
declare function DevulturViewerProvider({ baseUrl, issueViewerToken, tokenArgs, children, }: DevulturViewerProviderProps): React.JSX.Element;
|
|
689
|
-
declare function useDevulturProgress(): ProgressContextValue;
|
|
690
|
-
/**
|
|
691
|
-
* Ready-to-use delivery URL for a key, with the context's viewer token already injected. The consumer
|
|
692
|
-
* never touches the token or the query — it only declares what it wants (download, resize, etc.).
|
|
693
|
-
*
|
|
694
|
-
* @example
|
|
695
|
-
* <img src={useMediaUrl(key)} />
|
|
696
|
-
* <a href={useMediaUrl(key, { download: true })} download>Download</a>
|
|
697
|
-
* <img src={useMediaUrl(key, { width: 512, format: "webp" })} />
|
|
698
|
-
*/
|
|
699
|
-
declare function useMediaUrl(key: string | null | undefined, options?: MediaRenderOptions): string | null;
|
|
700
|
-
interface VideoProps {
|
|
701
|
-
src: string;
|
|
702
|
-
token: string | undefined;
|
|
703
|
-
captions: {
|
|
704
|
-
locale: string;
|
|
705
|
-
label: string;
|
|
706
|
-
src: string;
|
|
707
|
-
}[];
|
|
708
|
-
/** Session secret → `<VideoPlayer>` sends it in `${SESSION_HEADER}` on hls.js/captions requests. */
|
|
709
|
-
sessionSecret?: string;
|
|
710
|
-
}
|
|
711
|
-
/**
|
|
712
|
-
* Token-transparent props for `<VideoPlayer>` from a video reference: builds the HLS playlist `src`,
|
|
713
|
-
* the viewer `token` (only if private), and the `captions` for the requested locales.
|
|
714
|
-
* The consumer just does `<VideoPlayer {...useVideoProps(lesson.video, { locales })} />`.
|
|
715
|
-
*/
|
|
716
|
-
declare function useVideoProps(media: DevulturMedia | null | undefined, options?: {
|
|
717
|
-
locales?: string[];
|
|
718
|
-
}): VideoProps | null;
|
|
719
|
-
interface DownloadLinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, "href" | "download" | "media"> {
|
|
720
|
-
media: DevulturMedia | null | undefined;
|
|
721
|
-
/** Name it downloads as. Without this it uses the upload's original name. */
|
|
722
|
-
filename?: string;
|
|
723
|
-
/**
|
|
724
|
-
* A private download that failed: `token_unavailable` right away when the viewer token couldn't be issued
|
|
725
|
-
* (`useDevultur().retryToken()` tries again), `http_error` when the delivery refused it.
|
|
726
|
-
*/
|
|
727
|
-
onDownloadError?: (error: MediaFetchError) => void;
|
|
728
|
-
children: React.ReactNode;
|
|
729
|
-
}
|
|
730
|
-
/**
|
|
731
|
-
* `<a>` that downloads a media with its original name (token-transparent). The worker serves it with
|
|
732
|
-
* `Content-Disposition: attachment`, so a click downloads the file instead of opening it in a tab.
|
|
733
|
-
*
|
|
734
|
-
* Private: an `<a download>` NAVIGATES, and a navigation can't send `${SESSION_HEADER}` → with session
|
|
735
|
-
* binding the gate gives a 401. So, for private media, we intercept the click, blob-fetch with the header
|
|
736
|
-
* (like private `<Image>`) and trigger the download from the object URL. Public keeps native navigation.
|
|
737
|
-
*/
|
|
738
|
-
declare function DownloadLink({ media, filename, onDownloadError, children, ...anchorProps }: DownloadLinkProps): React.JSX.Element | null;
|
|
739
|
-
interface MediaStatusReturn {
|
|
740
|
-
status: MediaStatusValue;
|
|
741
|
-
/** Typed progress: `phase` is the pipeline step (no `as any`). */
|
|
742
|
-
progress: {
|
|
743
|
-
current: number;
|
|
744
|
-
total: number;
|
|
745
|
-
percent: number;
|
|
746
|
-
phase?: ProcessingPhase;
|
|
747
|
-
} | null;
|
|
748
|
-
error: string | null;
|
|
749
|
-
/** Categorized failure reason (null if it didn't fail). */
|
|
750
|
-
failureReason: FailureReason | null;
|
|
751
|
-
/** Whether the failure is retriable (null if it didn't fail). */
|
|
752
|
-
retriable: boolean | null;
|
|
753
|
-
isQueued: boolean;
|
|
754
|
-
isTranscoding: boolean;
|
|
755
|
-
isCaptioning: boolean;
|
|
756
|
-
isReady: boolean;
|
|
757
|
-
isFailed: boolean;
|
|
758
|
-
playlistUrl: string | null;
|
|
759
|
-
thumbnailKey: string | null;
|
|
760
|
-
captionLocales: string[];
|
|
761
|
-
duration: number | null;
|
|
762
|
-
isLoading: boolean;
|
|
763
|
-
}
|
|
764
|
-
declare function useDevulturMedia(key: string | null | undefined): MediaStatusReturn;
|
|
765
|
-
interface CaptionTrack {
|
|
766
|
-
locale: string;
|
|
767
|
-
label: string;
|
|
768
|
-
src: string;
|
|
769
|
-
}
|
|
770
|
-
/**
|
|
771
|
-
* A video's pipeline state as a **discriminated union** on `phase`: the render is an exhaustive
|
|
772
|
-
* `switch` (no boolean ordering or `as any`), and adding a new phase is a compile error until it's
|
|
773
|
-
* handled. `processing` carries typed `step`/`percent`; `ready` carries the ref + props ready for
|
|
774
|
-
* `<VideoPlayer>` (token-transparent); `failed` carries a categorized `reason` + `retriable`.
|
|
775
|
-
*/
|
|
776
|
-
type VideoState = {
|
|
777
|
-
phase: "idle";
|
|
778
|
-
} | {
|
|
779
|
-
phase: "queued";
|
|
780
|
-
} | {
|
|
781
|
-
phase: "processing";
|
|
782
|
-
step: ProcessingPhase;
|
|
783
|
-
percent: number;
|
|
784
|
-
} | {
|
|
785
|
-
phase: "ready";
|
|
786
|
-
media: DevulturMedia;
|
|
787
|
-
playlist: string;
|
|
788
|
-
duration: number;
|
|
789
|
-
captions: CaptionTrack[];
|
|
790
|
-
playerProps: VideoProps;
|
|
791
|
-
} | {
|
|
792
|
-
phase: "failed";
|
|
793
|
-
reason: FailureReason;
|
|
794
|
-
message: string;
|
|
795
|
-
retriable: boolean;
|
|
796
|
-
};
|
|
797
|
-
declare function useVideoState(media: DevulturMedia | null | undefined, options?: {
|
|
798
|
-
locales?: string[];
|
|
799
|
-
}): VideoState;
|
|
800
625
|
interface UseMediaUploadOptions {
|
|
801
|
-
/** Resource visibility. Omitted → config
|
|
626
|
+
/** Resource visibility. Omitted → `config.upload.visibility`, else the Worker's default by type. Your guard can rewrite it. */
|
|
802
627
|
visibility?: Visibility;
|
|
803
628
|
/** Fires ONCE, at the persistence point (PUT done + transcode requested). */
|
|
804
629
|
onComplete?: (media: DevulturMedia) => void;
|
|
@@ -829,4 +654,61 @@ interface UseMediaUploadReturn {
|
|
|
829
654
|
*/
|
|
830
655
|
declare function useMediaUpload(options?: UseMediaUploadOptions): UseMediaUploadReturn;
|
|
831
656
|
|
|
832
|
-
|
|
657
|
+
interface DevulturViewerProviderProps {
|
|
658
|
+
/** Media worker base (e.g. `https://media.your-domain.com`). */
|
|
659
|
+
baseUrl: string;
|
|
660
|
+
/**
|
|
661
|
+
* Your viewer token action. It receives `{ sessionSecret, ...tokenArgs }`, like `<DevulturProvider>`'s. Leave it
|
|
662
|
+
* out when every media is public: the provider then needs no Convex client, issues nothing, and a private media
|
|
663
|
+
* fails with `token_unavailable`.
|
|
664
|
+
*/
|
|
665
|
+
issueViewerToken?: ViewerTokenAction;
|
|
666
|
+
/**
|
|
667
|
+
* `true` → the token is issued only once a private media is shown (and renewed from then on), so a page of public
|
|
668
|
+
* media calls nothing. Code that reads `token` itself then calls `requestToken()` first. Default `false`: issued
|
|
669
|
+
* as soon as the provider mounts.
|
|
670
|
+
*/
|
|
671
|
+
lazyToken?: boolean;
|
|
672
|
+
/** Extra arguments for `issueViewerToken`, compared by value (see `<DevulturProvider tokenArgs>`). */
|
|
673
|
+
tokenArgs?: ViewerTokenArgs;
|
|
674
|
+
children: React.ReactNode;
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* A provider for apps that only display media: `<Image>`, `<Preview>`, `<DownloadLink>`, `useMediaObjectUrl` and the
|
|
678
|
+
* video hooks work, and it needs no upload or delete actions. It issues and renews the viewer token (with `lazyToken`,
|
|
679
|
+
* only once a private media is shown). Without `issueViewerToken` it needs no Convex client at all. `upload`, `uploadUrl` and `deleteMedia` throw a `DevulturCapabilityError`, as do the hooks that
|
|
680
|
+
* need the `api` (`useMediaUpload`, `useDevulturApi`, `<MediaLibrary>`, `<MediaPicker>`).
|
|
681
|
+
*
|
|
682
|
+
* @example
|
|
683
|
+
* <DevulturViewerProvider baseUrl={MEDIA_URL} issueViewerToken={api.admin.issueViewerToken} tokenArgs={{ workspaceId }}>
|
|
684
|
+
* <Preview media={document.file} />
|
|
685
|
+
* </DevulturViewerProvider>
|
|
686
|
+
*
|
|
687
|
+
* // Only public media: no token action, no Convex client.
|
|
688
|
+
* <DevulturViewerProvider baseUrl={MEDIA_URL}>
|
|
689
|
+
* <Image media={post.cover} alt="" />
|
|
690
|
+
* </DevulturViewerProvider>
|
|
691
|
+
*/
|
|
692
|
+
declare function DevulturViewerProvider({ issueViewerToken, ...props }: DevulturViewerProviderProps): React.JSX.Element;
|
|
693
|
+
|
|
694
|
+
interface DevulturProviderProps {
|
|
695
|
+
api: DevulturApi;
|
|
696
|
+
/** Media worker base (e.g. `https://media.your-domain.com`). Required for `useMediaUrl`. */
|
|
697
|
+
baseUrl?: string;
|
|
698
|
+
/**
|
|
699
|
+
* Extra arguments sent with `sessionSecret` on every viewer token issuance (first, renewal and re-issue), for
|
|
700
|
+
* example `{ workspaceId }`. Compared by value: when they change, the current token is dropped and a new one is
|
|
701
|
+
* issued. The component's own `issueViewerToken` accepts only `sessionSecret`, so pass your own action in
|
|
702
|
+
* `issueViewerToken` that takes these arguments.
|
|
703
|
+
*/
|
|
704
|
+
tokenArgs?: ViewerTokenArgs;
|
|
705
|
+
/**
|
|
706
|
+
* Your own viewer token action, used instead of `api.issueViewerToken`. It receives `{ sessionSecret, ...tokenArgs }`
|
|
707
|
+
* and returns what the component's `issueViewerToken` returns.
|
|
708
|
+
*/
|
|
709
|
+
issueViewerToken?: ViewerTokenAction;
|
|
710
|
+
children: React.ReactNode;
|
|
711
|
+
}
|
|
712
|
+
declare function DevulturProvider({ api, baseUrl, tokenArgs, issueViewerToken, children }: DevulturProviderProps): React.JSX.Element;
|
|
713
|
+
|
|
714
|
+
export { AttachmentCard, type AttachmentCardProps, AttachmentLabels, type CaptionTrack, CropUpload, type CropUploadLabels, type CropUploadProps, type CropUploadRenderProps, DevulturApi, type DevulturCapability, DevulturCapabilityError, DevulturProvider, DevulturViewerProvider, type DevulturViewerProviderProps, DocumentLink, type DocumentLinkProps, DownloadLink, type DownloadLinkProps, Image, type ImageProps, MediaFetchError, MediaLibrary, type MediaLibraryItemState, MediaLibraryLabels, type MediaLibraryPart, type MediaLibraryProps, type MediaLibraryState, type MediaLibraryStatus, type MediaObjectUrl, MediaPicker, MediaPickerLabels, type MediaPickerLibraryProps, type MediaPickerProps, type MediaPickerSelectionProps, type MediaPickerState, type MediaPickerUpload$1 as MediaPickerUpload, type MediaPickerUploadProps, type MediaPickerUploads, type MediaStatusReturn, type PdfPreviewConfig, PdfPreviewProvider, PdfThumbnail, type PdfThumbnailProps, PdfjsLoader, Preview, type PreviewKind, PreviewLabels, type PreviewProps, type UseMediaLibraryOptions, type UseMediaObjectUrlOptions, type UseMediaUploadOptions, type UseMediaUploadReturn, VideoProps, type VideoState, ViewerTokenArgs, matchesAccept, useDevulturMedia, useMediaLibrary, useMediaObjectUrl, useMediaPicker, useMediaUpload, useVideoState };
|