@devultur/convex 1.5.1 → 1.6.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/README.md +19 -3
- package/dist/{chunk-RDVBE3G3.js → chunk-34XXHYL3.js} +13 -1
- package/dist/{chunk-BDEO67OT.js → chunk-AUAWZ5BD.js} +8 -53
- package/dist/chunk-FOBFHC4A.js +55 -0
- package/dist/chunk-O76FU54F.js +0 -0
- package/dist/{chunk-YYOZ3PDH.js → chunk-V5YH4YJG.js} +25 -0
- package/dist/{hooks-uqpBd5UF.d.ts → contexts-6F8TJINX.d.ts} +9 -31
- package/dist/{error-labels-D0Vbp-qA.d.ts → error-labels-Sf6gow24.d.ts} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/locales/es-formal.d.ts +1 -1
- package/dist/locales/es-formal.js +3 -2
- package/dist/locales/es.d.ts +1 -1
- package/dist/locales/es.js +2 -2
- package/dist/react/contexts.d.ts +6 -0
- package/dist/react/contexts.js +22 -0
- package/dist/react/hooks.d.ts +35 -2
- package/dist/react/hooks.js +9 -4
- package/dist/react.d.ts +4 -2
- package/dist/react.js +10 -6
- package/docs/guides/plugins.md +13 -5
- package/docs/guides/self-host.md +25 -4
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -276,12 +276,28 @@ function Avatar({ media, fallbackUrl }) {
|
|
|
276
276
|
}
|
|
277
277
|
```
|
|
278
278
|
|
|
279
|
+
`useDevulturOptional()` is non-null under a `<DevulturProvider>` given no `baseUrl` too, where the hooks that build
|
|
280
|
+
URLs throw. `useCanDeliver()` answers that instead: `true` only under a provider with a non-empty `baseUrl`.
|
|
281
|
+
|
|
282
|
+
```tsx
|
|
283
|
+
function Cover({ media, fallbackUrl }) {
|
|
284
|
+
if (!useCanDeliver() || !media) return <img src={fallbackUrl} alt="" />;
|
|
285
|
+
return <Image media={media} alt="" />;
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Public media needs nothing more. Private media also needs the viewer token, which a provider may not have yet
|
|
290
|
+
(`lazyToken`) or can't issue (a `<DevulturViewerProvider>` without `issueViewerToken`); `tokenStatus` from
|
|
291
|
+
`useDevultur()` tells, and the components show their error state when it fails.
|
|
292
|
+
|
|
279
293
|
### Only the hooks
|
|
280
294
|
|
|
281
295
|
`@devultur/convex/react/hooks` exports the contexts and the hooks that only read them, without the components or
|
|
282
|
-
Convex's client: `useDevultur`, `useDevulturOptional`, `
|
|
283
|
-
`useVideoProps`, and the `DevulturContext`, `DevulturApiContext` and `DevulturProgressContext` objects.
|
|
284
|
-
|
|
296
|
+
Convex's client: `useDevultur`, `useDevulturOptional`, `useCanDeliver`, `useDevulturApi`, `useDevulturProgress`,
|
|
297
|
+
`useMediaUrl`, `useVideoProps`, and the `DevulturContext`, `DevulturApiContext` and `DevulturProgressContext` objects.
|
|
298
|
+
The contexts and the hooks that only read them sit in a chunk of their own, apart from `useMediaUrl`, `useVideoProps`
|
|
299
|
+
and `@devultur/core`'s URL helpers, so a shared component that only checks for a provider adds under 0.5 kB gzipped,
|
|
300
|
+
even to the entry of an app that lazy-loads `@devultur/convex/react` on a route:
|
|
285
301
|
|
|
286
302
|
```tsx
|
|
287
303
|
import { useDevulturOptional } from "@devultur/convex/react/hooks";
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
formatBytes,
|
|
8
8
|
formatDate,
|
|
9
9
|
labelText
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-V5YH4YJG.js";
|
|
11
11
|
|
|
12
12
|
// src/locales/es.ts
|
|
13
13
|
var LOCALE = "es";
|
|
@@ -57,6 +57,18 @@ var devulturErrorLabels = {
|
|
|
57
57
|
link_expired: "Este enlace de descarga ya venci\xF3.",
|
|
58
58
|
link_used: "Este enlace de descarga ya se us\xF3.",
|
|
59
59
|
not_configured: "Esta funci\xF3n no est\xE1 configurada.",
|
|
60
|
+
invalid_grant: "Este permiso de descarga no es v\xE1lido.",
|
|
61
|
+
grant_gone: "Este permiso de descarga ya no es v\xE1lido.",
|
|
62
|
+
grant_exhausted: "Este permiso de descarga ya emiti\xF3 todos sus enlaces.",
|
|
63
|
+
grant_exists: "Este permiso de descarga ya existe.",
|
|
64
|
+
grant_in_query: "Env\xEDa el permiso de descarga en el encabezado Authorization, nunca en una URL.",
|
|
65
|
+
grant_not_found: "Este permiso de descarga no existe.",
|
|
66
|
+
grant_cannot_delete: "Este permiso de descarga no puede eliminar su archivo.",
|
|
67
|
+
link_exceeds_grant: "El enlace de descarga supera lo que permite el permiso.",
|
|
68
|
+
invalid_link_caps: "Los l\xEDmites del enlace de descarga no son v\xE1lidos.",
|
|
69
|
+
invalid_max_links: "El n\xFAmero de enlaces no es v\xE1lido.",
|
|
70
|
+
invalid_can_delete: "Si el permiso puede eliminar su archivo debe ser verdadero o falso.",
|
|
71
|
+
invalid_metadata: "Los metadatos no son v\xE1lidos.",
|
|
60
72
|
retention_active: (details) => {
|
|
61
73
|
if (details.hold === true) return "Este archivo tiene una retenci\xF3n legal y no se puede modificar ni eliminar.";
|
|
62
74
|
const until = formatDate(details.until, LOCALE);
|
|
@@ -1,46 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
capability;
|
|
5
|
-
constructor(capability) {
|
|
6
|
-
super(
|
|
7
|
-
`Devultur: \`${capability}\` isn't available under <DevulturViewerProvider>. Use <DevulturProvider api> with the actions it needs.`
|
|
8
|
-
);
|
|
9
|
-
this.name = "DevulturCapabilityError";
|
|
10
|
-
this.capability = capability;
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
// src/devultur-context.ts
|
|
15
|
-
import React from "react";
|
|
16
|
-
var DevulturContext = /* @__PURE__ */ React.createContext(null);
|
|
17
|
-
var DevulturApiContext = /* @__PURE__ */ React.createContext(null);
|
|
18
|
-
function useDevultur() {
|
|
19
|
-
const context = React.use(DevulturContext);
|
|
20
|
-
if (!context) throw new Error("useDevultur must be used within <DevulturProvider> or <DevulturViewerProvider>");
|
|
21
|
-
return context;
|
|
22
|
-
}
|
|
23
|
-
function useDevulturOptional() {
|
|
24
|
-
return React.use(DevulturContext);
|
|
25
|
-
}
|
|
26
|
-
function useDevulturApi() {
|
|
27
|
-
const api = React.use(DevulturApiContext);
|
|
28
|
-
if (api) return api;
|
|
29
|
-
if (React.use(DevulturContext)) throw new DevulturCapabilityError("api");
|
|
30
|
-
throw new Error("useDevulturApi must be used within <DevulturProvider>");
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// src/progress-context.ts
|
|
34
|
-
import React2 from "react";
|
|
35
|
-
var DevulturProgressContext = /* @__PURE__ */ React2.createContext(null);
|
|
36
|
-
function useDevulturProgress() {
|
|
37
|
-
const context = React2.use(DevulturProgressContext);
|
|
38
|
-
if (!context) throw new Error("useDevulturProgress requires progress API in DevulturProvider");
|
|
39
|
-
return context;
|
|
40
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
useDevultur
|
|
3
|
+
} from "./chunk-FOBFHC4A.js";
|
|
41
4
|
|
|
42
5
|
// src/media-url-hooks.ts
|
|
43
|
-
import
|
|
6
|
+
import React2 from "react";
|
|
44
7
|
import {
|
|
45
8
|
buildMediaUrl,
|
|
46
9
|
CaptionLocaleLabel,
|
|
@@ -50,11 +13,11 @@ import {
|
|
|
50
13
|
} from "@devultur/core";
|
|
51
14
|
|
|
52
15
|
// src/request-token.ts
|
|
53
|
-
import
|
|
16
|
+
import React from "react";
|
|
54
17
|
function useRequestTokenWhen(session, isNeeded) {
|
|
55
18
|
const { requestToken, token } = session;
|
|
56
19
|
const hasToken = token !== null;
|
|
57
|
-
|
|
20
|
+
React.useEffect(() => {
|
|
58
21
|
if (isNeeded && !hasToken) requestToken();
|
|
59
22
|
}, [isNeeded, hasToken, requestToken]);
|
|
60
23
|
}
|
|
@@ -64,7 +27,7 @@ function useMediaUrl(key, options) {
|
|
|
64
27
|
const devultur = useDevultur();
|
|
65
28
|
const { token, baseUrl } = devultur;
|
|
66
29
|
useRequestTokenWhen(devultur, Boolean(key) && visibilityFromKey(key ?? "") !== "public");
|
|
67
|
-
return
|
|
30
|
+
return React2.useMemo(() => {
|
|
68
31
|
if (!key) return null;
|
|
69
32
|
if (!baseUrl) throw new Error("useMediaUrl requires `baseUrl` on <DevulturProvider>");
|
|
70
33
|
const isPublic = visibilityFromKey(key) === "public";
|
|
@@ -76,7 +39,7 @@ function useVideoProps(media, options) {
|
|
|
76
39
|
const { token, baseUrl, sessionSecret } = devultur;
|
|
77
40
|
useRequestTokenWhen(devultur, media?.kind === "video" && media.visibility === "private");
|
|
78
41
|
const locales = options?.locales;
|
|
79
|
-
return
|
|
42
|
+
return React2.useMemo(() => {
|
|
80
43
|
if (media?.kind !== "video") return null;
|
|
81
44
|
if (!baseUrl) throw new Error("useVideoProps requires `baseUrl` on <DevulturProvider>");
|
|
82
45
|
const viewerToken = media.visibility === "private" ? token ?? void 0 : void 0;
|
|
@@ -96,14 +59,6 @@ function useVideoProps(media, options) {
|
|
|
96
59
|
}
|
|
97
60
|
|
|
98
61
|
export {
|
|
99
|
-
DevulturCapabilityError,
|
|
100
|
-
DevulturContext,
|
|
101
|
-
DevulturApiContext,
|
|
102
|
-
useDevultur,
|
|
103
|
-
useDevulturOptional,
|
|
104
|
-
useDevulturApi,
|
|
105
|
-
DevulturProgressContext,
|
|
106
|
-
useDevulturProgress,
|
|
107
62
|
useRequestTokenWhen,
|
|
108
63
|
useMediaUrl,
|
|
109
64
|
useVideoProps
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/capability-error.ts
|
|
2
|
+
var DevulturCapabilityError = class extends Error {
|
|
3
|
+
code = "capability_unavailable";
|
|
4
|
+
capability;
|
|
5
|
+
constructor(capability) {
|
|
6
|
+
super(
|
|
7
|
+
`Devultur: \`${capability}\` isn't available under <DevulturViewerProvider>. Use <DevulturProvider api> with the actions it needs.`
|
|
8
|
+
);
|
|
9
|
+
this.name = "DevulturCapabilityError";
|
|
10
|
+
this.capability = capability;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// src/devultur-context.ts
|
|
15
|
+
import React from "react";
|
|
16
|
+
var DevulturContext = /* @__PURE__ */ React.createContext(null);
|
|
17
|
+
var DevulturApiContext = /* @__PURE__ */ React.createContext(null);
|
|
18
|
+
function useDevultur() {
|
|
19
|
+
const context = React.use(DevulturContext);
|
|
20
|
+
if (!context) throw new Error("useDevultur must be used within <DevulturProvider> or <DevulturViewerProvider>");
|
|
21
|
+
return context;
|
|
22
|
+
}
|
|
23
|
+
function useDevulturOptional() {
|
|
24
|
+
return React.use(DevulturContext);
|
|
25
|
+
}
|
|
26
|
+
function useCanDeliver() {
|
|
27
|
+
return Boolean(React.use(DevulturContext)?.baseUrl);
|
|
28
|
+
}
|
|
29
|
+
function useDevulturApi() {
|
|
30
|
+
const api = React.use(DevulturApiContext);
|
|
31
|
+
if (api) return api;
|
|
32
|
+
if (React.use(DevulturContext)) throw new DevulturCapabilityError("api");
|
|
33
|
+
throw new Error("useDevulturApi must be used within <DevulturProvider>");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/progress-context.ts
|
|
37
|
+
import React2 from "react";
|
|
38
|
+
var DevulturProgressContext = /* @__PURE__ */ React2.createContext(null);
|
|
39
|
+
function useDevulturProgress() {
|
|
40
|
+
const context = React2.use(DevulturProgressContext);
|
|
41
|
+
if (!context) throw new Error("useDevulturProgress requires progress API in DevulturProvider");
|
|
42
|
+
return context;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
DevulturCapabilityError,
|
|
47
|
+
DevulturContext,
|
|
48
|
+
DevulturApiContext,
|
|
49
|
+
useDevultur,
|
|
50
|
+
useDevulturOptional,
|
|
51
|
+
useCanDeliver,
|
|
52
|
+
useDevulturApi,
|
|
53
|
+
DevulturProgressContext,
|
|
54
|
+
useDevulturProgress
|
|
55
|
+
};
|
|
File without changes
|
|
@@ -40,6 +40,19 @@ var DEVULTUR_ERROR_CODES = [
|
|
|
40
40
|
"link_expired",
|
|
41
41
|
"link_used",
|
|
42
42
|
"not_configured",
|
|
43
|
+
// Download grants
|
|
44
|
+
"invalid_grant",
|
|
45
|
+
"grant_gone",
|
|
46
|
+
"grant_exhausted",
|
|
47
|
+
"grant_exists",
|
|
48
|
+
"grant_in_query",
|
|
49
|
+
"grant_not_found",
|
|
50
|
+
"grant_cannot_delete",
|
|
51
|
+
"link_exceeds_grant",
|
|
52
|
+
"invalid_link_caps",
|
|
53
|
+
"invalid_max_links",
|
|
54
|
+
"invalid_can_delete",
|
|
55
|
+
"invalid_metadata",
|
|
43
56
|
// Retention and holds
|
|
44
57
|
"retention_active",
|
|
45
58
|
"lock_conflict",
|
|
@@ -170,6 +183,18 @@ var devulturErrorLabels = {
|
|
|
170
183
|
link_expired: "This download link has expired.",
|
|
171
184
|
link_used: "This download link was already used.",
|
|
172
185
|
not_configured: "This feature isn't set up.",
|
|
186
|
+
invalid_grant: "This download grant isn't valid.",
|
|
187
|
+
grant_gone: "This download grant is no longer valid.",
|
|
188
|
+
grant_exhausted: "This download grant has issued all its links.",
|
|
189
|
+
grant_exists: "This download grant already exists.",
|
|
190
|
+
grant_in_query: "Send the download grant in the Authorization header, never in a URL.",
|
|
191
|
+
grant_not_found: "This download grant doesn't exist.",
|
|
192
|
+
grant_cannot_delete: "This download grant can't delete its file.",
|
|
193
|
+
link_exceeds_grant: "The download link exceeds what the grant allows.",
|
|
194
|
+
invalid_link_caps: "The download link limits aren't valid.",
|
|
195
|
+
invalid_max_links: "The number of links isn't valid.",
|
|
196
|
+
invalid_can_delete: "Whether the grant can delete its file must be true or false.",
|
|
197
|
+
invalid_metadata: "The metadata isn't valid.",
|
|
173
198
|
retention_active: (details) => {
|
|
174
199
|
if (details.hold === true) return "This file is on hold and can't be changed or deleted.";
|
|
175
200
|
const until = formatDate(details.until, "en");
|
|
@@ -120,42 +120,20 @@ declare function useDevultur(): DevulturContextValue;
|
|
|
120
120
|
* `<DevulturViewerProvider>`, and `null` outside both instead of throwing.
|
|
121
121
|
*/
|
|
122
122
|
declare function useDevulturOptional(): DevulturContextValue | null;
|
|
123
|
+
/**
|
|
124
|
+
* Whether the media hooks can build delivery URLs here: `true` under `<DevulturProvider>` or `<DevulturViewerProvider>`
|
|
125
|
+
* with a non-empty `baseUrl`; `false` outside both, or under a `<DevulturProvider>` without one, where `useMediaUrl`,
|
|
126
|
+
* `useVideoProps` and `url()` throw. That's all a public media needs. A private media also needs the viewer token,
|
|
127
|
+
* which the provider may not have yet (lazy issuance) or can't issue (no `issueViewerToken`): `tokenStatus` from
|
|
128
|
+
* `useDevultur()` tells, and the components handle it themselves.
|
|
129
|
+
*/
|
|
130
|
+
declare function useCanDeliver(): boolean;
|
|
123
131
|
/**
|
|
124
132
|
* The `api` passed to `<DevulturProvider>`: your app's exported Devultur functions. Under a `<DevulturViewerProvider>`
|
|
125
133
|
* it throws a `DevulturCapabilityError`.
|
|
126
134
|
*/
|
|
127
135
|
declare function useDevulturApi(): DevulturApi;
|
|
128
136
|
|
|
129
|
-
/**
|
|
130
|
-
* Ready-to-use delivery URL for a key, with the context's viewer token already injected. The consumer
|
|
131
|
-
* never touches the token or the query — it only declares what it wants (download, resize, etc.).
|
|
132
|
-
*
|
|
133
|
-
* @example
|
|
134
|
-
* <img src={useMediaUrl(key)} />
|
|
135
|
-
* <a href={useMediaUrl(key, { download: true })} download>Download</a>
|
|
136
|
-
* <img src={useMediaUrl(key, { width: 512, format: "webp" })} />
|
|
137
|
-
*/
|
|
138
|
-
declare function useMediaUrl(key: string | null | undefined, options?: MediaRenderOptions): string | null;
|
|
139
|
-
interface VideoProps {
|
|
140
|
-
src: string;
|
|
141
|
-
token: string | undefined;
|
|
142
|
-
captions: {
|
|
143
|
-
locale: string;
|
|
144
|
-
label: string;
|
|
145
|
-
src: string;
|
|
146
|
-
}[];
|
|
147
|
-
/** Session secret → `<VideoPlayer>` sends it in `${SESSION_HEADER}` on hls.js/captions requests. */
|
|
148
|
-
sessionSecret?: string;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* Token-transparent props for `<VideoPlayer>` from a video reference: builds the HLS playlist `src`,
|
|
152
|
-
* the viewer `token` (only if private), and the `captions` for the requested locales.
|
|
153
|
-
* The consumer just does `<VideoPlayer {...useVideoProps(lesson.video, { locales })} />`.
|
|
154
|
-
*/
|
|
155
|
-
declare function useVideoProps(media: DevulturMedia | null | undefined, options?: {
|
|
156
|
-
locales?: string[];
|
|
157
|
-
}): VideoProps | null;
|
|
158
|
-
|
|
159
137
|
interface DevulturProgressContextValue {
|
|
160
138
|
save: (videoId: string, position: number) => Promise<void>;
|
|
161
139
|
load: (videoId: string) => Promise<{
|
|
@@ -168,4 +146,4 @@ interface DevulturProgressContextValue {
|
|
|
168
146
|
declare const DevulturProgressContext: React.Context<DevulturProgressContextValue | null>;
|
|
169
147
|
declare function useDevulturProgress(): DevulturProgressContextValue;
|
|
170
148
|
|
|
171
|
-
export { type DevulturApi as D, type
|
|
149
|
+
export { type DevulturApi as D, type MediaRenderOptions as M, type TokenStatus as T, type UploadOptions as U, type ViewerTokenAction as V, type ViewerTokenArgs as a, DevulturApiContext as b, DevulturContext as c, type DevulturContextValue as d, DevulturProgressContext as e, type DevulturProgressContextValue as f, type UploadedMedia as g, type ViewerTokenResult as h, useDevultur as i, useDevulturApi as j, useDevulturOptional as k, useDevulturProgress as l, useCanDeliver as u };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare const DEVULTUR_ERROR_CODES: readonly ["file_too_large", "content_type_not_allowed", "content_type_mismatch", "content_unverified", "unsupported_content_type", "media_type_mismatch", "already_exists", "write_conflict", "upload_not_found", "invalid_upload_key", "invalid_path", "path_required", "invalid_expires_in", "invalid_file_expires_in", "invalid_cache_control", "invalid_limits", "invalid_prefix", "invalid_visibility", "invalid_cursor", "invalid_sha256", "sha256_mismatch", "max_files_reached", "invalid_multipart", "invalid_size", "invalid_part", "invalid_parts", "part_size_mismatch", "part_sha256_required", "invalid_media_metadata", "expired", "invalid_key", "invalid_max_uses", "link_exists", "link_not_found", "link_expired", "link_used", "not_configured", "retention_active", "lock_conflict", "compliance_extend_only", "lock_privilege_required", "lock_record_unreadable", "lock_below_minimum", "invalid_lock", "invalid_hold", "reserved_key", "keys_bucket_missing", "encryption_key_missing", "unauthorized", "session_mismatch", "token_rejected", "reserved_user_id", "invalid_scopes", "user_mismatch", "transcode_not_configured", "transcode_runner_unavailable", "transcode_launch_failed", "original_not_retained", "locale_not_allowed", "captions_provider_rate_limited", "captions_provider_error", "captions_failed", "webhook_secret_missing", "worker_auth_secret_missing", "worker_error", "http_error", "too_large", "unsupported_type", "type_mismatch", "token_unavailable", "page_cap", "render_failed", "capability_unavailable"];
|
|
1
|
+
declare const DEVULTUR_ERROR_CODES: readonly ["file_too_large", "content_type_not_allowed", "content_type_mismatch", "content_unverified", "unsupported_content_type", "media_type_mismatch", "already_exists", "write_conflict", "upload_not_found", "invalid_upload_key", "invalid_path", "path_required", "invalid_expires_in", "invalid_file_expires_in", "invalid_cache_control", "invalid_limits", "invalid_prefix", "invalid_visibility", "invalid_cursor", "invalid_sha256", "sha256_mismatch", "max_files_reached", "invalid_multipart", "invalid_size", "invalid_part", "invalid_parts", "part_size_mismatch", "part_sha256_required", "invalid_media_metadata", "expired", "invalid_key", "invalid_max_uses", "link_exists", "link_not_found", "link_expired", "link_used", "not_configured", "invalid_grant", "grant_gone", "grant_exhausted", "grant_exists", "grant_in_query", "grant_not_found", "grant_cannot_delete", "link_exceeds_grant", "invalid_link_caps", "invalid_max_links", "invalid_can_delete", "invalid_metadata", "retention_active", "lock_conflict", "compliance_extend_only", "lock_privilege_required", "lock_record_unreadable", "lock_below_minimum", "invalid_lock", "invalid_hold", "reserved_key", "keys_bucket_missing", "encryption_key_missing", "unauthorized", "session_mismatch", "token_rejected", "reserved_user_id", "invalid_scopes", "user_mismatch", "transcode_not_configured", "transcode_runner_unavailable", "transcode_launch_failed", "original_not_retained", "locale_not_allowed", "captions_provider_rate_limited", "captions_provider_error", "captions_failed", "webhook_secret_missing", "worker_auth_secret_missing", "worker_error", "http_error", "too_large", "unsupported_type", "type_mismatch", "token_unavailable", "page_cap", "render_failed", "capability_unavailable"];
|
|
2
2
|
/** A stable error code: match on it, not on `message`. */
|
|
3
3
|
type DevulturErrorCode = (typeof DEVULTUR_ERROR_CODES)[number];
|
|
4
4
|
declare function isDevulturErrorCode(code: unknown): code is DevulturErrorCode;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { FunctionReference, PaginationResult, FunctionVisibility, DefaultFunctio
|
|
|
4
4
|
import { PropertyValidators, Value, ConvexError } from 'convex/values';
|
|
5
5
|
import { M as MediaRecord, P as ProgressRecord, D as DevulturComponentConfig } from './types-C0ruHUcu.js';
|
|
6
6
|
export { a as DevulturUploadConfig } from './types-C0ruHUcu.js';
|
|
7
|
-
export { a as DEVULTUR_ERROR_CODES, b as DevulturErrorCode, c as DevulturErrorDetails, d as DevulturErrorLabel, D as DevulturErrorLabels, e as describeDevulturError, f as devulturErrorLabels, i as isDevulturErrorCode } from './error-labels-
|
|
7
|
+
export { a as DEVULTUR_ERROR_CODES, b as DevulturErrorCode, c as DevulturErrorDetails, d as DevulturErrorLabel, D as DevulturErrorLabels, e as describeDevulturError, f as devulturErrorLabels, i as isDevulturErrorCode } from './error-labels-Sf6gow24.js';
|
|
8
8
|
export { dv } from './validators.js';
|
|
9
9
|
|
|
10
10
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { VideoPlayerLabels } from '@devultur/react';
|
|
2
2
|
import { A as AttachmentLabels, M as MediaLibraryLabels, a as MediaPickerLabels, P as PreviewLabels } from '../preview-labels-C2nUUY_f.js';
|
|
3
|
-
import { D as DevulturErrorLabels } from '../error-labels-
|
|
3
|
+
import { D as DevulturErrorLabels } from '../error-labels-Sf6gow24.js';
|
|
4
4
|
import '../types-C0ruHUcu.js';
|
|
5
5
|
import '@devultur/core';
|
|
6
6
|
import 'convex/values';
|
|
@@ -5,12 +5,12 @@ import {
|
|
|
5
5
|
mediaPickerLabels,
|
|
6
6
|
previewLabels,
|
|
7
7
|
videoPlayerLabels
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-34XXHYL3.js";
|
|
9
9
|
import "../chunk-QBHIZBOQ.js";
|
|
10
10
|
import {
|
|
11
11
|
describeDevulturError,
|
|
12
12
|
labelText
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-V5YH4YJG.js";
|
|
14
14
|
|
|
15
15
|
// src/locales/es-formal.ts
|
|
16
16
|
var TRY_AGAIN = "Vuelva a intentarlo.";
|
|
@@ -30,6 +30,7 @@ var devulturErrorLabels2 = {
|
|
|
30
30
|
if (details.field === "tags") return "Use como m\xE1ximo 20 etiquetas, de hasta 50 caracteres cada una.";
|
|
31
31
|
return labelText(devulturErrorLabels.invalid_media_metadata, details);
|
|
32
32
|
},
|
|
33
|
+
grant_in_query: "Env\xEDe el permiso de descarga en el encabezado Authorization, nunca en una URL.",
|
|
33
34
|
lock_conflict: `La protecci\xF3n del archivo cambi\xF3 mientras tanto. ${TRY_AGAIN}`,
|
|
34
35
|
lock_privilege_required: "No tiene permiso para acortar ni quitar la protecci\xF3n de este archivo.",
|
|
35
36
|
encryption_key_missing: "Este archivo ya no se puede leer. Vuelva a subirlo.",
|
package/dist/locales/es.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { VideoPlayerLabels } from '@devultur/react';
|
|
2
2
|
import { A as AttachmentLabels, M as MediaLibraryLabels, a as MediaPickerLabels, P as PreviewLabels } from '../preview-labels-C2nUUY_f.js';
|
|
3
|
-
import { D as DevulturErrorLabels } from '../error-labels-
|
|
3
|
+
import { D as DevulturErrorLabels } from '../error-labels-Sf6gow24.js';
|
|
4
4
|
import '../types-C0ruHUcu.js';
|
|
5
5
|
import '@devultur/core';
|
|
6
6
|
import 'convex/values';
|
package/dist/locales/es.js
CHANGED
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
mediaPickerLabels,
|
|
6
6
|
previewLabels,
|
|
7
7
|
videoPlayerLabels
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-34XXHYL3.js";
|
|
9
9
|
import "../chunk-QBHIZBOQ.js";
|
|
10
|
-
import "../chunk-
|
|
10
|
+
import "../chunk-V5YH4YJG.js";
|
|
11
11
|
export {
|
|
12
12
|
attachmentLabels,
|
|
13
13
|
devulturErrorLabels,
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { D as DevulturApi, b as DevulturApiContext, c as DevulturContext, d as DevulturContextValue, e as DevulturProgressContext, f as DevulturProgressContextValue, U as UploadOptions, g as UploadedMedia, u as useCanDeliver, i as useDevultur, j as useDevulturApi, k as useDevulturOptional, l as useDevulturProgress } from '../contexts-6F8TJINX.js';
|
|
2
|
+
import 'react';
|
|
3
|
+
import '@devultur/core';
|
|
4
|
+
import '@devultur/react';
|
|
5
|
+
import 'convex/server';
|
|
6
|
+
import 'convex/values';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import "../chunk-O76FU54F.js";
|
|
3
|
+
import {
|
|
4
|
+
DevulturApiContext,
|
|
5
|
+
DevulturContext,
|
|
6
|
+
DevulturProgressContext,
|
|
7
|
+
useCanDeliver,
|
|
8
|
+
useDevultur,
|
|
9
|
+
useDevulturApi,
|
|
10
|
+
useDevulturOptional,
|
|
11
|
+
useDevulturProgress
|
|
12
|
+
} from "../chunk-FOBFHC4A.js";
|
|
13
|
+
export {
|
|
14
|
+
DevulturApiContext,
|
|
15
|
+
DevulturContext,
|
|
16
|
+
DevulturProgressContext,
|
|
17
|
+
useCanDeliver,
|
|
18
|
+
useDevultur,
|
|
19
|
+
useDevulturApi,
|
|
20
|
+
useDevulturOptional,
|
|
21
|
+
useDevulturProgress
|
|
22
|
+
};
|
package/dist/react/hooks.d.ts
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
import { DevulturMedia } from '@devultur/core';
|
|
2
|
+
import { M as MediaRenderOptions } from '../contexts-6F8TJINX.js';
|
|
3
|
+
export { D as DevulturApi, b as DevulturApiContext, c as DevulturContext, d as DevulturContextValue, e as DevulturProgressContext, f as DevulturProgressContextValue, U as UploadOptions, g as UploadedMedia, u as useCanDeliver, i as useDevultur, j as useDevulturApi, k as useDevulturOptional, l as useDevulturProgress } from '../contexts-6F8TJINX.js';
|
|
2
4
|
import 'react';
|
|
3
|
-
import '@devultur/core';
|
|
4
5
|
import '@devultur/react';
|
|
5
6
|
import 'convex/server';
|
|
6
7
|
import 'convex/values';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Ready-to-use delivery URL for a key, with the context's viewer token already injected. The consumer
|
|
11
|
+
* never touches the token or the query — it only declares what it wants (download, resize, etc.).
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* <img src={useMediaUrl(key)} />
|
|
15
|
+
* <a href={useMediaUrl(key, { download: true })} download>Download</a>
|
|
16
|
+
* <img src={useMediaUrl(key, { width: 512, format: "webp" })} />
|
|
17
|
+
*/
|
|
18
|
+
declare function useMediaUrl(key: string | null | undefined, options?: MediaRenderOptions): string | null;
|
|
19
|
+
interface VideoProps {
|
|
20
|
+
src: string;
|
|
21
|
+
token: string | undefined;
|
|
22
|
+
captions: {
|
|
23
|
+
locale: string;
|
|
24
|
+
label: string;
|
|
25
|
+
src: string;
|
|
26
|
+
}[];
|
|
27
|
+
/** Session secret → `<VideoPlayer>` sends it in `${SESSION_HEADER}` on hls.js/captions requests. */
|
|
28
|
+
sessionSecret?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Token-transparent props for `<VideoPlayer>` from a video reference: builds the HLS playlist `src`,
|
|
32
|
+
* the viewer `token` (only if private), and the `captions` for the requested locales.
|
|
33
|
+
* The consumer just does `<VideoPlayer {...useVideoProps(lesson.video, { locales })} />`.
|
|
34
|
+
*/
|
|
35
|
+
declare function useVideoProps(media: DevulturMedia | null | undefined, options?: {
|
|
36
|
+
locales?: string[];
|
|
37
|
+
}): VideoProps | null;
|
|
38
|
+
|
|
39
|
+
export { type VideoProps, useMediaUrl, useVideoProps };
|
package/dist/react/hooks.js
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import {
|
|
3
|
+
useMediaUrl,
|
|
4
|
+
useVideoProps
|
|
5
|
+
} from "../chunk-AUAWZ5BD.js";
|
|
6
|
+
import "../chunk-O76FU54F.js";
|
|
2
7
|
import {
|
|
3
8
|
DevulturApiContext,
|
|
4
9
|
DevulturContext,
|
|
5
10
|
DevulturProgressContext,
|
|
11
|
+
useCanDeliver,
|
|
6
12
|
useDevultur,
|
|
7
13
|
useDevulturApi,
|
|
8
14
|
useDevulturOptional,
|
|
9
|
-
useDevulturProgress
|
|
10
|
-
|
|
11
|
-
useVideoProps
|
|
12
|
-
} from "../chunk-BDEO67OT.js";
|
|
15
|
+
useDevulturProgress
|
|
16
|
+
} from "../chunk-FOBFHC4A.js";
|
|
13
17
|
export {
|
|
14
18
|
DevulturApiContext,
|
|
15
19
|
DevulturContext,
|
|
16
20
|
DevulturProgressContext,
|
|
21
|
+
useCanDeliver,
|
|
17
22
|
useDevultur,
|
|
18
23
|
useDevulturApi,
|
|
19
24
|
useDevulturOptional,
|
package/dist/react.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { V as
|
|
3
|
-
export {
|
|
2
|
+
import { V as ViewerTokenAction, a as ViewerTokenArgs, D as DevulturApi } from './contexts-6F8TJINX.js';
|
|
3
|
+
export { b as DevulturApiContext, c as DevulturContext, d as DevulturContextValue, e as DevulturProgressContext, f as DevulturProgressContextValue, T as TokenStatus, U as UploadOptions, g as UploadedMedia, h as ViewerTokenResult, u as useCanDeliver, i as useDevultur, j as useDevulturApi, k as useDevulturOptional, l as useDevulturProgress } from './contexts-6F8TJINX.js';
|
|
4
4
|
import { BakeOutputFormat, MediaUploadState, MediaUploadError } from '@devultur/react';
|
|
5
5
|
export { MediaUploadError, MediaUploadState, UploadProgress } from '@devultur/react';
|
|
6
6
|
import { A as AttachmentLabels, b as MediaFetchError, M as MediaLibraryLabels, P as PreviewLabels, a as MediaPickerLabels } from './preview-labels-C2nUUY_f.js';
|
|
7
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
8
|
import { Visibility, DevulturMedia, MediaUrlOptions, MediaStatusValue, ProcessingPhase, FailureReason } from '@devultur/core';
|
|
9
|
+
import { VideoProps } from './react/hooks.js';
|
|
10
|
+
export { useMediaUrl, useVideoProps } from './react/hooks.js';
|
|
9
11
|
import { M as MediaRecord } from './types-C0ruHUcu.js';
|
|
10
12
|
import { P as PdfjsLoader } from './pdf-render-BwJGagvz.js';
|
|
11
13
|
export { a as PdfjsModule } from './pdf-render-BwJGagvz.js';
|
package/dist/react.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import {
|
|
3
|
+
useMediaUrl,
|
|
4
|
+
useRequestTokenWhen,
|
|
5
|
+
useVideoProps
|
|
6
|
+
} from "./chunk-AUAWZ5BD.js";
|
|
2
7
|
import {
|
|
3
8
|
mediaFromRecord
|
|
4
9
|
} from "./chunk-KAIVI7RB.js";
|
|
@@ -23,20 +28,18 @@ import {
|
|
|
23
28
|
} from "./chunk-QBHIZBOQ.js";
|
|
24
29
|
import {
|
|
25
30
|
describeDevulturError
|
|
26
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-V5YH4YJG.js";
|
|
27
32
|
import {
|
|
28
33
|
DevulturApiContext,
|
|
29
34
|
DevulturCapabilityError,
|
|
30
35
|
DevulturContext,
|
|
31
36
|
DevulturProgressContext,
|
|
37
|
+
useCanDeliver,
|
|
32
38
|
useDevultur,
|
|
33
39
|
useDevulturApi,
|
|
34
40
|
useDevulturOptional,
|
|
35
|
-
useDevulturProgress
|
|
36
|
-
|
|
37
|
-
useRequestTokenWhen,
|
|
38
|
-
useVideoProps
|
|
39
|
-
} from "./chunk-BDEO67OT.js";
|
|
41
|
+
useDevulturProgress
|
|
42
|
+
} from "./chunk-FOBFHC4A.js";
|
|
40
43
|
|
|
41
44
|
// src/react.tsx
|
|
42
45
|
import React26 from "react";
|
|
@@ -2609,6 +2612,7 @@ export {
|
|
|
2609
2612
|
formatDuration,
|
|
2610
2613
|
formatFileSize,
|
|
2611
2614
|
matchesAccept,
|
|
2615
|
+
useCanDeliver,
|
|
2612
2616
|
useDevultur,
|
|
2613
2617
|
useDevulturApi,
|
|
2614
2618
|
useDevulturMedia,
|
package/docs/guides/plugins.md
CHANGED
|
@@ -8,7 +8,7 @@ same API as yours. Add plugins to extend the Worker, or replace a default one.
|
|
|
8
8
|
import { createWorker, defaultPlugins } from "@devultur/self-host";
|
|
9
9
|
import { usageLog } from "./plugins/usage-log";
|
|
10
10
|
|
|
11
|
-
export { DownloadLink } from "@devultur/self-host";
|
|
11
|
+
export { DownloadGrants, DownloadLink } from "@devultur/self-host";
|
|
12
12
|
|
|
13
13
|
export default createWorker({
|
|
14
14
|
plugins: [...defaultPlugins({ transcode: { maxResolution: "1080p" } }), usageLog()],
|
|
@@ -22,7 +22,7 @@ export default createWorker({
|
|
|
22
22
|
| `staticConfig(config)` | Applies the [rules](self-host.md#rules) to every request. Put it first: later plugins narrow it. |
|
|
23
23
|
| `workerSecretAuth()` | Control routes require `Authorization: Bearer <WORKER_AUTH_SECRET>`; the transcode runner uploads with the same secret. |
|
|
24
24
|
| `credentialPolicy(options?)` | Decides before a credential is issued. Without options it issues what is asked; `maxTtlSeconds: { viewer: 3600 }` caps a kind. |
|
|
25
|
-
| `downloadLinks()` | `POST /v1/token/download` and `GET /v1/download/<id>` (needs the `DOWNLOAD_LINKS` Durable Object). Without it
|
|
25
|
+
| `downloadLinks()` | `POST /v1/token/download` and `GET /v1/download/<id>` (needs the `DOWNLOAD_LINKS` Durable Object), and download grants: `/v1/token/grant` and `/v1/grant/*` (also need `DOWNLOAD_GRANTS`). Without it they answer `404`. |
|
|
26
26
|
|
|
27
27
|
`createWorker()` refuses to start when no plugin authenticates requests, so dropping `workerSecretAuth()` without
|
|
28
28
|
an auth plugin of yours fails at deploy, not in production.
|
|
@@ -42,6 +42,7 @@ interface WorkerPlugin {
|
|
|
42
42
|
routes?: Array<{ path: string; app: Hono }>;
|
|
43
43
|
issueCredential?: (context: Context, request: CredentialRequest) => CredentialDecision | Promise<CredentialDecision>;
|
|
44
44
|
beforeLinkRedeem?: (context: Context, link: DownloadLinkInfo) => Response | null | Promise<Response | null>;
|
|
45
|
+
authorizeGrant?: (context: Context, request: GrantAccessRequest) => Response | null | Promise<Response | null>;
|
|
45
46
|
authorizeLockChange?: (context: Context, request: LockChangeRequest) => LockChangeDecision | Promise<LockChangeDecision>;
|
|
46
47
|
onLockAudit?: (context: Context, record: LockAuditRecord) => void | Promise<void>;
|
|
47
48
|
}
|
|
@@ -94,8 +95,8 @@ updateRequestState(context, { context: { appId: "web" } });
|
|
|
94
95
|
|
|
95
96
|
## Hooks
|
|
96
97
|
|
|
97
|
-
**`issueCredential`** runs before the Worker issues a viewer token, an upload token, a download link
|
|
98
|
-
service token. It gets the `kind`, the `scopes`, the `path` it is bound to and the requested `expiresAt` (epoch ms).
|
|
98
|
+
**`issueCredential`** runs before the Worker issues a viewer token, an upload token, a download link, a download grant
|
|
99
|
+
or the runner's service token. It gets the `kind`, the `scopes`, the `path` it is bound to and the requested `expiresAt` (epoch ms).
|
|
99
100
|
Return `{ allow: false, response }` to refuse, or `{ allow: true, expiresAt?, claims? }` to issue it: `expiresAt`
|
|
100
101
|
caps the expiry, and `claims` are added to a token. The hooks of every plugin run in order: the first refusal wins,
|
|
101
102
|
the earliest `expiresAt` applies, and the claims of all of them are added.
|
|
@@ -120,6 +121,12 @@ allow gets `403 { "code": "token_rejected" }`; which claim failed is only logged
|
|
|
120
121
|
**`beforeLinkRedeem`** runs before `GET /v1/download/<id>` spends a use of a link. Return a `Response` to refuse it
|
|
121
122
|
(the use isn't spent), or `null` to let it go on. It gets the link's `storagePrefix`, `key` and plugin `context`.
|
|
122
123
|
|
|
124
|
+
**`authorizeGrant`** runs before a download grant is used, once the Worker checked the grant is live and belongs to the
|
|
125
|
+
request's storage prefix: `action` is `head`, `issue-link`, `delete-file` or `revoke` (its bearer), or `owner-revoke`
|
|
126
|
+
(the owner, by its public id). It also gets the `grant` (its key, caps, `linksIssued`, metadata and the plugin `context`
|
|
127
|
+
it was issued with, never its secret). Return a `Response` to refuse (a refused link spends nothing), or `null`. Use it
|
|
128
|
+
to tie a grant to the credential that issued it, for example to refuse it once that credential is revoked.
|
|
129
|
+
|
|
123
130
|
**`authorizeLockChange`** runs before the Worker changes a lock ([Retention and holds](object-lock.md)):
|
|
124
131
|
`PUT /v1/lock/<key>` once per change, and `POST /v1/lock/hold` once per page. It gets:
|
|
125
132
|
|
|
@@ -173,7 +180,8 @@ const auditToD1: WorkerPlugin = {
|
|
|
173
180
|
## After the route
|
|
174
181
|
|
|
175
182
|
- `getRouteResult(context)` tells a middleware that runs after `await next()` what the route did: `redeemedLink`
|
|
176
|
-
(the download link just redeemed), `
|
|
183
|
+
(the download link just redeemed), `issuedGrant` and `revokedGrant` (a download grant, with its public id; a revoke
|
|
184
|
+
says `by: "bearer"` or `"owner"`), `grantDeletedKey` (a grant deleted its file), `originalDeleted` (`transcode.complete` deleted the original),
|
|
177
185
|
`originalRetained` (it kept a locked original instead) and
|
|
178
186
|
`transcodeJob` (the job a runner callback belongs to, with its plugin `context`).
|
|
179
187
|
- `getPendingUpload(context)`, before the route, returns the upload an upload URL points to: its key, storage key,
|
package/docs/guides/self-host.md
CHANGED
|
@@ -44,7 +44,7 @@ media Worker from `@devultur/self-host`:
|
|
|
44
44
|
|
|
45
45
|
```typescript
|
|
46
46
|
import { createWorker } from "@devultur/self-host";
|
|
47
|
-
export { DownloadLink } from "@devultur/self-host";
|
|
47
|
+
export { DownloadGrants, DownloadLink } from "@devultur/self-host";
|
|
48
48
|
|
|
49
49
|
export default createWorker();
|
|
50
50
|
```
|
|
@@ -98,7 +98,7 @@ It prints a config snippet with the new namespace's `id`. Paste that id into the
|
|
|
98
98
|
|
|
99
99
|
#### 4. Write `wrangler.toml`
|
|
100
100
|
|
|
101
|
-
Bind both buckets, the KV namespace and the `DownloadLink` Durable
|
|
101
|
+
Bind both buckets, the KV namespace and the `DownloadLink` and `DownloadGrants` Durable Objects:
|
|
102
102
|
|
|
103
103
|
```toml
|
|
104
104
|
name = "media"
|
|
@@ -123,13 +123,22 @@ id = "<kv-namespace-id>"
|
|
|
123
123
|
name = "DOWNLOAD_LINKS"
|
|
124
124
|
class_name = "DownloadLink"
|
|
125
125
|
|
|
126
|
+
[[durable_objects.bindings]]
|
|
127
|
+
name = "DOWNLOAD_GRANTS"
|
|
128
|
+
class_name = "DownloadGrants"
|
|
129
|
+
|
|
126
130
|
[[migrations]]
|
|
127
131
|
tag = "v1"
|
|
128
132
|
new_sqlite_classes = ["DownloadLink"]
|
|
133
|
+
|
|
134
|
+
[[migrations]]
|
|
135
|
+
tag = "v2"
|
|
136
|
+
new_sqlite_classes = ["DownloadGrants"]
|
|
129
137
|
```
|
|
130
138
|
|
|
131
|
-
Without the `DOWNLOAD_LINKS` binding, `POST /v1/token/download` answers `501
|
|
132
|
-
|
|
139
|
+
Without the `DOWNLOAD_LINKS` binding, `POST /v1/token/download` answers `501`; without `DOWNLOAD_GRANTS`, the download
|
|
140
|
+
grant routes do. A Worker deployed before download grants keeps its `v1` migration and adds `v2`. For staging and
|
|
141
|
+
production in one file, see [Per-environment config](#per-environment-config).
|
|
133
142
|
|
|
134
143
|
#### 5. Set the secrets
|
|
135
144
|
|
|
@@ -189,6 +198,10 @@ account_id = "<your-account-id>"
|
|
|
189
198
|
tag = "v1"
|
|
190
199
|
new_sqlite_classes = ["DownloadLink"]
|
|
191
200
|
|
|
201
|
+
[[migrations]]
|
|
202
|
+
tag = "v2"
|
|
203
|
+
new_sqlite_classes = ["DownloadGrants"]
|
|
204
|
+
|
|
192
205
|
# Staging
|
|
193
206
|
[env.staging]
|
|
194
207
|
name = "media-staging"
|
|
@@ -209,6 +222,10 @@ id = "<staging-kv-namespace-id>"
|
|
|
209
222
|
name = "DOWNLOAD_LINKS"
|
|
210
223
|
class_name = "DownloadLink"
|
|
211
224
|
|
|
225
|
+
[[env.staging.durable_objects.bindings]]
|
|
226
|
+
name = "DOWNLOAD_GRANTS"
|
|
227
|
+
class_name = "DownloadGrants"
|
|
228
|
+
|
|
212
229
|
# Production
|
|
213
230
|
[env.production]
|
|
214
231
|
name = "media-production"
|
|
@@ -228,6 +245,10 @@ id = "<production-kv-namespace-id>"
|
|
|
228
245
|
[[env.production.durable_objects.bindings]]
|
|
229
246
|
name = "DOWNLOAD_LINKS"
|
|
230
247
|
class_name = "DownloadLink"
|
|
248
|
+
|
|
249
|
+
[[env.production.durable_objects.bindings]]
|
|
250
|
+
name = "DOWNLOAD_GRANTS"
|
|
251
|
+
class_name = "DownloadGrants"
|
|
231
252
|
```
|
|
232
253
|
|
|
233
254
|
`vars` aren't inherited either: repeat `[env.<name>.vars]` (for example `TRANSCODE_RUNNER`) in each one. Then set
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devultur/convex",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Convex component for Devultur media: media records, uploads, transcodes, watch progress and React bindings",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"convex",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
"docs"
|
|
70
70
|
],
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@devultur/core": "1.
|
|
73
|
-
"@devultur/react": "1.
|
|
72
|
+
"@devultur/core": "1.6.0",
|
|
73
|
+
"@devultur/react": "1.6.0"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"convex": ">=1.25.0",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"access": "public"
|
|
103
103
|
},
|
|
104
104
|
"scripts": {
|
|
105
|
-
"build": "tsup src/index.ts src/validators.ts src/react.tsx src/react/hooks.ts src/pdfjs.ts src/locales/es.ts src/locales/es-formal.ts src/bin/init.ts --format esm --dts --clean && tsc -p src/component/tsconfig.json && node scripts/add-import-extensions.ts && node ../../scripts/copy-guides.mts",
|
|
105
|
+
"build": "tsup src/index.ts src/validators.ts src/react.tsx src/react/hooks.ts src/react/contexts.ts src/pdfjs.ts src/locales/es.ts src/locales/es-formal.ts src/bin/init.ts --format esm --dts --clean && tsc -p src/component/tsconfig.json && node scripts/add-import-extensions.ts && node ../../scripts/copy-guides.mts",
|
|
106
106
|
"codegen": "node scripts/codegen.ts",
|
|
107
107
|
"dev": "tsup src/index.ts src/react.tsx --format esm --dts --watch",
|
|
108
108
|
"typecheck": "tsc --noEmit"
|