@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/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { ObjectLock, LockView, SetLockOptions, HoldPage, DevulturMedia } from '@devultur/core';
1
+ import { WorkerUploadResult, DeleteVideoResult, TranscodeJobResult, ObjectLock, LockView, SetLockOptions, HoldPage, DevulturMedia } from '@devultur/core';
2
2
  export { CaptionLocale, DevulturConfig, DevulturKind, DevulturMedia, ImageFit, ImageFormat, SecurityLevel, SpeechProvider, StorageProvider, TranscodePreset, TranscodeProvider, TranslationProvider, VideoModuleConfig, Visibility } from '@devultur/core';
3
- import { FunctionReference, FunctionVisibility, DefaultFunctionArgs, GenericQueryCtx, GenericDataModel, GenericMutationCtx, GenericActionCtx, RegisteredQuery, RegisteredMutation, RegisteredAction, PaginationOptions, PaginationResult } from 'convex/server';
3
+ import { FunctionReference, PaginationResult, FunctionVisibility, DefaultFunctionArgs, GenericQueryCtx, GenericDataModel, GenericMutationCtx, GenericActionCtx, RegisteredQuery, RegisteredMutation, RegisteredAction, PaginationOptions } from 'convex/server';
4
4
  import { PropertyValidators, Value, ConvexError } from 'convex/values';
5
- import { D as DevulturComponentConfig, M as MediaRecord } from './types-DZxN6Eij.js';
6
- export { P as ProgressRecord } from './types-DZxN6Eij.js';
5
+ import { M as MediaRecord, P as ProgressRecord, D as DevulturComponentConfig } from './types-C0ruHUcu.js';
6
+ export { a as DevulturUploadConfig } from './types-C0ruHUcu.js';
7
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-D0Vbp-qA.js';
8
8
  export { dv } from './validators.js';
9
9
 
@@ -188,6 +188,42 @@ type ComponentApi<Name extends string | undefined = string | undefined> = {
188
188
  };
189
189
  };
190
190
 
191
+ /** Convex's system fields on a document a component returns. Its `_id` is a plain string in your app. */
192
+ interface ComponentSystemFields {
193
+ _id: string;
194
+ _creationTime: number;
195
+ }
196
+ /** A media record as the component's functions return it: the stored fields and the system fields. */
197
+ interface MediaDocument extends MediaRecord, ComponentSystemFields {
198
+ }
199
+ /** A watch-progress record as the component's functions return it. */
200
+ interface ProgressDocument extends ProgressRecord, ComponentSystemFields {
201
+ }
202
+ /** The result of each exposed function, by name. */
203
+ interface DevulturFunctionResults {
204
+ issueViewerToken: {
205
+ token: string;
206
+ expiresIn: number;
207
+ };
208
+ createUploadUrl: WorkerUploadResult;
209
+ /** The record, or `null` when nothing is stored at the key. */
210
+ confirmUpload: MediaDocument | null;
211
+ /** The updated record, or `null` when there is none. */
212
+ updateMediaMeta: MediaDocument | null;
213
+ deleteMedia: null;
214
+ deleteVideo: DeleteVideoResult;
215
+ processVideo: TranscodeJobResult;
216
+ getMedia: MediaDocument | null;
217
+ listMediaPage: PaginationResult<MediaDocument>;
218
+ searchMedia: PaginationResult<MediaDocument>;
219
+ /** The progress record's id. */
220
+ saveProgress: string;
221
+ loadProgress: ProgressDocument | null;
222
+ /** The progress record's id. */
223
+ markComplete: string;
224
+ resetProgress: null;
225
+ }
226
+
191
227
  type FunctionKind = "query" | "mutation" | "action";
192
228
  type ContextOf<Kind extends FunctionKind> = Kind extends "query" ? GenericQueryCtx<GenericDataModel> : Kind extends "mutation" ? GenericMutationCtx<GenericDataModel> : GenericActionCtx<GenericDataModel>;
193
229
  /** What a guard tells the function about its caller. */
@@ -283,10 +319,10 @@ declare function exposedFunctions(component: ComponentApi, config?: DevulturComp
283
319
  };
284
320
  type ExposedFunctions = ReturnType<typeof exposedFunctions>;
285
321
  type ExposedFunctionName = keyof ExposedFunctions;
286
- type Registered<Fn, Visibility extends FunctionVisibility> = Fn extends ExposedFunction<"query", infer Args, infer Result> ? RegisteredQuery<Visibility, Args, Promise<Result>> : Fn extends ExposedFunction<"mutation", infer Args, infer Result> ? RegisteredMutation<Visibility, Args, Promise<Result>> : Fn extends ExposedFunction<"action", infer Args, infer Result> ? RegisteredAction<Visibility, Args, Promise<Result>> : never;
322
+ type Registered<Fn, Visibility extends FunctionVisibility, Result> = Fn extends ExposedFunction<"query", infer Args, unknown> ? RegisteredQuery<Visibility, Args, Promise<Result>> : Fn extends ExposedFunction<"mutation", infer Args, unknown> ? RegisteredMutation<Visibility, Args, Promise<Result>> : Fn extends ExposedFunction<"action", infer Args, unknown> ? RegisteredAction<Visibility, Args, Promise<Result>> : never;
287
323
  /** The Convex functions registered from `ExposedFunctions`, each with its own args and result. */
288
324
  type RegisteredFunctions<Visibility extends FunctionVisibility> = {
289
- [Name in ExposedFunctionName]: Registered<ExposedFunctions[Name], Visibility>;
325
+ [Name in ExposedFunctionName]: Registered<ExposedFunctions[Name], Visibility, DevulturFunctionResults[Name]>;
290
326
  };
291
327
 
292
328
  type DevulturComponent = ComponentApi;
@@ -329,34 +365,35 @@ declare class Devultur {
329
365
  /** The mounted component (`components.devultur`) this client calls. */
330
366
  readonly component: DevulturComponent;
331
367
  constructor(component: DevulturComponent);
332
- getMedia(ctx: QueryCtx, key: string): Promise<any>;
368
+ getMedia(ctx: QueryCtx, key: string): Promise<MediaDocument | null>;
369
+ /** Returns the progress record's id. */
333
370
  saveProgress(ctx: MutationCtx, args: {
334
371
  userId: string;
335
372
  videoId: string;
336
373
  position: number;
337
- }): Promise<any>;
374
+ }): Promise<string>;
338
375
  loadProgress(ctx: QueryCtx, args: {
339
376
  userId: string;
340
377
  videoId: string;
341
- }): Promise<any>;
378
+ }): Promise<ProgressDocument | null>;
342
379
  /** An upload URL from your server, optionally locked (retention and/or hold, written with the bytes). */
343
380
  createUploadUrl(ctx: ActionCtx, args: UploadUrlArgs & {
344
381
  lock?: ObjectLock;
345
382
  hold?: boolean;
346
- }): Promise<any>;
383
+ }): Promise<DevulturFunctionResults["createUploadUrl"]>;
347
384
  /**
348
385
  * Records an upload in the component once its bytes are stored (after the PUT): it then shows in `listMedia`.
349
386
  * Returns the record, or `null` when nothing is stored at `key`. Uploads nobody confirms are recorded a day later.
350
387
  * `width`, `height` and `pageCount` are the client's hints (positive integers up to 100,000); an image size the
351
388
  * Worker read from the bytes wins over them.
352
389
  */
353
- confirmUpload(ctx: ActionCtx, args: ConfirmUploadArgs): Promise<MediaRecord | null>;
390
+ confirmUpload(ctx: ActionCtx, args: ConfirmUploadArgs): Promise<MediaDocument | null>;
354
391
  /**
355
392
  * Sets a record's `title`, `alt` and/or `tags` (only the ones passed; an empty string clears a title or alt, `[]`
356
393
  * the tags). `key` is the media id. Trimmed and deduplicated; past title 200, alt 1000 or 20 tags of 50 characters
357
394
  * it throws `invalid_media_metadata`. Returns the updated record, or `null` when there is none.
358
395
  */
359
- updateMediaMeta(ctx: MutationCtx, args: MediaMetaArgs): Promise<MediaRecord | null>;
396
+ updateMediaMeta(ctx: MutationCtx, args: MediaMetaArgs): Promise<MediaDocument | null>;
360
397
  /**
361
398
  * The recorded media (every confirmed upload, and every video sent to `processVideo`), optionally of one type.
362
399
  * `mediaFromRecord(record)` turns a row into the reference `<Image>` and `dv.media()` take. Unbounded: it reads every
@@ -364,15 +401,15 @@ declare class Devultur {
364
401
  */
365
402
  listMedia(ctx: QueryCtx, args?: {
366
403
  type?: MediaType;
367
- }): Promise<MediaRecord[]>;
404
+ }): Promise<MediaDocument[]>;
368
405
  /** One page of the recorded media, newest first, optionally of one type. Takes Convex's `paginationOpts`. */
369
- listMediaPage(ctx: QueryCtx, args: MediaPageArgs): Promise<PaginationResult<MediaRecord>>;
406
+ listMediaPage(ctx: QueryCtx, args: MediaPageArgs): Promise<PaginationResult<MediaDocument>>;
370
407
  /**
371
408
  * One page of the records whose title or filename matches `search` (its last word as a prefix), best match first,
372
409
  * optionally of one type. A blank `search` lists newest first, like `listMediaPage`. Records from before 1.4.0
373
410
  * match once `backfillSearchText` (or any write) gives them a `searchText`.
374
411
  */
375
- searchMedia(ctx: QueryCtx, args: SearchMediaArgs): Promise<PaginationResult<MediaRecord>>;
412
+ searchMedia(ctx: QueryCtx, args: SearchMediaArgs): Promise<PaginationResult<MediaDocument>>;
376
413
  /**
377
414
  * One-off for records written before 1.4.0: gives every record without a `searchText` one, `batchSize` records
378
415
  * per mutation (default 100, at most 1000). Runs the first batch and schedules the rest. Safe to run again.
@@ -430,15 +467,32 @@ type DevulturGuardCtx<DataModel extends GenericDataModel = any> = GenericQueryCt
430
467
  /**
431
468
  * Throws to deny the call. May return what it learned about the caller: a `userId` becomes the subject of the token
432
469
  * `issueViewerToken` issues, and the only user the progress functions act for (another `userId` in their arguments is
433
- * refused with `user_mismatch`, unless the guard also returns `canActForOthers: true`).
470
+ * refused with `user_mismatch`, unless the guard also returns `canActForOthers: true`). May also return a `rewrite` of
471
+ * the caller's arguments (see `DevulturArgsRewrite`).
434
472
  */
435
- type DevulturGuard = (ctx: DevulturGuardCtx, operation: DevulturOperation) => GuardResult | Promise<GuardResult>;
436
- type GuardResult = CallerContext | undefined | void;
473
+ type DevulturGuard = (ctx: DevulturGuardCtx, operation: DevulturOperation) => DevulturGuardResult | Promise<DevulturGuardResult>;
474
+ /**
475
+ * Arguments a guard rewrites, on your server, before the function runs: each key of `args` replaces the caller's
476
+ * argument of that name. `name` is the operation's, so `args` are typed for it:
477
+ * `{ name: "createUploadUrl", args: { visibility: "private" } }` uploads privately whatever the browser asked for.
478
+ * A rewrite named for another operation than the one being guarded throws. The rewritten arguments aren't validated
479
+ * again.
480
+ */
481
+ type DevulturArgsRewrite = {
482
+ [Name in ExposedFunctionName]: {
483
+ name: Name;
484
+ args: Partial<ArgsOf<ExposedFunctions[Name]>>;
485
+ };
486
+ }[ExposedFunctionName];
487
+ /** What a guard returns: what it learned about the caller, and the arguments it rewrites. */
488
+ type DevulturGuardResult = (CallerContext & {
489
+ rewrite?: DevulturArgsRewrite;
490
+ }) | undefined | void;
437
491
  interface DevulturFunctionsOptions<Visibility extends FunctionVisibility> {
438
492
  guard: DevulturGuard;
439
493
  /** `"internal"` registers them as internal functions (callable from your server only). Default `"public"`. */
440
494
  visibility?: Visibility;
441
- /** Same as `Devultur.exposeApi`'s: the transcode preset, caption locales and upload lock. */
495
+ /** Same as `Devultur.exposeApi`'s: the transcode preset, caption locales, upload lock and default visibility. */
442
496
  config?: DevulturComponentConfig;
443
497
  }
444
498
  /** `Devultur.exposeApi`'s functions, each calling `options.guard` before it runs. Export the ones your app uses. */
@@ -451,4 +505,4 @@ declare function defineDevulturFunctions<Visibility extends FunctionVisibility =
451
505
  */
452
506
  declare function mediaFromRecord(record: MediaRecord): DevulturMedia | null;
453
507
 
454
- export { type CallerContext, Devultur, DevulturComponentConfig, type DevulturErrorData, type DevulturFunctionsOptions, type DevulturGuard, type DevulturGuardCtx, type DevulturOperation, MediaRecord, type RegisteredFunctions, defineDevulturFunctions, devulturErrorOf, isDevulturError, mediaFromRecord };
508
+ export { type CallerContext, type ComponentSystemFields, Devultur, type DevulturArgsRewrite, DevulturComponentConfig, type DevulturErrorData, type DevulturFunctionResults, type DevulturFunctionsOptions, type DevulturGuard, type DevulturGuardCtx, type DevulturGuardResult, type DevulturOperation, type MediaDocument, MediaRecord, type ProgressDocument, ProgressRecord, type RegisteredFunctions, defineDevulturFunctions, devulturErrorOf, isDevulturError, mediaFromRecord };
package/dist/index.js CHANGED
@@ -53,12 +53,16 @@ function progressArgsFor(args, caller) {
53
53
  });
54
54
  }
55
55
  function mediaIdOf(key) {
56
+ if (typeof key !== "string") {
57
+ throw new ConvexError({ code: "invalid_key", message: "The media key must be a string", status: 400 });
58
+ }
56
59
  return key.includes("/") ? extractId(key) : key;
57
60
  }
58
61
  function exposedFunctions(component, config) {
59
62
  const preset = config?.video?.transcodePreset;
60
63
  const locales = config?.video?.captionLocales ?? [];
61
64
  const uploadLock = config?.upload?.lock;
65
+ const defaultVisibility = config?.upload?.visibility;
62
66
  return {
63
67
  issueViewerToken: exposed(
64
68
  "action",
@@ -68,11 +72,18 @@ function exposedFunctions(component, config) {
68
72
  ...caller.userId ? { userId: caller.userId } : {}
69
73
  })
70
74
  ),
71
- // Optional per-resource visibility; omitted → the component resolves the config's default (secure-by-default).
75
+ // Visibility: the caller's (after the guard's rewrite), else `config.upload.visibility`, else the Worker's default.
72
76
  createUploadUrl: exposed(
73
77
  "action",
74
78
  { filename: v.string(), contentType: v.string(), visibility: visibilityArg },
75
- async (ctx, args) => ctx.runAction(component.public.createUploadUrl, { ...args, ...uploadLock ? { lock: uploadLock } : {} })
79
+ async (ctx, args) => {
80
+ const visibility = args.visibility ?? defaultVisibility;
81
+ return ctx.runAction(component.public.createUploadUrl, {
82
+ ...args,
83
+ ...visibility ? { visibility } : {},
84
+ ...uploadLock ? { lock: uploadLock } : {}
85
+ });
86
+ }
76
87
  ),
77
88
  // Records an upload once its bytes are stored (the Worker HEADs the key): a browser can't list anything
78
89
  // that isn't in your bucket. `useDevultur().upload()` and `useMediaUpload` call it after the PUT.
@@ -175,6 +186,7 @@ var Devultur = class {
175
186
  async getMedia(ctx, key) {
176
187
  return ctx.runQuery(this.component.public.getMediaByKey, { key });
177
188
  }
189
+ /** Returns the progress record's id. */
178
190
  async saveProgress(ctx, args) {
179
191
  return ctx.runMutation(this.component.public.saveProgress, args);
180
192
  }
@@ -263,11 +275,18 @@ function defineDevulturFunctions(devultur, options) {
263
275
  return registerFunctions(exposedFunctions(devultur.component, config), visibility, (name, fn) => {
264
276
  return async (ctx, args) => {
265
277
  const operation = { name, kind: fn.kind, args };
266
- const caller = await guard(ctx, operation) ?? {};
267
- return fn.handler(ctx, args, caller);
278
+ const { rewrite, ...caller } = await guard(ctx, operation) ?? {};
279
+ return fn.handler(ctx, rewrittenArgs(name, args, rewrite), caller);
268
280
  };
269
281
  });
270
282
  }
283
+ function rewrittenArgs(name, args, rewrite) {
284
+ if (!rewrite) return args;
285
+ if (rewrite.name !== name) {
286
+ throw new Error(`The guard rewrote ${rewrite.name}'s arguments while guarding ${name}`);
287
+ }
288
+ return { ...args, ...rewrite.args };
289
+ }
271
290
  export {
272
291
  CaptionLocale,
273
292
  DEVULTUR_ERROR_CODES,
@@ -1,6 +1,7 @@
1
- import { A as AttachmentLabels, M as MediaLibraryLabels, a as MediaPickerLabels, P as PreviewLabels } from '../preview-labels-B7HNa7Va.js';
1
+ import { VideoPlayerLabels } from '@devultur/react';
2
+ import { A as AttachmentLabels, M as MediaLibraryLabels, a as MediaPickerLabels, P as PreviewLabels } from '../preview-labels-C2nUUY_f.js';
2
3
  import { D as DevulturErrorLabels } from '../error-labels-D0Vbp-qA.js';
3
- import '../types-DZxN6Eij.js';
4
+ import '../types-C0ruHUcu.js';
4
5
  import '@devultur/core';
5
6
  import 'convex/values';
6
7
  import 'convex/server';
@@ -10,5 +11,6 @@ declare const attachmentLabels: AttachmentLabels;
10
11
  declare const previewLabels: PreviewLabels;
11
12
  declare const mediaLibraryLabels: MediaLibraryLabels;
12
13
  declare const mediaPickerLabels: MediaPickerLabels;
14
+ declare const videoPlayerLabels: VideoPlayerLabels;
13
15
 
14
- export { attachmentLabels, devulturErrorLabels, mediaLibraryLabels, mediaPickerLabels, previewLabels };
16
+ export { attachmentLabels, devulturErrorLabels, mediaLibraryLabels, mediaPickerLabels, previewLabels, videoPlayerLabels };
@@ -3,8 +3,9 @@ import {
3
3
  devulturErrorLabels,
4
4
  mediaLibraryLabels,
5
5
  mediaPickerLabels,
6
- previewLabels
7
- } from "../chunk-JZYKPLI4.js";
6
+ previewLabels,
7
+ videoPlayerLabels
8
+ } from "../chunk-RDVBE3G3.js";
8
9
  import "../chunk-QBHIZBOQ.js";
9
10
  import {
10
11
  describeDevulturError,
@@ -55,10 +56,12 @@ var mediaPickerLabels2 = {
55
56
  dropHint: (multiple) => multiple ? "o suelte los archivos aqu\xED" : "o suelte un archivo aqu\xED",
56
57
  uploadError: (error) => describeDevulturError(error, devulturErrorLabels2) ?? `La subida fall\xF3. ${TRY_AGAIN}`
57
58
  };
59
+ var videoPlayerLabels2 = videoPlayerLabels;
58
60
  export {
59
61
  attachmentLabels2 as attachmentLabels,
60
62
  devulturErrorLabels2 as devulturErrorLabels,
61
63
  mediaLibraryLabels2 as mediaLibraryLabels,
62
64
  mediaPickerLabels2 as mediaPickerLabels,
63
- previewLabels2 as previewLabels
65
+ previewLabels2 as previewLabels,
66
+ videoPlayerLabels2 as videoPlayerLabels
64
67
  };
@@ -1,6 +1,7 @@
1
- import { A as AttachmentLabels, M as MediaLibraryLabels, a as MediaPickerLabels, P as PreviewLabels } from '../preview-labels-B7HNa7Va.js';
1
+ import { VideoPlayerLabels } from '@devultur/react';
2
+ import { A as AttachmentLabels, M as MediaLibraryLabels, a as MediaPickerLabels, P as PreviewLabels } from '../preview-labels-C2nUUY_f.js';
2
3
  import { D as DevulturErrorLabels } from '../error-labels-D0Vbp-qA.js';
3
- import '../types-DZxN6Eij.js';
4
+ import '../types-C0ruHUcu.js';
4
5
  import '@devultur/core';
5
6
  import 'convex/values';
6
7
  import 'convex/server';
@@ -10,5 +11,6 @@ declare const previewLabels: PreviewLabels;
10
11
  declare const attachmentLabels: AttachmentLabels;
11
12
  declare const mediaLibraryLabels: MediaLibraryLabels;
12
13
  declare const mediaPickerLabels: MediaPickerLabels;
14
+ declare const videoPlayerLabels: VideoPlayerLabels;
13
15
 
14
- export { attachmentLabels, devulturErrorLabels, mediaLibraryLabels, mediaPickerLabels, previewLabels };
16
+ export { attachmentLabels, devulturErrorLabels, mediaLibraryLabels, mediaPickerLabels, previewLabels, videoPlayerLabels };
@@ -3,8 +3,9 @@ import {
3
3
  devulturErrorLabels,
4
4
  mediaLibraryLabels,
5
5
  mediaPickerLabels,
6
- previewLabels
7
- } from "../chunk-JZYKPLI4.js";
6
+ previewLabels,
7
+ videoPlayerLabels
8
+ } from "../chunk-RDVBE3G3.js";
8
9
  import "../chunk-QBHIZBOQ.js";
9
10
  import "../chunk-YYOZ3PDH.js";
10
11
  export {
@@ -12,5 +13,6 @@ export {
12
13
  devulturErrorLabels,
13
14
  mediaLibraryLabels,
14
15
  mediaPickerLabels,
15
- previewLabels
16
+ previewLabels,
17
+ videoPlayerLabels
16
18
  };
@@ -1,4 +1,4 @@
1
- import { M as MediaRecord } from './types-DZxN6Eij.js';
1
+ import { M as MediaRecord } from './types-C0ruHUcu.js';
2
2
 
3
3
  /** What an attachment is, for its icon and type label. */
4
4
  type AttachmentKind = "image" | "video" | "pdf" | "audio" | "text" | "file";
@@ -0,0 +1,6 @@
1
+ export { D as DevulturApi, c as DevulturApiContext, d as DevulturContext, e as DevulturContextValue, f as DevulturProgressContext, g as DevulturProgressContextValue, U as UploadOptions, h as UploadedMedia, V as VideoProps, u as useDevultur, j as useDevulturApi, k as useDevulturOptional, l as useDevulturProgress, m as useMediaUrl, n as useVideoProps } from '../hooks-uqpBd5UF.js';
2
+ import 'react';
3
+ import '@devultur/core';
4
+ import '@devultur/react';
5
+ import 'convex/server';
6
+ import 'convex/values';
@@ -0,0 +1,23 @@
1
+ "use client";
2
+ import {
3
+ DevulturApiContext,
4
+ DevulturContext,
5
+ DevulturProgressContext,
6
+ useDevultur,
7
+ useDevulturApi,
8
+ useDevulturOptional,
9
+ useDevulturProgress,
10
+ useMediaUrl,
11
+ useVideoProps
12
+ } from "../chunk-BDEO67OT.js";
13
+ export {
14
+ DevulturApiContext,
15
+ DevulturContext,
16
+ DevulturProgressContext,
17
+ useDevultur,
18
+ useDevulturApi,
19
+ useDevulturOptional,
20
+ useDevulturProgress,
21
+ useMediaUrl,
22
+ useVideoProps
23
+ };